Trending Vals
1
4
selfDestruct
@peterqliu
Script
๐ฅ Deletes the val using it, or whatever url is fed it. Handy for sharing single-use scripts without cluttering people's accounts. If used in an HTTP val, this will run immediately when anyone forks it, making for a zero-click execution as long as ValTown immediately serves a preview of the forked val. Add this to your code last and then do not run it, or you will lose your work. Recommend first checking that the val owner isn't you, so that only forked copies will self-destruct. Usage selfDestruct(import.meta.url) Returns a promise of successful deletion, though the val would not be around to read it.
5
slackScout
@sarahxc
Cron
Slack scout sends a slack notification every time your keywords are mentioned on Twitter, Hacker News, or Reddit. Get notified whenever you, your company, or topics of interest are mentioned online. Built with Browserbase . Inspired by f5bot.com . Full code tutorial . Getting Started To run Slack Scout, youโll need a Browserbase API key Slack Webhook URL: setup here Twitter Developer API key Browserbase Browserbase is a developer platform to run, manage, and monitor headless browsers at scale. Weโll use Browserbase to navigate to, and scrape our different news sources. Weโll also use Browserbaseโs Proxies to ensure we simulate authentic user interactions across multiple browser sessions . Get started with Browserbase for free here . Twitter Weโve decided to use the Twitter API to include Twitter post results. It costs $100 / month to have a Basic Twitter Developer account. If you decide to use Browserbase, we can lend our token. Comment below for access. Once you have the SLACK_WEBHOOK_URL , BROWSERBASE_API_KEY , and TWITTER_BEARER_TOKEN , input all of these as Val Town Environment Variables . Project created by Sarah Chieng and Alex Phan ๐
6
password_auth
@pomdtr
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 .
7
sqliteExplorerApp
@nbbaier
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
8
9
codeOnValTown
@andreterron
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.
11
aqi
@stevekrouse
Cron
AQI Alerts Get email alerts when AQI is unhealthy near you. Set up Click Fork Change location (Line 4) to describe your location. It accepts fairly flexible English descriptions which it turns into locations via nominatim's geocoder API . Click Run Background This val uses nominatim's geocoder to get your lat, lon, and air quality data from OpenAQ. It uses EPA's NowCast
AQI Index calculation and severity levels. Learn more: https://www.val.town/v/stevekrouse.easyAQI
13
routineTrackerApp
@ashryanio
HTTP
Routine Tracker This is a little React component to make our 7yo's after school routine self-serve so she can be a bit more independent after school. To change the items in the list, modify the routineTasks array of objects: [
{name: "item", timed: false},
{name: "item 2", timed: true, duration: 2 * 60 }
{name: "item 3", timed: false, requiresParent: true}
] You can set the parent password on this line: const PARENT_PASSWORD_HASH = simpleHash("1234"); Todos Make the parent password modal touch friendly Track dates/times of list completions Show a tracker of how many completions this week
15
16
18
19
fetchValInfo
@pomdtr
Script
Usage import { fetchValInfo } from "https://esm.town/v/pomdtr/fetchValInfo"
const val = await fetchValInfo(import.meta.url)
console.log(val.id) What's the difference with extractValInfo ? @pomdtr/extractValInfo get metadata synchronously by analysing the val import url, while @pomdtr/fetchValInfo perform an http call to the val.town REST api. Only use fetchValInfo if you need some metadata that are not available from extractValInfo .
22
determinedTurquoiseSlug
@vandermerwed
HTTP
Daily Schedule & Chores Tracker A flexible and interactive analogue clock schedule and chore tracker designed for my 8-year-old. This React component helps manage daily routines and tasks, featuring a visually appealing clock interface and a dynamic chore list. Features Analogue Clock Schedule: Displays daily activities in an analogue clock format with segments representing different time slots. Chore Tracker: Lists chores for the day, with checkboxes for completion tracking. Customizable: Accepts schedule and todoList props, allowing dynamic data from APIs or other sources. Real-time Updates: The clock updates every second to show the current time. Responsive Design: Styled with Tailwind CSS for a modern and clean appearance. Installation To use the component, include it in your React project and provide the necessary props. import AnalogueScheduleClock from './path-to-component';
// Example usage
<AnalogueScheduleClock
schedule={yourScheduleArray}
todoList={yourTodoListArray}
todoListHeading="Chores"
legendHeading="Today's Schedule"
initialTime={new Date()}
isLoading={false}
/> Props | Prop | Type | Description |
|------------------|------------------------|-----------------------------------------------------------------------------|
| schedule | ScheduleItem[] | Array of schedule items with start , end , label , and color properties. Defaults to a preset schedule. |
| todoList | TaskItem[] | Array of chores with id , name , and completed status. Defaults to a preset chore list. |
| todoListHeading | string | Heading for the chore list section. Default is "Kid's Chores" . |
| legendHeading | string | Heading for the schedule legend section. Default is "Daily Schedule" . |
| initialTime | Date | Initial time to display on the clock. Defaults to the current time. |
| isLoading | boolean | Displays a loading screen if set to true . Default is false . | Customizing the Schedule You can update the default schedule by modifying the defaultSchedule array or passing a custom schedule prop: const defaultSchedule: ScheduleItem[] = [
{ label: "๐ค", start: "19:00", end: "06:00", color: "#fca5a5" },
{ label: "๐ณ", start: "06:00", end: "07:15", color: "#93c5fd" },
{ label: "๐", start: "07:15", end: "07:30", color: "#d1d5db" },
{ label: "๐ซ", start: "07:30", end: "12:45", color: "#fdba74" },
{ label: "๐", start: "12:45", end: "13:00", color: "#d1d5db" },
{ label: "๐บ", start: "13:00", end: "14:00", color: "#86efac" },
{ label: "๐", start: "14:00", end: "16:00", color: "#fdba74" },
{ label: "๐ฎ", start: "16:00", end: "17:00", color: "#86efac" },
{ label: "๐ฝ๏ธ", start: "17:00", end: "18:00", color: "#93c5fd" },
{ label: "๐", start: "18:00", end: "19:00", color: "#d8b4fe" },
]; Feel free to customize the labels, start/end times, and colors to suit your child's daily routine. Customizing the Chore List To update the chores, modify the efaultTodoList array or provide a custom todoList prop: const defaultTodoList: TaskItem[] = [
{ id: "1", name: "Make bed", completed: false },
{ id: "2", name: "Clean room", completed: false },
{ id: "3", name: "Do homework", completed: false },
{ id: "4", name: "Feed pet", completed: false },
{ id: "5", name: "Set table", completed: false },
]; You can add, remove, or modify tasks to match your childโs responsibilities. Changing Headings To change the headings for the chores and schedule sections, update lines 229 and 230 in the code: todoListHeading = "Kid's Chores",
legendHeading = "Daily Schedule", Adjust these to fit your preferred labels or language.
23
api
@campsite
Script
Campsite API This val contains TypeScript utilities for working with the Campsite API . Usage: import * as Campsite from 'https://esm.town/v/campsite/api'
// business logic...
const post: Campsite.CreatePostRequest = {
title: "Test post",
content_markdown: "๐ Hello world!",
channel_id: "<your-channel-id>",
}
await Campsite.createPost(post, { apiKey: Deno.env.get("CAMPSITE_API_KEY") })
24
fileToDataURL
@stevekrouse
Script
File to Data URL Helpers to convert files to base64 & base64-encoded data URLs,
which are particularly helpful for sending images to LLMs
like ChatGPT, Anthropic, and Google. ChatGPT Live example import { fileToDataURL } from "https://esm.town/v/stevekrouse/fileToDataURL";
const dataURL = await fileToDataURL(file);
const response = await chat([
{
role: "system",
content: `You are an nutritionist.
Estimate the calories.
We only need a VERY ROUGH estimate.
Respond ONLY in a JSON array with values conforming to: {ingredient: string, calories: number}
`,
},
{
role: "user",
content: [{
type: "image_url",
image_url: {
url: dataURL,
},
}],
},
], {
model: "gpt-4o",
max_tokens: 200,
}); Anthropic Live example import { fileToBase64 } from "https://esm.town/v/stevekrouse/fileToDataURL";
const base64File = await fileToBase64(file);
let res = await anthropic.messages.create({
model: "claude-3-5-sonnet-20240620",
max_tokens: 1024,
messages: [
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": file.type,
"data": base64File,
},
},
{
"type": "text",
"text": `Write an HTML email
that evokes this photo in the funniest
way possible, with code fences.`,
},
],
},
],
}); Google Live example import { fileToBase64 } from "https://esm.town/v/stevekrouse/fileToDataURL";
const base64Image = await fileToBase64(image);
const result = await model.generateContent([
"Write all the names and authors of these books in JSON format. The response should be a valid JSON array of objects, each with 'title' and 'author' properties.",
{
inlineData: {
data: base64Image,
mimeType: image.type,
},
},
]);
27
eval
@maxm
Script
Eval web demo Security Caveats Be careful hosting this on your own account. You should 100% use authentication. It is easy to eval code that calls itself recursively over and over. Executed code will have access to import private modules from your account. Consider running this code on an isolated account if that is a concern. The unix socket that Deno uses to communicate with the host can be deleted and intercepted. This might mean that evaluated code can steal the socket and read the next request. You should not use this to evaluate code that should not be read by a previous evaluation. Overview You can use this library to evaluate code: import { evalCode } from "https://esm.town/maxm/eval"
console.log(await evalCode("export const foo = 1")) // => 1 You can use this library with https://www.val.town/v/maxm/transformEvalCode to return the last value without needing to export it. This is how the /eval api endpoint used to work and makes the library preform similarly to a repl. import { evalCode } from "https://esm.town/maxm/eval"
import { transform } from "https://esm.town/maxm/transformEvalCode"
console.log(await evalCode(transform("1+1"))) // => 2 Here's an example UI application that demonstrates how you can string this all together: https://maxm-evalui.web.val.run/ (source: https://www.val.town/v/maxm/evalUI) Security Model Code is evaluated using a dynamic import within a Worker. await import(`data:text/tsx,${encodeURIComponent(e.data)}`); Running the code withing a Worker prevents access to GlobalThis and window from leaking between evals. Similarly, access to Deno.env is prevented and evaluations will see errors when trying to access any environment variables. TODO: what else?
28
29
dailyStandupBot
@stevekrouse
Cron
Daily Standup Bot Every weekday at 9am EDT send a message to our team's #engineering Discord channel to start a thread to remind us to do our standup. Slack version: @mikker/dailySlackRoundup Note : We started doing in-person standups at Val Town, so this val was unscheduled.
To get it working for you, you'll need to: Fork it Change its type from Script to Cron and set a schedule like 0 13 * * 1-5