Edge & bindings
On Cloudflare and other edge runtimes, your platform bindings (KV, D1, Durable Objects, secrets) reach handlers through a fully-typed c.env.
Typed c.env
server<Env>() threads your Env type through the whole app: c.env is Env in every handler and in derive/decorate middleware — read c.env.KV directly, no cast. app.fetch(req, { env }) / toFetchHandler type-check the bindings too. In @nifrajs/web, a route's loader/action gets the same typed env.
// server<Env>() types the platform env end-to-end — c.env is your Env in every
// handler AND in derive/decorate middleware, with no cast.
interface Env { KV: KVNamespace; DB: D1Database }
const app = server<Env>()
.get("/u/:id", async (c) => {
const cached = await c.env.KV.get(c.params.id) // c.env is typed Env
return cached ?? "miss"
})
export default { fetch: (req: Request, env: Env, ctx: ExecutionContext) =>
app.fetch(req, { env, waitUntil: ctx.waitUntil.bind(ctx) }) }Background work
c.waitUntil(promise) keeps work alive after the response is sent — cache writes, analytics, fan-out — without blocking the user. (Typing is not validation: platform bindings are trusted inputs; validate anything untrusted at the boundary.)
// c.waitUntil keeps background work alive past the response (analytics, cache writes).
app.post("/event", (c) => {
c.waitUntil(c.env.KV.put("last", Date.now().toString()))
return { ok: true } // returns immediately; the put finishes in the background
})Validation on the edge
Edge runtimes block dynamic code generation (new Function), which trips many schema libraries. Nifra's t handles it transparently: it compiles a fast validator on Bun and Node, and falls back to an eval-free checker on Cloudflare Workers, Vercel Edge, and Deno Deploy — the same routes validate everywhere, with no edge-specific schema module. Because core validates any Standard Schema, you can also bring Zod, Valibot, or ArkType (all eval-free) — only t also emits OpenAPI from the same definition.
Scheduled (cron)
Pass scheduled to toFetchHandler to also export a Workers cron handler for a [triggers] schedule. It gets the platform controller plus the same typed env and waitUntil as your request handlers.
import { toFetchHandler } from "@nifrajs/core"
import { app } from "./app"
// Export fetch + a cron handler. Wire the schedule in wrangler.toml: [triggers] crons = ["0 * * * *"]
export default toFetchHandler(app, {
scheduled: (controller, { env, waitUntil }) =>
waitUntil(env.KV.put("last-run", String(controller.scheduledTime))),
})