Kynetra FX

Documentation

Context (ctx)

Every handler and middleware receives a single ctx object that bundles the incoming request, route metadata, and all response helpers. It is the sole argument to every handler — no juggling req and res separately.

Request access#

The raw Request object is on ctx.req. A pre-parsed URL instance is on ctx.url. Both are read-only.

app.ts
app.get('/info', (ctx) => {
const method = ctx.req.method // 'GET'
const pathname = ctx.url.pathname // '/info'
const host = ctx.url.host // 'api.example.com'
const ua = ctx.req.headers.get('user-agent')
return ctx.json({ method, pathname, host, ua })
})

Route params#

Named segments and wildcard captures are on ctx.params — a Record<string, string> that is always URL-decoded.

app.ts
app.get('/users/:id', (ctx) => {
const id = ctx.params.id // '42'
return ctx.json({ id })
})
 
app.get('/files/*', (ctx) => {
const path = ctx.params['*'] // 'assets/logo.png'
return ctx.text(path)
})

See Params for the full reference.

Query strings#

ctx.query(name) returns a single query value or null. ctx.query() returns all params as a record.

app.ts
// GET /search?q=edge&limit=20
app.get('/search', (ctx) => {
const q = ctx.query('q') // 'edge'
const limit = ctx.query('limit') // '20'
const all = ctx.query() // { q: 'edge', limit: '20' }
return ctx.json({ q, limit, all })
})

Request headers#

ctx.header(name) returns the value of a single request header as a string or null (case-insensitive).

app.ts
app.get('/whoami', (ctx) => {
const auth = ctx.header('authorization')
const accept = ctx.header('accept')
const tenant = ctx.header('x-tenant-id')
return ctx.json({ auth, accept, tenant })
})

Environment bindings#

Runtime environment bindings (Cloudflare Workers env, process.env, etc.) are available on ctx.env. Cast it to your declared Env interface for type safety.

app.ts
interface Env {
DB: D1Database
API_SECRET: string
}
 
app.get('/secret', (ctx) => {
const env = ctx.env as Env
return ctx.text(env.API_SECRET)
})

State#

ctx.state is a Map that lives for the lifetime of a single request. Use it to pass data between middleware and handlers without mutating global scope.

middleware/user.ts
// Middleware: attach user after auth
app.use(async (ctx, next) => {
const token = ctx.header('authorization')
if (token) {
ctx.state.set('user', { id: '42', name: 'Alice' })
}
return next()
})
 
// Handler: read from state
app.get('/me', (ctx) => {
const user = ctx.state.get('user')
return ctx.json(user ?? null)
})

Tip

Prefer context decorations (ctx.decorate /ctx.get) for values that plugins and middleware expose as part of a stable API. Use ctx.state for ad-hoc within-request data passing.

Decorations#

Plugins and middleware can attach named values to ctx with ctx.decorate(key, value). Read them back with ctx.get(key). Check existence with ctx.has(key).

plugin/db.ts
import { definePlugin } from '@kynetra/fx'
 
export const dbPlugin = definePlugin({
name: 'db',
register(app) {
app.decorateContext('db', (ctx) => {
// factory called per-request — binds D1 from env
return (ctx.env as any).DB
})
},
})
 
// In handlers:
app.get('/users', (ctx) => {
const db = ctx.get('db') // D1Database
return ctx.json({ ok: true })
})

Contract data#

When using app.route() with input or query schemas, the validated and typed values appear on ctx.input and ctx.validatedQuery respectively.

app.ts
app.route({
method: 'POST',
path: '/items',
input: fx.object({ name: fx.string(), qty: fx.number() }),
handler(ctx) {
// ctx.input: { name: string; qty: number }
const { name, qty } = ctx.input
return ctx.json({ name, qty }, { status: 201 })
},
})

See Contracts for details.

Full ctx reference#

NameTypeDescription
reqRequestThe incoming Web Standards Request object.
urlURLPre-parsed URL instance for the request.
paramsRecord<string, string>URL-decoded route parameters including wildcard capture as params["*"].
query(name?)string | null | Record<string, string>Query-string accessor. No arg returns all params as a record.
header(name)string | nullCase-insensitive request header accessor.
envunknownRuntime environment / bindings object. Cast to your Env type.
stateMap<string, unknown>Per-request key-value store for passing data between middleware.
inputT (inferred)Validated and typed request body (set by app.route() with input schema).
validatedQueryT (inferred)Validated and typed query params (set by app.route() with query schema).
decorate(key, value)voidAttach a named value to this ctx instance.
get<T>(key)TRead a decoration or context-decorator value by key.
has(key)booleanCheck whether a decoration exists on this ctx instance.
json(data, init?)ResponseReturn a JSON response.
text(s, init?)ResponseReturn a plain-text response.
html(s, init?)ResponseReturn an HTML response.
redirect(url, status?)ResponseReturn a redirect response (default 302).
stream(body, init?)ResponseReturn a streaming response.
response(body?, init?)ResponseReturn a raw Response.
status(code)ctx (chainable)Set the response status code. Chainable.
set(name, value)voidSet a response header.
append(name, value)voidAppend to a response header.
cookie(name)string | nullRead a request cookie by name.
setCookie(name, value, opts?)voidSet a response cookie.
jsonBody<T>()Promise<T>Parse the request body as JSON.
textBody()Promise<string>Parse the request body as text.
formBody()Promise<FormData>Parse the request body as FormData (multipart or URL-encoded).