Public
HTTP middleware that snapshots requests to blob storage
blob-storagehttploggingmiddleware
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

request-capture

A drop-in HTTP middleware for Val Town that snapshots every incoming request into val-scoped blob storage as a serializable object, without disturbing the handler you wrap.

Usage in your own HTTP val

Import and wrap your handler:

import { withRequestLogging } from "https://esm.town/v/nbbaier/request-capture/lib.ts"; export default withRequestLogging(async (req: Request) => { return Response.json({ ok: true }); });

By default each request is stored as a blob under captures:<uuid> containing:

{ id: string; // uuid method: string; url: string; timestamp: number; // ms time: string; // ISO headers: Record<string, string>; body?: string; // only when captureBody is enabled }

Sensitive headers (authorization, cookie, set-cookie, x-api-key, …) are redacted to name:redacted so secrets never land in storage.

Options

withRequestLogging(handler, { captureBody: true, // snapshot the body via req.clone() maxBodyBytes: 64 * 1024, // cap body capture size keyPrefix: "captures", // blob key prefix onCaptured: (cap) => console.log(cap.url), // fan out (fire-and-forget) });

The body is not consumed unless captureBody is set, so the wrapped handler can still read it. Even with body capture, it reads a clone — the original stays intact.

Reading captures

import { listCaptures, readRequest, pruneCaptures } from "https://esm.town/v/nbbaier/request-capture/lib.ts"; const all = await listCaptures(); // newest first, capped at `limit` const one = await readRequest(id); const removed = await pruneCaptures(7 * 24 * 60 * 60 * 1000); // delete old ones

Demo

The live endpoint wraps its own handler and exposes two inspection routes:

  • GET /log — list every captured request
  • GET /_prune — delete captures older than 30 days