import type { KvPair, RouteSchema } from './context.ts'; import type { ByteSize, Duration } from './units.ts'; import type { ErrorHook, Handler, Hook, Middleware, StageName } from './pipeline.ts'; export { HttpError } from './context.ts'; export type { Context, CookieOptions, MultipartPart } from './context.ts'; export type { Handler, Middleware, Hook, ErrorHook } from './pipeline.ts'; /** CORS (§6a). An `origin` function is not native — write a JS middleware for dynamic logic. */ export interface CorsConfig { origin?: string | string[]; methods?: string[]; allowedHeaders?: string[]; exposedHeaders?: string[]; credentials?: boolean; maxAge?: number; } /** TLS (§12): a PEM string, a file path, or a Buffer. */ export interface TlsConfig { cert: string | Buffer; key: string | Buffer; } /** HTTP/2 (§6c A1). */ export interface Http2Config { maxConcurrentStreams?: number; initialWindowSize?: ByteSize; maxResetStreamsPerSec?: number; } /** Probes and metrics (§11). An empty path disables the endpoint. */ export interface HealthConfig { path?: string; readyPath?: string; metricsPath?: string; /** A separate port: probes and metrics are then absent from the main port. */ port?: number; } /** Multipart limits (§9a). */ export interface MultipartConfig { maxFileSize?: ByteSize; maxFieldSize?: ByteSize; maxFiles?: number; maxFields?: number; allowedMimeTypes?: string[]; allowedExtensions?: string[]; } /** Server configuration. */ export interface ServerConfig { baseUrl?: string; requestId?: { header?: string; }; /** Max request body size; defaults to `'10mb'`. Pass `null` to remove the limit — * note that this also removes the bound on decompressed size (zip bombs). */ bodyLimit?: ByteSize | null; requestTimeout?: Duration; customIpHeaders?: string[]; customCountryHeaders?: string[]; cors?: CorsConfig; tls?: TlsConfig; /** h2c prior-knowledge on the plaintext port (§12). */ h2c?: boolean; http2?: Http2Config; headerReadTimeout?: Duration; bodyReadTimeout?: Duration; idleTimeout?: Duration; handshakeTimeout?: Duration; maxHeaders?: number; maxHeaderSize?: ByteSize; shutdownTimeout?: Duration; /** The "readiness dropped but still accepting" pause — 5–15s under k8s. */ preShutdownDelay?: Duration; handleSignals?: boolean; /** Install the process-wide `unhandledRejection` log handler (§8). Default `true`; * skipped anyway when the application already registered its own. */ installSafetyNet?: boolean; /** Watch for client disconnects even with no `onAbort` hook, so `c.req.signal` aborts * when the client goes away. Costs one pending promise per request, hence opt-in; * registering an `onAbort` hook enables the watch on its own. */ detectDisconnect?: boolean; backlog?: number; reusePort?: boolean; noDelay?: boolean; maxConnections?: number; proxyProtocol?: boolean; workerThreads?: number | 'auto'; health?: HealthConfig; accessLog?: boolean; maxConcurrentRequests?: number; maxQueue?: number; queueTimeout?: Duration; retryAfter?: number; overloadShedAfter?: Duration; } /** Native response cache for a route (§18). */ export interface RouteCacheConfig { /** Entry lifetime. Required. */ ttl: Duration; /** Request headers whose values become part of the cache key (e.g. `['x-tenant']`). */ vary?: string[]; /** Entry cap per route; defaults to 1024. */ maxEntries?: number; /** Responses with a larger body are not stored; defaults to `'1mb'`. */ maxBodyBytes?: ByteSize; } /** Route options: schemas, multipart, native response cache and route-level hooks. */ export type RouteOptions = { schema?: RouteSchema; multipart?: boolean | MultipartConfig; /** Native response cache (§18): after the first response, identical requests are * answered in Rust without waking JS. GET/HEAD/QUERY only. A bare duration is * shorthand for `{ ttl }`. */ cache?: Duration | RouteCacheConfig; } & Partial>; /** `listen()` arguments: TCP or a Unix socket. */ export interface ListenArgs { port?: number; host?: string; /** Unix socket (§6c B9); when set, `port`/`host` are ignored. */ path?: string; } /** A request for `app.inject()` (§17). */ export interface InjectRequest { method?: string; path?: string; headers?: Record; body?: Buffer | string | unknown; query?: Record; } /** The `app.inject()` response. */ export interface InjectResult { status: number; headers: Record; rawHeaders: KvPair[]; body: Buffer; text(): string; json(): T; } /** Server events (§6d B7). */ export type ServerEvent = 'listening' | 'error' | 'close' | 'shutdown'; /** Payload of the `listening` event: a TCP address or a Unix socket path. */ export interface ListeningInfo { port?: number; host?: string; path?: string; } /** Handler signatures per event. */ export interface ServerEventMap { listening: (info: ListeningInfo) => void; error: (err: unknown) => void; close: () => void; shutdown: () => void; } /** Options for the periodic readiness check (§11). */ export interface ReadinessCheckOptions { interval?: number; timeout?: number; } export declare class Server { #private; constructor(config?: ServerConfig); get(path: string, handler: Handler): this; get(path: string, options: RouteOptions, handler: Handler): this; get(path: string, ...a: Array): this; post(path: string, handler: Handler): this; post(path: string, options: RouteOptions, handler: Handler): this; post(path: string, ...a: Array): this; put(path: string, handler: Handler): this; put(path: string, options: RouteOptions, handler: Handler): this; put(path: string, ...a: Array): this; patch(path: string, handler: Handler): this; patch(path: string, options: RouteOptions, handler: Handler): this; patch(path: string, ...a: Array): this; delete(path: string, handler: Handler): this; delete(path: string, options: RouteOptions, handler: Handler): this; delete(path: string, ...a: Array): this; head(path: string, handler: Handler): this; head(path: string, options: RouteOptions, handler: Handler): this; head(path: string, ...a: Array): this; options(path: string, handler: Handler): this; options(path: string, options: RouteOptions, handler: Handler): this; options(path: string, ...a: Array): this; /** HTTP `QUERY` (draft-ietf-httpbis-safe-method-w-body): a safe method whose request * body describes the query — "GET with a body". Works with `schema.body` (validated * in Rust) and with the native response cache. */ query(path: string, handler: Handler): this; query(path: string, options: RouteOptions, handler: Handler): this; query(path: string, ...a: Array): this; all(path: string, handler: Handler): this; all(path: string, options: RouteOptions, handler: Handler): this; all(path: string, ...a: Array): this; /** `app.use(fn)` — global; `app.use(prefix, ...fns)` — scoped by prefix. */ use(...args: Array): this; /** Generic hook registration. */ addHook(name: StageName, fn: Hook | ErrorHook): this; /** The unified error handler `onError(err, c)`. Several may be registered. */ onError(fn: ErrorHook): this; onRequest(fn: Hook): this; preParsing(fn: Hook): this; preValidation(fn: Hook): this; preHandler(fn: Hook): this; preSerialization(fn: Hook): this; onSend(fn: Hook): this; onResponse(fn: Hook): this; onTimeout(fn: Hook): this; onAbort(fn: Hook): this; /** Mount a sub-application under a prefix (encapsulation via prefix matching). * * The sub-app is recorded by reference and folded in at `listen()`, so routes, * middleware and hooks added to it *after* this call are still picked up. Copying * eagerly meant anything registered later was silently dropped. */ route(prefix: string, sub: Server): this; /** Custom 404 handler (otherwise Rust answers 404 without waking JS). */ notFound(handler: Handler): this; /** Purge the native response cache (§18): everything, or entries whose request path * equals `path` exactly (every query/vary variant of it). Returns the number of * entries removed. The path includes `baseUrl`, exactly as the client sends it. */ purgeCache(path?: string): number; /** Listen on TCP (`{ port, host }`) or a Unix socket (`{ path }`) — §6c B9. */ listen({ port, host, path }?: ListenArgs): Promise; /** Subscribe to server events: `listening`, `error`, `close`, `shutdown` (§6d B7). */ on(event: E, fn: ServerEventMap[E]): this; off(event: E, fn: ServerEventMap[E]): this; /** Graceful shutdown (§10): close the listener, finish in-flight requests, then * resolve. Idempotent and safe for concurrent calls — they all await the same drain. */ close(): Promise; get listening(): boolean; /** Socket-free test harness (§17): the request travels through an in-memory pipe and * the very same pipeline — routing, schemas, CORS, metrics, the JS onion. * * If the server is not started yet we start it on an ephemeral port (routes and * schemas are compiled inside `listen()`); the request itself never uses a socket. */ inject(req?: InjectRequest): Promise; /** Manual readiness (§11): `false` → `/readyz` returns 503; liveness is untouched. */ setReady(ready: boolean): this; /** Periodic readiness check (§11): database, queue, cache warm-up. * * The callback runs on a timer on the JS side and pushes its verdict into Rust, while * `/readyz` answers instantly from an atomic. Otherwise every k8s probe (once a second * per pod) would wake the event loop — exactly what Rust-side probes exist to avoid. * A callback error or timeout counts as "not ready". */ setReadinessCheck(fn: () => boolean | void | Promise, { interval, timeout }?: ReadinessCheckOptions): this; } //# sourceMappingURL=index.d.ts.map