Val Town email subscriptions: daily stats

Cousin Val to @petermillspaugh/emailSubscription for emailing yourself daily subscriber stats.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/** @jsxImportSource https://esm.sh/preact */
import { email } from "https://esm.town/v/std/email?v=11";
import { sqlite } from "https://esm.town/v/std/sqlite?v=4";
import { render } from "npm:preact-render-to-string";
type SubscriberRow = [
name: string,
email: string,
];
type VerifiedStats = [
verified: 0 | 1,
totalSubs: number,
];
export async function dailyEmailSubscriptionStats(interval: Interval) {
const { rows: newSubs } = await sqlite.execute(`
SELECT name, email
FROM subscribers
WHERE subscribed_at > datetime('now', '-1 day')
AND verified = 1;
`) as unknown as { rows: SubscriberRow[] };
const { rows: verifiedStats } = await sqlite.execute(`
SELECT verified, COUNT(*) as total_subs
FROM subscribers
GROUP BY verified;
`) as unknown as { rows: VerifiedStats[] };
const nonVerifiedSubs = verifiedStats[0][1];
const verifiedSubs = verifiedStats[1][1];
const markup = render(
<main>
<h1>New subscribers since yesterday</h1>
<ul style={{ padding: "0px" }}>
{newSubs.map(([name, email]) => <li key={email}>{name} ({email})</li>)}
</ul>
<p>Total verified subscribers: {verifiedSubs}</p>
<p>Total non-verified subscribers: {nonVerifiedSubs}</p>
</main>,
);
const today = new Date().toLocaleDateString("en-US", { month: "2-digit", day: "2-digit" });
email({
subject: `Daily subscriber stats for petemillspaugh.com (${today})`,
html: markup,
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { email } from "https://esm.town/v/std/email?v=9";
// Fetches a random joke.
async function fetchRandomJoke() {
const response = await fetch(
"https://official-joke-api.appspot.com/random_joke",
);
return response.json();
}
const randomJoke = await fetchRandomJoke();
const setup = randomJoke.setup;
const punchline = randomJoke.punchline;
// Sends an email with the joke.
export const emailRandomJoke = email({
text: punchline,
subject: setup,
});
Runs every 1 days
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { email } from "https://esm.town/v/std/email?v=9";
// Fetches a random joke.
const fetchRandomJoke = async () => {
const response = await fetch(
"https://official-joke-api.appspot.com/random_joke",
);
return response.json();
};
const randomJoke = await fetchRandomJoke();
const setup = randomJoke.setup;
const punchline = randomJoke.punchline;
// Sends an email with the joke.
export const emailRandomJoke = email({
text: punchline,
subject: setup,
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { email } from "https://esm.town/v/std/email?v=9";
// export const SAMPLE_JOKE = {
// "setup": "What do you call a group of disorganized cats?",
// "punchline": "A cat-tastrophe.",
// };
// Fetches a random joke.
// function fetchRandomJoke() {
// const SAMPLE_JOKE = {
// "setup": "What do you call a group of disorganized cats?",
// "punchline": "A cat-tastrophe.",
// };
//
// return SAMPLE_JOKE;
// }
// Fetches a random joke.
// Fetches a random joke.
async function fetchRandomJoke() {
const response = await fetch(
"https://official-joke-api.appspot.com/random_joke",
);
return response.json();
}
const randomJoke = await fetchRandomJoke();
const setup = randomJoke.setup;
const punchline = randomJoke.punchline;
// Sends an email with the joke.
export const emailRandomJoke = email({
text: punchline,
subject: setup,
});
console.log(fetchRandomJoke());

Sends me an email if Sweden's requirements for EU Blue Card changes. Checks once an hour.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { blob } from "https://esm.town/v/std/blob?v=12";
import { email } from "https://esm.town/v/std/email?v=12";
const site =
"https://www.migrationsverket.se/English/Private-individuals/Working-in-Sweden/Employed/Special-rules-for-certain-occupations-and-citizens-of-certain-countries/EU-Blue-Card.html";
const dateChangedKey = "work-permit-change-date";
export default async function(interval: Interval) {
const page = await fetch(site).then(res => res.text());
const date = page.match(/Last updated: <time datetime="([^"]+)">/)?.[1].toString();
const lastChange = await blob.get(dateChangedKey).then(res => res?.text()).catch(() => "");
if (!date) {
throw new Error("Couldn't find date");
}
if (!lastChange || date === lastChange) {
return;
}
await blob.set(dateChangedKey, date);
await email({
subject: `EU Blue Card requirements page changed at ${new Date(date).toDateString()}`,
text: `Go check ${site}`,
});
}
Runs every 1 days
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Fetches a random joke.
async function fetchRandomJoke() {
const response = await fetch(
"https://official-joke-api.appspot.com/random_joke",
);
return response.json();
}
const randomJoke = await fetchRandomJoke();
const setup = randomJoke.setup;
const punchline = randomJoke.punchline;
import { email } from "https://esm.town/v/std/email?v=9";
// Sends an email with the joke.
export const emailRandomJoke = email({
text: punchline,
subject: setup,
});

Bluesky keyword alerts

Custom notifications for when you, your company, or anything you care about is mentioned on Bluesky.

1. Query

Specify your queries in the queries variable.

Bluesky doesn't support boolean OR yet so we do a separate search for each keyword.

2. Notification

Below I'm sending these mentions to a private channel in our company Discord, but you can customize that to whatever you want, @std/email, Slack, Telegram, whatever.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { blob } from "https://esm.town/v/std/blob";
import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
import { searchBlueskyPosts } from "https://esm.town/v/stevekrouse/searchBlueskyPosts";
const encounteredIDs_KEY = "bluesky_encounteredIDs";
const queries = ["val town", "val.town"];
export const blueskyAlert = async () => {
let posts = (await Promise.all(queries.map(searchBlueskyPosts))).flat();
// filter for new posts
let encounteredIDs = await blob.getJSON(encounteredIDs_KEY) ?? [];
let newPosts = posts.filter((post) => !encounteredIDs.includes(post.tid));
await blob.setJSON(encounteredIDs_KEY, [
...encounteredIDs,
...newPosts.map((post) => post.tid),
]);
if (newPosts.length === 0) return;
// format
const content = posts.map(
post => `https://bsky.app/profile/${post.user.handle}/post/${post.tid.split("/")[1]}`,
).join(
"\n",
);
// notify
await discordWebhook({
url: Deno.env.get("mentionsDiscord"),
content,
});
return newPosts;
};

remind_new_open_llm

This val sends you an email whenever a new LLM appears in the top 10 LLMs on the Open LLM Leaderboard. Use an interval of at least 12 hours as the top 10 doesn't change that frequently. You can adjust the array slice to change how many places on the leaderboard to monitor, or remove it entirely to fill up your mailbox.

Bugs

If a model unfairly gets to the top 10 and then gets flagged for it, you'll get a reminder for an LLM that's in most cases not new at all. Hopefully this doesn't happen too often.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { email } from "https://esm.town/v/std/email?v=9";
import { set } from "https://esm.town/v/std/set?v=11";
import { last_open_llm_top_10 } from "https://esm.town/v/mattx/last_open_llm_top_10";
import { scrape_open_llm_leaderboard } from "https://esm.town/v/mattx/scrape_open_llm_leaderboard";
export const remind_new_open_llm = async () => {
const data = (await scrape_open_llm_leaderboard()).slice(
0,
10,
);
if (!last_open_llm_top_10) {
console.log("First run, saving data");
await set("last_open_llm_top_10", data);
return;
}
if (
JSON.stringify(last_open_llm_top_10) != JSON.stringify(data)
) {
await email({
html: `<ul>${
data.filter((x) => !last_open_llm_top_10.includes(x)).map(
(x) =>
"<li>" + x + "</li>"
).join("")
}</ul>`,
subject: "New open LLMs",
});
await set("last_open_llm_top_10", data);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { email } from "https://esm.town/v/std/email?v=9";
import { hnEmail } from "https://esm.town/v/rodrigotello/hnEmail";
import { hnLatestPosts } from "https://esm.town/v/stevekrouse/hnLatestPosts?v=18";
export const hnFollowApp = function (authors: string[]) {
return async function ({ lastRunAt }) {
let posts = await hnLatestPosts({
authors,
lastSyncTime: lastRunAt,
search_by_date: true,
});
let { html, subject } = await hnEmail({ posts });
if (posts.length)
await email({ html, subject });
};
};
// Forked from @stevekrouse.hnFollowApp

Unlimited Anonymous Emails

Create anonymous emails and forward their results to your inbox.

1
2
3
4
5
6
7
8
9
10
11
import { email } from "https://esm.town/v/std/email?v=11";
export function forwarder(e: {
from: string;
to: string[];
subject: string;
text: string;
html: string;
}) {
return email({ html: e.html, subject: e.from + ": " + e.subject });
}
Runs every 1 days
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { email } from "https://esm.town/v/std/email?v=9";
// Fetches a random joke.
async function fetchRandomJoke() {
const response = await fetch(
"https://official-joke-api.appspot.com/random_joke",
);
return response.json();
}
const randomJoke = await fetchRandomJoke();
const setup = randomJoke.setup;
const punchline = randomJoke.punchline;
// Sends an email with the joke.
export const emailRandomJoke = email({
text: punchline,
subject: setup,
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Usage exmaple:
// https://username-valname.web.val.run?k=myKey&s=mySubject&m=myMessage
import { email } from "https://esm.town/v/std/email";
import { Hono } from "npm:hono@3";
const app = new Hono();
app.get("/", async (c) => {
const now = new Date();
let { to, s, m, k } = c.req.query();
s = s || "message from api";
m = m || "<empty>";
const checks = [
c.req.header("cf-ipcountry") === "US",
k === Deno.env.get("EMAIL_KEY"),
];
const failedChecks = checks.filter(el => el === false).length;
if (failedChecks > 0) {
c.status(401);
return c.text(`unauthorized - ${failedChecks}`);
}
if (m.length > 280) {
return c.text("invalid message length");
}
if (s.length > 80) {
return c.text("invalid subject length");
}
try {
await email({ to: to, subject: s, text: m });
return c.text(`message sent at ${now.toUTCString()}`);
} catch (err) {
c.status(500);
return c.text("something went wrong");
}
});
export default app.fetch;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { email } from "https://esm.town/v/std/email?v=9";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export const email_apod = (async () => {
const marked = await import("npm:marked");
const apod = await fetchJSON("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
const output = `
<h1> ${apod.title}</h1>
<p>${apod.explanation}</p>
<img src="${apod.url}" />
`;
const res = await email({
subject: `APOD: ${apod.title}`,
html: output,
});
return res;
})();
Runs every 1 days
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { email } from "https://esm.town/v/std/email?v=9";
// Fetches a random joke.
async function fetchRandomJoke() {
const response = await fetch(
"https://official-joke-api.appspot.com/random_joke",
);
return response.json();
}
const randomJoke = await fetchRandomJoke();
const setup = randomJoke.setup;
const punchline = randomJoke.punchline;
// Sends an email with the joke.
export const emailRandomJoke = email({
text: punchline,
subject: setup,
});
Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
import { email } from "https://esm.town/v/std/email?v=9";
import { hasValTownStyleGuideUpdated } from "https://esm.town/v/stevekrouse/hasValTownStyleGuideUpdated";
export async function valTownStyleGuideUpdated({ lastRunAt }) {
if (await hasValTownStyleGuideUpdated(lastRunAt))
email({
subject: "🎨 Val Town Style Guide has been updated!",
});
}