Search
valle_tmp_87252716729376250552603497646944
@janpaul123
// Handle story submission
HTTP
import { faker } from "npm:@faker-js/faker";
const SAMPLE_STORIES_KEY = "hn_sample_stories";
async function initializeSampleStories() {
const existingStories = await blob.getJSON(SAMPLE_STORIES_KEY);
if (!existingStories) {
valle_tmp_26078469653238519037257020956977
@janpaul123
An interactive, runnable TypeScript val by janpaul123
HTTP
import { faker } from "npm:@faker-js/faker";
const SAMPLE_STORIES_KEY = "hn_realistic_sample_stories";
async function initializeSampleStories() {
const existingStories = await blob.getJSON(SAMPLE_STORIES_KEY);
if (!existingStories) {
criticEmail
@paulkinlan
An interactive, runnable TypeScript val by paulkinlan
Email
import { extractValInfo } from "https://esm.town/v/stevekrouse/extractValInfo";
import { OpenAI } from "npm:openai";
function stripHtmlBackticks(html: string): string {
return html.replace(/^```html\n?/, "").replace(/\n?```$/, "");
export default async function(e: Email) {
const openai = new OpenAI();
console.log(`from: ${e.from} to: ${e.to} subject: ${e.subject}, cc: ${e.cc}, bcc: ${e.bcc}`);
duckdbExample
@hamilton
DuckDB DuckDB works on Val Town, with only one small tweak! We're basically using DuckDB in the same way you'd use it with a browser - using the WASM package with its dependencies fetched from jsdelivr . The only trick is to create the worker ourselves rather than using duckdb.createWorker . DuckDB's built-in createWorker method doesn't specify a worker type, which causes type to default to classic , and Deno (our runtime) doesn't support classic workers.
Script
import { fetch } from "https://esm.town/v/std/fetch";
export let duckdbExample = (async () => {
async function createWorker(url: string) {
const workerScript = await fetch(url);
const workerURL = URL.createObjectURL(await workerScript.blob());
sonnet
@manyone
Anthropic Claude Claude 3.5 Sonnet
Script
import Anthropic from "npm:@anthropic-ai/sdk";
export default async function generatePoem() {
try {
// Retrieve the Anthropic API key from environment variables
body: error.response.body,
throw error;
// If this script is run directly, execute the function
if (import.meta.main) {
console.log("🚀 Script Execution Started");

love_letter
@pomdtr
<3 Val Town Val Town is my new favourite thing. Never heard of it ? Well, according to it's homepage, Val Town is a social website to write and deploy TypeScript. It's often introduced as zappier for developers , or twitter for code . The idea is simple: you write down a javascript snippet (named vals) in your browser, and it's instantly executed on a server. You can use it to: execute a function on a cron schedule host a small websites (this article hosted on Val Town ) send yourself emails ... But there is more to Val Town than this. If you take a look at the trending vals , you will quickly notice a pattern: most of the vals are about Val Town itself. People are using Val Town to extend Val Town, and it's fascinating to see what they come up with. I've built a few of these extensions myself, and this article is about one of them. Fixing the Val Town Search Val.town is built around the http import feature of Deno. Each val is a standalone module, that you can import in other vals. It works both for your own vals, and for the vals of other users. All of this is great, but there is one big issue: the search feature is terrible . It only works for exact text matches, and there is no way to set any filters based on username , creation_date , or anything else. This makes it really hard to find a val you are looking for, even if you are the one who wrote it. In any other platform, I would have just given up and moved on. But Val Town is different. I was confident that I could address this issue in userspace, without having to wait for the platform to implement it. Val Town allows you to run a val on a cron schedule, so I wrote a val that would fetch all the vals from the API, and store them as a sqlite table (did I mention that every user get it's own sqlite database ?). const createQuery = `CREATE TABLE IF NOT EXISTS vals (
...
);`;
// run every hour
export default function(interval: Interval) {
// create the val table
await options.sqlite.execute(createQuery);
let url = "https://api.val.town/v1/search/vals?query=%20&limit=100";
// fetch all vals, and store them in the sqlite table
while (true) {
const resp = await fetch(url);
if (!resp.ok) {
throw new Error(await resp.text());
}
const res = await resp.json();
const rows = res.data.map(valToRow);
await insertRows(rows, options);
if (!res.links.next) {
break;
}
url = res.links.next;
}
} Once the val had finished running, I had a table with all the vals from the platform. I could now run queries on this table to find the vals I was looking for. import { sqlite } from "https://esm.town/v/std/sqlite"
const res = await sqlite.execute(`SELECT * FROM vals WHERE author = 'pomdtr' && code LIKE '%search%'`); Of course I could have stopped there, but I wanted to go further. I wanted to share this table with other users, so they could run their own queries on it. Isolating the Vals Table There was still a challenge to overcome: the table was part of my account database, and I didn't want to give everyone access to it (there are some sensitive tables in there). One way to solve this issue would be to publish a stripped-down api that only allows a few predefined queries. But that would be boring, and I wanted to give users the full power of SQL. So I decided to isolate the val table in a separate account. There is a neat trick to achieve this on val.town: each val get's it own email address, and email sent to vals can be forwarded to your own email address. import { email as sendEmail } from "https://esm.town/v/std/email?v=11";
// triggered each time an email is sent to pomdtr.sqlite_email@valtown.email
export default async function(email: Email) {
// forward the email to my own email address
await sendEmail({
subject: email.subject,
html: email.html,
text: email.text,
});
} Since val.town account can be created with a val.email address, you can create an infinite number of accounts (and thus sqlite databases) using this trick. So say hello to the sqlite account , which is a separate account that only contains the vals table. After creating the account, I just needed to fork the cron val from my main account to get a copy of the vals table in the sqlite account. Publishing the Table The val.town stdlib provides a neat rpc function that provides a simple way to expose a function as an API. So I decided to write a simple val that would run a query on the table, and return the result. import { rpc } from "https://esm.town/v/std/rpc?v=5";
import { InStatement, sqlite } from "https://esm.town/v/std/sqlite?v=4";
// rpc create an server, exposed on the val http endpoint
export default rpc(async (statement: InStatement) => {
try {
// run the query, then return the result as json
return await sqlite.execute(statement);
} catch (e) {
throw new Response(e.message, {
status: 500,
});
}
}); Everyone can now run queries on the table thanks a publically accessible endpoint (you even have write access to it, but I trust you to not mess with it). You can test it locally using curl and jq : echo "SELECT * FROM vals WHERE lower(name) LIKE '%feed%' and lower(name) like '%email%' LIMIT 100" | jq -R '{args: [.]} ' | xargs -0 -I {} curl -X POST "https://sqlite-execute.web.val.run" -H "Content-Type: application/json" -d {} | jq Of course I don't expect the average val.town user to use shell commands to run queries, so I also built an helper val to interact with the API, allowing users to run queries from their own vals. // only the import changed from the previous example
import { db } from "https://esm.town/v/sqlite/db";
// this query will run on the `sqlite` account
const res = await db.execute(`SELECT * FROM vals WHERE author = 'pomdtr' && code LIKE '%search%'`); I've seen some really cool vals built on top of this API. Someone even wrote down a guide to help users interact with it from the command-line! I hope that someone will build an search UI to interact with it at some point, but in the meantime, you can use a community-contributed sqlite web interface to run queries on top of the vals table. Val.town as a code-taking app As I've tried to show, having both a runtime, an editor and an API on the same platform is quite a magic formula. It's probably why val.town resonates so much with me. Using CodeSandbox, Stackblitz, Repl.it, Gitpod, Github Codespaces or Gitpod feels pretty much the same, everything still revolves around the same concept of a project/repository. They feel uninspired somehow, trying to replicate the desktop IDE experience in the browser, instead of embracing the new possibilities that the web platform offers. Val.town breaks this mold. I see it as a code-taking app, a place where I can just dump my ideas without worrying about the usual frictions of writing and deploying code.
HTTP
The idea is simple: you write down a javascript snippet (named vals) in your browser, and it's instantly executed on a server. You can use it to:
- execute a function on a cron schedule
- host a small websites (this article [hosted on Val Town](https://www.val.town/v/pomdtr/love_letter))
// run every hour
export default function(interval: Interval) {
// create the val table
// triggered each time an email is sent to pomdtr.sqlite_email@valtown.email
export default async function(email: Email) {
// forward the email to my own email address
## Publishing the Table
The val.town stdlib provides a neat `rpc` function that provides a simple way to expose a function as an API. So I decided to write a simple val that would run a query on the table, and return the result.
```ts
excitedScarletQuail
@charmaine
Framer Fetch: Basic A basic example of an API endpoint to use with Framer Fetch.
HTTP
export default async function(req: Request): Promise<Response> {
// Pick a random greeting
const greetings = ["Hello!", "Welcome!", "Hi!", "Heya!", "Hoi!"];

greenCockroach
@pomdtr
An interactive, runnable TypeScript val by pomdtr
Script
import { Kysely, sql } from "npm:kysely";
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable("person")
.column("owner_id")
.execute();
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropTable("pet").execute();
await db.schema.dropTable("person").execute();
opengraphImageCreator
@itseieio
@jsxImportSource https://esm.sh/react
HTTP
angle?: number;
function App() {
const [backgroundImage, setBackgroundImage] = useState<string | null>(null);
</div>
function client() {
createRoot(document.getElementById("root")).render(<App />);
if (typeof document !== "undefined") { client(); }
export default async function server(request: Request): Promise<Response> {
return new Response(`
allvalsindex
@ejfox
@jsxImportSource https://esm.sh/react
HTTP
import { createRoot } from "https://esm.sh/react-dom/client";
// Function to get a random emoji
function getRandomEmoji() {
const emojis = ['😀', '😎', '🤖', '👻', '🚀', '🌈', '🍕', '🎉', '💡', '🔥', '🌟', '🦄'];
return emojis[Math.floor(Math.random() * emojis.length)];
function App() {
const [vals, setVals] = useState([]);
</div>
function client() {
createRoot(document.getElementById("root")).render(<App />);
if (typeof document !== "undefined") { client(); }
async function server(request: Request): Promise<Response> {
const { pathname } = new URL(request.url);

whiteXerinae
@stevekrouse
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 (v66) 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 [ ] 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 [ ] 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
HTTP
- [x] make result tables scrollable
- [x] add export to CSV, and JSON (CSV and JSON helper functions written in [this val](https://www.val.town/v/nbbaier/sqliteExportHelpers). Thanks to @pomdtr for merging the initial version!)
- [x] add listener for cmd+enter to submit query
rumsey_roulette
@sammeltassen
Rumsey Roulette This val returns a random Georeference Annotation from the David Rumsey Map Collection . More information about the source data can be found here . You can use this val by copying its HTTP endpoint and opening it in Allmaps Viewer : https://viewer.allmaps.org/?url=https://sammeltassen-rumsey_roulette.web.val.run Each time you refresh the page, the viewer will load a random map from the Rumsey collection! In total 56626 maps have been georeferenced.
HTTP
return map;
async function getRandomObject() {
const result = await sqlite.execute(`
return generateAnnotation(map);
function parseData(ndjson: string) {
return ndjson.split(/[\r\n]+/)
.map((line) => JSON.parse(line));
function createChunks(arr: any[]) {
let chunks = new Array();
return chunks;
export default async function(req: Request): Promise<Response> {
const method = req.method;

automergeDemo
@stevekrouse
An interactive, runnable TypeScript val by stevekrouse
HTTP
import * as automerge from "npm:@automerge/automerge/slim";
await automerge.next.initializeBase64Wasm(automergeWasmBase64);
export default async function(req: Request): Promise<Response> {
// from https://automerge.org/automerge/api-docs/js/
type DocType = { ideas: Array<automerge.Text> };
hnFollowPollJobTest
@andreterron
An interactive, runnable TypeScript val by andreterron
Script
import { hackerNewsAuthors } from "https://esm.town/v/andreterron/hackerNewsAuthors";
import { hnLatestPosts } from "https://esm.town/v/stevekrouse/hnLatestPosts?v=18";
export async function hnFollowPollJobTest(interval: Interval) {
let posts = await hnLatestPosts({
authors: hackerNewsAuthors,