CORE CONCEPTS

WinterCG Adapter

toWinterCgHandler() turns a Futon instance into the { fetch } default-export shape used by every WinterCG-compatible runtime — Cloudflare Workers, Deno, Bun, and Service Workers all expect this exact signature.

Usage

Cloudflare Workers
import { Futon, toWinterCgHandler, json } from '@rasenganjs/futon'; const app = new Futon(); app.get('/api/health', async () => json({ status: 'ok' })); export default { fetch: toWinterCgHandler(app) };
Bun / Deno
import { Futon, toWinterCgHandler } from '@rasenganjs/futon'; const app = new Futon(); // ... routes Bun.serve({ fetch: toWinterCgHandler(app) });

Normalizing Runtime Differences

Different WinterCG runtimes call the fetch handler with different argument shapes:

RuntimeSignature
Cloudflare Workers(request, env, ctx)
Deno(request, info)
Bun(request, server)
Service Workers(request) only

toWinterCgHandler() inspects the arguments it receives and normalizes them into Futon's RuntimeContext ({ env, server }) regardless of which shape shows up — your route handlers never need to know which runtime they're running under.

waitUntil for Background Work

On runtimes that support it (Cloudflare Workers), the adapter exposes ctx.waitUntil() for background tasks that should keep running after the response is sent — triggered when your response includes an X-Rasengan-Background header. This is an edge-case escape hatch; most handlers won't need it.

Choosing an Adapter

  • Deploying to a serverless edge runtime (Workers, Deno Deploy)? Use toWinterCgHandler().
  • Running inside Bun's own server (Bun.serve)? Same handler works — Bun implements the WinterCG fetch contract natively.
  • Embedding Futon inside an existing Express app? Use toExpressHandler() instead.
  • Running a standalone Node process (dev or prod)? Use the runtime adapters from @rasenganjs/runtime — they bind an actual http.Server for you.
Express Adapter
Runtime Adapters