This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Two-stroke is a lightweight TypeScript framework for building type-safe APIs on Cloudflare Workers. It provides structured routing, authentication (PBKDF, JWT/JWK), Zod-based request/response validation, auto-generated OpenAPI docs, queue/cron/email handlers, and Sentry error tracking.
All commands are exposed as bin scripts (no npm run prefix needed when installed):
pnpm lint— ESLint + Prettier check (fails on violations)pnpm format— ESLint fix + Prettier writepnpm test— Builds withwrangler deploy --dry-run, then runs Vitest with Cloudflare Workers pool (Miniflare)pnpm type-check—wrangler deploy --dry-run+tsc --noEmitpnpm dev— Local dev server viawrangler devpnpm deploy <env> <version>— Deploy with Sentry release trackingpnpm api-types <url>— Generate TypeScript types from an OpenAPI endpoint
There is no way to run a single test file directly — use Vitest's built-in filtering (e.g., vitest run src/foo.test.ts).
index.ts— MaintwoStroke<T>()factory. Returnsfetch,queue,scheduled,emailhandlers plus route registration methods (get,post,put,delete) and auth builders (noAuth,pbkdf,jwt). Routes are regex-matched with path parameters like{userId}.types.ts— Core type definitions:Env(CF bindings union),Route<T, A>,Handler<T, I, O, A, P>,ExtractParameterNames<S>(extracts{param}from path strings).open-api.ts— Generates OpenAPI 3.1.0 spec from registered routes; served at/doc.test.ts— Test utilities:setupTests()(fetch mocking, OpenAPI client),fakeJWK()(RS256 test tokens), request recording helpers,waitForQueue().cmd.mjs— Shared utility for spawning subprocesses in bin scripts.
- Route matched by regex against URL pathname
- Auth handler runs (returns claims or throws)
- Request body parsed and validated against Zod input schema (POST/PUT)
- Handler executes with typed context:
{ req, env, body, params, searchParams, claims, sentry, waitUntil } - Response validated against Zod output schema
- CORS + security headers applied automatically
- Zod v4 — imported as
zod/v4(notzod) - ESM only —
"type": "module"withverbatimModuleSyntaxin tsconfig - Strict TypeScript —
strict: true,noUncheckedIndexedAccess: true,isolatedModules: true - Node 24.9+ required, pnpm 10.30+ via Corepack
- Prettier — 100 char print width
- ESLint config — extends
eslint-config-two-stroke - Testing — Vitest with
@cloudflare/vitest-pool-workerspool; globals enabled (no imports needed fordescribe,it,expect)