Trending Vals
3
stevekrouse
twitterAlert
Cron
Twitter/𝕏 keyword alerts Custom notifications for when you, your company, or anything you care about is mentioned on Twitter. If you believe in Twitter/𝕏-driven development, you want to get notified
when anyone is talking about your tech, even if they're not tagging you. To get this Twitter Alert bot running for you,
fork this val and modify the query and where the notification gets delivered. 1. Query Change the keywords for what you want to get notified for
and the excludes for what you don't want to get notified for. You can use Twitter's search operators to customize your query, for some collection of keywords, filtering out others, and much more! 2. Notification Below I'm sending these mentions to a public channel in our company Discord, but you can customize that to whatever you want, @std/email, Slack, Telegram, whatever. Twitter Data & Limitations The Twitter API has become unusable. This val gets Twitter data via SocialData ,
an affordable Twitter scraping API. In order to make this val easy for
you to fork & use without signing up for another API, I am proxying
SocialData via @stevekrouse/socialDataProxy. Val Town Pro users can call this proxy
100 times per day, so be sure not to set this cron to run more than once every 15 min. If you want to run it more, get your own SocialData
API token and pay for it directly.
2
4
nbbaier
sqliteExplorerApp
HTTP
SQLite Explorer View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal . This is now more an SPA, with tables, queries and results showing up on the same page. Install Install the latest stable version (v86) by forking this val: Authentication Login to your SQLite Explorer with password authentication with your Val Town API Token as the password. Todos / Plans [ ] improve error handling [ ] improve table formatting [ ] sticky table headers [x] add codemirror [ ] add loading indication to the run button (initial version shipped) [ ] add ability to favorite queries [ ] add saving of last query run for a table (started) [ ] add visible output for non-query statements [ ] add schema viewing [ ] add refresh to table list sidebar after CREATE/DROP/ALTER statements [ ] add automatic execution of initial select query on double click [x] add views to the sidebar [ ] add triggers to sidebar [ ] add upload from SQL, CSV and JSON [ ] add ability to connect to a non-val town Turso database [x] fix wonky sidebar separator height problem (thanks to @stevekrouse) [x] make result tables scrollable [x] add export to CSV, and JSON (CSV and JSON helper functions written in this val . Thanks to @pomdtr for merging the initial version!) [x] add listener for cmd+enter to submit query
20
8
9
stevekrouse
discordWebhook
Script
Send a Discord message Send a message to a Discord channel from Val Town. It's useful for notifying your team or community when someone interesting happens, like a user signup, Stripe payment, mention on social media, etc. import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
await discordWebhook({
url: Deno.env.get("engDiscord"),
content: "Hi from val town!",
});
Example val: https://www.val.town/v/stevekrouse.discordWebhookEx Setup 1. Create a Discord Webhook Follow the instructions here: https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks It really only takes 2 minutes. 2. Copy webhook URL Paste it into your secrets as discordWebhook . 3. Send a message! import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
await discordWebhook({
url: Deno.env.get("engDiscord"),
content: "Hi from val town!",
}); Example val: https://www.val.town/v/stevekrouse.discordWebhookEx
1
10
11
andreterron
codeOnValTown
Script
Code on Val Town Adds a "Code on Val Town" ribbon to your page. This lets your website visitors navigate to the code behind it. This uses github-fork-ribbon-css under the hood. Usage Here are 2 different ways to add the "Code on Val Town" ribbon: 1. Wrap your fetch handler (recommended) import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { html } from "https://esm.town/v/stevekrouse/html?v=5";
export default modifyFetchHandler(async (req: Request): Promise<Response> => {
return html(`<h2>Hello world!</h2>`);
}); Example: @andreterron/openable_handler 2. Wrap your HTML string import { modifyHtmlString } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { html } from "https://esm.town/v/stevekrouse/html?v=5";
export default async (req: Request): Promise<Response> => {
return html(modifyHtmlString(`<h2>Hello world!</h2>`));
}; Example: @andreterron/openable_html Other ways We made sure this was very modular, so you can also add the ribbon using these methods: Get the element string directly: @andreterron/codeOnVT_ribbonElement Modify an HTTP Response: @andreterron/codeOnVT_modifyResponse Use .pipeThrough to append to a stream: @andreterron/InjectCodeOnValTownStream Customization Linking to the val These functions infer the val using the call stack or the request URL. If the inference isn't working, or if you want to ensure it links to a specific val, pass the val argument: modifyFetchHandler(handler, {val: { handle: "andre", name: "foo" }}) modifyHtmlString("<html>...", {val: { handle: "andre", name: "foo" }}) Styling You can set the style parameter to a css string to customize the ribbon. Check out github-fork-ribbon-css to learn more about how to style the element. modifyFetchHandler(handler, {style: ".github-fork-ribbon:before { background-color: #333; }"}) modifyHtmlString("<html>...", {style: ".github-fork-ribbon:before { background-color: #333; }"}) Here's how you can hide the ribbon on small screens: modifyFetchHandler(handler, {style: `@media (max-width: 768px) {
.github-fork-ribbon {
display: none !important;
}
}`}) To-dos [ ] Let users customize the ribbon. Some ideas are the text, color or placement.
5
12
pomdtr
password_auth
Script
Password Auth Middleware Protect your vals behind a password. Use session cookies to persist authentication. Usage import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=84";
export default passwordAuth(() => {
return new Response("OK");
}, { verifyPassword: (password) => password == Deno.env.get("VAL_PASSWORD") }); If you want to use an api token to authenticate: import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=84";
import { verifyToken } from "https://esm.town/v/pomdtr/verifyToken";
export default passwordAuth(() => {
return new Response("OK");
}, { verifyPassword: verifyToken }); TODO [x] allow to authenticate using a val town token [ ] add a way to send an email to ask a password from the val owner [ ] automatically extend the session [ ] automatically remove expired sessions FAQ How to sign out ? Navigate to <your-site>/signout .
15
13
14
15
maxm
valSession
HTTP
Val Session import { ValSession } from "https://esm.town/v/maxm/valSession";
// Generate a token from your valtown api key.
const token = await ValSession.newSession(Deno.env.get("valtown"));
// Other services can use it to authenticate
const user = await ValSession.validate(token); Fork it, provide your own VT_SESSION_PRIVATE_KEY, and update the hardcoded public key. You can generate your own keys like so: import { crypto } from "https://deno.land/std@0.198.0/crypto/mod.ts";
// Generate a key pair for JWT signing and verification
const { privateKey, publicKey } = await crypto.subtle.generateKey(
{
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
}, true, ["sign", "verify"],
);
function formatPEM(b64: string, type: "PRIVATE KEY" | "PUBLIC KEY"): string {
const lines = b64.match(/.{1,64}/g) || [];
return `-----BEGIN ${type}-----\n${lines.join("\n")}\n-----END ${type}-----`;
}
const privateKeyPem = formatPEM(
btoa(String.fromCharCode(...new Uint8Array(exportPrivateKey))),
"PRIVATE KEY",
);
const publicKeyPem = formatPEM(
btoa(String.fromCharCode(...new Uint8Array(exportPublicKey))),
"PUBLIC KEY",
);
console.log(privateKeyPem, publicKeyPem);
2
16
19
stevekrouse
openai
Script
OpenAI ChatGPT helper function This val uses your OpenAI token if you have one, and the @std/openai if not, so it provides limited OpenAI usage for free. import { chat } from "https://esm.town/v/stevekrouse/openai";
const { content } = await chat("Hello, GPT!");
console.log(content); import { chat } from "https://esm.town/v/stevekrouse/openai";
const { content } = await chat(
[
{ role: "system", content: "You are Alan Kay" },
{ role: "user", content: "What is the real computer revolution?"}
],
{ max_tokens: 50, model: "gpt-4o" }
);
console.log(content);
1
20
maxm
wide
HTTP
WIDE Store any unstructured JSON data. Retrieve it with an expressive and efficient query system. WIDE is a library and service hosted on Val Town. Authenticate and use it with your Val Town credentials, or fork it and connect it to your own Clickhouse Instance. import { ValSession } from 'https://esm.town/v/maxm/valSession';
import { Wide } from 'https://esm.town/v/maxm/wide';
// Use your Val Town API Token to create a session
const wide = new Wide(await ValSession.new(Deno.env.get("valtown")))
// Write any data.
await wide.write([
{ user: {id: 1, name: 'Alice', email: 'alice@example.com' }},
{ user: {id: 2, name: 'Bob', email: 'bob@example.com' }},
{ user: {id: 3, name: 'Charlie', email: 'charlie@example.com' }},
]);
await wide.fields("user.")
// => [
// { fieldName: "user.email", fieldType: "string", count: 3 },
// { fieldName: "user.id", fieldType: "number", count: 3 },
// { fieldName: "user.name", fieldType: "string", count: 3 }
// ]
await wide.values("user.email")
// [
// { value: "bob@example.com", count: 1 },
// { value: "charlie@example.com", count: 1 },
// { value: "alice@example.com", count: 1 }
// ]
await wide.search({
start: new Date(Date.now() - 1000 * 60 * 10),
end: new Date(),
filters: [{ fieldName: "user.name", operator: "equals", value: "Alice" }],
})
// [{ user: { name: "Alice", email: "alice@example.com", id: 1 } }];
2
21
23
stevekrouse
pollRSSFeeds
Cron
Poll RSS feeds This val periodically polls specified RSS feeds and send the author an email with new items. It checks each feed defined in rssFeeds for new content since the last run and sends an email with the details of the new items. Usage Fork @stevekrouse/rssFeeds and update it with your desired RSS feeds; Fork this val and replace the https://esm.town/v/stevekrouse/rssFeeds import with your newly forked val; Enjoy RSS updates on your email!
5
24
stevekrouse
dns_record_debugger
HTTP
Proxied Web Browser – DNS Debugger Proxied web browser for debugging new DNS records It's difficult to verify new DNS records. If you check too early, the old records may get cached on your computer, browser, or local network. This tool uses a proxied fetch so you can always view your web page uncached. Uses @std/fetch on the backend to ensure the DNS records of the request are from new places every request. Version 4 of this val also showed DNS records, pulled on the server,
but I removed that featured, because those records are likely
subject to caching. It'd be an improvement to this tool if we
could add an uncached DNS check in here. In a couple min I wasn't
able to find a free DNS checker API. Pull requests welcome!
2
28
gwoods22
scraper_template
Script
Website Scraper Template A basic website scraper template that can be ran on an interval to check for changes. It uses blob storage to save whatever data you'd like to compare the website to. Uses my sendNotification val to alert yourself of the change. Steps to use Add the scrapeURL you would like to scrape and pick a name for your blob storage blobKey . Change the "selector" value to fit your needs. cheerio is used to find the part of the page you'd like to check. Adjust the if statement to detect changes and update your blob Craft a message to be sent with sendNotification() function
1
29