← Val TownCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Val Town
Snapshot Sep 30, 2026 · 22:50 UTC · version 3.0.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "http-endpoints",
"description": "Use when building an HTTP val — a web endpoint, API route, webhook receiver, or any val that responds to HTTP requests. Covers the handler signature, Hono usage, the endpoint URL, CORS behavior, redirects, and Val Town-specific limitations.",
"included_files": [],
"skill_md_contents": "---\nname: http-endpoints\ndescription: Use when building an HTTP val — a web endpoint, API route, webhook receiver, or any val that responds to HTTP requests. Covers the handler signature, Hono usage, the endpoint URL, CORS behavior, redirects, and Val Town-specific limitations.\n---\n\n# HTTP Endpoints\n\nHTTP vals (`fileType: \"http\"`) export a request handler and run on every incoming HTTP request. Each HTTP file is assigned a live URL — never construct it yourself; read `links.endpoint` from `list_files` or `create_file` responses, or call `fetch_val_endpoint`.\n\nThat URL is open to anyone unless the val's app access (`httpPrivacy`) is `restricted`, in which case unauthenticated callers get a `302` to a login page instead of your response — see the `restricted-access` skill.\n\n## Basic handler\n\n```ts\n// Learn more: https://docs.val.town/vals/http/\nexport default async function (req: Request): Promise<Response> {\n return Response.json({ ok: true });\n}\n```\n\nThe file must have an `export` — `export default` for the handler.\n\n## Hono\n\nWhen using Hono, export `app.fetch` (not `app`):\n\n```ts\nimport { Hono } from \"npm:hono\";\nimport { parseVal, serveImmutableFile } from \"https://esm.town/v/std/utils/index.ts\";\n\nconst app = new Hono();\n\napp.get(\"/\", (c) => c.text(\"hello\"));\n\n// Immutable asset caching (see the client-side-js skill): serves the\n// current-version URLs your HTML shell stamps with immutableFileUrl()\napp.get(\"/__immutable/*\", (c) => serveImmutableFile(c.req.path));\n\n// View source redirect\napp.get(\"/source\", (c) => c.redirect(parseVal().links.self.val));\n\n// Always add this for full stack traces on errors:\napp.onError((err) => Promise.reject(err));\n\nexport default app.fetch;\n```\n\nHono's `serveStatic` does **not** work on Val Town. Use `serveFile` / `staticHTTPServer` from `std/utils` for static files. For the full `std/utils` API (`readFile`, `serveFile`, `staticHTTPServer`, `listFiles`, `listFilesByPath`, `httpEndpoint`, `parseVal`, …), fetch `https://utilities.val.run/docs.md`.\n\n## CORS\n\nVal Town adds permissive CORS headers by default (`Access-Control-Allow-Origin: *`), so in 99% of cases, you should never need to do anything with CORS. Using Hono's `cors` middleware is almost always unnecessary. \n\nIf you set **any** CORS header yourself, Val Town stops adding **all** default headers — so either handle CORS completely yourself or don't touch it at all.\n\n## Redirects\n\n`Response.redirect` is broken on Val Town. Use one of:\n\n```ts\nreturn new Response(null, { status: 302, headers: { Location: \"/path\" } });\n// or, with Hono:\nreturn c.redirect(\"/path\");\n```\n\n## What's not available\n\n- **WebSockets**: Val Town does not accept incoming WebSocket connections. Use polling, long polling, or server-sent events instead.\n- **Filesystem access**: see the platform constraints. For persistent state, use `std/sqlite` or `std/blob`.\n\n## Surfacing client-side errors\n\nFor HTML responses, add this script tag to send browser errors back to val logs (visible via `get_logs`):\n\n```html\n<script src=\"https://esm.town/v/std/catch\"></script>\n```\n\n## Verifying changes\n\nAfter editing an HTTP val, fetch it to confirm it returns the expected HTTP response. Do not report a change as done without this step.\n"
}SHA-256: 37638ba1b3cf9d5919761bd76206e41f249d37ffddd2c6b6a4fbc8731a6775cb