Search

Results include substring matches and semantically similar vals. Learn more
andreterron avatar
getFileIndexPosition
@andreterron
An interactive, runnable TypeScript val by andreterron
Script
export async function getFileIndexPosition({ line, col }, textContents) {
const lines = textContents.split("\n");
let position = 0;
charmaine avatar
cancelledStripeSubscriber
@charmaine
Cancelled Stripe Subscription Handler This val processes cancelled Stripe subscribers to Val Town Pro. It sends our team a Discord notification. It takes a couple of steps if you'd like to set up something similar for your own Stripe account. Setup Fork this HTTP val Create a new webhook in Stripe Add your val's HTTP endpoint URL into the Stripe webhook Select customer.subscription.cancelled as the only event to listen to (more on this below) Add your stripe_sk_customer_readonly to your Val Town Env Variables Add your webhook's signing secret as STRIPE_WEBHOOK_SECRET to you Val Town Env Variables How the code is structured Verifies the signature to make sure it's really from Stripe Sends off the Discord message
HTTP
const stripe = new Stripe(Deno.env.get("stripe_sk_customer_readonly") as string, {
apiVersion: "2020-08-27",
function getStripeCustomer(customerId: string) {
console.log(customerId);
return stripe.customers.retrieve(customerId);
vladimyr avatar
jwkToDidKey
@vladimyr
// SPDX-License-Identifier: 0BSD
Script
x: string;
[propName: string]: unknown;
export function jwkToMultibase(jwk: JWK) {
if (jwk.kty === "OKP") {
const bytes = base64url.baseDecode(jwk.x);
return bytesToMultibase(bytes, jwk.crv);
throw new TypeError("error: unsupported key type");
export function jwkToDidKey(jwk: JWK) {
const keyMultibase = jwkToMultibase(jwk);
return `did:key:${keyMultibase}`;
dthyresson avatar
resetFavoriteSongSearches
@dthyresson
Reset Favorite Song Searches Cron to clear and reset favoritre Spotify song searches periodically.
Cron
{ artist: "Primal Scream", title: "Higher than the Sun" },
] as Track[];
export default async function(interval: Interval) {
await sqlite.execute(`drop table if exists favorite_song_searches;`);
await sqlite.execute(`
andreterron avatar
tidbytSkipped
@andreterron
An interactive, runnable TypeScript val by andreterron
Script
import { tidbytCircle } from "https://esm.town/v/andreterron/tidbytCircle";
export async function tidbytSkipped({ size = 7, bg = 0xffffff80, line = 3 }: {
size?: number;
bg?: number;
jxnblk avatar
valTownBadgeExample
@jxnblk
Example of how to add a Val Town badge to your val Demo: https://jxnblk-valtownbadgeexample.web.val.run/ Option 1 Wrap your HTTP response handler with https://www.val.town/v/jxnblk/valTownBadgeMiddleware [^1] import wrapper from "https://esm.town/v/jxnblk/valTownBadgeMiddleware"; async function handler(req: Request): Promise<Response> { const html = ` <h1>Hello, world</h1> `; return new Response(html, { headers: { "Content-Type": "text/html; charset=utf-8", }, }); } export default wrapper(handler, import.meta.url); Option 2 Get the HTML string for the badge using https://www.val.town/v/jxnblk/valTownBadge Add the HTML to your response's HTML string wherever you like import valTownBadge from "https://esm.town/v/jxnblk/valTownBadge"; export default async function(req: Request): Promise<Response> { const badge = valTownBadge(import.meta.url); const html = ` <h1>Hello, world</h1> ${badge} `; return new Response(html, { headers: { "Content-Type": "text/html; charset=utf-8", }, }); } Manual options You can also edit the snippet below to manually add the badge in HTML <a href="https://www.val.town/v/jxnblk/valTownBadgeExample" target="_blank" style="text-decoration:none;color:inherit"> <img src="https://jxnblk-valtownbadgesvg.web.val.run/" width="160" height="160"> </a> Or markdown: [![View source on Val Town](https://jxnblk-valtownbadgesvg.web.val.run/)](https://www.val.town/v/jxnblk/valTownBadgeExample) [^1]: Middleware is not recommended when using client-side hydration in apps like React or when returning a full, valid HTML response
HTTP
import wrapper from "https://esm.town/v/jxnblk/valTownBadgeMiddleware";
async function handler(req: Request): Promise<Response> {
const html = `
import valTownBadge from "https://esm.town/v/jxnblk/valTownBadge";
export default async function(req: Request): Promise<Response> {
const badge = valTownBadge(import.meta.url);
import { render } from "npm:preact-render-to-string";
function handler(req: Request): Promise<Response> {
const body = render(
postpostscript avatar
interruptibleChain
@postpostscript
interruptibleChain: simple interface for pausing and resuming execution chains ⚠️ Moved to GitHub ⚠️ import { $chain } from "https://esm.town/v/postpostscript/interruptibleChain"; const multiply = $chain() .then(() => 1) .then((x) => x + 3) .then(async (x) => { await new Promise((resolve) => setTimeout(resolve, 1000)); return x * 2; }); const handle = multiply.init(); console.log(await handle.untilDone()); // { done: true, value: 8, handle: InterruptibleChainHandle { ... } } const handle2 = multiply.init({ index: 2, value: 4, }); await handle2.advance(); console.log(handle2.done, handle2.state); // true { index: 3, value: 8 } /**** Interrupts ****/ const handle3 = $chain().then(() => { throw new Error("failed"); }).init(); await handle3.advance(); console.log(handle3.done, handle3.interrupt); // false Interrupt { reason: Error: failed, chain: InterruptibleChain { index: 0 } } console.log(await handle3.untilDone()); // { done: false, interrupt: Interrupt { ... }, handle: InterruptibleChainHandle { ... } } const handle4 = $chain().then((_, interrupt) => { return interrupt("call me later"); }).init(); await handle4.advance() console.log(handle4.done, handle4.interrupt); // false Interrupt { reason: "call me later", chain: InterruptibleChain { index: 0 } }
Script
import type { MaybePromise } from "https://esm.town/v/postpostscript/typeUtils";
export function $chain<T, P>(method: InterruptibleChainMethod<T, P>): InterruptibleChain<T, P>;
export function $chain(): InterruptibleChain<void, void>;
export function $chain<T, P>(
method?: InterruptibleChainMethod<T, P>,
type SubchainState = InterruptibleChainState | undefined;
export function subchainMethod<T, P = any>(chain: InterruptibleChain<T>): InterruptibleChainMethod<T, P> {
return async (previous, interrupt, intermediateState: SubchainState) => {
status.handle.state,
export function join<Chains extends InterruptibleChain<any>[]>(
...chains: Chains
: Return;
export function append<Chains extends InterruptibleChain<any>[]>(
...chains: Chains
paulkinlan avatar
timeZoneCompareTool
@paulkinlan
// This timezone comparison tool will use the Luxon library for date and time manipulation.
HTTP
"Australia/Sydney",
// Helper function to group timezones by country
function groupTimezonesByCountry(timezones) {
return timezones.reduce((acc, zone) => {
"Pacific/Auckland",
function TimezoneSelect({ onSelect }) {
const [selectedZone, setSelectedZone] = useState("");
</div>
function App({ initialTime }: { initialTime: string }) {
const [currentTime, setCurrentTime] = useState(DateTime.now());
</div>
function TimezoneRow({ zone, currentTime }: { zone: string; currentTime: DateTime }) {
const localTime = currentTime.setZone(zone || 'UTC');
window.addEventListener('load', client);
async function server(request: Request): Promise<Response> {
try {
postpostscript avatar
expiringUUID
@postpostscript
An interactive, runnable TypeScript val by postpostscript
Script
import { v7, version } from "npm:uuid";
export function create(expireAt: Date | number) {
return v7({
msecs: new Date(expireAt).getTime(),
export function getTimestamp(uuid: string): number {
if (version(uuid) !== 7) {
return parseInt(tsHex, 16);
export function* getExpired(ids: Iterable<string>, presorted = false, logErrors = true): Generator<string> {
const now = new Date().getTime();
console.error(`id ${id} is invalid:`, e);
export async function* getExpiredAsync(
sortedIDs: AsyncIterable<string>,
vladimyr avatar
libarmor
@vladimyr
// SPDX-License-Identifier: 0BSD
Script
// SPDX-License-Identifier: 0BSD
export function createPacketReader({
packetStartMarker,
packetStartMarker += "\n";
return function readPacket(input: string) {
input = input.trim();
return input.substring(contentOffset, contentOffset + contentLength);
export function createSignedPacketReader({
packetStartMarker,
signatureStartMarker += "\n";
return function readSignedPacket(input: string) {
input = input.trim();
mxdvl avatar
round
@mxdvl
Round numbers with arbitrary decimal precision
Script
/** round with abitrary decimal precision */
export function round(number: number, precision = 5) {
return Math.round(number * Math.pow(10, precision)) / Math.pow(10, precision);
dandivelbiss avatar
basic_auth
@dandivelbiss
Basic Auth Middleware A middleware for wrapping an HTTP val with Basic authentication. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication See also: https://www.val.town/v/pomdtr/basicAuth for a different approach
HTTP
const { username, password } = options;
return `Basic ${btoa(`${username}:${password}`)}`;
export function authMiddleware(
handler: (Request) => Promise<Response>,
options: Options,
return new Response("Unauthorized", { status: 401 });
return handler(request);
export default async function(req: Request): Promise<Response> {
return new Response("This is middleware only");
rwev avatar
adjustMsToWeekday
@rwev
An interactive, runnable TypeScript val by rwev
Script
import { msToIsoDate } from "https://esm.town/v/rwev/msToIsoDate";
import { msDay as msDay2 } from "https://esm.town/v/stevekrouse/msDay?v=1";
export function adjustMsToWeekday(msDay) {
let date = new Date(msDay);
while (date.getDay() == 0 || date.getDay() == 6) {
dantaeyoung avatar
btcPriceAlert
@dantaeyoung
BTC Price Alert This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency. Fork this val to get these notifications on your inbox.
Cron
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
richardkaplan avatar
btcPriceAlert
@richardkaplan
BTC Price Alert This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency. Fork this val to get these notifications on your inbox.
Cron
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");