@nifrajs/cli 2.12.1 → 2.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities-tool.d.ts +54 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +146 -18
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/check.d.ts +11 -11
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +235 -47
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +96 -406
- package/dist/cli.js.map +1 -1
- package/dist/command-catalog.d.ts +244 -0
- package/dist/command-catalog.d.ts.map +1 -0
- package/dist/command-catalog.js +1014 -0
- package/dist/command-catalog.js.map +1 -0
- package/dist/contracts.d.ts +9 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +22 -6
- package/dist/contracts.js.map +1 -1
- package/dist/doctor.d.ts +18 -11
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +30 -230
- package/dist/doctor.js.map +1 -1
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +22 -5
- package/dist/load.js.map +1 -1
- package/dist/manifest-tool.d.ts +15 -1
- package/dist/manifest-tool.d.ts.map +1 -1
- package/dist/manifest-tool.js +23 -9
- package/dist/manifest-tool.js.map +1 -1
- package/dist/mcp-http.js +1 -1
- package/dist/mcp.d.ts +8 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +59 -349
- package/dist/mcp.js.map +1 -1
- package/dist/project-facts.d.ts +40 -0
- package/dist/project-facts.d.ts.map +1 -0
- package/dist/project-facts.js +36 -0
- package/dist/project-facts.js.map +1 -0
- package/dist/release-verification.d.ts +45 -0
- package/dist/release-verification.d.ts.map +1 -0
- package/dist/release-verification.js +303 -0
- package/dist/release-verification.js.map +1 -0
- package/dist/rules/comment-markers.d.ts +8 -0
- package/dist/rules/comment-markers.d.ts.map +1 -1
- package/dist/rules/comment-markers.js +36 -0
- package/dist/rules/comment-markers.js.map +1 -1
- package/dist/rules/index.d.ts +2 -3
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/routes.d.ts.map +1 -1
- package/dist/rules/routes.js +12 -14
- package/dist/rules/routes.js.map +1 -1
- package/dist/rules/security.js +14 -14
- package/dist/rules/security.js.map +1 -1
- package/docs/types.json +28 -15
- package/package.json +9 -9
- package/src/capabilities-tool.ts +229 -21
- package/src/check.ts +286 -64
- package/src/cli.ts +106 -399
- package/src/command-catalog.ts +1415 -0
- package/src/contracts.ts +28 -7
- package/src/doctor.ts +56 -264
- package/src/load.ts +25 -6
- package/src/manifest-tool.ts +43 -12
- package/src/mcp-http.ts +1 -1
- package/src/mcp.ts +82 -414
- package/src/project-facts.ts +86 -0
- package/src/release-verification.ts +377 -0
- package/src/rules/comment-markers.ts +36 -0
- package/src/rules/index.ts +3 -4
- package/src/rules/routes.ts +13 -14
- package/src/rules/security.ts +14 -14
package/docs/types.json
CHANGED
|
@@ -4995,8 +4995,7 @@
|
|
|
4995
4995
|
"name": "generateServerManifest",
|
|
4996
4996
|
"kind": "function",
|
|
4997
4997
|
"package": "@nifrajs/web",
|
|
4998
|
-
"signature": "export declare function generateServerManifest(manifest: Manifest, options: GenerateServerManifestOptions): string;"
|
|
4999
|
-
"doc": "/**\n * Codegen: emit a **server manifest** module (as source) for disk-less edge runtimes (Cloudflare\n * Workers, …) - and, with a `target`, any portable server bundle. `discoverRoutes` scans `node:fs`\n * and dynamic-imports each route by a *runtime* path - neither exists on workerd. This instead emits\n * **statically-analyzable** imports of every route/layout/`_error`/terminal status page (so the bundler includes them) and\n * rebuilds the manifest with `buildManifest` - the SAME pure logic `discoverRoutes` feeds, so patterns\n * + layout chains are identical. Eager (`import * as`) by default; `lazy` emits `() => import(...)` so\n * a code-splitting bundler chunks per route. The emitted module exports `manifest` (consumed by\n * `createWebApp`, unchanged) + `clientEntry` (baked). Write it to a file and bundle it into the worker\n * entry (see `buildServer` in `@nifrajs/web/build`).\n */"
|
|
4998
|
+
"signature": "export declare function generateServerManifest(manifest: Manifest, options: GenerateServerManifestOptions): string;"
|
|
5000
4999
|
},
|
|
5001
5000
|
{
|
|
5002
5001
|
"name": "GenerateServerManifestOptions",
|
|
@@ -6045,7 +6044,7 @@
|
|
|
6045
6044
|
"name": "Jsonify",
|
|
6046
6045
|
"kind": "type",
|
|
6047
6046
|
"package": "@nifrajs/client",
|
|
6048
|
-
"signature": "export type Jsonify<T> = [unknown] extends [T] ? unknown : T extends BinaryResponse ? Blob : T extends string | number | boolean | null ? T : T extends Date ? string : T extends bigint ? never : T extends (...args: never[]) => unknown ? never : T extends undefined ? never : T extends ReadonlyArray<infer U> ? Array<Jsonify<U>> : T extends object ? {\n [K in keyof T as [Jsonify<T[K]>] extends [never] ? never : K]: Jsonify<T[K]>;\n} : never;",
|
|
6047
|
+
"signature": "export type Jsonify<T> = [unknown] extends [T] ? unknown : T extends BinaryResponse ? Blob : T extends RawResponse<infer U> ? Jsonify<U> : T extends string | number | boolean | null ? T : T extends Date ? string : T extends bigint ? never : T extends (...args: never[]) => unknown ? never : T extends undefined ? never : T extends ReadonlyArray<infer U> ? Array<Jsonify<U>> : T extends object ? {\n [K in keyof T as [Jsonify<T[K]>] extends [never] ? never : K]: Jsonify<T[K]>;\n} : never;",
|
|
6049
6048
|
"doc": "/**\n * Maps a value to the shape it takes after a JSON round-trip, so the client's\n * `data` type reflects the wire - not the handler's in-memory return.\n *\n * - `Date` → `string`; `undefined` / functions / `bigint` → dropped from objects\n * - arrays and plain objects recurse; optionality (`?`) is preserved\n *\n * Pragmatic by design: `Map`/`Set`/class instances/custom `toJSON` are treated as\n * plain objects (best-effort), not specially handled. Documented, not magic.\n */"
|
|
6050
6049
|
},
|
|
6051
6050
|
{
|
|
@@ -8196,8 +8195,8 @@
|
|
|
8196
8195
|
"name": "parseManifestRouteFiles",
|
|
8197
8196
|
"kind": "function",
|
|
8198
8197
|
"package": "@nifrajs/web",
|
|
8199
|
-
"signature": "export declare function parseManifestRouteFiles(source: string,
|
|
8200
|
-
"doc": "/**\n * Extract the route-relative file list
|
|
8198
|
+
"signature": "export declare function parseManifestRouteFiles(source: string, _routesPrefix?: string): string[];",
|
|
8199
|
+
"doc": "/**\n * Extract the route-relative file list a committed server-manifest declares, as the same\n * `routes/`-relative keys `discoverRoutes` produces (e.g. `docs/index.tsx`). Reads the route map's KEYS,\n * which carry the file extension and no directory prefix - exactly discovery's shape - so the result is\n * independent of the specifier prefix the manifest happened to import with. The `@nifrajs/web` import and\n * the baked `clientEntry`/`styles`/`routeStyles` lines carry no route-map entry and are ignored.\n *\n * `_routesPrefix` is accepted for call-site compatibility but no longer needed: the keys are already\n * prefix-free. Pure - operates on source text.\n */"
|
|
8201
8200
|
},
|
|
8202
8201
|
{
|
|
8203
8202
|
"name": "parseManifestRouteStyles",
|
|
@@ -8608,7 +8607,7 @@
|
|
|
8608
8607
|
"name": "ProjectFacts",
|
|
8609
8608
|
"kind": "interface",
|
|
8610
8609
|
"package": "@nifrajs/cli",
|
|
8611
|
-
"signature": "export interface ProjectFacts {\n readonly [
|
|
8610
|
+
"signature": "export interface ProjectFacts {\n readonly source: SourceIndex;\n readonly routes: readonly StaticRouteFinding[];\n readonly importGraph: readonly TransitiveServerImportFinding[];\n readonly packages: ProjectPackageFacts;\n readonly pipeline?: PipelineReport;\n readonly policies: ProjectPolicyFacts;\n readonly sourceFindings: ProjectSourceFindings;\n readonly legacyDiagnostics: readonly CheckDiagnostic[];\n}"
|
|
8612
8611
|
},
|
|
8613
8612
|
{
|
|
8614
8613
|
"name": "ProjectWorkGraphResult",
|
|
@@ -8922,6 +8921,13 @@
|
|
|
8922
8921
|
"signature": "export interface RateLimitStore {\n hit(key: string, windowMs: number): Promise<RateLimitResult>;\n}",
|
|
8923
8922
|
"doc": "/**\n * Counter backend. Production deploys MUST use a shared store (Redis, etc.) so the\n * limit holds across instances - that's a user dependency, not ours, hence the\n * interface. {@link MemoryStore} is for dev / single-instance only.\n */"
|
|
8924
8923
|
},
|
|
8924
|
+
{
|
|
8925
|
+
"name": "raw",
|
|
8926
|
+
"kind": "function",
|
|
8927
|
+
"package": "@nifrajs/core",
|
|
8928
|
+
"signature": "export declare function raw<T>(response: Response): RawResponse<T>;",
|
|
8929
|
+
"doc": "/**\n * Brand a hand-built `Response` with the payload type `T` its body serializes to, so a route that must\n * return a `Response` directly still types `res.data` as `Jsonify<T>` on the client instead of `never`.\n * Use it for the endpoints that build their own `Response` - a token minted by a third-party SDK, a\n * redirect that also carries a JSON body, a hand-tuned cache header - but should still be part of the\n * contract. Purely a type assertion: the `Response` is returned unchanged, nothing is added at runtime.\n *\n * app.get(\"/livekit-token\", async (c) =>\n * raw<{ token: string }>(Response.json({ token: await mint(c) })))\n * // client: res.data is typed { token: string }\n *\n * The payload `T` is the type the body serializes to - it is not validated, so it is a promise the route\n * must keep. For bytes prefer {@link bytes}, which also sets the media-type headers.\n */"
|
|
8930
|
+
},
|
|
8925
8931
|
{
|
|
8926
8932
|
"name": "raw",
|
|
8927
8933
|
"kind": "function",
|
|
@@ -8936,6 +8942,13 @@
|
|
|
8936
8942
|
"signature": "export declare class RawHtml {\n readonly value: string;\n constructor(value: string);\n}",
|
|
8937
8943
|
"doc": "/** Branded wrapper marking a string as pre-trusted markup. Construct only via {@link raw}. */"
|
|
8938
8944
|
},
|
|
8945
|
+
{
|
|
8946
|
+
"name": "RawResponse",
|
|
8947
|
+
"kind": "type",
|
|
8948
|
+
"package": "@nifrajs/core",
|
|
8949
|
+
"signature": "export type RawResponse<T> = Response & {\n readonly [NIFRA_RAW]: T;\n};",
|
|
8950
|
+
"doc": "/**\n * A raw `Response` whose JSON body a route declared as `T`. Returning a bare `Response` drops a route\n * out of the typed contract - the client reads its `data` as `never`, since a `Response`'s own\n * properties say nothing about the payload. {@link raw} brands the `Response` with the shape it\n * actually serializes, so `Jsonify` answers `Jsonify<T>` and the route stays inside the typed client.\n * The brand is a phantom: nothing is added at runtime.\n */"
|
|
8951
|
+
},
|
|
8939
8952
|
{
|
|
8940
8953
|
"name": "reactAdapter",
|
|
8941
8954
|
"kind": "const",
|
|
@@ -10692,7 +10705,7 @@
|
|
|
10692
10705
|
"name": "ServeOptions",
|
|
10693
10706
|
"kind": "interface",
|
|
10694
10707
|
"package": "@nifrajs/node",
|
|
10695
|
-
"signature": "export interface ServeOptions {\n readonly port: number;\n readonly hostname?: string;\n /**\n * Protocol used when the adapter constructs `Request.url`.\n *\n * `@nifrajs/node` creates a plain Node `http` server, so the safe default is `\"http\"`. Deployments behind\n * TLS termination can set `\"https\"` (or a trusted infra-aware function) so app code that reads\n * `request.url` sees the public scheme. Forwarded headers are not trusted implicitly.\n */\n readonly protocol?: RequestProtocolOption;\n /** Reject requests whose normalized Host authority is not in this allowlist or callback result. */\n readonly allowedHosts?: readonly string[] | ((host: string) => boolean);\n /** Use this validated authority when constructing Request.url, ignoring the inbound Host value. */\n readonly canonicalHost?: string;\n /**\n * Install SIGTERM/SIGINT handlers that call `stop()` for a graceful drain on\n * `docker stop` / Ctrl-C. Off by default - taking over process signals is opt-in,\n * mirroring nifra's Bun `listen({ gracefulSignals })`.\n *\n * The app-level request timeout (`server({ requestTimeoutMs })` → 503) and body cap\n * are *not* set here - they live inside `app.fetch`, so they already apply through\n * this adapter. Slow-client protection is Node's built-in `requestTimeout` (300s) /\n * `headersTimeout` (60s) defaults.\n */\n readonly signals?: boolean;\n /**\n * Serve static files from disk for matching GET/HEAD requests *before* the app runs - non-matching\n * requests fall through to `app.fetch` with the node-direct fast path intact (no perf regression on\n * SSR/API routes). Replaces the hand-rolled `/assets/*` reader in self-hosted entries.\n */\n readonly static?: ServeStaticOptions;\n}"
|
|
10708
|
+
"signature": "export interface ServeOptions {\n readonly port: number;\n readonly hostname?: string;\n /**\n * Protocol used when the adapter constructs `Request.url`.\n *\n * `@nifrajs/node` creates a plain Node `http` server, so the safe default is `\"http\"`. Deployments behind\n * TLS termination can set `\"https\"` (or a trusted infra-aware function) so app code that reads\n * `request.url` sees the public scheme. Forwarded headers are not trusted implicitly.\n */\n readonly protocol?: RequestProtocolOption;\n /** Reject requests whose normalized Host authority is not in this allowlist or callback result. */\n readonly allowedHosts?: readonly string[] | ((host: string) => boolean);\n /** Use this validated authority when constructing Request.url, ignoring the inbound Host value. */\n readonly canonicalHost?: string;\n /**\n * Install SIGTERM/SIGINT handlers that call `stop()` for a graceful drain on\n * `docker stop` / Ctrl-C. Off by default - taking over process signals is opt-in,\n * mirroring nifra's Bun `listen({ gracefulSignals })`.\n *\n * The app-level request timeout (`server({ requestTimeoutMs })` → 503) and body cap\n * are *not* set here - they live inside `app.fetch`, so they already apply through\n * this adapter. Slow-client protection is Node's built-in `requestTimeout` (300s) /\n * `headersTimeout` (60s) defaults.\n */\n readonly signals?: boolean;\n /**\n * Serve static files from disk for matching GET/HEAD requests *before* the app runs - non-matching\n * requests fall through to `app.fetch` with the node-direct fast path intact (no perf regression on\n * SSR/API routes). Replaces the hand-rolled `/assets/*` reader in self-hosted entries.\n */\n readonly static?: ServeStaticOptions;\n /**\n * Make a hand-rolled `return new Response(body)` ride the direct-write lane, by swapping\n * `globalThis.Response` for a stand-in that defers a *simple* construction (a string body, no\n * `statusText`, no headers or a plain header record) the way `c.text` / `c.json` already do.\n *\n * Off by default: prefer `c.text` / `c.json`, which get this without a global swap. Reach for the\n * flag only when handlers construct `Response` by hand on the hot path. It patches a process-global\n * builtin, so every `new Response(...)` anywhere in the process goes through the stand-in -\n * transparent (non-simple bodies build a real `Response`, and simple ones stay `instanceof\n * Response`), but a broad enough change to be opt-in.\n */\n readonly fastResponse?: boolean;\n}"
|
|
10696
10709
|
},
|
|
10697
10710
|
{
|
|
10698
10711
|
"name": "servePublicDir",
|
|
@@ -10725,14 +10738,14 @@
|
|
|
10725
10738
|
"name": "Server",
|
|
10726
10739
|
"kind": "class",
|
|
10727
10740
|
"package": "@nifrajs/core",
|
|
10728
|
-
"signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext> {\n /**\n * Which copy of `@nifrajs/core` declared this type. Two copies in one build (a linked sibling repo,\n * a hoisting split) produce two unrelated `Server` types whose assignment error is a wall of\n * missing internals; the brand puts the feature version in the type itself, so `typeof app` on\n * hover - and `NifraFeatureVersion` in an assertion - says which core an app is talking to.\n * `nifra doctor` is the diagnosis that names both install paths.\n *\n * `declare` = type-only: no field is emitted, nothing is allocated per server.\n */\n readonly __nifraCoreVersion: NifraFeatureVersion;\n private readonly catalog;\n /** WebSocket routes, matched separately at upgrade time (a GET + `Upgrade: websocket`). */\n private readonly wsRouter;\n private wsRouteCount;\n /** In-process pub/sub backing `ws.subscribe(topic)` + `app.publish(topic, data)` (single-instance).\n * Created by the first `app.ws()` via the `@nifrajs/core/ws` runtime - `undefined` until then, so a\n * no-WebSocket app never constructs (or bundles) it. */\n private topics;\n private readonly maxBodyBytes;\n private readonly protoPoisoning;\n /** `trustBodyFraming`: mark every `app.fetch` request as runtime-framed (see ServerOptions). */\n private readonly trustBodyFraming;\n private readonly wsMaxPayloadBytes;\n private readonly requestTimeoutMs;\n /** Installed by the `responseContract()` plugin; `undefined` = not installed, which is the default\n * and the state in which a declared `response` schema stays a compile-time contract only. */\n private responseContractRuntime;\n /** Opt-in caller-IP trust declaration; `undefined` = socket peer only, no forwarded header believed. */\n private readonly clientIpTrust;\n private readonly acceptInboundDeadlines;\n private readonly maxInboundDeadlineMs;\n private readonly deadlineAdmissionOptions;\n private readonly gracefulSignals;\n private readonly stopHooks;\n private readonly fetchMounts;\n /** Capacity-admission gate; `undefined` = off (the request path pays nothing). */\n private readonly capacityGate;\n private readonly onCapabilityUse;\n private readonly capabilityInterceptors;\n private readonly capabilityObservers;\n /** The installed effect-ledger runtime (owns the sink + per-route resolution + settle), or\n * `undefined` when the effect-ledger plugin is not installed. */\n private effectLedgerRuntime;\n /** The installed idempotency runtime (owns the app-wide default store + the dedupe lane), or\n * `undefined` when the idempotency plugin is not installed. */\n private idempotencyRuntime;\n /** Installed opt-in runtime for `.tool()`/`.resource()`/`.prompt()`; `undefined` until `.use(mcp())`. */\n private mcpRuntime;\n /** Installed Node-direct renderer for direct `resolveNode()` callers; `undefined` until `.use(nodeDirect())`. */\n private nodeOutcomeRuntime;\n /** Installed streaming runtime for `.sse()` routes; `undefined` until `.use(streaming())`. */\n private sseRuntime;\n /** Installed WebSocket runtime for `.ws()` routes; `undefined` until `.use(websocket())`. */\n private wsRuntime;\n private readonly logger;\n /** How much of an unhandled error {@link logRequestError} records. See `ServerOptions.errorLogDetail`. */\n private readonly errorLogDetail;\n /** App-wide validation-error fallback; a route's own `schema.onValidationError` takes precedence. */\n private readonly defaultOnValidationError?;\n private bunServer;\n private sealed;\n private readonly derives;\n private readonly decorations;\n private readonly beforeHandleHooks;\n private readonly afterHandleHooks;\n private readonly onErrorHooks;\n private readonly aroundHooks;\n private readonly onRequestHooks;\n private readonly onNodeRequestHooks;\n /** Registration-time eligibility for the Node request twin lane. */\n private nodeRequestHooksComplete;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /**\n * True once a bundle registers a RAW `onNodeResponse` twin - one handed the outcome's header\n * record itself rather than the case-normalizing view. Their names are contractually the wire\n * spelling, but registration cannot PROVE it, so such an app forgoes the all-lowercase mark and\n * every reader re-derives the answer, exactly as before the mark existed.\n */\n private hasRawNodeResponseHook;\n private readonly onResponseFinalizedHooks;\n /**\n * Statically declared response headers, merged and prebuilt at registration; `undefined` (the\n * default) leaves every render path in its original shape. These are NOT response hooks - they are\n * folded into response construction - so declaring them keeps the fused native lanes an\n * `onResponse` hook would have disabled.\n */\n private staticResponseHeaders;\n /** `wrapResponse` for the Web lanes: identity until static headers exist to fold into the\n * framework's own error/404/timeout renders, which are built outside the header init. */\n private wrapWebResponse;\n private webResponseTimeout;\n /** Body/raw response hooks need a framework-payload marker; keep that decision per app. */\n private responseBodyTag;\n private readonly responseBodyOwners;\n private readonly finalizeResponse;\n private readonly responseRequests;\n /** Original source → request observed by generic request hooks, including in-place mutations. */\n private readonly responseSources;\n /** Memoized NodeRequestContext per plain-`Request` source - see {@link nodeRequestContextOf}. */\n private readonly nodeContexts;\n /** Names of plugins/middleware already applied via `use` - for idempotent dedupe. */\n private readonly appliedPlugins;\n /** Order-scoped evidence captured by routes registered after an assured plugin. */\n private readonly activeAssurance;\n /** App-wide evidence from global hooks; applies retroactively to every route. */\n private readonly globalAssurance;\n /** App-declared MCP resources / prompts (via {@link resource} / {@link prompt}), read by `nifra mcp`. */\n private readonly mcpResourceList;\n private readonly mcpPromptList;\n constructor(options?: ServerOptions);\n private assertConfigurable;\n /** Register a callback awaited after graceful drain and server stop. Hung callbacks are bounded. */\n onStop(fn: StopHook): this;\n /**\n * Mount a legacy fetch handler under a literal path prefix. Mounted handlers sit behind typed\n * routes, so routes can move one at a time while the remaining legacy surface stays live.\n * Mounted responses are outside Nifra's typed route and response-contract checks.\n */\n mountFetch(path: string, handler: FetchHandler<EnvOf<Ctx>>, options?: MountFetchOptions): this;\n /** Add a per-request, computed context extension for subsequent routes. */\n derive<D extends object>(fn: (context: Context & Ctx) => MaybePromise<D>): Server<R, Ctx & D>;\n /** Add a static context value for subsequent routes. */\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>>;\n /**\n * Run before routing on the raw request. Return a `Response` to short-circuit, or a replacement\n * `Request` to continue routing with a rewritten method/URL/headers. Global.\n */\n onRequest(fn: (req: Request, platform?: Platform<EnvOf<Ctx>>) => MaybePromise<OnRequestResult>): this;\n /** Run after validation, before the handler; a non-`undefined` return short-circuits. Order-scoped. */\n beforeHandle(fn: (context: Context & Ctx) => MaybePromise<unknown>): this;\n /**\n * Wrap the matched route lifecycle for subsequent routes. This is intentionally generic over the\n * route output, so wrappers like async context storage do not force Node's direct JSON path through\n * a Web `Response`. The first registered wrapper is outermost.\n */\n around(fn: <T>(context: Context & Ctx, next: () => MaybePromise<T>) => MaybePromise<T>): this;\n /**\n * Asynchronously admit each subsequent `executeCapability()` call before its owned effect runs.\n * Interceptors receive token-only metadata plus an abort signal and must call `next()` exactly once\n * to admit. Returning without `next()`, timing out, aborting, or throwing fails the effect closed.\n */\n aroundCapability(interceptor: CapabilityInterceptor, options?: AroundCapabilityOptions): this;\n /** Observe token-only admission/execution lifecycle events for subsequent capability routes. */\n observeCapability(observer: EffectLifecycleObserver): this;\n /** Transform the handler's result before it is serialized. Order-scoped. */\n afterHandle(fn: (result: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Handle a thrown error; a non-`undefined` return becomes the response (else the default 500). Order-scoped. */\n onError(fn: (error: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Transform every outgoing response - success, error, 404, 405, short-circuit. Global. */\n onResponse(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Declare response headers with NO per-request decision behind them - and pay nothing for them on\n * the request path.\n *\n * These are not a hook. Because the values are known at wire-up, they are folded into response\n * construction (one prebuilt init for JSON renders, one record merge where the request set its own\n * headers), so an app whose only response middleware is static keeps every fused and native lane -\n * `onResponse`/`onResponseHeaders` disable Bun's fused native routes and, for a full `onResponse`,\n * the Node direct writer. They apply to EVERY response, exactly as a response hook would: success,\n * error, 404/405, timeout, and short-circuit alike.\n *\n * app.responseHeaders({ \"x-frame-options\": \"DENY\", \"referrer-policy\": \"no-referrer\" })\n *\n * They are DEFAULTS: a value the request itself produced (`c.set.headers`, or a response hook)\n * wins, whatever casing it used. Names are lowercased once here; a non-string value, an invalid\n * name, `__proto__`, or a name the render owns (`content-type`, `content-length`,\n * `transfer-encoding`, `set-cookie`) throws a `TypeError` at wire-up.\n *\n * ORDERING: declarations made before any response hook fold into one static record. One made AFTER\n * a response hook cannot - the hook may already have written that name and must keep winning - so\n * it registers as an ordinary `onResponseHeaders` hook instead, preserving registration order at\n * the cost of the static tier's speed. Declare static headers first.\n */\n responseHeaders(record: Readonly<Record<string, string>>): this;\n /** Wire an already-validated lowercase record into the static tier, or - once a dynamic response\n * hook owns part of the header state - into a hook that runs in the right order. */\n private addStaticResponseHeaders;\n private enableResponseBodyTagging;\n /**\n * Register a response transform for raw/streamed Responses. Framework-serialized payloads stay on\n * the body tier; this hook is only entered for untagged Responses (streams, proxied fetches, and\n * framework-generated error responses). A no-op native twin keeps buffered JSON on the direct lane.\n */\n onResponseRaw(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Register a PORTABLE header-only response hook - one implementation, fast on every runtime.\n *\n * The hook receives a mutable case-insensitive header view, a minimal request view, and the\n * status. On the Web serving paths it runs inside the normal `onResponse` walk against the\n * response's own `Headers` (mutating in place - no clone). On Node it self-pairs as a native\n * response hook against the outcome's plain header record, so registering one NEVER forces the\n * Node adapter off its direct socket writer the way a full `onResponse(res: Response)` hook does.\n * Prefer this over `onResponse` whenever the middleware only reads/writes headers.\n */\n onResponseHeaders(fn: ResponseHeadersHook): this;\n /**\n * Register a PORTABLE post-serialization body hook - the payload tier. The hook receives the\n * FINAL framework-serialized bytes (plus the mutable header view and status) and may return\n * replacement bytes; `undefined` keeps the body. On the Node direct writer the bytes come\n * straight off the outcome record; on the Web serving paths they ride the framework-built\n * Response as a tag, so no body stream is ever drained on any runtime. A handler-returned raw\n * `Response` (proxied fetch, SSE, streamed SSR) is skipped by contract - transforming those is\n * what the full `onResponse` hook is for.\n */\n onResponseBody(fn: ResponseBodyHook): this;\n /** Observe the terminal response after all transformations. Observers are ordered and fail-open. */\n onResponseFinalized(fn: (outcome: ResponseFinalization, req: Request) => MaybePromise<void>): this;\n /**\n * Apply a type-**identity** plugin ({@link IdentityPlugin}, from {@link defineIdentityPlugin}) - it\n * registers routes/hooks but doesn't change the types, so this returns `this` with the route registry\n * and context fully intact. This overload exists specifically so a *named* identity plugin (e.g.\n * `@nifrajs/better-auth`) threads the registry: its `& { pluginName }` intersection would otherwise\n * defeat the generic inference of the transforming overload below and collapse the result to `any`.\n */\n use(plugin: IdentityPlugin): this;\n /**\n * Apply a **context** plugin ({@link ContextPlugin}, from {@link defineContextPlugin}) - it adds `D`\n * to the handler context and changes nothing else, so the route registry `R` and the existing context\n * `Ctx` thread through untouched. Like the identity overload above, this exists because the generic\n * `(app: this) => Out` overload below cannot infer through a *generic* plugin signature: it erases the\n * plugin's own type parameters to their constraints, which silently widens `R` to `Registry`.\n */\n use<D extends object>(plugin: ContextPlugin<D>): Server<R, Ctx & D>;\n /**\n * Apply a **plugin function** - `(app) => app`, typically built with {@link definePlugin}. It's\n * called with `this` and its result is returned, so an inline plugin's `derive`/`decorate` thread\n * the added context to handlers defined after `use` (the overload is generic over the concrete\n * `this`). A named plugin already applied is skipped (idempotent dedupe).\n */\n use<Out extends AnyServer>(plugin: (app: this) => Out): Out;\n /**\n * Apply a {@link Middleware} bundle - wire each hook it provides to its lifecycle point. Returns\n * `this` (no context-type merging); call it before the routes its `beforeHandle`/`afterHandle`\n * should cover (those are order-scoped; `onRequest`/`onResponse` are global). A named bundle already\n * applied is skipped (idempotent).\n */\n use(mw: Middleware): this;\n get<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n get<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Register a **typed SSE route** - a GET endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. The handler receives the validated context plus a\n * {@link TypedSSEStream}: `stream.send(event)` is compile-time-checked against the schema and\n * JSON-serialized into the SSE `data:` field. The typed client sees the marker and grows a\n * `.subscribe(onEvent)` for the route with the same payload type - end-to-end typed streaming.\n *\n * import { streaming } from \"@nifrajs/core/sse\" // .use(streaming()) enables .sse()\n * const app = server().use(streaming()).sse(\"/feed\", { sse: t.object({ id: t.integer(), title: t.string() }) },\n * async (c, stream) => {\n * stream.send({ id: 1, title: \"hello\" }) // typed\n * await waitForDisconnect(stream.signal)\n * },\n * { keepAlive: 15_000 })\n *\n * // client: const off = api.feed.subscribe((post) => console.log(post.title))\n *\n * `init` passes through to the underlying {@link sse} helper (`keepAlive`, extra headers). The\n * connection closes when the handler resolves, `stream.close()` runs, or the client disconnects\n * (`stream.signal`). Query/body schemas validate exactly as on any other route.\n */\n sse<Path extends string, S extends RouteSchema & {\n sse: StandardSchemaV1;\n }>(path: Path, schema: S, run: (context: Context<Path, S> & Ctx, stream: TypedSSEStream<InferOutput<S[\"sse\"]>>) => void | Promise<void>, init?: SSEInit): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, Response>>, Ctx>;\n post<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n post<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n put<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n put<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n patch<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n patch<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n delete<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n delete<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Declare an **MCP tool** an agent can call (via `nifra mcp`, or a mounted MCP endpoint): a typed\n * `POST /_nifra/tool/<name>` route whose `input`/`output` schemas contract the call and surface in\n * `tools/list`. Requires `.use(mcp())` - without it, `.tool()` is a registration error, so an\n * ordinary HTTP app never bundles the MCP wiring. Siblings: {@link resource}, {@link prompt}.\n *\n * import { mcp } from \"@nifrajs/core/mcp\"\n * const app = server().use(mcp()).tool(\n * \"search\",\n * { description: \"Search posts\", input: t.object({ q: t.string() }) },\n * ({ q }) => findPosts(q),\n * )\n */\n tool<Name extends string, S extends {\n description: string;\n input: StandardSchemaV1;\n output?: StandardSchemaV1;\n annotations?: ToolAnnotations;\n }, H extends (input: InferOutput<S[\"input\"]>, ctx: Context & Ctx) => MaybePromise<S[\"output\"] extends StandardSchemaV1 ? InferOutput<S[\"output\"]> : unknown>>(name: Name, config: S, handler: H): Server<AddRoute<R, \"POST\", `/_nifra/tool/${Name}`, RouteInfoFor<`/_nifra/tool/${Name}`, S[\"output\"] extends StandardSchemaV1 ? {\n body: S[\"input\"];\n response: S[\"output\"];\n } : {\n body: S[\"input\"];\n }, OutputOf<H>>>, Ctx>;\n /**\n * Declare an MCP **resource** - read-only data an agent can fetch through `nifra mcp` (app config, a\n * generated document, …). `read` runs in the app process, so capture whatever app state it needs in the\n * closure. `uri` is the MCP resource identifier (e.g. `\"myapp://config\"`). The sibling of {@link tool}\n * for the resource half of MCP.\n */\n resource(uri: string, config: {\n readonly name: string;\n readonly description?: string;\n readonly mimeType?: string;\n }, read: McpResourceDescriptor[\"read\"]): Server<R, Ctx>;\n /**\n * Declare an MCP **prompt** - a reusable prompt template an agent can fetch through `nifra mcp`.\n * `handler` receives the caller's arguments and returns the rendered messages.\n */\n prompt(name: string, config: {\n readonly description: string;\n readonly arguments?: readonly PromptArgument[];\n }, handler: McpPromptDescriptor[\"handler\"]): Server<R, Ctx>;\n /** The MCP resources declared via {@link resource} - enumerated by `nifra mcp`. */\n mcpResources(): readonly McpResourceDescriptor[];\n /** The MCP prompts declared via {@link prompt} - enumerated by `nifra mcp`. */\n mcpPrompts(): readonly McpPromptDescriptor[];\n /**\n * Register a **WebSocket** route. The connection upgrades on a `GET` to `path` carrying\n * `Upgrade: websocket`; the optional `handler.upgrade(c)` runs in the request context first and may\n * reject (return a `Response`) or seed per-connection `ws.data`. WebSockets are served by the\n * adapter (`listen()`, `@nifrajs/node`, `@nifrajs/deno`, `toFetchHandler`) - not by bare `app.fetch`, which\n * has no socket (a WS path through `app.fetch` is a normal HTTP response).\n *\n * The route also enters the type-level registry (under the pseudo-method `\"WS\"`), so the typed\n * client grows a `.ws()` handle for it: `messageSchema` types what the client may `send`,\n * `sendSchema` types the frames it receives. Passing explicit type arguments (`ws<MyData>(…)`)\n * defeats path-literal inference and skips the registry entry - the route still serves, it is just\n * invisible to `client<App>`; prefer typing `data` via `upgrade()`'s return.\n *\n * app.ws(\"/chat\", { open: (ws) => ws.send(\"hi\"), message: (ws, data) => ws.send(data) })\n */\n ws<Data = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined, Path extends string = string>(path: Path, handler: WebSocketHandler<Data, EnvOf<Ctx>, Schema, Send>): string extends Path ? Server<R, Ctx> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx>;\n /**\n * Broadcast `data` to every WebSocket connection subscribed to `topic` (via `ws.subscribe(topic)`).\n * In-process and **single-instance** (see {@link TopicRegistry}) - a multi-instance deploy must bridge\n * an external fan-out (Redis, a Durable Object) to this. A no-op when nobody is subscribed.\n */\n publish(topic: string, data: string | ArrayBufferView | ArrayBuffer): void;\n private route;\n /**\n * Low-level route registration shared by the inline builder and `implement()`.\n * Captures the server's current `derive`/`decorate` chain into the route - this\n * is the \"compiled\", order-scoped per-route chain.\n */\n register(method: Method, path: string, schema: RouteSchema | undefined, handler: (context: never) => unknown): void;\n /** Register a contract/group route batch atomically. Every route captures the same current chain it\n * would capture through {@link register}; no route becomes visible unless the full batch validates. */\n registerBatch(routes: readonly {\n readonly method: Method;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n private prepareRoute;\n /** The idempotency lane's bridge back into the normal matched lanes, resolved to a concrete Response\n * (the lane buffers the body, then replays it through the route's real validation + handler). */\n private idempotencyRunLanes;\n /** @internal Symbol-keyed install seam for the `responseContract()` plugin. Off the public typed surface. */\n [INSTALL_RESPONSE_CONTRACT](runtime: ResponseContractRuntime): void;\n /** @internal Symbol-keyed install seam for the `idempotency()` plugin. Off the public typed surface. */\n [INSTALL_IDEMPOTENCY](runtime: IdempotencyRuntime): void;\n /** @internal Symbol-keyed install seam for the `mcp()` plugin. Off the public typed surface. */\n [INSTALL_MCP](runtime: McpRuntime): void;\n /** @internal Symbol-keyed install seam for the `nodeDirect()` plugin. Off the public typed surface. */\n [INSTALL_NODE_DIRECT](runtime: NodeOutcomeRuntime): void;\n /** @internal Symbol-keyed install seam for the `streaming()` plugin. Off the public typed surface. */\n [INSTALL_SSE](runtime: SseRuntime): void;\n /** @internal Symbol-keyed install seam for the `websocket()` plugin. Off the public typed surface. */\n [INSTALL_WS](runtime: WsRuntime): void;\n /**\n * Merge another server's routes into this one - the composition escape hatch for large apps.\n *\n * WHY: the fluent chain accumulates one type-alias level per route, and TypeScript resolves\n * that stack in one recursion - a single chain hits TS2589 at ~95 routes. Groups keep every\n * chain short: build each domain (`listings`, `agents`, …) as its own `server()` (its registry\n * resolves independently), then `app.merge(listings).merge(agents)` - each merge adds ONE level\n * regardless of group size. 300+ routes stay fully typed (see many-routes.test-d.ts). The\n * other escape hatch is contract-first `implement()`, whose registry is a single object type.\n *\n * Semantics: merged routes keep the chains captured where they were DEFINED - the group's\n * `derive`/`decorate`/`beforeHandle`/`afterHandle`/`onError`/`around` apply to its routes\n * exactly as they did standalone, so a group wires its own plugins. The same locality rule\n * covers the group's `onRequest` hooks: they run only for requests that route to the GROUP's\n * routes (a `bodyLimit()` mounted on an uploads group must not start gating the whole app\n * because the app composed it in), and the group's global assurance follows its hooks onto\n * exactly those routes. A group with hooks but NO routes is a middleware bundle - its hooks\n * can only mean app-wide intent, so they are appended globally, unchanged. Response-side hooks\n * (`onResponse`/`onResponseFinalized`) are appended to this server's. This server's\n * route-scoped chains do NOT retroactively wrap merged routes (order-scoped, like routes\n * registered before a `derive`). Fail closed: a path+method collision throws\n * `RouteConfigError` at merge time, and a group with WebSocket routes is refused (register\n * those on the parent).\n */\n merge<R2 extends Registry, Ctx2>(other: Server<R2, Ctx2>): Server<R & R2, Ctx>;\n /** A fused renderer closes over runtime services to keep its seven-argument JSC fast path. Merging\n * rebinds that closure once to the executing server; generic plans already receive the runtime. */\n private bindFusedRuntime;\n /**\n * Enumerate the registered routes (method, path, input schemas), in registration\n * order. Powers `toOpenAPI` and other introspection; the router trie itself no\n * longer holds the original patterns.\n */\n routes(): ReadonlyArray<RouteDescriptor>;\n /**\n * Resolve a `Request` to a `Response` - the whole lifecycle, testable without a port. The\n * optional `platform` carries edge inputs (`env`, `waitUntil`); edge adapters pass it, and\n * Bun/Node/Deno omit it (then `c.env` is `undefined` and `c.waitUntil` runs fire-and-forget).\n */\n fetch(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<Response>;\n private fetchSource;\n private fetchSourceInner;\n /** Web response path when Bun already matched the route. The lifecycle and response hooks remain\n * exactly the same as {@link fetchSource}; only portable URL scanning + trie lookup are skipped. */\n private fetchMatched;\n private fetchMatchedInner;\n /**\n * Run `produce` under the capacity gate: admit → run → release exactly once when the response is\n * produced (or the run throws). Only reached when {@link capacityGate} is set, so the off path pays\n * nothing. The slot is held for the duration of handler execution, not the streaming of the body -\n * capacity here bounds concurrent *work*, matching how in-flight is counted.\n */\n private admitGated;\n private runAdmitted;\n /**\n * Like {@link fetch}, but renders a plain-data result **without** building a Web `Response` - the\n * `@nifrajs/node` adapter serializes the returned primitives straight to the socket, skipping the undici\n * `Response` build + body drain (the bulk of the Node bridge cost, measured ≈4µs/req). A handler that\n * returns a `Response`, an error/short-circuit, or a response hook that replaces/consumes the buffered\n * body stays on the full Web path; an in-place response hook can still use the direct writer. Same\n * lifecycle as {@link fetch} (body cap, validation, hooks all run); only the final render differs.\n */\n resolveNode(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<NodeServeOutcome>;\n resolveNodeSource(source: RequestSource, platform?: Platform<EnvOf<Ctx>>, suppliedRuntime?: NodeOutcomeRuntime): MaybePromise<NodeServeOutcome>;\n /** Run generic Web response middleware while retaining direct writes for untouched buffered bodies. */\n private finishNodeWebResponse;\n /** True only when every transforming Web response hook has a header-only Node equivalent. */\n private canUseNodeResponseHooks;\n /** Apply paired native hooks to data outcomes; preserve the complete Web hook pipeline for Response outcomes. */\n private finishNodeResponse;\n private withNodeResponseHeaders;\n /** Synchronous until a native response hook actually returns a Promise. */\n private applyNodeResponseHooks;\n private continueNodeResponseHooks;\n /**\n * Resolve a WebSocket upgrade - the seam every serving adapter uses. Returns `pass` (not a WS\n * upgrade for a registered route → handle as normal HTTP), `reject` (a WS route matched but\n * `upgrade()` rejected, or the path was malformed → return `response`), or `upgrade` (perform the\n * runtime upgrade, then dispatch the native socket's events to `handler`, seeding `ws.data` with\n * `data`). Runs the route's `upgrade(c)` guard in a real request context. Synchronous unless\n * `upgrade()` is async; a throw rejects with a flat 500 (no detail leaked).\n */\n resolveWebSocketUpgrade(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<WebSocketUpgradeOutcome>;\n /** Bun `fetch` when WS routes exist: try a WS upgrade first, else run the normal HTTP lifecycle.\n * `undefined` ⇒ Bun owns the upgraded socket; a `Response` ⇒ a normal reply or a rejected upgrade.\n * (The socket dispatch itself lives in `ws-bun.ts`, loaded via `@nifrajs/core/ws`.) */\n private bunFetchWithWebSocket;\n /**\n * The shared lifecycle, generic over how the final value is rendered: `finalize` turns a handler's\n * result + `set` into the output `T` (`toResponse` → a Web `Response`; `toNodeOutcome` → node-direct\n * primitives), `wrapResponse` lifts an early/error `Response` into that same `T`, and `onTimeout`\n * produces the 503. The Web `fetch` and `resolveNode` are thin callers over this one routing +\n * context + lifecycle implementation - no duplication across the trust boundary.\n */\n /** Apply the `clientIp` trust declaration to the adapter's raw socket peer, returning a platform\n * whose `clientIp` is the derived caller. Only called when a trust declaration is configured. */\n private deriveClientIp;\n private dispatch;\n /** Node-native request hook walk. A header-only hook can inspect the lazy source without forcing a\n * Web `Request`; arbitrary request rewrites and full Web hooks use {@link runWithOnRequest}. */\n private runWithNodeRequest;\n private continueNodeRequest;\n private canUseNodeRequestHooks;\n /**\n * onRequest short-circuit path. Synchronous as long as every hook returns synchronously (the\n * common case - e.g. CORS returning `undefined` for a non-preflight request): an `async` version\n * here put EVERY request of any app with one onRequest hook onto the promise machinery, profiled\n * at ~13% of a realistic request. The first hook that returns a Promise hands the REMAINING\n * hooks to the async continuation; behavior is identical.\n */\n private runWithOnRequest;\n /** Async tail of {@link runWithOnRequest}: applies the first awaited hook's outcome, then runs\n * the remaining hooks (awaiting freely - we're already async here). */\n private continueOnRequest;\n private takeResponseRequest;\n /**\n * The NodeRequestContext for a source, MEMOIZED per source so the request twins and the response\n * twins receive the exact same object within one request - that identity is the documented\n * contract stateful twins key their WeakMaps on. An adapter source (which already speaks the\n * interface) is returned as-is; a plain `Request` source (a direct `resolveNode` caller) gets one\n * cached wrapper.\n */\n private nodeRequestContextOf;\n /** Preserve the request visible to generic onRequest hooks for paired native response hooks. */\n private takeNodeResponseRequest;\n /**\n * Route → build context → run. Synchronous through to the handler for a **bare** route\n * (selected by its compiled plan), so a sync handler produces its result with zero promise allocations;\n * routes with validation/hooks keep the full async {@link runLifecycle}, unchanged.\n */\n private routeAndRun;\n private fetchMount;\n /** Run a route that has already been matched by the runtime or Nifra's portable router. */\n private runMatched;\n /** Supply request-specific deadline state to the route's precompiled execution plan. */\n private runMatchedLanes;\n /** @internal Symbol-keyed install seam for the `effectLedger()` plugin. Off the public typed surface. */\n [INSTALL_EFFECT_LEDGER](runtime: EffectLedgerRuntime): void;\n /** The narrowest bare route: a syntactic `() => ...` handler cannot observe the context argument, so\n * successful requests can skip allocating `RequestContext`. Errors still allocate one for logging. */\n private runContextlessBare;\n private contextlessBareError;\n /**\n * The synchronous fast path selected by a route's execution plan: apply static decorations, call the\n * handler, render the result - **no `await`** unless the handler itself returns a promise. It mirrors\n * the bare slice of {@link runLifecycle} (which a bare route would otherwise no-op through) and shares\n * {@link logRequestError}; a bare route has no `onError` hooks, so error handling is fully synchronous\n * (a thrown `Response` is control flow; anything else is a logged flat 500). This is where nifra skips\n * the per-request async-frame tax - the same win codegen routers get, but without `eval`.\n */\n private runBare;\n /** Bare-route error rendering - identical to {@link runLifecycle}'s catch minus the (absent) onError\n * loop: a thrown `Response` is returned as deliberate control flow; anything else is logged + 500. */\n /**\n * Build a route's fused Web renderer. Composition happens once at\n * registration; the returned closure is what every request to the route runs. Behavior is\n * byte-identical to the generic `runBare`/`runContextlessBare` + `toResponse` pair - same\n * decoration order, same error routing (thrown `Response` = control flow; anything else logs and\n * 500s), same respond semantics (the lifecycle parity suite pins it).\n */\n private buildFusedWeb;\n /** Compile the eligible body-only route's parser → validator → handler continuation once. The\n * bounded parser remains shared with the generic lane; only the route-invariant entry lookups and\n * lifecycle dispatch disappear from the common synchronous-validator/synchronous-handler case. */\n private buildFusedBodyRunner;\n /** Web adapter wrapper for the shared body runner. Node passes its native finalizer directly through\n * the execution plan, while Web needs the live context to preserve lazy `c.set` controls. */\n private buildFusedBodyWeb;\n /** The fused Web lane for a route whose only lifecycle step is a query schema: parse + validate +\n * handler + respond in one closure, no lifecycle promise when the validator and handler are sync.\n * Eligibility is decided at registration (see `fusedQuery` in {@link register}); the semantics here\n * are exactly `runQueryOnly`'s for that eligible shape - invalid input returns\n * `validationError(issues)` (recovery hooks disqualify the route from this lane), a thrown\n * `Response` passes through, anything else logs and returns a flat 500, and an async validator\n * falls to a then-chain with the same steps. */\n private buildFusedQueryWeb;\n private bareError;\n private runWithAround;\n private runAround;\n private runBodyOnly;\n /** Shared bounded body framing/parser. Both body lanes use the same trust-boundary checks; only\n * the validation + handler continuation differs. */\n private readBodyInput;\n /** Validate + run the handler for the bodyOnly path - shared by the inline fast path and the\n * streaming fallback. A method (not per-request closures) so the hot path allocates nothing\n * beyond the one `.then` continuation. */\n private finishBodyOnly;\n private executeHandler;\n private handleValidationErrorRecovery;\n private applyBodyValidation;\n private runQueryOnly;\n /** Validate-result → set `ctx.query` → run handler. A method (not a per-request closure), the\n * query analogue of {@link applyBodyValidation}. */\n private applyQueryValidation;\n /**\n * Thread the response through each global `onResponse` hook. Stays SYNCHRONOUS until a hook\n * actually returns a Promise - an `async` version forced a promise + microtask on EVERY response\n * of any app with an onResponse hook (cors/securityHeaders/etag/timing all use onResponse), the\n * same ~13%/req tax the onRequest walk was de-async'd to avoid. The first async hook hands the\n * rest to {@link continueOnResponse}.\n */\n private applyOnResponse;\n private applyOnResponseAndFinalize;\n private completeResponseFinalization;\n private failResponseFinalization;\n /** Notify terminal observers in order while isolating both sync and async failures. */\n private notifyResponseFinalized;\n /** Async tail of {@link applyOnResponse}: runs the remaining hooks once one has gone async. */\n private continueOnResponse;\n /**\n * Bound the response time. On timeout we abort `ctx.signal` (so cancellation-aware\n * handlers can bail) and return 503; the in-flight work keeps running but its\n * result is discarded - JS can't forcibly cancel a promise.\n */\n private withTimeout;\n /**\n * The post-match lifecycle: validate → derive → beforeHandle → handler → afterHandle, with onError.\n * Generic over the render: a success value goes through `finalize(result, set)` (a Web `Response`, or\n * node-direct primitives); an early/error `Response` (validation, thrown, 500) through `wrapResponse`.\n */\n /** Synchronous until a validator, lifecycle hook, handler, or contract check actually returns a Promise. */\n private runLifecycle;\n private runLifecycleAfterHeadersResult;\n private runLifecycleAfterHeaders;\n /** Registration-specialized query lifecycle: query validation (including recovery) → hooks. */\n private runLifecycleQuery;\n /** Registration-specialized body lifecycle: bounded body validation (including recovery) → hooks. */\n private runLifecycleBody;\n /** Registration-specialized body + query lifecycle: bounded body validation → query validation → hooks. */\n private runLifecycleBodyQuery;\n /** Registration-specialized no-body lifecycle: query validation (if present) → derives/hooks. */\n private runQueryAndLifecycle;\n private runQueryAndLifecycleResult;\n private runLifecycleAfterParamsResult;\n private runLifecycleAfterParams;\n private runLifecycleAfterParamsSettled;\n private runLifecycleAfterBody;\n private runLifecycleAfterQueryResult;\n private runLifecycleAfterQuery;\n private runLifecycleHooks;\n /** Registration-specialized derive → before → handler lifecycle. */\n private runLifecycleDeriveBefore;\n /** Finalize the specialized lane without rechecking its registration-proven invariants. */\n private finishSimpleLifecycleResult;\n private continueLifecycleAfterDerive;\n private runLifecycleHooksAsync;\n private continueLifecycleAfterBefore;\n private runLifecycleHandlerAsync;\n private finishLifecycleResult;\n private continueLifecycleAfterHandle;\n private finishLifecycleContract;\n private finishContractOutcome;\n private handleLifecycleError;\n /** Log an unhandled request error to the (redacting) logger - shared by {@link runLifecycle} and the\n * bare fast path ({@link bareError}) so both record the same fields. Never throws; never leaks. */\n private logRequestError;\n private readAndValidateBody;\n /** Apply validation and its recovery hook on the generic lifecycle lane. Recovery is completed\n * before derives/beforeHandle run, matching the body-only and query-only execution lanes. */\n private applyLifecycleValidation;\n private finishLifecycleValidationRecovery;\n /**\n * Read + parse the JSON body, capped at `maxBodyBytes` and screened by the server's\n * `protoPoisoning` policy. Rejects a `Content-Length` over the cap *before* buffering,\n * re-checks what was actually delivered after the read, and aborts a chunked or\n * length-less body mid-stream once the running byte count exceeds the cap - so a lying\n * or absent length can't force us to buffer an oversized payload.\n */\n private readBoundedJson;\n /** Adapt one route's compiled execution plan to Bun's already-matched request shape. Route\n * semantics remain in the plan; this closure only supplies native params and deadline fallback. */\n private compileBunNativeHandler;\n /** Compile portable route registrations into Bun's native route table. Apps with request-rewrite\n * hooks or WebSockets retain the single portable dispatcher because those features must run before\n * route selection/upgrade. Named wildcards also stay on the fallback until Bun exposes their raw\n * capture semantics; static and `:param` routes take the native lane. */\n private buildBunNativeRoutes;\n /**\n * Start a `Bun.serve` instance bound to `port` (use `0` for an ephemeral port).\n *\n * `reusePort` sets `SO_REUSEPORT` so **multiple processes can bind the same port** and the kernel\n * load-balances connections across them - the standard way to use every core (Bun is\n * single-threaded per process). Spawn one process per core, each calling\n * `app.listen(PORT, { reusePort: true })`; see `examples/cluster.ts`. Every process must opt in,\n * and all of them must be the same app. Linux balances ~evenly; macOS accepts the flag but may\n * favor one socket (fine for dev, measure on Linux for production numbers).\n *\n * `hostname` is the bind address, defaulting to Bun's `0.0.0.0` (every interface). Pass\n * `\"127.0.0.1\"` to bind loopback only - an admin surface, a sidecar, or anything that must not be\n * reachable off the box. Omitting it when you meant to restrict is a real exposure, so it is a\n * first-class option rather than something a caller has to drop down to `Bun.serve` for.\n *\n * `idleTimeoutSec` is how long Bun tolerates a connection with no bytes moving before it closes\n * the socket. Bun's default is **10 seconds**, and a request whose handler is still working sends\n * nothing - so any endpoint slower than 10s (a render, an export, a long upstream call) has its\n * connection cut mid-flight regardless of `requestTimeoutMs`. Apps with such endpoints must raise\n * this above their slowest expected response, which is why it is a first-class option and not a\n * reason to drop down to `Bun.serve`. `0` disables the timeout entirely; max 255.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n }): RunningServer;\n /**\n * Gracefully stop: wait for in-flight requests to finish (up to `drainMs`), then\n * issue a single terminal stop - graceful if everything drained, forced if\n * stragglers remain. Safe to call when not listening.\n *\n * The Bun semantics: poll `pendingRequests` (awaiting\n * `stop()`'s promise drops in-flight requests), and decide graceful-vs-forced in\n * ONE call (Bun can't escalate an already-graceful `stop()` to a forced close).\n * New connections may be accepted during the drain window; in a real deploy the\n * load balancer has already stopped routing here, and `drainMs` bounds it.\n */\n stop({ drainMs }?: {\n drainMs?: number;\n }): Promise<void>;\n private installSignalHandlers;\n}",
|
|
10741
|
+
"signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext> {\n /**\n * Which copy of `@nifrajs/core` declared this type. Two copies in one build (a linked sibling repo,\n * a hoisting split) produce two unrelated `Server` types whose assignment error is a wall of\n * missing internals; the brand puts the feature version in the type itself, so `typeof app` on\n * hover - and `NifraFeatureVersion` in an assertion - says which core an app is talking to.\n * `nifra doctor` is the diagnosis that names both install paths.\n *\n * `declare` = type-only: no field is emitted, nothing is allocated per server.\n */\n readonly __nifraCoreVersion: NifraFeatureVersion;\n private readonly catalog;\n /** WebSocket routes, matched separately at upgrade time (a GET + `Upgrade: websocket`). */\n private readonly wsRouter;\n private wsRouteCount;\n /** In-process pub/sub backing `ws.subscribe(topic)` + `app.publish(topic, data)` (single-instance).\n * Created by the first `app.ws()` via the `@nifrajs/core/ws` runtime - `undefined` until then, so a\n * no-WebSocket app never constructs (or bundles) it. */\n private topics;\n private readonly maxBodyBytes;\n private readonly protoPoisoning;\n /** `trustBodyFraming`: mark every `app.fetch` request as runtime-framed (see ServerOptions). */\n private readonly trustBodyFraming;\n private readonly wsMaxPayloadBytes;\n private readonly requestTimeoutMs;\n /** Installed by the `responseContract()` plugin; `undefined` = not installed, which is the default\n * and the state in which a declared `response` schema stays a compile-time contract only. */\n private responseContractRuntime;\n /** Opt-in caller-IP trust declaration; `undefined` = socket peer only, no forwarded header believed. */\n private readonly clientIpTrust;\n private readonly acceptInboundDeadlines;\n private readonly maxInboundDeadlineMs;\n private readonly deadlineAdmissionOptions;\n private readonly gracefulSignals;\n private readonly stopHooks;\n private readonly fetchMounts;\n /** Capacity-admission gate; `undefined` = off (the request path pays nothing). */\n private readonly capacityGate;\n private readonly onCapabilityUse;\n private readonly capabilityInterceptors;\n private readonly capabilityObservers;\n /** The installed effect-ledger runtime (owns the sink + per-route resolution + settle), or\n * `undefined` when the effect-ledger plugin is not installed. */\n private effectLedgerRuntime;\n /** The installed idempotency runtime (owns the app-wide default store + the dedupe lane), or\n * `undefined` when the idempotency plugin is not installed. */\n private idempotencyRuntime;\n /** Installed opt-in runtime for `.tool()`/`.resource()`/`.prompt()`; `undefined` until `.use(mcp())`. */\n private mcpRuntime;\n /** Installed Node-direct renderer for direct `resolveNode()` callers; `undefined` until `.use(nodeDirect())`. */\n private nodeOutcomeRuntime;\n /** Installed streaming runtime for `.sse()` routes; `undefined` until `.use(streaming())`. */\n private sseRuntime;\n /** Installed WebSocket runtime for `.ws()` routes; `undefined` until `.use(websocket())`. */\n private wsRuntime;\n private readonly logger;\n /** How much of an unhandled error {@link logRequestError} records. See `ServerOptions.errorLogDetail`. */\n private readonly errorLogDetail;\n /** App-wide validation-error fallback; a route's own `schema.onValidationError` takes precedence. */\n private readonly defaultOnValidationError?;\n private bunServer;\n private sealed;\n private readonly derives;\n private readonly decorations;\n private readonly beforeHandleHooks;\n private readonly afterHandleHooks;\n private readonly onErrorHooks;\n private readonly aroundHooks;\n private readonly onRequestHooks;\n private readonly onNodeRequestHooks;\n /** Registration-time eligibility for the Node request twin lane. */\n private nodeRequestHooksComplete;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /**\n * True once a bundle registers a RAW `onNodeResponse` twin - one handed the outcome's header\n * record itself rather than the case-normalizing view. Their names are contractually the wire\n * spelling, but registration cannot PROVE it, so such an app forgoes the all-lowercase mark and\n * every reader re-derives the answer, exactly as before the mark existed.\n */\n private hasRawNodeResponseHook;\n private readonly onResponseFinalizedHooks;\n /**\n * Statically declared response headers, merged and prebuilt at registration; `undefined` (the\n * default) leaves every render path in its original shape. These are NOT response hooks - they are\n * folded into response construction - so declaring them keeps the fused native lanes an\n * `onResponse` hook would have disabled.\n */\n private staticResponseHeaders;\n /** `wrapResponse` for the Web lanes: identity until static headers exist to fold into the\n * framework's own error/404/timeout renders, which are built outside the header init. */\n private wrapWebResponse;\n private webResponseTimeout;\n /** Body/raw response hooks need a framework-payload marker; keep that decision per app. */\n private responseBodyTag;\n private readonly responseBodyOwners;\n private readonly finalizeResponse;\n private readonly responseRequests;\n /** Original source → request observed by generic request hooks, including in-place mutations. */\n private readonly responseSources;\n /** Memoized NodeRequestContext per plain-`Request` source - see {@link nodeRequestContextOf}. */\n private readonly nodeContexts;\n /** Names of plugins/middleware already applied via `use` - for idempotent dedupe. */\n private readonly appliedPlugins;\n /** Order-scoped evidence captured by routes registered after an assured plugin. */\n private readonly activeAssurance;\n /** App-wide evidence from global hooks; applies retroactively to every route. */\n private readonly globalAssurance;\n /** App-declared MCP resources / prompts (via {@link resource} / {@link prompt}), read by `nifra mcp`. */\n private readonly mcpResourceList;\n private readonly mcpPromptList;\n constructor(options?: ServerOptions);\n private assertConfigurable;\n /** Register a callback awaited after graceful drain and server stop. Hung callbacks are bounded. */\n onStop(fn: StopHook): this;\n /**\n * Mount a legacy fetch handler under a literal path prefix. Mounted handlers sit behind typed\n * routes, so routes can move one at a time while the remaining legacy surface stays live.\n * Mounted responses are outside Nifra's typed route and response-contract checks.\n */\n mountFetch(path: string, handler: FetchHandler<EnvOf<Ctx>>, options?: MountFetchOptions): this;\n /**\n * Add a per-request, computed context extension. Order-scoped: it is snapshotted into every route\n * declared *after* this call, and reaches none declared before. One added after the last route\n * (e.g. on the app returned by a route-registering factory) covers nothing - see\n * {@link ServerOptions.unusedScopedHooks}.\n */\n derive<D extends object>(fn: (context: Context & Ctx) => MaybePromise<D>): Server<R, Ctx & D>;\n /**\n * Add a static context value. Order-scoped: captured by every route declared *after* this call, and\n * by none before; one added after the last route reaches nothing\n * (see {@link ServerOptions.unusedScopedHooks}).\n */\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>>;\n /**\n * Run before routing on the raw request. Return a `Response` to short-circuit, or a replacement\n * `Request` to continue routing with a rewritten method/URL/headers. Global.\n */\n onRequest(fn: (req: Request, platform?: Platform<EnvOf<Ctx>>) => MaybePromise<OnRequestResult>): this;\n /**\n * Run after validation, before the handler; a non-`undefined` return short-circuits. Order-scoped:\n * it is snapshotted into every route declared *after* this call and covers none declared before, so\n * one added after the last route reaches nothing (see {@link ServerOptions.unusedScopedHooks}).\n */\n beforeHandle(fn: (context: Context & Ctx) => MaybePromise<unknown>): this;\n /**\n * Wrap the matched route lifecycle for subsequent routes. This is intentionally generic over the\n * route output, so wrappers like async context storage do not force Node's direct JSON path through\n * a Web `Response`. The first registered wrapper is outermost.\n *\n * Order-scoped: captured by every route declared *after* this call, none before; one added after the\n * last route reaches nothing (see {@link ServerOptions.unusedScopedHooks}).\n */\n around(fn: <T>(context: Context & Ctx, next: () => MaybePromise<T>) => MaybePromise<T>): this;\n /**\n * Asynchronously admit each subsequent `executeCapability()` call before its owned effect runs.\n * Interceptors receive token-only metadata plus an abort signal and must call `next()` exactly once\n * to admit. Returning without `next()`, timing out, aborting, or throwing fails the effect closed.\n */\n aroundCapability(interceptor: CapabilityInterceptor, options?: AroundCapabilityOptions): this;\n /** Observe token-only admission/execution lifecycle events for subsequent capability routes. */\n observeCapability(observer: EffectLifecycleObserver): this;\n /** Transform the handler's result before it is serialized. Order-scoped: captured by routes declared\n * *after* this call, none before; one added after the last route reaches nothing (see\n * {@link ServerOptions.unusedScopedHooks}). */\n afterHandle(fn: (result: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Handle a thrown error; a non-`undefined` return becomes the response (else the default 500).\n * Order-scoped: captured by routes declared *after* this call, none before; one added after the last\n * route reaches nothing (see {@link ServerOptions.unusedScopedHooks}). */\n onError(fn: (error: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Transform every outgoing response - success, error, 404, 405, short-circuit. Global. */\n onResponse(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Declare response headers with NO per-request decision behind them - and pay nothing for them on\n * the request path.\n *\n * These are not a hook. Because the values are known at wire-up, they are folded into response\n * construction (one prebuilt init for JSON renders, one record merge where the request set its own\n * headers), so an app whose only response middleware is static keeps every fused and native lane -\n * `onResponse`/`onResponseHeaders` disable Bun's fused native routes and, for a full `onResponse`,\n * the Node direct writer. They apply to EVERY response, exactly as a response hook would: success,\n * error, 404/405, timeout, and short-circuit alike.\n *\n * app.responseHeaders({ \"x-frame-options\": \"DENY\", \"referrer-policy\": \"no-referrer\" })\n *\n * They are DEFAULTS: a value the request itself produced (`c.set.headers`, or a response hook)\n * wins, whatever casing it used. Names are lowercased once here; a non-string value, an invalid\n * name, `__proto__`, or a name the render owns (`content-type`, `content-length`,\n * `transfer-encoding`, `set-cookie`) throws a `TypeError` at wire-up.\n *\n * ORDERING: declarations made before any response hook fold into one static record. One made AFTER\n * a response hook cannot - the hook may already have written that name and must keep winning - so\n * it registers as an ordinary `onResponseHeaders` hook instead, preserving registration order at\n * the cost of the static tier's speed. Declare static headers first.\n */\n responseHeaders(record: Readonly<Record<string, string>>): this;\n /** Wire an already-validated lowercase record into the static tier, or - once a dynamic response\n * hook owns part of the header state - into a hook that runs in the right order. */\n private addStaticResponseHeaders;\n private enableResponseBodyTagging;\n /**\n * Register a response transform for raw/streamed Responses. Framework-serialized payloads stay on\n * the body tier; this hook is only entered for untagged Responses (streams, proxied fetches, and\n * framework-generated error responses). A no-op native twin keeps buffered JSON on the direct lane.\n */\n onResponseRaw(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Register a PORTABLE header-only response hook - one implementation, fast on every runtime.\n *\n * The hook receives a mutable case-insensitive header view, a minimal request view, and the\n * status. On the Web serving paths it runs inside the normal `onResponse` walk against the\n * response's own `Headers` (mutating in place - no clone). On Node it self-pairs as a native\n * response hook against the outcome's plain header record, so registering one NEVER forces the\n * Node adapter off its direct socket writer the way a full `onResponse(res: Response)` hook does.\n * Prefer this over `onResponse` whenever the middleware only reads/writes headers.\n */\n onResponseHeaders(fn: ResponseHeadersHook): this;\n /**\n * Register a PORTABLE post-serialization body hook - the payload tier. The hook receives the\n * FINAL framework-serialized bytes (plus the mutable header view and status) and may return\n * replacement bytes; `undefined` keeps the body. On the Node direct writer the bytes come\n * straight off the outcome record; on the Web serving paths they ride the framework-built\n * Response as a tag, so no body stream is ever drained on any runtime. A handler-returned raw\n * `Response` (proxied fetch, SSE, streamed SSR) is skipped by contract - transforming those is\n * what the full `onResponse` hook is for.\n */\n onResponseBody(fn: ResponseBodyHook): this;\n /** Observe the terminal response after all transformations. Observers are ordered and fail-open. */\n onResponseFinalized(fn: (outcome: ResponseFinalization, req: Request) => MaybePromise<void>): this;\n /**\n * Apply a type-**identity** plugin ({@link IdentityPlugin}, from {@link defineIdentityPlugin}) - it\n * registers routes/hooks but doesn't change the types, so this returns `this` with the route registry\n * and context fully intact. This overload exists specifically so a *named* identity plugin (e.g.\n * `@nifrajs/better-auth`) threads the registry: its `& { pluginName }` intersection would otherwise\n * defeat the generic inference of the transforming overload below and collapse the result to `any`.\n */\n use(plugin: IdentityPlugin): this;\n /**\n * Apply a **context** plugin ({@link ContextPlugin}, from {@link defineContextPlugin}) - it adds `D`\n * to the handler context and changes nothing else, so the route registry `R` and the existing context\n * `Ctx` thread through untouched. Like the identity overload above, this exists because the generic\n * `(app: this) => Out` overload below cannot infer through a *generic* plugin signature: it erases the\n * plugin's own type parameters to their constraints, which silently widens `R` to `Registry`.\n */\n use<D extends object>(plugin: ContextPlugin<D>): Server<R, Ctx & D>;\n /**\n * Apply a **plugin function** - `(app) => app`, typically built with {@link definePlugin}. It's\n * called with `this` and its result is returned, so an inline plugin's `derive`/`decorate` thread\n * the added context to handlers defined after `use` (the overload is generic over the concrete\n * `this`). A named plugin already applied is skipped (idempotent dedupe).\n *\n * If the plugin's return type is unpinned - `Server<any, any>`, as a hand-rolled `(app) => app` or a\n * `NifraPlugin<AnyServer, AnyServer>` infers (e.g. an auth plugin whose own types collapsed) - this\n * returns the non-callable {@link PluginTypeCollapsed} instead of silently widening the whole typed\n * client to `any`. `.get()`/`.post()` then fail right here rather than surfacing as `any` hundreds of\n * lines away. Fix at the plugin: build it with {@link defineIdentityPlugin}/{@link defineContextPlugin},\n * or pin its input server type. This mirrors the guard {@link definePlugin} already applies.\n */\n use<Out extends AnyServer>(plugin: (app: this) => Out): [ServerTypeUnpinned<Out>] extends [true] ? PluginTypeCollapsed : Out;\n /**\n * Apply a {@link Middleware} bundle - wire each hook it provides to its lifecycle point. Returns\n * `this` (no context-type merging); call it before the routes its `beforeHandle`/`afterHandle`\n * should cover (those are order-scoped; `onRequest`/`onResponse` are global). A bundle applied after\n * the last route reaches nothing - {@link ServerOptions.unusedScopedHooks} logs that at seal. A named\n * bundle already applied is skipped (idempotent).\n */\n use(mw: Middleware): this;\n get<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n get<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Register a **typed SSE route** - a GET endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. The handler receives the validated context plus a\n * {@link TypedSSEStream}: `stream.send(event)` is compile-time-checked against the schema and\n * JSON-serialized into the SSE `data:` field. The typed client sees the marker and grows a\n * `.subscribe(onEvent)` for the route with the same payload type - end-to-end typed streaming.\n *\n * import { streaming } from \"@nifrajs/core/sse\" // .use(streaming()) enables .sse()\n * const app = server().use(streaming()).sse(\"/feed\", { sse: t.object({ id: t.integer(), title: t.string() }) },\n * async (c, stream) => {\n * stream.send({ id: 1, title: \"hello\" }) // typed\n * await waitForDisconnect(stream.signal)\n * },\n * { keepAlive: 15_000 })\n *\n * // client: const off = api.feed.subscribe((post) => console.log(post.title))\n *\n * `init` passes through to the underlying {@link sse} helper (`keepAlive`, extra headers). The\n * connection closes when the handler resolves, `stream.close()` runs, or the client disconnects\n * (`stream.signal`). Query/body schemas validate exactly as on any other route.\n */\n sse<Path extends string, S extends RouteSchema & {\n sse: StandardSchemaV1;\n }>(path: Path, schema: S, run: (context: Context<Path, S> & Ctx, stream: TypedSSEStream<InferOutput<S[\"sse\"]>>) => void | Promise<void>, init?: SSEInit): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, Response>>, Ctx>;\n post<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n post<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n put<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n put<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n patch<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n patch<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n delete<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n delete<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Declare an **MCP tool** an agent can call (via `nifra mcp`, or a mounted MCP endpoint): a typed\n * `POST /_nifra/tool/<name>` route whose `input`/`output` schemas contract the call and surface in\n * `tools/list`. Requires `.use(mcp())` - without it, `.tool()` is a registration error, so an\n * ordinary HTTP app never bundles the MCP wiring. Siblings: {@link resource}, {@link prompt}.\n *\n * import { mcp } from \"@nifrajs/core/mcp\"\n * const app = server().use(mcp()).tool(\n * \"search\",\n * { description: \"Search posts\", input: t.object({ q: t.string() }) },\n * ({ q }) => findPosts(q),\n * )\n */\n tool<Name extends string, S extends {\n description: string;\n input: StandardSchemaV1;\n output?: StandardSchemaV1;\n annotations?: ToolAnnotations;\n }, H extends (input: InferOutput<S[\"input\"]>, ctx: Context & Ctx) => MaybePromise<S[\"output\"] extends StandardSchemaV1 ? InferOutput<S[\"output\"]> : unknown>>(name: Name, config: S, handler: H): Server<AddRoute<R, \"POST\", `/_nifra/tool/${Name}`, RouteInfoFor<`/_nifra/tool/${Name}`, S[\"output\"] extends StandardSchemaV1 ? {\n body: S[\"input\"];\n response: S[\"output\"];\n } : {\n body: S[\"input\"];\n }, OutputOf<H>>>, Ctx>;\n /**\n * Declare an MCP **resource** - read-only data an agent can fetch through `nifra mcp` (app config, a\n * generated document, …). `read` runs in the app process, so capture whatever app state it needs in the\n * closure. `uri` is the MCP resource identifier (e.g. `\"myapp://config\"`). The sibling of {@link tool}\n * for the resource half of MCP.\n */\n resource(uri: string, config: {\n readonly name: string;\n readonly description?: string;\n readonly mimeType?: string;\n }, read: McpResourceDescriptor[\"read\"]): Server<R, Ctx>;\n /**\n * Declare an MCP **prompt** - a reusable prompt template an agent can fetch through `nifra mcp`.\n * `handler` receives the caller's arguments and returns the rendered messages.\n */\n prompt(name: string, config: {\n readonly description: string;\n readonly arguments?: readonly PromptArgument[];\n }, handler: McpPromptDescriptor[\"handler\"]): Server<R, Ctx>;\n /** The MCP resources declared via {@link resource} - enumerated by `nifra mcp`. */\n mcpResources(): readonly McpResourceDescriptor[];\n /** The MCP prompts declared via {@link prompt} - enumerated by `nifra mcp`. */\n mcpPrompts(): readonly McpPromptDescriptor[];\n /**\n * Register a **WebSocket** route. The connection upgrades on a `GET` to `path` carrying\n * `Upgrade: websocket`; the optional `handler.upgrade(c)` runs in the request context first and may\n * reject (return a `Response`) or seed per-connection `ws.data`. WebSockets are served by the\n * adapter (`listen()`, `@nifrajs/node`, `@nifrajs/deno`, `toFetchHandler`) - not by bare `app.fetch`, which\n * has no socket (a WS path through `app.fetch` is a normal HTTP response).\n *\n * The route also enters the type-level registry (under the pseudo-method `\"WS\"`), so the typed\n * client grows a `.ws()` handle for it: `messageSchema` types what the client may `send`,\n * `sendSchema` types the frames it receives. Passing explicit type arguments (`ws<MyData>(…)`)\n * defeats path-literal inference and skips the registry entry - the route still serves, it is just\n * invisible to `client<App>`; prefer typing `data` via `upgrade()`'s return.\n *\n * app.ws(\"/chat\", { open: (ws) => ws.send(\"hi\"), message: (ws, data) => ws.send(data) })\n */\n ws<Data = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined, Path extends string = string>(path: Path, handler: WebSocketHandler<Data, EnvOf<Ctx>, Schema, Send>): string extends Path ? Server<R, Ctx> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx>;\n /**\n * Broadcast `data` to every WebSocket connection subscribed to `topic` (via `ws.subscribe(topic)`).\n * In-process and **single-instance** (see {@link TopicRegistry}) - a multi-instance deploy must bridge\n * an external fan-out (Redis, a Durable Object) to this. A no-op when nobody is subscribed.\n */\n publish(topic: string, data: string | ArrayBufferView | ArrayBuffer): void;\n private route;\n /**\n * Low-level route registration shared by the inline builder and `implement()`.\n * Captures the server's current `derive`/`decorate` chain into the route - this\n * is the \"compiled\", order-scoped per-route chain.\n */\n register(method: Method, path: string, schema: RouteSchema | undefined, handler: (context: never) => unknown): void;\n /** Register a contract/group route batch atomically. Every route captures the same current chain it\n * would capture through {@link register}; no route becomes visible unless the full batch validates. */\n registerBatch(routes: readonly {\n readonly method: Method;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n private prepareRoute;\n /** The idempotency lane's bridge back into the normal matched lanes, resolved to a concrete Response\n * (the lane buffers the body, then replays it through the route's real validation + handler). */\n private idempotencyRunLanes;\n /** @internal Symbol-keyed install seam for the `responseContract()` plugin. Off the public typed surface. */\n [INSTALL_RESPONSE_CONTRACT](runtime: ResponseContractRuntime): void;\n /** @internal Symbol-keyed install seam for the `idempotency()` plugin. Off the public typed surface. */\n [INSTALL_IDEMPOTENCY](runtime: IdempotencyRuntime): void;\n /** @internal Symbol-keyed install seam for the `mcp()` plugin. Off the public typed surface. */\n [INSTALL_MCP](runtime: McpRuntime): void;\n /** @internal Symbol-keyed install seam for the `nodeDirect()` plugin. Off the public typed surface. */\n [INSTALL_NODE_DIRECT](runtime: NodeOutcomeRuntime): void;\n /** @internal Symbol-keyed install seam for the `streaming()` plugin. Off the public typed surface. */\n [INSTALL_SSE](runtime: SseRuntime): void;\n /** @internal Symbol-keyed install seam for the `websocket()` plugin. Off the public typed surface. */\n [INSTALL_WS](runtime: WsRuntime): void;\n /**\n * Merge another server's routes into this one - the composition escape hatch for large apps.\n *\n * WHY: the fluent chain accumulates one type-alias level per route, and TypeScript resolves\n * that stack in one recursion - a single chain hits TS2589 at ~95 routes. Groups keep every\n * chain short: build each domain (`listings`, `agents`, …) as its own `server()` (its registry\n * resolves independently), then `app.merge(listings).merge(agents)` - each merge adds ONE level\n * regardless of group size. 300+ routes stay fully typed (see many-routes.test-d.ts). The\n * other escape hatch is contract-first `implement()`, whose registry is a single object type.\n *\n * Semantics: merged routes keep the chains captured where they were DEFINED - the group's\n * `derive`/`decorate`/`beforeHandle`/`afterHandle`/`onError`/`around` apply to its routes\n * exactly as they did standalone, so a group wires its own plugins. The same locality rule\n * covers the group's `onRequest` hooks: they run only for requests that route to the GROUP's\n * routes (a `bodyLimit()` mounted on an uploads group must not start gating the whole app\n * because the app composed it in), and the group's global assurance follows its hooks onto\n * exactly those routes. A group with hooks but NO routes is a middleware bundle - its hooks\n * can only mean app-wide intent, so they are appended globally, unchanged. Response-side hooks\n * (`onResponse`/`onResponseFinalized`) are appended to this server's. This server's\n * route-scoped chains do NOT retroactively wrap merged routes (order-scoped, like routes\n * registered before a `derive`). Fail closed: a path+method collision throws\n * `RouteConfigError` at merge time, and a group with WebSocket routes is refused (register\n * those on the parent).\n */\n merge<R2 extends Registry, Ctx2>(other: Server<R2, Ctx2>): Server<R & R2, Ctx>;\n /** A fused renderer closes over runtime services to keep its seven-argument JSC fast path. Merging\n * rebinds that closure once to the executing server; generic plans already receive the runtime. */\n private bindFusedRuntime;\n /**\n * Enumerate the registered routes (method, path, input schemas), in registration\n * order. Powers `toOpenAPI` and other introspection; the router trie itself no\n * longer holds the original patterns.\n */\n routes(): ReadonlyArray<RouteDescriptor>;\n /**\n * Resolve a `Request` to a `Response` - the whole lifecycle, testable without a port. The\n * optional `platform` carries edge inputs (`env`, `waitUntil`); edge adapters pass it, and\n * Bun/Node/Deno omit it (then `c.env` is `undefined` and `c.waitUntil` runs fire-and-forget).\n */\n fetch(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<Response>;\n private fetchSource;\n private fetchSourceInner;\n /** Web response path when Bun already matched the route. The lifecycle and response hooks remain\n * exactly the same as {@link fetchSource}; only portable URL scanning + trie lookup are skipped. */\n private fetchMatched;\n private fetchMatchedInner;\n /**\n * Run `produce` under the capacity gate: admit → run → release exactly once when the response is\n * produced (or the run throws). Only reached when {@link capacityGate} is set, so the off path pays\n * nothing. The slot is held for the duration of handler execution, not the streaming of the body -\n * capacity here bounds concurrent *work*, matching how in-flight is counted.\n */\n private admitGated;\n private runAdmitted;\n /**\n * Like {@link fetch}, but renders a plain-data result **without** building a Web `Response` - the\n * `@nifrajs/node` adapter serializes the returned primitives straight to the socket, skipping the undici\n * `Response` build + body drain (the bulk of the Node bridge cost, measured ≈4µs/req). A handler that\n * returns a `Response`, an error/short-circuit, or a response hook that replaces/consumes the buffered\n * body stays on the full Web path; an in-place response hook can still use the direct writer. Same\n * lifecycle as {@link fetch} (body cap, validation, hooks all run); only the final render differs.\n */\n resolveNode(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<NodeServeOutcome>;\n resolveNodeSource(source: RequestSource, platform?: Platform<EnvOf<Ctx>>, suppliedRuntime?: NodeOutcomeRuntime): MaybePromise<NodeServeOutcome>;\n /** Run generic Web response middleware while retaining direct writes for untouched buffered bodies. */\n private finishNodeWebResponse;\n /** True only when every transforming Web response hook has a header-only Node equivalent. */\n private canUseNodeResponseHooks;\n /** Apply paired native hooks to data outcomes; preserve the complete Web hook pipeline for Response outcomes. */\n private finishNodeResponse;\n private withNodeResponseHeaders;\n /** Synchronous until a native response hook actually returns a Promise. */\n private applyNodeResponseHooks;\n private continueNodeResponseHooks;\n /**\n * Resolve a WebSocket upgrade - the seam every serving adapter uses. Returns `pass` (not a WS\n * upgrade for a registered route → handle as normal HTTP), `reject` (a WS route matched but\n * `upgrade()` rejected, or the path was malformed → return `response`), or `upgrade` (perform the\n * runtime upgrade, then dispatch the native socket's events to `handler`, seeding `ws.data` with\n * `data`). Runs the route's `upgrade(c)` guard in a real request context. Synchronous unless\n * `upgrade()` is async; a throw rejects with a flat 500 (no detail leaked).\n */\n resolveWebSocketUpgrade(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<WebSocketUpgradeOutcome>;\n /** Bun `fetch` when WS routes exist: try a WS upgrade first, else run the normal HTTP lifecycle.\n * `undefined` ⇒ Bun owns the upgraded socket; a `Response` ⇒ a normal reply or a rejected upgrade.\n * (The socket dispatch itself lives in `ws-bun.ts`, loaded via `@nifrajs/core/ws`.) */\n private bunFetchWithWebSocket;\n /**\n * The shared lifecycle, generic over how the final value is rendered: `finalize` turns a handler's\n * result + `set` into the output `T` (`toResponse` → a Web `Response`; `toNodeOutcome` → node-direct\n * primitives), `wrapResponse` lifts an early/error `Response` into that same `T`, and `onTimeout`\n * produces the 503. The Web `fetch` and `resolveNode` are thin callers over this one routing +\n * context + lifecycle implementation - no duplication across the trust boundary.\n */\n /** Apply the `clientIp` trust declaration to the adapter's raw socket peer, returning a platform\n * whose `clientIp` is the derived caller. Only called when a trust declaration is configured. */\n private deriveClientIp;\n private dispatch;\n /** Node-native request hook walk. A header-only hook can inspect the lazy source without forcing a\n * Web `Request`; arbitrary request rewrites and full Web hooks use {@link runWithOnRequest}. */\n private runWithNodeRequest;\n private continueNodeRequest;\n private canUseNodeRequestHooks;\n /**\n * onRequest short-circuit path. Synchronous as long as every hook returns synchronously (the\n * common case - e.g. CORS returning `undefined` for a non-preflight request): an `async` version\n * here put EVERY request of any app with one onRequest hook onto the promise machinery, profiled\n * at ~13% of a realistic request. The first hook that returns a Promise hands the REMAINING\n * hooks to the async continuation; behavior is identical.\n */\n private runWithOnRequest;\n /** Async tail of {@link runWithOnRequest}: applies the first awaited hook's outcome, then runs\n * the remaining hooks (awaiting freely - we're already async here). */\n private continueOnRequest;\n private takeResponseRequest;\n /**\n * The NodeRequestContext for a source, MEMOIZED per source so the request twins and the response\n * twins receive the exact same object within one request - that identity is the documented\n * contract stateful twins key their WeakMaps on. An adapter source (which already speaks the\n * interface) is returned as-is; a plain `Request` source (a direct `resolveNode` caller) gets one\n * cached wrapper.\n */\n private nodeRequestContextOf;\n /** Preserve the request visible to generic onRequest hooks for paired native response hooks. */\n private takeNodeResponseRequest;\n /**\n * Route → build context → run. Synchronous through to the handler for a **bare** route\n * (selected by its compiled plan), so a sync handler produces its result with zero promise allocations;\n * routes with validation/hooks keep the full async {@link runLifecycle}, unchanged.\n */\n private routeAndRun;\n private fetchMount;\n /** Run a route that has already been matched by the runtime or Nifra's portable router. */\n private runMatched;\n /** Supply request-specific deadline state to the route's precompiled execution plan. */\n private runMatchedLanes;\n /** @internal Symbol-keyed install seam for the `effectLedger()` plugin. Off the public typed surface. */\n [INSTALL_EFFECT_LEDGER](runtime: EffectLedgerRuntime): void;\n /** The narrowest bare route: a syntactic `() => ...` handler cannot observe the context argument, so\n * successful requests can skip allocating `RequestContext`. Errors still allocate one for logging. */\n private runContextlessBare;\n private contextlessBareError;\n /**\n * The synchronous fast path selected by a route's execution plan: apply static decorations, call the\n * handler, render the result - **no `await`** unless the handler itself returns a promise. It mirrors\n * the bare slice of {@link runLifecycle} (which a bare route would otherwise no-op through) and shares\n * {@link logRequestError}; a bare route has no `onError` hooks, so error handling is fully synchronous\n * (a thrown `Response` is control flow; anything else is a logged flat 500). This is where nifra skips\n * the per-request async-frame tax - the same win codegen routers get, but without `eval`.\n */\n private runBare;\n /** Bare-route error rendering - identical to {@link runLifecycle}'s catch minus the (absent) onError\n * loop: a thrown `Response` is returned as deliberate control flow; anything else is logged + 500. */\n /**\n * Build a route's fused Web renderer. Composition happens once at\n * registration; the returned closure is what every request to the route runs. Behavior is\n * byte-identical to the generic `runBare`/`runContextlessBare` + `toResponse` pair - same\n * decoration order, same error routing (thrown `Response` = control flow; anything else logs and\n * 500s), same respond semantics (the lifecycle parity suite pins it).\n */\n private buildFusedWeb;\n /** Compile the eligible body-only route's parser → validator → handler continuation once. The\n * bounded parser remains shared with the generic lane; only the route-invariant entry lookups and\n * lifecycle dispatch disappear from the common synchronous-validator/synchronous-handler case. */\n private buildFusedBodyRunner;\n /** Web adapter wrapper for the shared body runner. Node passes its native finalizer directly through\n * the execution plan, while Web needs the live context to preserve lazy `c.set` controls. */\n private buildFusedBodyWeb;\n /** The fused Web lane for a route whose only lifecycle step is a query schema: parse + validate +\n * handler + respond in one closure, no lifecycle promise when the validator and handler are sync.\n * Eligibility is decided at registration (see `fusedQuery` in {@link register}); the semantics here\n * are exactly `runQueryOnly`'s for that eligible shape - invalid input returns\n * `validationError(issues)` (recovery hooks disqualify the route from this lane), a thrown\n * `Response` passes through, anything else logs and returns a flat 500, and an async validator\n * falls to a then-chain with the same steps. */\n private buildFusedQueryWeb;\n private bareError;\n private runWithAround;\n private runAround;\n private runBodyOnly;\n /** Shared bounded body framing/parser. Both body lanes use the same trust-boundary checks; only\n * the validation + handler continuation differs. */\n private readBodyInput;\n /** Validate + run the handler for the bodyOnly path - shared by the inline fast path and the\n * streaming fallback. A method (not per-request closures) so the hot path allocates nothing\n * beyond the one `.then` continuation. */\n private finishBodyOnly;\n private executeHandler;\n private handleValidationErrorRecovery;\n private applyBodyValidation;\n private runQueryOnly;\n /** Validate-result → set `ctx.query` → run handler. A method (not a per-request closure), the\n * query analogue of {@link applyBodyValidation}. */\n private applyQueryValidation;\n /**\n * Thread the response through each global `onResponse` hook. Stays SYNCHRONOUS until a hook\n * actually returns a Promise - an `async` version forced a promise + microtask on EVERY response\n * of any app with an onResponse hook (cors/securityHeaders/etag/timing all use onResponse), the\n * same ~13%/req tax the onRequest walk was de-async'd to avoid. The first async hook hands the\n * rest to {@link continueOnResponse}.\n */\n private applyOnResponse;\n private applyOnResponseAndFinalize;\n private completeResponseFinalization;\n private failResponseFinalization;\n /** Notify terminal observers in order while isolating both sync and async failures. */\n private notifyResponseFinalized;\n /** Async tail of {@link applyOnResponse}: runs the remaining hooks once one has gone async. */\n private continueOnResponse;\n /**\n * Bound the response time. On timeout we abort `ctx.signal` (so cancellation-aware\n * handlers can bail) and return 503; the in-flight work keeps running but its\n * result is discarded - JS can't forcibly cancel a promise.\n */\n private withTimeout;\n /**\n * The post-match lifecycle: validate → derive → beforeHandle → handler → afterHandle, with onError.\n * Generic over the render: a success value goes through `finalize(result, set)` (a Web `Response`, or\n * node-direct primitives); an early/error `Response` (validation, thrown, 500) through `wrapResponse`.\n */\n /** Synchronous until a validator, lifecycle hook, handler, or contract check actually returns a Promise. */\n private runLifecycle;\n private runLifecycleAfterHeadersResult;\n private runLifecycleAfterHeaders;\n /** Registration-specialized query lifecycle: query validation (including recovery) → hooks. */\n private runLifecycleQuery;\n /** Registration-specialized body lifecycle: bounded body validation (including recovery) → hooks. */\n private runLifecycleBody;\n /** Registration-specialized body + query lifecycle: bounded body validation → query validation → hooks. */\n private runLifecycleBodyQuery;\n /** Registration-specialized no-body lifecycle: query validation (if present) → derives/hooks. */\n private runQueryAndLifecycle;\n private runQueryAndLifecycleResult;\n private runLifecycleAfterParamsResult;\n private runLifecycleAfterParams;\n private runLifecycleAfterParamsSettled;\n private runLifecycleAfterBody;\n private runLifecycleAfterQueryResult;\n private runLifecycleAfterQuery;\n private runLifecycleHooks;\n /** Registration-specialized derive → before → handler lifecycle. */\n private runLifecycleDeriveBefore;\n /** Finalize the specialized lane without rechecking its registration-proven invariants. */\n private finishSimpleLifecycleResult;\n private continueLifecycleAfterDerive;\n private runLifecycleHooksAsync;\n private continueLifecycleAfterBefore;\n private runLifecycleHandlerAsync;\n private finishLifecycleResult;\n private continueLifecycleAfterHandle;\n private finishLifecycleContract;\n private finishContractOutcome;\n private handleLifecycleError;\n /** Log an unhandled request error to the (redacting) logger - shared by {@link runLifecycle} and the\n * bare fast path ({@link bareError}) so both record the same fields. Never throws; never leaks. */\n private logRequestError;\n private readAndValidateBody;\n /** Apply validation and its recovery hook on the generic lifecycle lane. Recovery is completed\n * before derives/beforeHandle run, matching the body-only and query-only execution lanes. */\n private applyLifecycleValidation;\n private finishLifecycleValidationRecovery;\n /**\n * Read + parse the JSON body, capped at `maxBodyBytes` and screened by the server's\n * `protoPoisoning` policy. Rejects a `Content-Length` over the cap *before* buffering,\n * re-checks what was actually delivered after the read, and aborts a chunked or\n * length-less body mid-stream once the running byte count exceeds the cap - so a lying\n * or absent length can't force us to buffer an oversized payload.\n */\n private readBoundedJson;\n /** Adapt one route's compiled execution plan to Bun's already-matched request shape. Route\n * semantics remain in the plan; this closure only supplies native params and deadline fallback. */\n private compileBunNativeHandler;\n /** Compile portable route registrations into Bun's native route table. Apps with request-rewrite\n * hooks or WebSockets retain the single portable dispatcher because those features must run before\n * route selection/upgrade. Named wildcards also stay on the fallback until Bun exposes their raw\n * capture semantics; static and `:param` routes take the native lane. */\n private buildBunNativeRoutes;\n /**\n * Start a `Bun.serve` instance bound to `port` (use `0` for an ephemeral port).\n *\n * `reusePort` sets `SO_REUSEPORT` so **multiple processes can bind the same port** and the kernel\n * load-balances connections across them - the standard way to use every core (Bun is\n * single-threaded per process). Spawn one process per core, each calling\n * `app.listen(PORT, { reusePort: true })`; see `examples/cluster.ts`. Every process must opt in,\n * and all of them must be the same app. Linux balances ~evenly; macOS accepts the flag but may\n * favor one socket (fine for dev, measure on Linux for production numbers).\n *\n * `hostname` is the bind address, defaulting to Bun's `0.0.0.0` (every interface). Pass\n * `\"127.0.0.1\"` to bind loopback only - an admin surface, a sidecar, or anything that must not be\n * reachable off the box. Omitting it when you meant to restrict is a real exposure, so it is a\n * first-class option rather than something a caller has to drop down to `Bun.serve` for.\n *\n * `idleTimeoutSec` is how long Bun tolerates a connection with no bytes moving before it closes\n * the socket. Bun's default is **10 seconds**, and a request whose handler is still working sends\n * nothing - so any endpoint slower than 10s (a render, an export, a long upstream call) has its\n * connection cut mid-flight regardless of `requestTimeoutMs`. Apps with such endpoints must raise\n * this above their slowest expected response, which is why it is a first-class option and not a\n * reason to drop down to `Bun.serve`. `0` disables the timeout entirely; max 255.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n }): RunningServer;\n /**\n * Gracefully stop: wait for in-flight requests to finish (up to `drainMs`), then\n * issue a single terminal stop - graceful if everything drained, forced if\n * stragglers remain. Safe to call when not listening.\n *\n * The Bun semantics: poll `pendingRequests` (awaiting\n * `stop()`'s promise drops in-flight requests), and decide graceful-vs-forced in\n * ONE call (Bun can't escalate an already-graceful `stop()` to a forced close).\n * New connections may be accepted during the drain window; in a real deploy the\n * load balancer has already stopped routing here, and `drainMs` bounds it.\n */\n stop({ drainMs }?: {\n drainMs?: number;\n }): Promise<void>;\n private installSignalHandlers;\n}",
|
|
10729
10742
|
"doc": "/**\n * The inline server. Routes are chainable and fully type-inferred. `derive`/\n * `decorate` extend the handler context (`Ctx`) for routes defined *after* them,\n * with full types; `Ctx` is server-only and never touches the client registry.\n *\n * app.decorate(\"db\", db).derive((c) => ({ user: auth(c) }))\n * .get(\"/me\", (c) => c.user) // c.user + c.db are typed\n */"
|
|
10730
10743
|
},
|
|
10731
10744
|
{
|
|
10732
10745
|
"name": "Server",
|
|
10733
10746
|
"kind": "class",
|
|
10734
10747
|
"package": "nifra",
|
|
10735
|
-
"signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext> {\n /**\n * Which copy of `@nifrajs/core` declared this type. Two copies in one build (a linked sibling repo,\n * a hoisting split) produce two unrelated `Server` types whose assignment error is a wall of\n * missing internals; the brand puts the feature version in the type itself, so `typeof app` on\n * hover - and `NifraFeatureVersion` in an assertion - says which core an app is talking to.\n * `nifra doctor` is the diagnosis that names both install paths.\n *\n * `declare` = type-only: no field is emitted, nothing is allocated per server.\n */\n readonly __nifraCoreVersion: NifraFeatureVersion;\n private readonly catalog;\n /** WebSocket routes, matched separately at upgrade time (a GET + `Upgrade: websocket`). */\n private readonly wsRouter;\n private wsRouteCount;\n /** In-process pub/sub backing `ws.subscribe(topic)` + `app.publish(topic, data)` (single-instance).\n * Created by the first `app.ws()` via the `@nifrajs/core/ws` runtime - `undefined` until then, so a\n * no-WebSocket app never constructs (or bundles) it. */\n private topics;\n private readonly maxBodyBytes;\n private readonly protoPoisoning;\n /** `trustBodyFraming`: mark every `app.fetch` request as runtime-framed (see ServerOptions). */\n private readonly trustBodyFraming;\n private readonly wsMaxPayloadBytes;\n private readonly requestTimeoutMs;\n /** Installed by the `responseContract()` plugin; `undefined` = not installed, which is the default\n * and the state in which a declared `response` schema stays a compile-time contract only. */\n private responseContractRuntime;\n /** Opt-in caller-IP trust declaration; `undefined` = socket peer only, no forwarded header believed. */\n private readonly clientIpTrust;\n private readonly acceptInboundDeadlines;\n private readonly maxInboundDeadlineMs;\n private readonly deadlineAdmissionOptions;\n private readonly gracefulSignals;\n private readonly stopHooks;\n private readonly fetchMounts;\n /** Capacity-admission gate; `undefined` = off (the request path pays nothing). */\n private readonly capacityGate;\n private readonly onCapabilityUse;\n private readonly capabilityInterceptors;\n private readonly capabilityObservers;\n /** The installed effect-ledger runtime (owns the sink + per-route resolution + settle), or\n * `undefined` when the effect-ledger plugin is not installed. */\n private effectLedgerRuntime;\n /** The installed idempotency runtime (owns the app-wide default store + the dedupe lane), or\n * `undefined` when the idempotency plugin is not installed. */\n private idempotencyRuntime;\n /** Installed opt-in runtime for `.tool()`/`.resource()`/`.prompt()`; `undefined` until `.use(mcp())`. */\n private mcpRuntime;\n /** Installed Node-direct renderer for direct `resolveNode()` callers; `undefined` until `.use(nodeDirect())`. */\n private nodeOutcomeRuntime;\n /** Installed streaming runtime for `.sse()` routes; `undefined` until `.use(streaming())`. */\n private sseRuntime;\n /** Installed WebSocket runtime for `.ws()` routes; `undefined` until `.use(websocket())`. */\n private wsRuntime;\n private readonly logger;\n /** How much of an unhandled error {@link logRequestError} records. See `ServerOptions.errorLogDetail`. */\n private readonly errorLogDetail;\n /** App-wide validation-error fallback; a route's own `schema.onValidationError` takes precedence. */\n private readonly defaultOnValidationError?;\n private bunServer;\n private sealed;\n private readonly derives;\n private readonly decorations;\n private readonly beforeHandleHooks;\n private readonly afterHandleHooks;\n private readonly onErrorHooks;\n private readonly aroundHooks;\n private readonly onRequestHooks;\n private readonly onNodeRequestHooks;\n /** Registration-time eligibility for the Node request twin lane. */\n private nodeRequestHooksComplete;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /**\n * True once a bundle registers a RAW `onNodeResponse` twin - one handed the outcome's header\n * record itself rather than the case-normalizing view. Their names are contractually the wire\n * spelling, but registration cannot PROVE it, so such an app forgoes the all-lowercase mark and\n * every reader re-derives the answer, exactly as before the mark existed.\n */\n private hasRawNodeResponseHook;\n private readonly onResponseFinalizedHooks;\n /**\n * Statically declared response headers, merged and prebuilt at registration; `undefined` (the\n * default) leaves every render path in its original shape. These are NOT response hooks - they are\n * folded into response construction - so declaring them keeps the fused native lanes an\n * `onResponse` hook would have disabled.\n */\n private staticResponseHeaders;\n /** `wrapResponse` for the Web lanes: identity until static headers exist to fold into the\n * framework's own error/404/timeout renders, which are built outside the header init. */\n private wrapWebResponse;\n private webResponseTimeout;\n /** Body/raw response hooks need a framework-payload marker; keep that decision per app. */\n private responseBodyTag;\n private readonly responseBodyOwners;\n private readonly finalizeResponse;\n private readonly responseRequests;\n /** Original source → request observed by generic request hooks, including in-place mutations. */\n private readonly responseSources;\n /** Memoized NodeRequestContext per plain-`Request` source - see {@link nodeRequestContextOf}. */\n private readonly nodeContexts;\n /** Names of plugins/middleware already applied via `use` - for idempotent dedupe. */\n private readonly appliedPlugins;\n /** Order-scoped evidence captured by routes registered after an assured plugin. */\n private readonly activeAssurance;\n /** App-wide evidence from global hooks; applies retroactively to every route. */\n private readonly globalAssurance;\n /** App-declared MCP resources / prompts (via {@link resource} / {@link prompt}), read by `nifra mcp`. */\n private readonly mcpResourceList;\n private readonly mcpPromptList;\n constructor(options?: ServerOptions);\n private assertConfigurable;\n /** Register a callback awaited after graceful drain and server stop. Hung callbacks are bounded. */\n onStop(fn: StopHook): this;\n /**\n * Mount a legacy fetch handler under a literal path prefix. Mounted handlers sit behind typed\n * routes, so routes can move one at a time while the remaining legacy surface stays live.\n * Mounted responses are outside Nifra's typed route and response-contract checks.\n */\n mountFetch(path: string, handler: FetchHandler<EnvOf<Ctx>>, options?: MountFetchOptions): this;\n /** Add a per-request, computed context extension for subsequent routes. */\n derive<D extends object>(fn: (context: Context & Ctx) => MaybePromise<D>): Server<R, Ctx & D>;\n /** Add a static context value for subsequent routes. */\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>>;\n /**\n * Run before routing on the raw request. Return a `Response` to short-circuit, or a replacement\n * `Request` to continue routing with a rewritten method/URL/headers. Global.\n */\n onRequest(fn: (req: Request, platform?: Platform<EnvOf<Ctx>>) => MaybePromise<OnRequestResult>): this;\n /** Run after validation, before the handler; a non-`undefined` return short-circuits. Order-scoped. */\n beforeHandle(fn: (context: Context & Ctx) => MaybePromise<unknown>): this;\n /**\n * Wrap the matched route lifecycle for subsequent routes. This is intentionally generic over the\n * route output, so wrappers like async context storage do not force Node's direct JSON path through\n * a Web `Response`. The first registered wrapper is outermost.\n */\n around(fn: <T>(context: Context & Ctx, next: () => MaybePromise<T>) => MaybePromise<T>): this;\n /**\n * Asynchronously admit each subsequent `executeCapability()` call before its owned effect runs.\n * Interceptors receive token-only metadata plus an abort signal and must call `next()` exactly once\n * to admit. Returning without `next()`, timing out, aborting, or throwing fails the effect closed.\n */\n aroundCapability(interceptor: CapabilityInterceptor, options?: AroundCapabilityOptions): this;\n /** Observe token-only admission/execution lifecycle events for subsequent capability routes. */\n observeCapability(observer: EffectLifecycleObserver): this;\n /** Transform the handler's result before it is serialized. Order-scoped. */\n afterHandle(fn: (result: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Handle a thrown error; a non-`undefined` return becomes the response (else the default 500). Order-scoped. */\n onError(fn: (error: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Transform every outgoing response - success, error, 404, 405, short-circuit. Global. */\n onResponse(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Declare response headers with NO per-request decision behind them - and pay nothing for them on\n * the request path.\n *\n * These are not a hook. Because the values are known at wire-up, they are folded into response\n * construction (one prebuilt init for JSON renders, one record merge where the request set its own\n * headers), so an app whose only response middleware is static keeps every fused and native lane -\n * `onResponse`/`onResponseHeaders` disable Bun's fused native routes and, for a full `onResponse`,\n * the Node direct writer. They apply to EVERY response, exactly as a response hook would: success,\n * error, 404/405, timeout, and short-circuit alike.\n *\n * app.responseHeaders({ \"x-frame-options\": \"DENY\", \"referrer-policy\": \"no-referrer\" })\n *\n * They are DEFAULTS: a value the request itself produced (`c.set.headers`, or a response hook)\n * wins, whatever casing it used. Names are lowercased once here; a non-string value, an invalid\n * name, `__proto__`, or a name the render owns (`content-type`, `content-length`,\n * `transfer-encoding`, `set-cookie`) throws a `TypeError` at wire-up.\n *\n * ORDERING: declarations made before any response hook fold into one static record. One made AFTER\n * a response hook cannot - the hook may already have written that name and must keep winning - so\n * it registers as an ordinary `onResponseHeaders` hook instead, preserving registration order at\n * the cost of the static tier's speed. Declare static headers first.\n */\n responseHeaders(record: Readonly<Record<string, string>>): this;\n /** Wire an already-validated lowercase record into the static tier, or - once a dynamic response\n * hook owns part of the header state - into a hook that runs in the right order. */\n private addStaticResponseHeaders;\n private enableResponseBodyTagging;\n /**\n * Register a response transform for raw/streamed Responses. Framework-serialized payloads stay on\n * the body tier; this hook is only entered for untagged Responses (streams, proxied fetches, and\n * framework-generated error responses). A no-op native twin keeps buffered JSON on the direct lane.\n */\n onResponseRaw(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Register a PORTABLE header-only response hook - one implementation, fast on every runtime.\n *\n * The hook receives a mutable case-insensitive header view, a minimal request view, and the\n * status. On the Web serving paths it runs inside the normal `onResponse` walk against the\n * response's own `Headers` (mutating in place - no clone). On Node it self-pairs as a native\n * response hook against the outcome's plain header record, so registering one NEVER forces the\n * Node adapter off its direct socket writer the way a full `onResponse(res: Response)` hook does.\n * Prefer this over `onResponse` whenever the middleware only reads/writes headers.\n */\n onResponseHeaders(fn: ResponseHeadersHook): this;\n /**\n * Register a PORTABLE post-serialization body hook - the payload tier. The hook receives the\n * FINAL framework-serialized bytes (plus the mutable header view and status) and may return\n * replacement bytes; `undefined` keeps the body. On the Node direct writer the bytes come\n * straight off the outcome record; on the Web serving paths they ride the framework-built\n * Response as a tag, so no body stream is ever drained on any runtime. A handler-returned raw\n * `Response` (proxied fetch, SSE, streamed SSR) is skipped by contract - transforming those is\n * what the full `onResponse` hook is for.\n */\n onResponseBody(fn: ResponseBodyHook): this;\n /** Observe the terminal response after all transformations. Observers are ordered and fail-open. */\n onResponseFinalized(fn: (outcome: ResponseFinalization, req: Request) => MaybePromise<void>): this;\n /**\n * Apply a type-**identity** plugin ({@link IdentityPlugin}, from {@link defineIdentityPlugin}) - it\n * registers routes/hooks but doesn't change the types, so this returns `this` with the route registry\n * and context fully intact. This overload exists specifically so a *named* identity plugin (e.g.\n * `@nifrajs/better-auth`) threads the registry: its `& { pluginName }` intersection would otherwise\n * defeat the generic inference of the transforming overload below and collapse the result to `any`.\n */\n use(plugin: IdentityPlugin): this;\n /**\n * Apply a **context** plugin ({@link ContextPlugin}, from {@link defineContextPlugin}) - it adds `D`\n * to the handler context and changes nothing else, so the route registry `R` and the existing context\n * `Ctx` thread through untouched. Like the identity overload above, this exists because the generic\n * `(app: this) => Out` overload below cannot infer through a *generic* plugin signature: it erases the\n * plugin's own type parameters to their constraints, which silently widens `R` to `Registry`.\n */\n use<D extends object>(plugin: ContextPlugin<D>): Server<R, Ctx & D>;\n /**\n * Apply a **plugin function** - `(app) => app`, typically built with {@link definePlugin}. It's\n * called with `this` and its result is returned, so an inline plugin's `derive`/`decorate` thread\n * the added context to handlers defined after `use` (the overload is generic over the concrete\n * `this`). A named plugin already applied is skipped (idempotent dedupe).\n */\n use<Out extends AnyServer>(plugin: (app: this) => Out): Out;\n /**\n * Apply a {@link Middleware} bundle - wire each hook it provides to its lifecycle point. Returns\n * `this` (no context-type merging); call it before the routes its `beforeHandle`/`afterHandle`\n * should cover (those are order-scoped; `onRequest`/`onResponse` are global). A named bundle already\n * applied is skipped (idempotent).\n */\n use(mw: Middleware): this;\n get<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n get<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Register a **typed SSE route** - a GET endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. The handler receives the validated context plus a\n * {@link TypedSSEStream}: `stream.send(event)` is compile-time-checked against the schema and\n * JSON-serialized into the SSE `data:` field. The typed client sees the marker and grows a\n * `.subscribe(onEvent)` for the route with the same payload type - end-to-end typed streaming.\n *\n * import { streaming } from \"@nifrajs/core/sse\" // .use(streaming()) enables .sse()\n * const app = server().use(streaming()).sse(\"/feed\", { sse: t.object({ id: t.integer(), title: t.string() }) },\n * async (c, stream) => {\n * stream.send({ id: 1, title: \"hello\" }) // typed\n * await waitForDisconnect(stream.signal)\n * },\n * { keepAlive: 15_000 })\n *\n * // client: const off = api.feed.subscribe((post) => console.log(post.title))\n *\n * `init` passes through to the underlying {@link sse} helper (`keepAlive`, extra headers). The\n * connection closes when the handler resolves, `stream.close()` runs, or the client disconnects\n * (`stream.signal`). Query/body schemas validate exactly as on any other route.\n */\n sse<Path extends string, S extends RouteSchema & {\n sse: StandardSchemaV1;\n }>(path: Path, schema: S, run: (context: Context<Path, S> & Ctx, stream: TypedSSEStream<InferOutput<S[\"sse\"]>>) => void | Promise<void>, init?: SSEInit): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, Response>>, Ctx>;\n post<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n post<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n put<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n put<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n patch<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n patch<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n delete<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n delete<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Declare an **MCP tool** an agent can call (via `nifra mcp`, or a mounted MCP endpoint): a typed\n * `POST /_nifra/tool/<name>` route whose `input`/`output` schemas contract the call and surface in\n * `tools/list`. Requires `.use(mcp())` - without it, `.tool()` is a registration error, so an\n * ordinary HTTP app never bundles the MCP wiring. Siblings: {@link resource}, {@link prompt}.\n *\n * import { mcp } from \"@nifrajs/core/mcp\"\n * const app = server().use(mcp()).tool(\n * \"search\",\n * { description: \"Search posts\", input: t.object({ q: t.string() }) },\n * ({ q }) => findPosts(q),\n * )\n */\n tool<Name extends string, S extends {\n description: string;\n input: StandardSchemaV1;\n output?: StandardSchemaV1;\n annotations?: ToolAnnotations;\n }, H extends (input: InferOutput<S[\"input\"]>, ctx: Context & Ctx) => MaybePromise<S[\"output\"] extends StandardSchemaV1 ? InferOutput<S[\"output\"]> : unknown>>(name: Name, config: S, handler: H): Server<AddRoute<R, \"POST\", `/_nifra/tool/${Name}`, RouteInfoFor<`/_nifra/tool/${Name}`, S[\"output\"] extends StandardSchemaV1 ? {\n body: S[\"input\"];\n response: S[\"output\"];\n } : {\n body: S[\"input\"];\n }, OutputOf<H>>>, Ctx>;\n /**\n * Declare an MCP **resource** - read-only data an agent can fetch through `nifra mcp` (app config, a\n * generated document, …). `read` runs in the app process, so capture whatever app state it needs in the\n * closure. `uri` is the MCP resource identifier (e.g. `\"myapp://config\"`). The sibling of {@link tool}\n * for the resource half of MCP.\n */\n resource(uri: string, config: {\n readonly name: string;\n readonly description?: string;\n readonly mimeType?: string;\n }, read: McpResourceDescriptor[\"read\"]): Server<R, Ctx>;\n /**\n * Declare an MCP **prompt** - a reusable prompt template an agent can fetch through `nifra mcp`.\n * `handler` receives the caller's arguments and returns the rendered messages.\n */\n prompt(name: string, config: {\n readonly description: string;\n readonly arguments?: readonly PromptArgument[];\n }, handler: McpPromptDescriptor[\"handler\"]): Server<R, Ctx>;\n /** The MCP resources declared via {@link resource} - enumerated by `nifra mcp`. */\n mcpResources(): readonly McpResourceDescriptor[];\n /** The MCP prompts declared via {@link prompt} - enumerated by `nifra mcp`. */\n mcpPrompts(): readonly McpPromptDescriptor[];\n /**\n * Register a **WebSocket** route. The connection upgrades on a `GET` to `path` carrying\n * `Upgrade: websocket`; the optional `handler.upgrade(c)` runs in the request context first and may\n * reject (return a `Response`) or seed per-connection `ws.data`. WebSockets are served by the\n * adapter (`listen()`, `@nifrajs/node`, `@nifrajs/deno`, `toFetchHandler`) - not by bare `app.fetch`, which\n * has no socket (a WS path through `app.fetch` is a normal HTTP response).\n *\n * The route also enters the type-level registry (under the pseudo-method `\"WS\"`), so the typed\n * client grows a `.ws()` handle for it: `messageSchema` types what the client may `send`,\n * `sendSchema` types the frames it receives. Passing explicit type arguments (`ws<MyData>(…)`)\n * defeats path-literal inference and skips the registry entry - the route still serves, it is just\n * invisible to `client<App>`; prefer typing `data` via `upgrade()`'s return.\n *\n * app.ws(\"/chat\", { open: (ws) => ws.send(\"hi\"), message: (ws, data) => ws.send(data) })\n */\n ws<Data = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined, Path extends string = string>(path: Path, handler: WebSocketHandler<Data, EnvOf<Ctx>, Schema, Send>): string extends Path ? Server<R, Ctx> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx>;\n /**\n * Broadcast `data` to every WebSocket connection subscribed to `topic` (via `ws.subscribe(topic)`).\n * In-process and **single-instance** (see {@link TopicRegistry}) - a multi-instance deploy must bridge\n * an external fan-out (Redis, a Durable Object) to this. A no-op when nobody is subscribed.\n */\n publish(topic: string, data: string | ArrayBufferView | ArrayBuffer): void;\n private route;\n /**\n * Low-level route registration shared by the inline builder and `implement()`.\n * Captures the server's current `derive`/`decorate` chain into the route - this\n * is the \"compiled\", order-scoped per-route chain.\n */\n register(method: Method, path: string, schema: RouteSchema | undefined, handler: (context: never) => unknown): void;\n /** Register a contract/group route batch atomically. Every route captures the same current chain it\n * would capture through {@link register}; no route becomes visible unless the full batch validates. */\n registerBatch(routes: readonly {\n readonly method: Method;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n private prepareRoute;\n /** The idempotency lane's bridge back into the normal matched lanes, resolved to a concrete Response\n * (the lane buffers the body, then replays it through the route's real validation + handler). */\n private idempotencyRunLanes;\n /** @internal Symbol-keyed install seam for the `responseContract()` plugin. Off the public typed surface. */\n [INSTALL_RESPONSE_CONTRACT](runtime: ResponseContractRuntime): void;\n /** @internal Symbol-keyed install seam for the `idempotency()` plugin. Off the public typed surface. */\n [INSTALL_IDEMPOTENCY](runtime: IdempotencyRuntime): void;\n /** @internal Symbol-keyed install seam for the `mcp()` plugin. Off the public typed surface. */\n [INSTALL_MCP](runtime: McpRuntime): void;\n /** @internal Symbol-keyed install seam for the `nodeDirect()` plugin. Off the public typed surface. */\n [INSTALL_NODE_DIRECT](runtime: NodeOutcomeRuntime): void;\n /** @internal Symbol-keyed install seam for the `streaming()` plugin. Off the public typed surface. */\n [INSTALL_SSE](runtime: SseRuntime): void;\n /** @internal Symbol-keyed install seam for the `websocket()` plugin. Off the public typed surface. */\n [INSTALL_WS](runtime: WsRuntime): void;\n /**\n * Merge another server's routes into this one - the composition escape hatch for large apps.\n *\n * WHY: the fluent chain accumulates one type-alias level per route, and TypeScript resolves\n * that stack in one recursion - a single chain hits TS2589 at ~95 routes. Groups keep every\n * chain short: build each domain (`listings`, `agents`, …) as its own `server()` (its registry\n * resolves independently), then `app.merge(listings).merge(agents)` - each merge adds ONE level\n * regardless of group size. 300+ routes stay fully typed (see many-routes.test-d.ts). The\n * other escape hatch is contract-first `implement()`, whose registry is a single object type.\n *\n * Semantics: merged routes keep the chains captured where they were DEFINED - the group's\n * `derive`/`decorate`/`beforeHandle`/`afterHandle`/`onError`/`around` apply to its routes\n * exactly as they did standalone, so a group wires its own plugins. The same locality rule\n * covers the group's `onRequest` hooks: they run only for requests that route to the GROUP's\n * routes (a `bodyLimit()` mounted on an uploads group must not start gating the whole app\n * because the app composed it in), and the group's global assurance follows its hooks onto\n * exactly those routes. A group with hooks but NO routes is a middleware bundle - its hooks\n * can only mean app-wide intent, so they are appended globally, unchanged. Response-side hooks\n * (`onResponse`/`onResponseFinalized`) are appended to this server's. This server's\n * route-scoped chains do NOT retroactively wrap merged routes (order-scoped, like routes\n * registered before a `derive`). Fail closed: a path+method collision throws\n * `RouteConfigError` at merge time, and a group with WebSocket routes is refused (register\n * those on the parent).\n */\n merge<R2 extends Registry, Ctx2>(other: Server<R2, Ctx2>): Server<R & R2, Ctx>;\n /** A fused renderer closes over runtime services to keep its seven-argument JSC fast path. Merging\n * rebinds that closure once to the executing server; generic plans already receive the runtime. */\n private bindFusedRuntime;\n /**\n * Enumerate the registered routes (method, path, input schemas), in registration\n * order. Powers `toOpenAPI` and other introspection; the router trie itself no\n * longer holds the original patterns.\n */\n routes(): ReadonlyArray<RouteDescriptor>;\n /**\n * Resolve a `Request` to a `Response` - the whole lifecycle, testable without a port. The\n * optional `platform` carries edge inputs (`env`, `waitUntil`); edge adapters pass it, and\n * Bun/Node/Deno omit it (then `c.env` is `undefined` and `c.waitUntil` runs fire-and-forget).\n */\n fetch(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<Response>;\n private fetchSource;\n private fetchSourceInner;\n /** Web response path when Bun already matched the route. The lifecycle and response hooks remain\n * exactly the same as {@link fetchSource}; only portable URL scanning + trie lookup are skipped. */\n private fetchMatched;\n private fetchMatchedInner;\n /**\n * Run `produce` under the capacity gate: admit → run → release exactly once when the response is\n * produced (or the run throws). Only reached when {@link capacityGate} is set, so the off path pays\n * nothing. The slot is held for the duration of handler execution, not the streaming of the body -\n * capacity here bounds concurrent *work*, matching how in-flight is counted.\n */\n private admitGated;\n private runAdmitted;\n /**\n * Like {@link fetch}, but renders a plain-data result **without** building a Web `Response` - the\n * `@nifrajs/node` adapter serializes the returned primitives straight to the socket, skipping the undici\n * `Response` build + body drain (the bulk of the Node bridge cost, measured ≈4µs/req). A handler that\n * returns a `Response`, an error/short-circuit, or a response hook that replaces/consumes the buffered\n * body stays on the full Web path; an in-place response hook can still use the direct writer. Same\n * lifecycle as {@link fetch} (body cap, validation, hooks all run); only the final render differs.\n */\n resolveNode(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<NodeServeOutcome>;\n resolveNodeSource(source: RequestSource, platform?: Platform<EnvOf<Ctx>>, suppliedRuntime?: NodeOutcomeRuntime): MaybePromise<NodeServeOutcome>;\n /** Run generic Web response middleware while retaining direct writes for untouched buffered bodies. */\n private finishNodeWebResponse;\n /** True only when every transforming Web response hook has a header-only Node equivalent. */\n private canUseNodeResponseHooks;\n /** Apply paired native hooks to data outcomes; preserve the complete Web hook pipeline for Response outcomes. */\n private finishNodeResponse;\n private withNodeResponseHeaders;\n /** Synchronous until a native response hook actually returns a Promise. */\n private applyNodeResponseHooks;\n private continueNodeResponseHooks;\n /**\n * Resolve a WebSocket upgrade - the seam every serving adapter uses. Returns `pass` (not a WS\n * upgrade for a registered route → handle as normal HTTP), `reject` (a WS route matched but\n * `upgrade()` rejected, or the path was malformed → return `response`), or `upgrade` (perform the\n * runtime upgrade, then dispatch the native socket's events to `handler`, seeding `ws.data` with\n * `data`). Runs the route's `upgrade(c)` guard in a real request context. Synchronous unless\n * `upgrade()` is async; a throw rejects with a flat 500 (no detail leaked).\n */\n resolveWebSocketUpgrade(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<WebSocketUpgradeOutcome>;\n /** Bun `fetch` when WS routes exist: try a WS upgrade first, else run the normal HTTP lifecycle.\n * `undefined` ⇒ Bun owns the upgraded socket; a `Response` ⇒ a normal reply or a rejected upgrade.\n * (The socket dispatch itself lives in `ws-bun.ts`, loaded via `@nifrajs/core/ws`.) */\n private bunFetchWithWebSocket;\n /**\n * The shared lifecycle, generic over how the final value is rendered: `finalize` turns a handler's\n * result + `set` into the output `T` (`toResponse` → a Web `Response`; `toNodeOutcome` → node-direct\n * primitives), `wrapResponse` lifts an early/error `Response` into that same `T`, and `onTimeout`\n * produces the 503. The Web `fetch` and `resolveNode` are thin callers over this one routing +\n * context + lifecycle implementation - no duplication across the trust boundary.\n */\n /** Apply the `clientIp` trust declaration to the adapter's raw socket peer, returning a platform\n * whose `clientIp` is the derived caller. Only called when a trust declaration is configured. */\n private deriveClientIp;\n private dispatch;\n /** Node-native request hook walk. A header-only hook can inspect the lazy source without forcing a\n * Web `Request`; arbitrary request rewrites and full Web hooks use {@link runWithOnRequest}. */\n private runWithNodeRequest;\n private continueNodeRequest;\n private canUseNodeRequestHooks;\n /**\n * onRequest short-circuit path. Synchronous as long as every hook returns synchronously (the\n * common case - e.g. CORS returning `undefined` for a non-preflight request): an `async` version\n * here put EVERY request of any app with one onRequest hook onto the promise machinery, profiled\n * at ~13% of a realistic request. The first hook that returns a Promise hands the REMAINING\n * hooks to the async continuation; behavior is identical.\n */\n private runWithOnRequest;\n /** Async tail of {@link runWithOnRequest}: applies the first awaited hook's outcome, then runs\n * the remaining hooks (awaiting freely - we're already async here). */\n private continueOnRequest;\n private takeResponseRequest;\n /**\n * The NodeRequestContext for a source, MEMOIZED per source so the request twins and the response\n * twins receive the exact same object within one request - that identity is the documented\n * contract stateful twins key their WeakMaps on. An adapter source (which already speaks the\n * interface) is returned as-is; a plain `Request` source (a direct `resolveNode` caller) gets one\n * cached wrapper.\n */\n private nodeRequestContextOf;\n /** Preserve the request visible to generic onRequest hooks for paired native response hooks. */\n private takeNodeResponseRequest;\n /**\n * Route → build context → run. Synchronous through to the handler for a **bare** route\n * (selected by its compiled plan), so a sync handler produces its result with zero promise allocations;\n * routes with validation/hooks keep the full async {@link runLifecycle}, unchanged.\n */\n private routeAndRun;\n private fetchMount;\n /** Run a route that has already been matched by the runtime or Nifra's portable router. */\n private runMatched;\n /** Supply request-specific deadline state to the route's precompiled execution plan. */\n private runMatchedLanes;\n /** @internal Symbol-keyed install seam for the `effectLedger()` plugin. Off the public typed surface. */\n [INSTALL_EFFECT_LEDGER](runtime: EffectLedgerRuntime): void;\n /** The narrowest bare route: a syntactic `() => ...` handler cannot observe the context argument, so\n * successful requests can skip allocating `RequestContext`. Errors still allocate one for logging. */\n private runContextlessBare;\n private contextlessBareError;\n /**\n * The synchronous fast path selected by a route's execution plan: apply static decorations, call the\n * handler, render the result - **no `await`** unless the handler itself returns a promise. It mirrors\n * the bare slice of {@link runLifecycle} (which a bare route would otherwise no-op through) and shares\n * {@link logRequestError}; a bare route has no `onError` hooks, so error handling is fully synchronous\n * (a thrown `Response` is control flow; anything else is a logged flat 500). This is where nifra skips\n * the per-request async-frame tax - the same win codegen routers get, but without `eval`.\n */\n private runBare;\n /** Bare-route error rendering - identical to {@link runLifecycle}'s catch minus the (absent) onError\n * loop: a thrown `Response` is returned as deliberate control flow; anything else is logged + 500. */\n /**\n * Build a route's fused Web renderer. Composition happens once at\n * registration; the returned closure is what every request to the route runs. Behavior is\n * byte-identical to the generic `runBare`/`runContextlessBare` + `toResponse` pair - same\n * decoration order, same error routing (thrown `Response` = control flow; anything else logs and\n * 500s), same respond semantics (the lifecycle parity suite pins it).\n */\n private buildFusedWeb;\n /** Compile the eligible body-only route's parser → validator → handler continuation once. The\n * bounded parser remains shared with the generic lane; only the route-invariant entry lookups and\n * lifecycle dispatch disappear from the common synchronous-validator/synchronous-handler case. */\n private buildFusedBodyRunner;\n /** Web adapter wrapper for the shared body runner. Node passes its native finalizer directly through\n * the execution plan, while Web needs the live context to preserve lazy `c.set` controls. */\n private buildFusedBodyWeb;\n /** The fused Web lane for a route whose only lifecycle step is a query schema: parse + validate +\n * handler + respond in one closure, no lifecycle promise when the validator and handler are sync.\n * Eligibility is decided at registration (see `fusedQuery` in {@link register}); the semantics here\n * are exactly `runQueryOnly`'s for that eligible shape - invalid input returns\n * `validationError(issues)` (recovery hooks disqualify the route from this lane), a thrown\n * `Response` passes through, anything else logs and returns a flat 500, and an async validator\n * falls to a then-chain with the same steps. */\n private buildFusedQueryWeb;\n private bareError;\n private runWithAround;\n private runAround;\n private runBodyOnly;\n /** Shared bounded body framing/parser. Both body lanes use the same trust-boundary checks; only\n * the validation + handler continuation differs. */\n private readBodyInput;\n /** Validate + run the handler for the bodyOnly path - shared by the inline fast path and the\n * streaming fallback. A method (not per-request closures) so the hot path allocates nothing\n * beyond the one `.then` continuation. */\n private finishBodyOnly;\n private executeHandler;\n private handleValidationErrorRecovery;\n private applyBodyValidation;\n private runQueryOnly;\n /** Validate-result → set `ctx.query` → run handler. A method (not a per-request closure), the\n * query analogue of {@link applyBodyValidation}. */\n private applyQueryValidation;\n /**\n * Thread the response through each global `onResponse` hook. Stays SYNCHRONOUS until a hook\n * actually returns a Promise - an `async` version forced a promise + microtask on EVERY response\n * of any app with an onResponse hook (cors/securityHeaders/etag/timing all use onResponse), the\n * same ~13%/req tax the onRequest walk was de-async'd to avoid. The first async hook hands the\n * rest to {@link continueOnResponse}.\n */\n private applyOnResponse;\n private applyOnResponseAndFinalize;\n private completeResponseFinalization;\n private failResponseFinalization;\n /** Notify terminal observers in order while isolating both sync and async failures. */\n private notifyResponseFinalized;\n /** Async tail of {@link applyOnResponse}: runs the remaining hooks once one has gone async. */\n private continueOnResponse;\n /**\n * Bound the response time. On timeout we abort `ctx.signal` (so cancellation-aware\n * handlers can bail) and return 503; the in-flight work keeps running but its\n * result is discarded - JS can't forcibly cancel a promise.\n */\n private withTimeout;\n /**\n * The post-match lifecycle: validate → derive → beforeHandle → handler → afterHandle, with onError.\n * Generic over the render: a success value goes through `finalize(result, set)` (a Web `Response`, or\n * node-direct primitives); an early/error `Response` (validation, thrown, 500) through `wrapResponse`.\n */\n /** Synchronous until a validator, lifecycle hook, handler, or contract check actually returns a Promise. */\n private runLifecycle;\n private runLifecycleAfterHeadersResult;\n private runLifecycleAfterHeaders;\n /** Registration-specialized query lifecycle: query validation (including recovery) → hooks. */\n private runLifecycleQuery;\n /** Registration-specialized body lifecycle: bounded body validation (including recovery) → hooks. */\n private runLifecycleBody;\n /** Registration-specialized body + query lifecycle: bounded body validation → query validation → hooks. */\n private runLifecycleBodyQuery;\n /** Registration-specialized no-body lifecycle: query validation (if present) → derives/hooks. */\n private runQueryAndLifecycle;\n private runQueryAndLifecycleResult;\n private runLifecycleAfterParamsResult;\n private runLifecycleAfterParams;\n private runLifecycleAfterParamsSettled;\n private runLifecycleAfterBody;\n private runLifecycleAfterQueryResult;\n private runLifecycleAfterQuery;\n private runLifecycleHooks;\n /** Registration-specialized derive → before → handler lifecycle. */\n private runLifecycleDeriveBefore;\n /** Finalize the specialized lane without rechecking its registration-proven invariants. */\n private finishSimpleLifecycleResult;\n private continueLifecycleAfterDerive;\n private runLifecycleHooksAsync;\n private continueLifecycleAfterBefore;\n private runLifecycleHandlerAsync;\n private finishLifecycleResult;\n private continueLifecycleAfterHandle;\n private finishLifecycleContract;\n private finishContractOutcome;\n private handleLifecycleError;\n /** Log an unhandled request error to the (redacting) logger - shared by {@link runLifecycle} and the\n * bare fast path ({@link bareError}) so both record the same fields. Never throws; never leaks. */\n private logRequestError;\n private readAndValidateBody;\n /** Apply validation and its recovery hook on the generic lifecycle lane. Recovery is completed\n * before derives/beforeHandle run, matching the body-only and query-only execution lanes. */\n private applyLifecycleValidation;\n private finishLifecycleValidationRecovery;\n /**\n * Read + parse the JSON body, capped at `maxBodyBytes` and screened by the server's\n * `protoPoisoning` policy. Rejects a `Content-Length` over the cap *before* buffering,\n * re-checks what was actually delivered after the read, and aborts a chunked or\n * length-less body mid-stream once the running byte count exceeds the cap - so a lying\n * or absent length can't force us to buffer an oversized payload.\n */\n private readBoundedJson;\n /** Adapt one route's compiled execution plan to Bun's already-matched request shape. Route\n * semantics remain in the plan; this closure only supplies native params and deadline fallback. */\n private compileBunNativeHandler;\n /** Compile portable route registrations into Bun's native route table. Apps with request-rewrite\n * hooks or WebSockets retain the single portable dispatcher because those features must run before\n * route selection/upgrade. Named wildcards also stay on the fallback until Bun exposes their raw\n * capture semantics; static and `:param` routes take the native lane. */\n private buildBunNativeRoutes;\n /**\n * Start a `Bun.serve` instance bound to `port` (use `0` for an ephemeral port).\n *\n * `reusePort` sets `SO_REUSEPORT` so **multiple processes can bind the same port** and the kernel\n * load-balances connections across them - the standard way to use every core (Bun is\n * single-threaded per process). Spawn one process per core, each calling\n * `app.listen(PORT, { reusePort: true })`; see `examples/cluster.ts`. Every process must opt in,\n * and all of them must be the same app. Linux balances ~evenly; macOS accepts the flag but may\n * favor one socket (fine for dev, measure on Linux for production numbers).\n *\n * `hostname` is the bind address, defaulting to Bun's `0.0.0.0` (every interface). Pass\n * `\"127.0.0.1\"` to bind loopback only - an admin surface, a sidecar, or anything that must not be\n * reachable off the box. Omitting it when you meant to restrict is a real exposure, so it is a\n * first-class option rather than something a caller has to drop down to `Bun.serve` for.\n *\n * `idleTimeoutSec` is how long Bun tolerates a connection with no bytes moving before it closes\n * the socket. Bun's default is **10 seconds**, and a request whose handler is still working sends\n * nothing - so any endpoint slower than 10s (a render, an export, a long upstream call) has its\n * connection cut mid-flight regardless of `requestTimeoutMs`. Apps with such endpoints must raise\n * this above their slowest expected response, which is why it is a first-class option and not a\n * reason to drop down to `Bun.serve`. `0` disables the timeout entirely; max 255.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n }): RunningServer;\n /**\n * Gracefully stop: wait for in-flight requests to finish (up to `drainMs`), then\n * issue a single terminal stop - graceful if everything drained, forced if\n * stragglers remain. Safe to call when not listening.\n *\n * The Bun semantics: poll `pendingRequests` (awaiting\n * `stop()`'s promise drops in-flight requests), and decide graceful-vs-forced in\n * ONE call (Bun can't escalate an already-graceful `stop()` to a forced close).\n * New connections may be accepted during the drain window; in a real deploy the\n * load balancer has already stopped routing here, and `drainMs` bounds it.\n */\n stop({ drainMs }?: {\n drainMs?: number;\n }): Promise<void>;\n private installSignalHandlers;\n}",
|
|
10748
|
+
"signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext> {\n /**\n * Which copy of `@nifrajs/core` declared this type. Two copies in one build (a linked sibling repo,\n * a hoisting split) produce two unrelated `Server` types whose assignment error is a wall of\n * missing internals; the brand puts the feature version in the type itself, so `typeof app` on\n * hover - and `NifraFeatureVersion` in an assertion - says which core an app is talking to.\n * `nifra doctor` is the diagnosis that names both install paths.\n *\n * `declare` = type-only: no field is emitted, nothing is allocated per server.\n */\n readonly __nifraCoreVersion: NifraFeatureVersion;\n private readonly catalog;\n /** WebSocket routes, matched separately at upgrade time (a GET + `Upgrade: websocket`). */\n private readonly wsRouter;\n private wsRouteCount;\n /** In-process pub/sub backing `ws.subscribe(topic)` + `app.publish(topic, data)` (single-instance).\n * Created by the first `app.ws()` via the `@nifrajs/core/ws` runtime - `undefined` until then, so a\n * no-WebSocket app never constructs (or bundles) it. */\n private topics;\n private readonly maxBodyBytes;\n private readonly protoPoisoning;\n /** `trustBodyFraming`: mark every `app.fetch` request as runtime-framed (see ServerOptions). */\n private readonly trustBodyFraming;\n private readonly wsMaxPayloadBytes;\n private readonly requestTimeoutMs;\n /** Installed by the `responseContract()` plugin; `undefined` = not installed, which is the default\n * and the state in which a declared `response` schema stays a compile-time contract only. */\n private responseContractRuntime;\n /** Opt-in caller-IP trust declaration; `undefined` = socket peer only, no forwarded header believed. */\n private readonly clientIpTrust;\n private readonly acceptInboundDeadlines;\n private readonly maxInboundDeadlineMs;\n private readonly deadlineAdmissionOptions;\n private readonly gracefulSignals;\n private readonly stopHooks;\n private readonly fetchMounts;\n /** Capacity-admission gate; `undefined` = off (the request path pays nothing). */\n private readonly capacityGate;\n private readonly onCapabilityUse;\n private readonly capabilityInterceptors;\n private readonly capabilityObservers;\n /** The installed effect-ledger runtime (owns the sink + per-route resolution + settle), or\n * `undefined` when the effect-ledger plugin is not installed. */\n private effectLedgerRuntime;\n /** The installed idempotency runtime (owns the app-wide default store + the dedupe lane), or\n * `undefined` when the idempotency plugin is not installed. */\n private idempotencyRuntime;\n /** Installed opt-in runtime for `.tool()`/`.resource()`/`.prompt()`; `undefined` until `.use(mcp())`. */\n private mcpRuntime;\n /** Installed Node-direct renderer for direct `resolveNode()` callers; `undefined` until `.use(nodeDirect())`. */\n private nodeOutcomeRuntime;\n /** Installed streaming runtime for `.sse()` routes; `undefined` until `.use(streaming())`. */\n private sseRuntime;\n /** Installed WebSocket runtime for `.ws()` routes; `undefined` until `.use(websocket())`. */\n private wsRuntime;\n private readonly logger;\n /** How much of an unhandled error {@link logRequestError} records. See `ServerOptions.errorLogDetail`. */\n private readonly errorLogDetail;\n /** App-wide validation-error fallback; a route's own `schema.onValidationError` takes precedence. */\n private readonly defaultOnValidationError?;\n private bunServer;\n private sealed;\n private readonly derives;\n private readonly decorations;\n private readonly beforeHandleHooks;\n private readonly afterHandleHooks;\n private readonly onErrorHooks;\n private readonly aroundHooks;\n private readonly onRequestHooks;\n private readonly onNodeRequestHooks;\n /** Registration-time eligibility for the Node request twin lane. */\n private nodeRequestHooksComplete;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /**\n * True once a bundle registers a RAW `onNodeResponse` twin - one handed the outcome's header\n * record itself rather than the case-normalizing view. Their names are contractually the wire\n * spelling, but registration cannot PROVE it, so such an app forgoes the all-lowercase mark and\n * every reader re-derives the answer, exactly as before the mark existed.\n */\n private hasRawNodeResponseHook;\n private readonly onResponseFinalizedHooks;\n /**\n * Statically declared response headers, merged and prebuilt at registration; `undefined` (the\n * default) leaves every render path in its original shape. These are NOT response hooks - they are\n * folded into response construction - so declaring them keeps the fused native lanes an\n * `onResponse` hook would have disabled.\n */\n private staticResponseHeaders;\n /** `wrapResponse` for the Web lanes: identity until static headers exist to fold into the\n * framework's own error/404/timeout renders, which are built outside the header init. */\n private wrapWebResponse;\n private webResponseTimeout;\n /** Body/raw response hooks need a framework-payload marker; keep that decision per app. */\n private responseBodyTag;\n private readonly responseBodyOwners;\n private readonly finalizeResponse;\n private readonly responseRequests;\n /** Original source → request observed by generic request hooks, including in-place mutations. */\n private readonly responseSources;\n /** Memoized NodeRequestContext per plain-`Request` source - see {@link nodeRequestContextOf}. */\n private readonly nodeContexts;\n /** Names of plugins/middleware already applied via `use` - for idempotent dedupe. */\n private readonly appliedPlugins;\n /** Order-scoped evidence captured by routes registered after an assured plugin. */\n private readonly activeAssurance;\n /** App-wide evidence from global hooks; applies retroactively to every route. */\n private readonly globalAssurance;\n /** App-declared MCP resources / prompts (via {@link resource} / {@link prompt}), read by `nifra mcp`. */\n private readonly mcpResourceList;\n private readonly mcpPromptList;\n constructor(options?: ServerOptions);\n private assertConfigurable;\n /** Register a callback awaited after graceful drain and server stop. Hung callbacks are bounded. */\n onStop(fn: StopHook): this;\n /**\n * Mount a legacy fetch handler under a literal path prefix. Mounted handlers sit behind typed\n * routes, so routes can move one at a time while the remaining legacy surface stays live.\n * Mounted responses are outside Nifra's typed route and response-contract checks.\n */\n mountFetch(path: string, handler: FetchHandler<EnvOf<Ctx>>, options?: MountFetchOptions): this;\n /**\n * Add a per-request, computed context extension. Order-scoped: it is snapshotted into every route\n * declared *after* this call, and reaches none declared before. One added after the last route\n * (e.g. on the app returned by a route-registering factory) covers nothing - see\n * {@link ServerOptions.unusedScopedHooks}.\n */\n derive<D extends object>(fn: (context: Context & Ctx) => MaybePromise<D>): Server<R, Ctx & D>;\n /**\n * Add a static context value. Order-scoped: captured by every route declared *after* this call, and\n * by none before; one added after the last route reaches nothing\n * (see {@link ServerOptions.unusedScopedHooks}).\n */\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>>;\n /**\n * Run before routing on the raw request. Return a `Response` to short-circuit, or a replacement\n * `Request` to continue routing with a rewritten method/URL/headers. Global.\n */\n onRequest(fn: (req: Request, platform?: Platform<EnvOf<Ctx>>) => MaybePromise<OnRequestResult>): this;\n /**\n * Run after validation, before the handler; a non-`undefined` return short-circuits. Order-scoped:\n * it is snapshotted into every route declared *after* this call and covers none declared before, so\n * one added after the last route reaches nothing (see {@link ServerOptions.unusedScopedHooks}).\n */\n beforeHandle(fn: (context: Context & Ctx) => MaybePromise<unknown>): this;\n /**\n * Wrap the matched route lifecycle for subsequent routes. This is intentionally generic over the\n * route output, so wrappers like async context storage do not force Node's direct JSON path through\n * a Web `Response`. The first registered wrapper is outermost.\n *\n * Order-scoped: captured by every route declared *after* this call, none before; one added after the\n * last route reaches nothing (see {@link ServerOptions.unusedScopedHooks}).\n */\n around(fn: <T>(context: Context & Ctx, next: () => MaybePromise<T>) => MaybePromise<T>): this;\n /**\n * Asynchronously admit each subsequent `executeCapability()` call before its owned effect runs.\n * Interceptors receive token-only metadata plus an abort signal and must call `next()` exactly once\n * to admit. Returning without `next()`, timing out, aborting, or throwing fails the effect closed.\n */\n aroundCapability(interceptor: CapabilityInterceptor, options?: AroundCapabilityOptions): this;\n /** Observe token-only admission/execution lifecycle events for subsequent capability routes. */\n observeCapability(observer: EffectLifecycleObserver): this;\n /** Transform the handler's result before it is serialized. Order-scoped: captured by routes declared\n * *after* this call, none before; one added after the last route reaches nothing (see\n * {@link ServerOptions.unusedScopedHooks}). */\n afterHandle(fn: (result: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Handle a thrown error; a non-`undefined` return becomes the response (else the default 500).\n * Order-scoped: captured by routes declared *after* this call, none before; one added after the last\n * route reaches nothing (see {@link ServerOptions.unusedScopedHooks}). */\n onError(fn: (error: unknown, context: Context & Ctx) => MaybePromise<unknown>): this;\n /** Transform every outgoing response - success, error, 404, 405, short-circuit. Global. */\n onResponse(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Declare response headers with NO per-request decision behind them - and pay nothing for them on\n * the request path.\n *\n * These are not a hook. Because the values are known at wire-up, they are folded into response\n * construction (one prebuilt init for JSON renders, one record merge where the request set its own\n * headers), so an app whose only response middleware is static keeps every fused and native lane -\n * `onResponse`/`onResponseHeaders` disable Bun's fused native routes and, for a full `onResponse`,\n * the Node direct writer. They apply to EVERY response, exactly as a response hook would: success,\n * error, 404/405, timeout, and short-circuit alike.\n *\n * app.responseHeaders({ \"x-frame-options\": \"DENY\", \"referrer-policy\": \"no-referrer\" })\n *\n * They are DEFAULTS: a value the request itself produced (`c.set.headers`, or a response hook)\n * wins, whatever casing it used. Names are lowercased once here; a non-string value, an invalid\n * name, `__proto__`, or a name the render owns (`content-type`, `content-length`,\n * `transfer-encoding`, `set-cookie`) throws a `TypeError` at wire-up.\n *\n * ORDERING: declarations made before any response hook fold into one static record. One made AFTER\n * a response hook cannot - the hook may already have written that name and must keep winning - so\n * it registers as an ordinary `onResponseHeaders` hook instead, preserving registration order at\n * the cost of the static tier's speed. Declare static headers first.\n */\n responseHeaders(record: Readonly<Record<string, string>>): this;\n /** Wire an already-validated lowercase record into the static tier, or - once a dynamic response\n * hook owns part of the header state - into a hook that runs in the right order. */\n private addStaticResponseHeaders;\n private enableResponseBodyTagging;\n /**\n * Register a response transform for raw/streamed Responses. Framework-serialized payloads stay on\n * the body tier; this hook is only entered for untagged Responses (streams, proxied fetches, and\n * framework-generated error responses). A no-op native twin keeps buffered JSON on the direct lane.\n */\n onResponseRaw(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n /**\n * Register a PORTABLE header-only response hook - one implementation, fast on every runtime.\n *\n * The hook receives a mutable case-insensitive header view, a minimal request view, and the\n * status. On the Web serving paths it runs inside the normal `onResponse` walk against the\n * response's own `Headers` (mutating in place - no clone). On Node it self-pairs as a native\n * response hook against the outcome's plain header record, so registering one NEVER forces the\n * Node adapter off its direct socket writer the way a full `onResponse(res: Response)` hook does.\n * Prefer this over `onResponse` whenever the middleware only reads/writes headers.\n */\n onResponseHeaders(fn: ResponseHeadersHook): this;\n /**\n * Register a PORTABLE post-serialization body hook - the payload tier. The hook receives the\n * FINAL framework-serialized bytes (plus the mutable header view and status) and may return\n * replacement bytes; `undefined` keeps the body. On the Node direct writer the bytes come\n * straight off the outcome record; on the Web serving paths they ride the framework-built\n * Response as a tag, so no body stream is ever drained on any runtime. A handler-returned raw\n * `Response` (proxied fetch, SSE, streamed SSR) is skipped by contract - transforming those is\n * what the full `onResponse` hook is for.\n */\n onResponseBody(fn: ResponseBodyHook): this;\n /** Observe the terminal response after all transformations. Observers are ordered and fail-open. */\n onResponseFinalized(fn: (outcome: ResponseFinalization, req: Request) => MaybePromise<void>): this;\n /**\n * Apply a type-**identity** plugin ({@link IdentityPlugin}, from {@link defineIdentityPlugin}) - it\n * registers routes/hooks but doesn't change the types, so this returns `this` with the route registry\n * and context fully intact. This overload exists specifically so a *named* identity plugin (e.g.\n * `@nifrajs/better-auth`) threads the registry: its `& { pluginName }` intersection would otherwise\n * defeat the generic inference of the transforming overload below and collapse the result to `any`.\n */\n use(plugin: IdentityPlugin): this;\n /**\n * Apply a **context** plugin ({@link ContextPlugin}, from {@link defineContextPlugin}) - it adds `D`\n * to the handler context and changes nothing else, so the route registry `R` and the existing context\n * `Ctx` thread through untouched. Like the identity overload above, this exists because the generic\n * `(app: this) => Out` overload below cannot infer through a *generic* plugin signature: it erases the\n * plugin's own type parameters to their constraints, which silently widens `R` to `Registry`.\n */\n use<D extends object>(plugin: ContextPlugin<D>): Server<R, Ctx & D>;\n /**\n * Apply a **plugin function** - `(app) => app`, typically built with {@link definePlugin}. It's\n * called with `this` and its result is returned, so an inline plugin's `derive`/`decorate` thread\n * the added context to handlers defined after `use` (the overload is generic over the concrete\n * `this`). A named plugin already applied is skipped (idempotent dedupe).\n *\n * If the plugin's return type is unpinned - `Server<any, any>`, as a hand-rolled `(app) => app` or a\n * `NifraPlugin<AnyServer, AnyServer>` infers (e.g. an auth plugin whose own types collapsed) - this\n * returns the non-callable {@link PluginTypeCollapsed} instead of silently widening the whole typed\n * client to `any`. `.get()`/`.post()` then fail right here rather than surfacing as `any` hundreds of\n * lines away. Fix at the plugin: build it with {@link defineIdentityPlugin}/{@link defineContextPlugin},\n * or pin its input server type. This mirrors the guard {@link definePlugin} already applies.\n */\n use<Out extends AnyServer>(plugin: (app: this) => Out): [ServerTypeUnpinned<Out>] extends [true] ? PluginTypeCollapsed : Out;\n /**\n * Apply a {@link Middleware} bundle - wire each hook it provides to its lifecycle point. Returns\n * `this` (no context-type merging); call it before the routes its `beforeHandle`/`afterHandle`\n * should cover (those are order-scoped; `onRequest`/`onResponse` are global). A bundle applied after\n * the last route reaches nothing - {@link ServerOptions.unusedScopedHooks} logs that at seal. A named\n * bundle already applied is skipped (idempotent).\n */\n use(mw: Middleware): this;\n get<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n get<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Register a **typed SSE route** - a GET endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. The handler receives the validated context plus a\n * {@link TypedSSEStream}: `stream.send(event)` is compile-time-checked against the schema and\n * JSON-serialized into the SSE `data:` field. The typed client sees the marker and grows a\n * `.subscribe(onEvent)` for the route with the same payload type - end-to-end typed streaming.\n *\n * import { streaming } from \"@nifrajs/core/sse\" // .use(streaming()) enables .sse()\n * const app = server().use(streaming()).sse(\"/feed\", { sse: t.object({ id: t.integer(), title: t.string() }) },\n * async (c, stream) => {\n * stream.send({ id: 1, title: \"hello\" }) // typed\n * await waitForDisconnect(stream.signal)\n * },\n * { keepAlive: 15_000 })\n *\n * // client: const off = api.feed.subscribe((post) => console.log(post.title))\n *\n * `init` passes through to the underlying {@link sse} helper (`keepAlive`, extra headers). The\n * connection closes when the handler resolves, `stream.close()` runs, or the client disconnects\n * (`stream.signal`). Query/body schemas validate exactly as on any other route.\n */\n sse<Path extends string, S extends RouteSchema & {\n sse: StandardSchemaV1;\n }>(path: Path, schema: S, run: (context: Context<Path, S> & Ctx, stream: TypedSSEStream<InferOutput<S[\"sse\"]>>) => void | Promise<void>, init?: SSEInit): Server<AddRoute<R, \"GET\", Path, RouteInfoFor<Path, S, Response>>, Ctx>;\n post<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n post<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"POST\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n put<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n put<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PUT\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n patch<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n patch<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"PATCH\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n delete<Path extends string, S extends RouteSchema, H extends Handler<Path, S, Ctx>>(path: Path, schema: S, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, S, OutputOf<H>>>, Ctx>;\n delete<Path extends string, H extends Handler<Path, RouteSchema, Ctx>>(path: Path, handler: H): Server<AddRoute<R, \"DELETE\", Path, RouteInfoFor<Path, Record<never, never>, OutputOf<H>>>, Ctx>;\n /**\n * Declare an **MCP tool** an agent can call (via `nifra mcp`, or a mounted MCP endpoint): a typed\n * `POST /_nifra/tool/<name>` route whose `input`/`output` schemas contract the call and surface in\n * `tools/list`. Requires `.use(mcp())` - without it, `.tool()` is a registration error, so an\n * ordinary HTTP app never bundles the MCP wiring. Siblings: {@link resource}, {@link prompt}.\n *\n * import { mcp } from \"@nifrajs/core/mcp\"\n * const app = server().use(mcp()).tool(\n * \"search\",\n * { description: \"Search posts\", input: t.object({ q: t.string() }) },\n * ({ q }) => findPosts(q),\n * )\n */\n tool<Name extends string, S extends {\n description: string;\n input: StandardSchemaV1;\n output?: StandardSchemaV1;\n annotations?: ToolAnnotations;\n }, H extends (input: InferOutput<S[\"input\"]>, ctx: Context & Ctx) => MaybePromise<S[\"output\"] extends StandardSchemaV1 ? InferOutput<S[\"output\"]> : unknown>>(name: Name, config: S, handler: H): Server<AddRoute<R, \"POST\", `/_nifra/tool/${Name}`, RouteInfoFor<`/_nifra/tool/${Name}`, S[\"output\"] extends StandardSchemaV1 ? {\n body: S[\"input\"];\n response: S[\"output\"];\n } : {\n body: S[\"input\"];\n }, OutputOf<H>>>, Ctx>;\n /**\n * Declare an MCP **resource** - read-only data an agent can fetch through `nifra mcp` (app config, a\n * generated document, …). `read` runs in the app process, so capture whatever app state it needs in the\n * closure. `uri` is the MCP resource identifier (e.g. `\"myapp://config\"`). The sibling of {@link tool}\n * for the resource half of MCP.\n */\n resource(uri: string, config: {\n readonly name: string;\n readonly description?: string;\n readonly mimeType?: string;\n }, read: McpResourceDescriptor[\"read\"]): Server<R, Ctx>;\n /**\n * Declare an MCP **prompt** - a reusable prompt template an agent can fetch through `nifra mcp`.\n * `handler` receives the caller's arguments and returns the rendered messages.\n */\n prompt(name: string, config: {\n readonly description: string;\n readonly arguments?: readonly PromptArgument[];\n }, handler: McpPromptDescriptor[\"handler\"]): Server<R, Ctx>;\n /** The MCP resources declared via {@link resource} - enumerated by `nifra mcp`. */\n mcpResources(): readonly McpResourceDescriptor[];\n /** The MCP prompts declared via {@link prompt} - enumerated by `nifra mcp`. */\n mcpPrompts(): readonly McpPromptDescriptor[];\n /**\n * Register a **WebSocket** route. The connection upgrades on a `GET` to `path` carrying\n * `Upgrade: websocket`; the optional `handler.upgrade(c)` runs in the request context first and may\n * reject (return a `Response`) or seed per-connection `ws.data`. WebSockets are served by the\n * adapter (`listen()`, `@nifrajs/node`, `@nifrajs/deno`, `toFetchHandler`) - not by bare `app.fetch`, which\n * has no socket (a WS path through `app.fetch` is a normal HTTP response).\n *\n * The route also enters the type-level registry (under the pseudo-method `\"WS\"`), so the typed\n * client grows a `.ws()` handle for it: `messageSchema` types what the client may `send`,\n * `sendSchema` types the frames it receives. Passing explicit type arguments (`ws<MyData>(…)`)\n * defeats path-literal inference and skips the registry entry - the route still serves, it is just\n * invisible to `client<App>`; prefer typing `data` via `upgrade()`'s return.\n *\n * app.ws(\"/chat\", { open: (ws) => ws.send(\"hi\"), message: (ws, data) => ws.send(data) })\n */\n ws<Data = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined, Path extends string = string>(path: Path, handler: WebSocketHandler<Data, EnvOf<Ctx>, Schema, Send>): string extends Path ? Server<R, Ctx> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx>;\n /**\n * Broadcast `data` to every WebSocket connection subscribed to `topic` (via `ws.subscribe(topic)`).\n * In-process and **single-instance** (see {@link TopicRegistry}) - a multi-instance deploy must bridge\n * an external fan-out (Redis, a Durable Object) to this. A no-op when nobody is subscribed.\n */\n publish(topic: string, data: string | ArrayBufferView | ArrayBuffer): void;\n private route;\n /**\n * Low-level route registration shared by the inline builder and `implement()`.\n * Captures the server's current `derive`/`decorate` chain into the route - this\n * is the \"compiled\", order-scoped per-route chain.\n */\n register(method: Method, path: string, schema: RouteSchema | undefined, handler: (context: never) => unknown): void;\n /** Register a contract/group route batch atomically. Every route captures the same current chain it\n * would capture through {@link register}; no route becomes visible unless the full batch validates. */\n registerBatch(routes: readonly {\n readonly method: Method;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n private prepareRoute;\n /** The idempotency lane's bridge back into the normal matched lanes, resolved to a concrete Response\n * (the lane buffers the body, then replays it through the route's real validation + handler). */\n private idempotencyRunLanes;\n /** @internal Symbol-keyed install seam for the `responseContract()` plugin. Off the public typed surface. */\n [INSTALL_RESPONSE_CONTRACT](runtime: ResponseContractRuntime): void;\n /** @internal Symbol-keyed install seam for the `idempotency()` plugin. Off the public typed surface. */\n [INSTALL_IDEMPOTENCY](runtime: IdempotencyRuntime): void;\n /** @internal Symbol-keyed install seam for the `mcp()` plugin. Off the public typed surface. */\n [INSTALL_MCP](runtime: McpRuntime): void;\n /** @internal Symbol-keyed install seam for the `nodeDirect()` plugin. Off the public typed surface. */\n [INSTALL_NODE_DIRECT](runtime: NodeOutcomeRuntime): void;\n /** @internal Symbol-keyed install seam for the `streaming()` plugin. Off the public typed surface. */\n [INSTALL_SSE](runtime: SseRuntime): void;\n /** @internal Symbol-keyed install seam for the `websocket()` plugin. Off the public typed surface. */\n [INSTALL_WS](runtime: WsRuntime): void;\n /**\n * Merge another server's routes into this one - the composition escape hatch for large apps.\n *\n * WHY: the fluent chain accumulates one type-alias level per route, and TypeScript resolves\n * that stack in one recursion - a single chain hits TS2589 at ~95 routes. Groups keep every\n * chain short: build each domain (`listings`, `agents`, …) as its own `server()` (its registry\n * resolves independently), then `app.merge(listings).merge(agents)` - each merge adds ONE level\n * regardless of group size. 300+ routes stay fully typed (see many-routes.test-d.ts). The\n * other escape hatch is contract-first `implement()`, whose registry is a single object type.\n *\n * Semantics: merged routes keep the chains captured where they were DEFINED - the group's\n * `derive`/`decorate`/`beforeHandle`/`afterHandle`/`onError`/`around` apply to its routes\n * exactly as they did standalone, so a group wires its own plugins. The same locality rule\n * covers the group's `onRequest` hooks: they run only for requests that route to the GROUP's\n * routes (a `bodyLimit()` mounted on an uploads group must not start gating the whole app\n * because the app composed it in), and the group's global assurance follows its hooks onto\n * exactly those routes. A group with hooks but NO routes is a middleware bundle - its hooks\n * can only mean app-wide intent, so they are appended globally, unchanged. Response-side hooks\n * (`onResponse`/`onResponseFinalized`) are appended to this server's. This server's\n * route-scoped chains do NOT retroactively wrap merged routes (order-scoped, like routes\n * registered before a `derive`). Fail closed: a path+method collision throws\n * `RouteConfigError` at merge time, and a group with WebSocket routes is refused (register\n * those on the parent).\n */\n merge<R2 extends Registry, Ctx2>(other: Server<R2, Ctx2>): Server<R & R2, Ctx>;\n /** A fused renderer closes over runtime services to keep its seven-argument JSC fast path. Merging\n * rebinds that closure once to the executing server; generic plans already receive the runtime. */\n private bindFusedRuntime;\n /**\n * Enumerate the registered routes (method, path, input schemas), in registration\n * order. Powers `toOpenAPI` and other introspection; the router trie itself no\n * longer holds the original patterns.\n */\n routes(): ReadonlyArray<RouteDescriptor>;\n /**\n * Resolve a `Request` to a `Response` - the whole lifecycle, testable without a port. The\n * optional `platform` carries edge inputs (`env`, `waitUntil`); edge adapters pass it, and\n * Bun/Node/Deno omit it (then `c.env` is `undefined` and `c.waitUntil` runs fire-and-forget).\n */\n fetch(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<Response>;\n private fetchSource;\n private fetchSourceInner;\n /** Web response path when Bun already matched the route. The lifecycle and response hooks remain\n * exactly the same as {@link fetchSource}; only portable URL scanning + trie lookup are skipped. */\n private fetchMatched;\n private fetchMatchedInner;\n /**\n * Run `produce` under the capacity gate: admit → run → release exactly once when the response is\n * produced (or the run throws). Only reached when {@link capacityGate} is set, so the off path pays\n * nothing. The slot is held for the duration of handler execution, not the streaming of the body -\n * capacity here bounds concurrent *work*, matching how in-flight is counted.\n */\n private admitGated;\n private runAdmitted;\n /**\n * Like {@link fetch}, but renders a plain-data result **without** building a Web `Response` - the\n * `@nifrajs/node` adapter serializes the returned primitives straight to the socket, skipping the undici\n * `Response` build + body drain (the bulk of the Node bridge cost, measured ≈4µs/req). A handler that\n * returns a `Response`, an error/short-circuit, or a response hook that replaces/consumes the buffered\n * body stays on the full Web path; an in-place response hook can still use the direct writer. Same\n * lifecycle as {@link fetch} (body cap, validation, hooks all run); only the final render differs.\n */\n resolveNode(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<NodeServeOutcome>;\n resolveNodeSource(source: RequestSource, platform?: Platform<EnvOf<Ctx>>, suppliedRuntime?: NodeOutcomeRuntime): MaybePromise<NodeServeOutcome>;\n /** Run generic Web response middleware while retaining direct writes for untouched buffered bodies. */\n private finishNodeWebResponse;\n /** True only when every transforming Web response hook has a header-only Node equivalent. */\n private canUseNodeResponseHooks;\n /** Apply paired native hooks to data outcomes; preserve the complete Web hook pipeline for Response outcomes. */\n private finishNodeResponse;\n private withNodeResponseHeaders;\n /** Synchronous until a native response hook actually returns a Promise. */\n private applyNodeResponseHooks;\n private continueNodeResponseHooks;\n /**\n * Resolve a WebSocket upgrade - the seam every serving adapter uses. Returns `pass` (not a WS\n * upgrade for a registered route → handle as normal HTTP), `reject` (a WS route matched but\n * `upgrade()` rejected, or the path was malformed → return `response`), or `upgrade` (perform the\n * runtime upgrade, then dispatch the native socket's events to `handler`, seeding `ws.data` with\n * `data`). Runs the route's `upgrade(c)` guard in a real request context. Synchronous unless\n * `upgrade()` is async; a throw rejects with a flat 500 (no detail leaked).\n */\n resolveWebSocketUpgrade(req: Request, platform?: Platform<EnvOf<Ctx>>): MaybePromise<WebSocketUpgradeOutcome>;\n /** Bun `fetch` when WS routes exist: try a WS upgrade first, else run the normal HTTP lifecycle.\n * `undefined` ⇒ Bun owns the upgraded socket; a `Response` ⇒ a normal reply or a rejected upgrade.\n * (The socket dispatch itself lives in `ws-bun.ts`, loaded via `@nifrajs/core/ws`.) */\n private bunFetchWithWebSocket;\n /**\n * The shared lifecycle, generic over how the final value is rendered: `finalize` turns a handler's\n * result + `set` into the output `T` (`toResponse` → a Web `Response`; `toNodeOutcome` → node-direct\n * primitives), `wrapResponse` lifts an early/error `Response` into that same `T`, and `onTimeout`\n * produces the 503. The Web `fetch` and `resolveNode` are thin callers over this one routing +\n * context + lifecycle implementation - no duplication across the trust boundary.\n */\n /** Apply the `clientIp` trust declaration to the adapter's raw socket peer, returning a platform\n * whose `clientIp` is the derived caller. Only called when a trust declaration is configured. */\n private deriveClientIp;\n private dispatch;\n /** Node-native request hook walk. A header-only hook can inspect the lazy source without forcing a\n * Web `Request`; arbitrary request rewrites and full Web hooks use {@link runWithOnRequest}. */\n private runWithNodeRequest;\n private continueNodeRequest;\n private canUseNodeRequestHooks;\n /**\n * onRequest short-circuit path. Synchronous as long as every hook returns synchronously (the\n * common case - e.g. CORS returning `undefined` for a non-preflight request): an `async` version\n * here put EVERY request of any app with one onRequest hook onto the promise machinery, profiled\n * at ~13% of a realistic request. The first hook that returns a Promise hands the REMAINING\n * hooks to the async continuation; behavior is identical.\n */\n private runWithOnRequest;\n /** Async tail of {@link runWithOnRequest}: applies the first awaited hook's outcome, then runs\n * the remaining hooks (awaiting freely - we're already async here). */\n private continueOnRequest;\n private takeResponseRequest;\n /**\n * The NodeRequestContext for a source, MEMOIZED per source so the request twins and the response\n * twins receive the exact same object within one request - that identity is the documented\n * contract stateful twins key their WeakMaps on. An adapter source (which already speaks the\n * interface) is returned as-is; a plain `Request` source (a direct `resolveNode` caller) gets one\n * cached wrapper.\n */\n private nodeRequestContextOf;\n /** Preserve the request visible to generic onRequest hooks for paired native response hooks. */\n private takeNodeResponseRequest;\n /**\n * Route → build context → run. Synchronous through to the handler for a **bare** route\n * (selected by its compiled plan), so a sync handler produces its result with zero promise allocations;\n * routes with validation/hooks keep the full async {@link runLifecycle}, unchanged.\n */\n private routeAndRun;\n private fetchMount;\n /** Run a route that has already been matched by the runtime or Nifra's portable router. */\n private runMatched;\n /** Supply request-specific deadline state to the route's precompiled execution plan. */\n private runMatchedLanes;\n /** @internal Symbol-keyed install seam for the `effectLedger()` plugin. Off the public typed surface. */\n [INSTALL_EFFECT_LEDGER](runtime: EffectLedgerRuntime): void;\n /** The narrowest bare route: a syntactic `() => ...` handler cannot observe the context argument, so\n * successful requests can skip allocating `RequestContext`. Errors still allocate one for logging. */\n private runContextlessBare;\n private contextlessBareError;\n /**\n * The synchronous fast path selected by a route's execution plan: apply static decorations, call the\n * handler, render the result - **no `await`** unless the handler itself returns a promise. It mirrors\n * the bare slice of {@link runLifecycle} (which a bare route would otherwise no-op through) and shares\n * {@link logRequestError}; a bare route has no `onError` hooks, so error handling is fully synchronous\n * (a thrown `Response` is control flow; anything else is a logged flat 500). This is where nifra skips\n * the per-request async-frame tax - the same win codegen routers get, but without `eval`.\n */\n private runBare;\n /** Bare-route error rendering - identical to {@link runLifecycle}'s catch minus the (absent) onError\n * loop: a thrown `Response` is returned as deliberate control flow; anything else is logged + 500. */\n /**\n * Build a route's fused Web renderer. Composition happens once at\n * registration; the returned closure is what every request to the route runs. Behavior is\n * byte-identical to the generic `runBare`/`runContextlessBare` + `toResponse` pair - same\n * decoration order, same error routing (thrown `Response` = control flow; anything else logs and\n * 500s), same respond semantics (the lifecycle parity suite pins it).\n */\n private buildFusedWeb;\n /** Compile the eligible body-only route's parser → validator → handler continuation once. The\n * bounded parser remains shared with the generic lane; only the route-invariant entry lookups and\n * lifecycle dispatch disappear from the common synchronous-validator/synchronous-handler case. */\n private buildFusedBodyRunner;\n /** Web adapter wrapper for the shared body runner. Node passes its native finalizer directly through\n * the execution plan, while Web needs the live context to preserve lazy `c.set` controls. */\n private buildFusedBodyWeb;\n /** The fused Web lane for a route whose only lifecycle step is a query schema: parse + validate +\n * handler + respond in one closure, no lifecycle promise when the validator and handler are sync.\n * Eligibility is decided at registration (see `fusedQuery` in {@link register}); the semantics here\n * are exactly `runQueryOnly`'s for that eligible shape - invalid input returns\n * `validationError(issues)` (recovery hooks disqualify the route from this lane), a thrown\n * `Response` passes through, anything else logs and returns a flat 500, and an async validator\n * falls to a then-chain with the same steps. */\n private buildFusedQueryWeb;\n private bareError;\n private runWithAround;\n private runAround;\n private runBodyOnly;\n /** Shared bounded body framing/parser. Both body lanes use the same trust-boundary checks; only\n * the validation + handler continuation differs. */\n private readBodyInput;\n /** Validate + run the handler for the bodyOnly path - shared by the inline fast path and the\n * streaming fallback. A method (not per-request closures) so the hot path allocates nothing\n * beyond the one `.then` continuation. */\n private finishBodyOnly;\n private executeHandler;\n private handleValidationErrorRecovery;\n private applyBodyValidation;\n private runQueryOnly;\n /** Validate-result → set `ctx.query` → run handler. A method (not a per-request closure), the\n * query analogue of {@link applyBodyValidation}. */\n private applyQueryValidation;\n /**\n * Thread the response through each global `onResponse` hook. Stays SYNCHRONOUS until a hook\n * actually returns a Promise - an `async` version forced a promise + microtask on EVERY response\n * of any app with an onResponse hook (cors/securityHeaders/etag/timing all use onResponse), the\n * same ~13%/req tax the onRequest walk was de-async'd to avoid. The first async hook hands the\n * rest to {@link continueOnResponse}.\n */\n private applyOnResponse;\n private applyOnResponseAndFinalize;\n private completeResponseFinalization;\n private failResponseFinalization;\n /** Notify terminal observers in order while isolating both sync and async failures. */\n private notifyResponseFinalized;\n /** Async tail of {@link applyOnResponse}: runs the remaining hooks once one has gone async. */\n private continueOnResponse;\n /**\n * Bound the response time. On timeout we abort `ctx.signal` (so cancellation-aware\n * handlers can bail) and return 503; the in-flight work keeps running but its\n * result is discarded - JS can't forcibly cancel a promise.\n */\n private withTimeout;\n /**\n * The post-match lifecycle: validate → derive → beforeHandle → handler → afterHandle, with onError.\n * Generic over the render: a success value goes through `finalize(result, set)` (a Web `Response`, or\n * node-direct primitives); an early/error `Response` (validation, thrown, 500) through `wrapResponse`.\n */\n /** Synchronous until a validator, lifecycle hook, handler, or contract check actually returns a Promise. */\n private runLifecycle;\n private runLifecycleAfterHeadersResult;\n private runLifecycleAfterHeaders;\n /** Registration-specialized query lifecycle: query validation (including recovery) → hooks. */\n private runLifecycleQuery;\n /** Registration-specialized body lifecycle: bounded body validation (including recovery) → hooks. */\n private runLifecycleBody;\n /** Registration-specialized body + query lifecycle: bounded body validation → query validation → hooks. */\n private runLifecycleBodyQuery;\n /** Registration-specialized no-body lifecycle: query validation (if present) → derives/hooks. */\n private runQueryAndLifecycle;\n private runQueryAndLifecycleResult;\n private runLifecycleAfterParamsResult;\n private runLifecycleAfterParams;\n private runLifecycleAfterParamsSettled;\n private runLifecycleAfterBody;\n private runLifecycleAfterQueryResult;\n private runLifecycleAfterQuery;\n private runLifecycleHooks;\n /** Registration-specialized derive → before → handler lifecycle. */\n private runLifecycleDeriveBefore;\n /** Finalize the specialized lane without rechecking its registration-proven invariants. */\n private finishSimpleLifecycleResult;\n private continueLifecycleAfterDerive;\n private runLifecycleHooksAsync;\n private continueLifecycleAfterBefore;\n private runLifecycleHandlerAsync;\n private finishLifecycleResult;\n private continueLifecycleAfterHandle;\n private finishLifecycleContract;\n private finishContractOutcome;\n private handleLifecycleError;\n /** Log an unhandled request error to the (redacting) logger - shared by {@link runLifecycle} and the\n * bare fast path ({@link bareError}) so both record the same fields. Never throws; never leaks. */\n private logRequestError;\n private readAndValidateBody;\n /** Apply validation and its recovery hook on the generic lifecycle lane. Recovery is completed\n * before derives/beforeHandle run, matching the body-only and query-only execution lanes. */\n private applyLifecycleValidation;\n private finishLifecycleValidationRecovery;\n /**\n * Read + parse the JSON body, capped at `maxBodyBytes` and screened by the server's\n * `protoPoisoning` policy. Rejects a `Content-Length` over the cap *before* buffering,\n * re-checks what was actually delivered after the read, and aborts a chunked or\n * length-less body mid-stream once the running byte count exceeds the cap - so a lying\n * or absent length can't force us to buffer an oversized payload.\n */\n private readBoundedJson;\n /** Adapt one route's compiled execution plan to Bun's already-matched request shape. Route\n * semantics remain in the plan; this closure only supplies native params and deadline fallback. */\n private compileBunNativeHandler;\n /** Compile portable route registrations into Bun's native route table. Apps with request-rewrite\n * hooks or WebSockets retain the single portable dispatcher because those features must run before\n * route selection/upgrade. Named wildcards also stay on the fallback until Bun exposes their raw\n * capture semantics; static and `:param` routes take the native lane. */\n private buildBunNativeRoutes;\n /**\n * Start a `Bun.serve` instance bound to `port` (use `0` for an ephemeral port).\n *\n * `reusePort` sets `SO_REUSEPORT` so **multiple processes can bind the same port** and the kernel\n * load-balances connections across them - the standard way to use every core (Bun is\n * single-threaded per process). Spawn one process per core, each calling\n * `app.listen(PORT, { reusePort: true })`; see `examples/cluster.ts`. Every process must opt in,\n * and all of them must be the same app. Linux balances ~evenly; macOS accepts the flag but may\n * favor one socket (fine for dev, measure on Linux for production numbers).\n *\n * `hostname` is the bind address, defaulting to Bun's `0.0.0.0` (every interface). Pass\n * `\"127.0.0.1\"` to bind loopback only - an admin surface, a sidecar, or anything that must not be\n * reachable off the box. Omitting it when you meant to restrict is a real exposure, so it is a\n * first-class option rather than something a caller has to drop down to `Bun.serve` for.\n *\n * `idleTimeoutSec` is how long Bun tolerates a connection with no bytes moving before it closes\n * the socket. Bun's default is **10 seconds**, and a request whose handler is still working sends\n * nothing - so any endpoint slower than 10s (a render, an export, a long upstream call) has its\n * connection cut mid-flight regardless of `requestTimeoutMs`. Apps with such endpoints must raise\n * this above their slowest expected response, which is why it is a first-class option and not a\n * reason to drop down to `Bun.serve`. `0` disables the timeout entirely; max 255.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n }): RunningServer;\n /**\n * Gracefully stop: wait for in-flight requests to finish (up to `drainMs`), then\n * issue a single terminal stop - graceful if everything drained, forced if\n * stragglers remain. Safe to call when not listening.\n *\n * The Bun semantics: poll `pendingRequests` (awaiting\n * `stop()`'s promise drops in-flight requests), and decide graceful-vs-forced in\n * ONE call (Bun can't escalate an already-graceful `stop()` to a forced close).\n * New connections may be accepted during the drain window; in a real deploy the\n * load balancer has already stopped routing here, and `drainMs` bounds it.\n */\n stop({ drainMs }?: {\n drainMs?: number;\n }): Promise<void>;\n private installSignalHandlers;\n}",
|
|
10736
10749
|
"doc": "/**\n * The inline server. Routes are chainable and fully type-inferred. `derive`/\n * `decorate` extend the handler context (`Ctx`) for routes defined *after* them,\n * with full types; `Ctx` is server-only and never touches the client registry.\n *\n * app.decorate(\"db\", db).derive((c) => ({ user: auth(c) }))\n * .get(\"/me\", (c) => c.user) // c.user + c.db are typed\n */"
|
|
10737
10750
|
},
|
|
10738
10751
|
{
|
|
@@ -10893,7 +10906,7 @@
|
|
|
10893
10906
|
"name": "serverFunctions",
|
|
10894
10907
|
"kind": "function",
|
|
10895
10908
|
"package": "@nifrajs/web",
|
|
10896
|
-
"signature": "export declare function serverFunctions
|
|
10909
|
+
"signature": "export declare function serverFunctions(namespace: string, module: ServerFnModule): IdentityPlugin;",
|
|
10897
10910
|
"doc": "/**\n * Mount a module's server functions under `namespace`, returning a plugin for `app.use(...)`.\n *\n * import * as todos from \"./actions/todos.fn\"\n * app.use(serverFunctions(\"todos\", todos)) // -> POST /_nifra/fn/todos/addTodo\n *\n * The namespace is explicit rather than derived from the file path: a path-derived one would put the\n * build machine's layout in a public URL, and this keeps the route readable in logs and greppable in\n * the codebase. Phase 2's transform supplies it automatically from the file's location in the project.\n *\n * Exports that are not server functions are ignored, so `export type` and helpers can live alongside.\n */"
|
|
10898
10911
|
},
|
|
10899
10912
|
{
|
|
@@ -10928,13 +10941,13 @@
|
|
|
10928
10941
|
"name": "ServerOptions",
|
|
10929
10942
|
"kind": "interface",
|
|
10930
10943
|
"package": "@nifrajs/core",
|
|
10931
|
-
"signature": "export interface ServerOptions {\n /**\n * Max request body size (bytes), the default transport cap for every route. Default 1_000_000.\n * A route can choose a finite `schema.bodyLimit` of its own; an explicit `'unlimited'` route\n * requires `schema.bodyLimitReason` and is intended only for a separately bounded streaming or\n * upload integration.\n *\n * Framework readers (the body-schema lane, `c.boundedJson`) enforce the cap when they read. A\n * route WITHOUT a body schema (raw body, file upload, BYO-validation) is covered too: direct\n * `c.req` reads (`json()`, `arrayBuffer()`, the raw `body` stream, ...) are capped in place -\n * lazily, nothing is buffered until code actually reads - and answer 413 past the limit.\n * `c.boundedBody(n)` states its own explicit per-read limit, above or below the route's cap.\n */\n readonly maxBodyBytes?: number;\n /**\n * Prototype-poisoning policy for JSON bodies (the schema path and `c.boundedJson`). An own\n * `__proto__` key, or a `constructor` carrying a `prototype`, is the payload shape that turns a\n * later innocent merge/assign into prototype pollution. `\"reject\"` (default) answers the same\n * flat 400 as malformed JSON; `\"strip\"` removes the offending keys and continues; `\"ignore\"`\n * parses as-is (only for routes that never merge body input into other objects). Clean payloads\n * pay a substring pre-scan only - the deep walk runs solely on suspect text.\n */\n readonly protoPoisoning?: \"reject\" | \"strip\" | \"ignore\";\n /**\n * Declare that every `Request` reaching `app.fetch` was framed by a runtime HTTP parser, so its\n * `Content-Length` is an exact transport boundary rather than a hint. Set this ONLY when the\n * runtime's own request object is handed through untouched with no adapter in between to mark it -\n * a bare `export default app` on an edge runtime. Every supported ingress already marks itself:\n * `listen()` on Bun, `toFetchHandler(app)` on Workers/edge, `@nifrajs/deno`, and `@nifrajs/node`\n * (which reads exact bytes and never needs the mark). Reach for this option only for an ingress\n * nifra does not ship an adapter for.\n *\n * Left off (default), the JSON body lane copies the body out and enforces the cap on DELIVERED\n * bytes, because an unmarked request may have been rebuilt by an adapter that kept a caller's\n * `content-length` while decoding a payload of a different size. That check costs an extra pass\n * over the body, which is why an edge deployment that cannot be lied to may opt out of it.\n *\n * Do not set this on an app whose `fetch` is also called with `Request`s assembled from\n * untrusted input.\n */\n readonly trustBodyFraming?: boolean;\n /** Max inbound WebSocket message size (bytes) when `listen()`ing on Bun - frames over this are rejected\n * by the runtime before reaching your handler (so a huge frame can't be JSON-parsed into memory).\n * Default: `maxBodyBytes` (1 MB). */\n readonly wsMaxPayloadBytes?: number;\n /** Per-request timeout (ms): a slower request gets a 503 and `ctx.signal` aborts. 0 disables (default). */\n readonly requestTimeoutMs?: number;\n /**\n * How to derive `c.clientIp` behind a reverse proxy or CDN. Omit (default) to trust only the raw\n * socket peer and never believe a forwarded header. Set `{ trustedHops: n }` when the app sits\n * behind `n` proxies you operate (the caller is read from `X-Forwarded-For` past those hops), or\n * `{ header: name }` to trust one edge-set header's first value. Declaring trust the app can't\n * actually enforce lets clients forge their IP, so leave it unset unless a proxy really fronts you.\n */\n readonly clientIp?: ClientIpTrust;\n /**\n * Admit the public `x-nifra-deadline` header and let it shorten local work. Disabled by default:\n * services that participate in trusted cross-service deadline propagation opt in explicitly,\n * while ordinary/public HTTP routes pay no header-admission tax and ignore hostile client values.\n */\n readonly acceptInboundDeadlines?: boolean;\n /**\n * Maximum time accepted from an inbound `x-nifra-deadline`, in milliseconds. An incoming absolute\n * deadline may shorten this cap (and `requestTimeoutMs`, when configured), never extend it.\n * Default 30_000; applies only when `acceptInboundDeadlines` is enabled and the header is present.\n */\n readonly maxInboundDeadlineMs?: number;\n /** When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false. */\n readonly gracefulSignals?: boolean;\n /**\n * Capacity-admission gate (see {@link AdmissionController}). Bounds concurrent in-flight work so a\n * healthy instance sheds load (`429` + `Retry-After`) instead of accepting more than it can finish.\n * Off by default. Enabling it disables the fused native-route fast path (requests route through the\n * shared matched lane where the gate runs); when unset, the request path pays nothing.\n */\n readonly admission?: AdmissionController;\n /**\n * Optional token-only observation hook called by `useCapability(c, id)`. It receives no request,\n * parameters, body, tenant, or values. Routes without capability declarations keep the old hot path.\n */\n readonly onCapabilityUse?: (event: CapabilityUseEvent) => void;\n /** Structured logger for framework events (redacts secrets). Default: JSON to stderr. */\n readonly logger?: Logger;\n /**\n * How much of an unhandled error reaches the log for a 500. Never reaches the client either way -\n * the response is always a bare `internal_error`.\n *\n * - `\"full\"` (default) - `name`, the error's own text as `detail`, and `stack`.\n * - `\"message\"` - `name` and `detail`, no stack.\n * - `\"none\"` - `name` only.\n *\n * An error's text can quote the input that produced it, which is how request data ends up in a log\n * sink. The framework's answer is the redacting logger rather than blanket suppression: pass\n * `logger: jsonLogger({ valuePatterns: commonSecretPatterns })` to scrub tokens, JWTs, and emails\n * out of `detail` and `stack` while keeping the diagnosis. Reach for `\"none\"` when the sink itself\n * is the thing you don't trust.\n */\n readonly errorLogDetail?: \"full\" | \"message\" | \"none\";\n /**\n * App-wide fallback fired when a route **without its own `onValidationError`** fails body/query\n * validation. Same contract as the per-route hook (`(issues, ctx, kind) => Response | repaired-value |\n * undefined`): a route's own hook takes precedence, and a route can fall through to the plain `422` by\n * returning `undefined`. Use it for one app-wide error envelope (like tRPC's `errorFormatter` /\n * Fastify's `setErrorHandler`) instead of repeating a formatter per route.\n */\n readonly onValidationError?: RouteSchema[\"onValidationError\"];\n}"
|
|
10944
|
+
"signature": "export interface ServerOptions {\n /**\n * Max request body size (bytes), the default transport cap for every route. Default 1_000_000.\n * A route can choose a finite `schema.bodyLimit` of its own; an explicit `'unlimited'` route\n * requires `schema.bodyLimitReason` and is intended only for a separately bounded streaming or\n * upload integration.\n *\n * Framework readers (the body-schema lane, `c.boundedJson`) enforce the cap when they read. A\n * route WITHOUT a body schema (raw body, file upload, BYO-validation) is covered too: direct\n * `c.req` reads (`json()`, `arrayBuffer()`, the raw `body` stream, ...) are capped in place -\n * lazily, nothing is buffered until code actually reads - and answer 413 past the limit.\n * `c.boundedBody(n)` states its own explicit per-read limit, above or below the route's cap.\n */\n readonly maxBodyBytes?: number;\n /**\n * Prototype-poisoning policy for JSON bodies (the schema path and `c.boundedJson`). An own\n * `__proto__` key, or a `constructor` carrying a `prototype`, is the payload shape that turns a\n * later innocent merge/assign into prototype pollution. `\"reject\"` (default) answers the same\n * flat 400 as malformed JSON; `\"strip\"` removes the offending keys and continues; `\"ignore\"`\n * parses as-is (only for routes that never merge body input into other objects). Clean payloads\n * pay a substring pre-scan only - the deep walk runs solely on suspect text.\n */\n readonly protoPoisoning?: \"reject\" | \"strip\" | \"ignore\";\n /**\n * Declare that every `Request` reaching `app.fetch` was framed by a runtime HTTP parser, so its\n * `Content-Length` is an exact transport boundary rather than a hint. Set this ONLY when the\n * runtime's own request object is handed through untouched with no adapter in between to mark it -\n * a bare `export default app` on an edge runtime. Every supported ingress already marks itself:\n * `listen()` on Bun, `toFetchHandler(app)` on Workers/edge, `@nifrajs/deno`, and `@nifrajs/node`\n * (which reads exact bytes and never needs the mark). Reach for this option only for an ingress\n * nifra does not ship an adapter for.\n *\n * Left off (default), the JSON body lane copies the body out and enforces the cap on DELIVERED\n * bytes, because an unmarked request may have been rebuilt by an adapter that kept a caller's\n * `content-length` while decoding a payload of a different size. That check costs an extra pass\n * over the body, which is why an edge deployment that cannot be lied to may opt out of it.\n *\n * Do not set this on an app whose `fetch` is also called with `Request`s assembled from\n * untrusted input.\n */\n readonly trustBodyFraming?: boolean;\n /** Max inbound WebSocket message size (bytes) when `listen()`ing on Bun - frames over this are rejected\n * by the runtime before reaching your handler (so a huge frame can't be JSON-parsed into memory).\n * Default: `maxBodyBytes` (1 MB). */\n readonly wsMaxPayloadBytes?: number;\n /** Per-request timeout (ms): a slower request gets a 503 and `ctx.signal` aborts. 0 disables (default). */\n readonly requestTimeoutMs?: number;\n /**\n * How to derive `c.clientIp` behind a reverse proxy or CDN. Omit (default) to trust only the raw\n * socket peer and never believe a forwarded header. Set `{ trustedHops: n }` when the app sits\n * behind `n` proxies you operate (the caller is read from `X-Forwarded-For` past those hops), or\n * `{ header: name }` to trust one edge-set header's first value. Declaring trust the app can't\n * actually enforce lets clients forge their IP, so leave it unset unless a proxy really fronts you.\n */\n readonly clientIp?: ClientIpTrust;\n /**\n * Admit the public `x-nifra-deadline` header and let it shorten local work. Disabled by default:\n * services that participate in trusted cross-service deadline propagation opt in explicitly,\n * while ordinary/public HTTP routes pay no header-admission tax and ignore hostile client values.\n */\n readonly acceptInboundDeadlines?: boolean;\n /**\n * Maximum time accepted from an inbound `x-nifra-deadline`, in milliseconds. An incoming absolute\n * deadline may shorten this cap (and `requestTimeoutMs`, when configured), never extend it.\n * Default 30_000; applies only when `acceptInboundDeadlines` is enabled and the header is present.\n */\n readonly maxInboundDeadlineMs?: number;\n /** When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false. */\n readonly gracefulSignals?: boolean;\n /**\n * Capacity-admission gate (see {@link AdmissionController}). Bounds concurrent in-flight work so a\n * healthy instance sheds load (`429` + `Retry-After`) instead of accepting more than it can finish.\n * Off by default. Enabling it disables the fused native-route fast path (requests route through the\n * shared matched lane where the gate runs); when unset, the request path pays nothing.\n */\n readonly admission?: AdmissionController;\n /**\n * Optional token-only observation hook called by `useCapability(c, id)`. It receives no request,\n * parameters, body, tenant, or values. Routes without capability declarations keep the old hot path.\n */\n readonly onCapabilityUse?: (event: CapabilityUseEvent) => void;\n /** Structured logger for framework events (redacts secrets). Default: JSON to stderr. */\n readonly logger?: Logger;\n /**\n * How much of an unhandled error reaches the log for a 500. Never reaches the client either way -\n * the response is always a bare `internal_error`.\n *\n * - `\"full\"` (default) - `name`, the error's own text as `detail`, and `stack`.\n * - `\"message\"` - `name` and `detail`, no stack.\n * - `\"none\"` - `name` only.\n *\n * An error's text can quote the input that produced it, which is how request data ends up in a log\n * sink. The framework's answer is the redacting logger rather than blanket suppression: pass\n * `logger: jsonLogger({ valuePatterns: commonSecretPatterns })` to scrub tokens, JWTs, and emails\n * out of `detail` and `stack` while keeping the diagnosis. Reach for `\"none\"` when the sink itself\n * is the thing you don't trust.\n */\n readonly errorLogDetail?: \"full\" | \"message\" | \"none\";\n /**\n * App-wide fallback fired when a route **without its own `onValidationError`** fails body/query\n * validation. Same contract as the per-route hook (`(issues, ctx, kind) => Response | repaired-value |\n * undefined`): a route's own hook takes precedence, and a route can fall through to the plain `422` by\n * returning `undefined`. Use it for one app-wide error envelope (like tRPC's `errorFormatter` /\n * Fastify's `setErrorHandler`) instead of repeating a formatter per route.\n */\n readonly onValidationError?: RouteSchema[\"onValidationError\"];\n /**\n * What to do when an order-scoped hook (`derive`/`beforeHandle`/`around`/`aroundCapability`/\n * `afterHandle`/`onError`/`decorate`) covers no route because it was added after the last route was\n * registered. `register()` snapshots the current chain into each route as it is declared, so a hook\n * appended after every route reaches nothing and is silently dead. `\"warn\"` (default) logs once at\n * seal (first `listen()`/`fetch`/`resolveNode`); `\"error\"` throws a `FrameworkError`\n * (`UNUSED_SCOPED_HOOKS`); `\"off\"` skips the bookkeeping entirely, including the one-frame stack\n * capture. App-global hooks (`onRequest`/`onResponse`/...) are unaffected in every mode.\n *\n * This is a development-time diagnostic: the whole audit is guarded by `process.env.NODE_ENV !==\n * \"production\"`, so any bundler that defines `NODE_ENV` (vite/esbuild/webpack/next, `bun build\n * --production`) dead-code-eliminates it, leaving zero bytes and zero per-request cost in the shipped\n * bundle. It fires in development, test, and CI - where you catch the mistake - not in production.\n */\n readonly unusedScopedHooks?: \"warn\" | \"error\" | \"off\";\n}"
|
|
10932
10945
|
},
|
|
10933
10946
|
{
|
|
10934
10947
|
"name": "ServerOptions",
|
|
10935
10948
|
"kind": "interface",
|
|
10936
10949
|
"package": "nifra",
|
|
10937
|
-
"signature": "export interface ServerOptions {\n /**\n * Max request body size (bytes), the default transport cap for every route. Default 1_000_000.\n * A route can choose a finite `schema.bodyLimit` of its own; an explicit `'unlimited'` route\n * requires `schema.bodyLimitReason` and is intended only for a separately bounded streaming or\n * upload integration.\n *\n * Framework readers (the body-schema lane, `c.boundedJson`) enforce the cap when they read. A\n * route WITHOUT a body schema (raw body, file upload, BYO-validation) is covered too: direct\n * `c.req` reads (`json()`, `arrayBuffer()`, the raw `body` stream, ...) are capped in place -\n * lazily, nothing is buffered until code actually reads - and answer 413 past the limit.\n * `c.boundedBody(n)` states its own explicit per-read limit, above or below the route's cap.\n */\n readonly maxBodyBytes?: number;\n /**\n * Prototype-poisoning policy for JSON bodies (the schema path and `c.boundedJson`). An own\n * `__proto__` key, or a `constructor` carrying a `prototype`, is the payload shape that turns a\n * later innocent merge/assign into prototype pollution. `\"reject\"` (default) answers the same\n * flat 400 as malformed JSON; `\"strip\"` removes the offending keys and continues; `\"ignore\"`\n * parses as-is (only for routes that never merge body input into other objects). Clean payloads\n * pay a substring pre-scan only - the deep walk runs solely on suspect text.\n */\n readonly protoPoisoning?: \"reject\" | \"strip\" | \"ignore\";\n /**\n * Declare that every `Request` reaching `app.fetch` was framed by a runtime HTTP parser, so its\n * `Content-Length` is an exact transport boundary rather than a hint. Set this ONLY when the\n * runtime's own request object is handed through untouched with no adapter in between to mark it -\n * a bare `export default app` on an edge runtime. Every supported ingress already marks itself:\n * `listen()` on Bun, `toFetchHandler(app)` on Workers/edge, `@nifrajs/deno`, and `@nifrajs/node`\n * (which reads exact bytes and never needs the mark). Reach for this option only for an ingress\n * nifra does not ship an adapter for.\n *\n * Left off (default), the JSON body lane copies the body out and enforces the cap on DELIVERED\n * bytes, because an unmarked request may have been rebuilt by an adapter that kept a caller's\n * `content-length` while decoding a payload of a different size. That check costs an extra pass\n * over the body, which is why an edge deployment that cannot be lied to may opt out of it.\n *\n * Do not set this on an app whose `fetch` is also called with `Request`s assembled from\n * untrusted input.\n */\n readonly trustBodyFraming?: boolean;\n /** Max inbound WebSocket message size (bytes) when `listen()`ing on Bun - frames over this are rejected\n * by the runtime before reaching your handler (so a huge frame can't be JSON-parsed into memory).\n * Default: `maxBodyBytes` (1 MB). */\n readonly wsMaxPayloadBytes?: number;\n /** Per-request timeout (ms): a slower request gets a 503 and `ctx.signal` aborts. 0 disables (default). */\n readonly requestTimeoutMs?: number;\n /**\n * How to derive `c.clientIp` behind a reverse proxy or CDN. Omit (default) to trust only the raw\n * socket peer and never believe a forwarded header. Set `{ trustedHops: n }` when the app sits\n * behind `n` proxies you operate (the caller is read from `X-Forwarded-For` past those hops), or\n * `{ header: name }` to trust one edge-set header's first value. Declaring trust the app can't\n * actually enforce lets clients forge their IP, so leave it unset unless a proxy really fronts you.\n */\n readonly clientIp?: ClientIpTrust;\n /**\n * Admit the public `x-nifra-deadline` header and let it shorten local work. Disabled by default:\n * services that participate in trusted cross-service deadline propagation opt in explicitly,\n * while ordinary/public HTTP routes pay no header-admission tax and ignore hostile client values.\n */\n readonly acceptInboundDeadlines?: boolean;\n /**\n * Maximum time accepted from an inbound `x-nifra-deadline`, in milliseconds. An incoming absolute\n * deadline may shorten this cap (and `requestTimeoutMs`, when configured), never extend it.\n * Default 30_000; applies only when `acceptInboundDeadlines` is enabled and the header is present.\n */\n readonly maxInboundDeadlineMs?: number;\n /** When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false. */\n readonly gracefulSignals?: boolean;\n /**\n * Capacity-admission gate (see {@link AdmissionController}). Bounds concurrent in-flight work so a\n * healthy instance sheds load (`429` + `Retry-After`) instead of accepting more than it can finish.\n * Off by default. Enabling it disables the fused native-route fast path (requests route through the\n * shared matched lane where the gate runs); when unset, the request path pays nothing.\n */\n readonly admission?: AdmissionController;\n /**\n * Optional token-only observation hook called by `useCapability(c, id)`. It receives no request,\n * parameters, body, tenant, or values. Routes without capability declarations keep the old hot path.\n */\n readonly onCapabilityUse?: (event: CapabilityUseEvent) => void;\n /** Structured logger for framework events (redacts secrets). Default: JSON to stderr. */\n readonly logger?: Logger;\n /**\n * How much of an unhandled error reaches the log for a 500. Never reaches the client either way -\n * the response is always a bare `internal_error`.\n *\n * - `\"full\"` (default) - `name`, the error's own text as `detail`, and `stack`.\n * - `\"message\"` - `name` and `detail`, no stack.\n * - `\"none\"` - `name` only.\n *\n * An error's text can quote the input that produced it, which is how request data ends up in a log\n * sink. The framework's answer is the redacting logger rather than blanket suppression: pass\n * `logger: jsonLogger({ valuePatterns: commonSecretPatterns })` to scrub tokens, JWTs, and emails\n * out of `detail` and `stack` while keeping the diagnosis. Reach for `\"none\"` when the sink itself\n * is the thing you don't trust.\n */\n readonly errorLogDetail?: \"full\" | \"message\" | \"none\";\n /**\n * App-wide fallback fired when a route **without its own `onValidationError`** fails body/query\n * validation. Same contract as the per-route hook (`(issues, ctx, kind) => Response | repaired-value |\n * undefined`): a route's own hook takes precedence, and a route can fall through to the plain `422` by\n * returning `undefined`. Use it for one app-wide error envelope (like tRPC's `errorFormatter` /\n * Fastify's `setErrorHandler`) instead of repeating a formatter per route.\n */\n readonly onValidationError?: RouteSchema[\"onValidationError\"];\n}"
|
|
10950
|
+
"signature": "export interface ServerOptions {\n /**\n * Max request body size (bytes), the default transport cap for every route. Default 1_000_000.\n * A route can choose a finite `schema.bodyLimit` of its own; an explicit `'unlimited'` route\n * requires `schema.bodyLimitReason` and is intended only for a separately bounded streaming or\n * upload integration.\n *\n * Framework readers (the body-schema lane, `c.boundedJson`) enforce the cap when they read. A\n * route WITHOUT a body schema (raw body, file upload, BYO-validation) is covered too: direct\n * `c.req` reads (`json()`, `arrayBuffer()`, the raw `body` stream, ...) are capped in place -\n * lazily, nothing is buffered until code actually reads - and answer 413 past the limit.\n * `c.boundedBody(n)` states its own explicit per-read limit, above or below the route's cap.\n */\n readonly maxBodyBytes?: number;\n /**\n * Prototype-poisoning policy for JSON bodies (the schema path and `c.boundedJson`). An own\n * `__proto__` key, or a `constructor` carrying a `prototype`, is the payload shape that turns a\n * later innocent merge/assign into prototype pollution. `\"reject\"` (default) answers the same\n * flat 400 as malformed JSON; `\"strip\"` removes the offending keys and continues; `\"ignore\"`\n * parses as-is (only for routes that never merge body input into other objects). Clean payloads\n * pay a substring pre-scan only - the deep walk runs solely on suspect text.\n */\n readonly protoPoisoning?: \"reject\" | \"strip\" | \"ignore\";\n /**\n * Declare that every `Request` reaching `app.fetch` was framed by a runtime HTTP parser, so its\n * `Content-Length` is an exact transport boundary rather than a hint. Set this ONLY when the\n * runtime's own request object is handed through untouched with no adapter in between to mark it -\n * a bare `export default app` on an edge runtime. Every supported ingress already marks itself:\n * `listen()` on Bun, `toFetchHandler(app)` on Workers/edge, `@nifrajs/deno`, and `@nifrajs/node`\n * (which reads exact bytes and never needs the mark). Reach for this option only for an ingress\n * nifra does not ship an adapter for.\n *\n * Left off (default), the JSON body lane copies the body out and enforces the cap on DELIVERED\n * bytes, because an unmarked request may have been rebuilt by an adapter that kept a caller's\n * `content-length` while decoding a payload of a different size. That check costs an extra pass\n * over the body, which is why an edge deployment that cannot be lied to may opt out of it.\n *\n * Do not set this on an app whose `fetch` is also called with `Request`s assembled from\n * untrusted input.\n */\n readonly trustBodyFraming?: boolean;\n /** Max inbound WebSocket message size (bytes) when `listen()`ing on Bun - frames over this are rejected\n * by the runtime before reaching your handler (so a huge frame can't be JSON-parsed into memory).\n * Default: `maxBodyBytes` (1 MB). */\n readonly wsMaxPayloadBytes?: number;\n /** Per-request timeout (ms): a slower request gets a 503 and `ctx.signal` aborts. 0 disables (default). */\n readonly requestTimeoutMs?: number;\n /**\n * How to derive `c.clientIp` behind a reverse proxy or CDN. Omit (default) to trust only the raw\n * socket peer and never believe a forwarded header. Set `{ trustedHops: n }` when the app sits\n * behind `n` proxies you operate (the caller is read from `X-Forwarded-For` past those hops), or\n * `{ header: name }` to trust one edge-set header's first value. Declaring trust the app can't\n * actually enforce lets clients forge their IP, so leave it unset unless a proxy really fronts you.\n */\n readonly clientIp?: ClientIpTrust;\n /**\n * Admit the public `x-nifra-deadline` header and let it shorten local work. Disabled by default:\n * services that participate in trusted cross-service deadline propagation opt in explicitly,\n * while ordinary/public HTTP routes pay no header-admission tax and ignore hostile client values.\n */\n readonly acceptInboundDeadlines?: boolean;\n /**\n * Maximum time accepted from an inbound `x-nifra-deadline`, in milliseconds. An incoming absolute\n * deadline may shorten this cap (and `requestTimeoutMs`, when configured), never extend it.\n * Default 30_000; applies only when `acceptInboundDeadlines` is enabled and the header is present.\n */\n readonly maxInboundDeadlineMs?: number;\n /** When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false. */\n readonly gracefulSignals?: boolean;\n /**\n * Capacity-admission gate (see {@link AdmissionController}). Bounds concurrent in-flight work so a\n * healthy instance sheds load (`429` + `Retry-After`) instead of accepting more than it can finish.\n * Off by default. Enabling it disables the fused native-route fast path (requests route through the\n * shared matched lane where the gate runs); when unset, the request path pays nothing.\n */\n readonly admission?: AdmissionController;\n /**\n * Optional token-only observation hook called by `useCapability(c, id)`. It receives no request,\n * parameters, body, tenant, or values. Routes without capability declarations keep the old hot path.\n */\n readonly onCapabilityUse?: (event: CapabilityUseEvent) => void;\n /** Structured logger for framework events (redacts secrets). Default: JSON to stderr. */\n readonly logger?: Logger;\n /**\n * How much of an unhandled error reaches the log for a 500. Never reaches the client either way -\n * the response is always a bare `internal_error`.\n *\n * - `\"full\"` (default) - `name`, the error's own text as `detail`, and `stack`.\n * - `\"message\"` - `name` and `detail`, no stack.\n * - `\"none\"` - `name` only.\n *\n * An error's text can quote the input that produced it, which is how request data ends up in a log\n * sink. The framework's answer is the redacting logger rather than blanket suppression: pass\n * `logger: jsonLogger({ valuePatterns: commonSecretPatterns })` to scrub tokens, JWTs, and emails\n * out of `detail` and `stack` while keeping the diagnosis. Reach for `\"none\"` when the sink itself\n * is the thing you don't trust.\n */\n readonly errorLogDetail?: \"full\" | \"message\" | \"none\";\n /**\n * App-wide fallback fired when a route **without its own `onValidationError`** fails body/query\n * validation. Same contract as the per-route hook (`(issues, ctx, kind) => Response | repaired-value |\n * undefined`): a route's own hook takes precedence, and a route can fall through to the plain `422` by\n * returning `undefined`. Use it for one app-wide error envelope (like tRPC's `errorFormatter` /\n * Fastify's `setErrorHandler`) instead of repeating a formatter per route.\n */\n readonly onValidationError?: RouteSchema[\"onValidationError\"];\n /**\n * What to do when an order-scoped hook (`derive`/`beforeHandle`/`around`/`aroundCapability`/\n * `afterHandle`/`onError`/`decorate`) covers no route because it was added after the last route was\n * registered. `register()` snapshots the current chain into each route as it is declared, so a hook\n * appended after every route reaches nothing and is silently dead. `\"warn\"` (default) logs once at\n * seal (first `listen()`/`fetch`/`resolveNode`); `\"error\"` throws a `FrameworkError`\n * (`UNUSED_SCOPED_HOOKS`); `\"off\"` skips the bookkeeping entirely, including the one-frame stack\n * capture. App-global hooks (`onRequest`/`onResponse`/...) are unaffected in every mode.\n *\n * This is a development-time diagnostic: the whole audit is guarded by `process.env.NODE_ENV !==\n * \"production\"`, so any bundler that defines `NODE_ENV` (vite/esbuild/webpack/next, `bun build\n * --production`) dead-code-eliminates it, leaving zero bytes and zero per-request cost in the shipped\n * bundle. It fires in development, test, and CI - where you catch the mistake - not in production.\n */\n readonly unusedScopedHooks?: \"warn\" | \"error\" | \"off\";\n}"
|
|
10938
10951
|
},
|
|
10939
10952
|
{
|
|
10940
10953
|
"name": "ServeStaticOptions",
|
|
@@ -13207,14 +13220,14 @@
|
|
|
13207
13220
|
"name": "VERSION",
|
|
13208
13221
|
"kind": "const",
|
|
13209
13222
|
"package": "@nifrajs/core",
|
|
13210
|
-
"signature": "export declare const VERSION: \"2.
|
|
13223
|
+
"signature": "export declare const VERSION: \"2.14.1\";",
|
|
13211
13224
|
"doc": "/**\n * Current package version. A hardcoded literal on purpose - core runs on the edge (no fs), so it can't\n * read its own package.json at runtime. `scripts/version.ts` rewrites it on every release bump and\n * `check:publish` asserts it equals `@nifrajs/core`'s package version.\n */"
|
|
13212
13225
|
},
|
|
13213
13226
|
{
|
|
13214
13227
|
"name": "VERSION",
|
|
13215
13228
|
"kind": "const",
|
|
13216
13229
|
"package": "nifra",
|
|
13217
|
-
"signature": "export declare const VERSION: \"2.
|
|
13230
|
+
"signature": "export declare const VERSION: \"2.14.1\";",
|
|
13218
13231
|
"doc": "/**\n * Current package version. A hardcoded literal on purpose - core runs on the edge (no fs), so it can't\n * read its own package.json at runtime. `scripts/version.ts` rewrites it on every release bump and\n * `check:publish` asserts it equals `@nifrajs/core`'s package version.\n */"
|
|
13219
13232
|
},
|
|
13220
13233
|
{
|
|
@@ -13234,7 +13247,7 @@
|
|
|
13234
13247
|
"name": "ViteDevServerOptions",
|
|
13235
13248
|
"kind": "interface",
|
|
13236
13249
|
"package": "@nifrajs/web",
|
|
13237
|
-
"signature": "export interface ViteDevServerOptions {\n /** Absolute (or cwd-relative) path to the `routes/` dir. */\n readonly routesDir: string;\n /** Client runtime module providing `mountRouter` (e.g. `\"@nifrajs/web-react/client\"`). */\n readonly clientModule: string;\n /**\n * Build the nifra app for the given dev client-entry URL.\n *\n * `load` resolves a route module through **Vite's** graph (`ssrLoadModule`). Pass it to\n * `discoverRoutes(routesDir, { load })` so SSR and the client are resolved by the SAME toolchain.\n * Without it SSR resolves through Bun while the client resolves through Vite - two resolvers, one\n * process - which is what makes `resolve.dedupe` fail to reach SSR and produces the dual-React\n * crash. Vite re-evaluates on change, so no `importQuery` cache-buster is needed alongside it.\n */\n readonly createApp: (clientEntry: string, load: (absolutePath: string) => Promise<unknown>) => FetchApp | Promise<FetchApp>;\n /** Vite plugins - inject your framework's official plugin, e.g. `[react()]`. */\n readonly plugins?: readonly unknown[];\n /**\n * Extra `resolve.conditions` prepended ahead of nifra's defaults - some frameworks need their own\n * (e.g. Solid's `\"solid\"` condition routes `solid-js` to its source/JSX-dev build).\n */\n readonly conditions?: readonly string[];\n /**\n * Compile-time `define` replacements (e.g. Vue's `__VUE_OPTIONS_API__` flags). Vite already sets\n * `process.env.NODE_ENV` in dev; this is for framework feature flags the plugin doesn't inject.\n */\n readonly define?: Readonly<Record<string, string>>;\n /** Vite project root (default `process.cwd()`). */\n readonly root?: string;\n /** Port (default {@link DEFAULT_DEV_PORT}). */\n readonly port?: number;\n /**\n * Use polling for the file watcher. Native fs events (fsevents/inotify) are unreliable inside\n * containers, networked filesystems, and some sandboxes - there, HMR silently never fires. Set\n * `true` (or the env var `CHOKIDAR_USEPOLLING=1`) to poll instead. Default: off (native events).\n */\n readonly poll?: boolean;\n /** Vite public directory. Defaults to `<root>/public`; `false` disables it. */\n readonly publicDir?: string | false;\n /** Client-visible environment prefix (default `\"PUBLIC_\"`; empty disables exposure). */\n readonly publicEnvPrefix?: string;\n}"
|
|
13250
|
+
"signature": "export interface ViteDevServerOptions {\n /** Absolute (or cwd-relative) path to the `routes/` dir. */\n readonly routesDir: string;\n /** Client runtime module providing `mountRouter` (e.g. `\"@nifrajs/web-react/client\"`). */\n readonly clientModule: string;\n /**\n * Build the nifra app for the given dev client-entry URL.\n *\n * `load` resolves a route module through **Vite's** graph (`ssrLoadModule`). Pass it to\n * `discoverRoutes(routesDir, { load })` so SSR and the client are resolved by the SAME toolchain.\n * Without it SSR resolves through Bun while the client resolves through Vite - two resolvers, one\n * process - which is what makes `resolve.dedupe` fail to reach SSR and produces the dual-React\n * crash. Vite re-evaluates on change, so no `importQuery` cache-buster is needed alongside it.\n */\n readonly createApp: (clientEntry: string, load: (absolutePath: string) => Promise<unknown>) => FetchApp | Promise<FetchApp>;\n /** Vite plugins - inject your framework's official plugin, e.g. `[react()]`. */\n readonly plugins?: readonly unknown[];\n /**\n * Extra `resolve.conditions` prepended ahead of nifra's defaults - some frameworks need their own\n * (e.g. Solid's `\"solid\"` condition routes `solid-js` to its source/JSX-dev build).\n */\n readonly conditions?: readonly string[];\n /**\n * Compile-time `define` replacements (e.g. Vue's `__VUE_OPTIONS_API__` flags). Vite already sets\n * `process.env.NODE_ENV` in dev; this is for framework feature flags the plugin doesn't inject.\n */\n readonly define?: Readonly<Record<string, string>>;\n /** Vite project root (default `process.cwd()`). */\n readonly root?: string;\n /** Port (default {@link DEFAULT_DEV_PORT}). */\n readonly port?: number;\n /**\n * Use polling for the file watcher. Native fs events (fsevents/inotify) are unreliable inside\n * containers, networked filesystems, and some sandboxes - there, HMR silently never fires. Set\n * `true` (or the env var `CHOKIDAR_USEPOLLING=1`) to poll instead. Default: off (native events).\n */\n readonly poll?: boolean;\n /** Vite public directory. Defaults to `<root>/public`; `false` disables it. */\n readonly publicDir?: string | false;\n /** Client-visible environment prefix (default `\"PUBLIC_\"`; empty disables exposure). */\n readonly publicEnvPrefix?: string;\n /**\n * Downgrade the startup identity-parity check from a hard failure to a loud warning (dev only).\n * The check catches two physical copies of an identity-sensitive package (e.g. React) resolving in\n * one process, which reliably breaks hydration and framework context. When a duplicate comes from a\n * linked sibling repo you cannot fix in the moment, set this to keep the dev server running while you\n * resolve it; `nifra build` never honors it. Wired to `nifra dev --allow-duplicate-identity`.\n */\n readonly allowDuplicateIdentity?: boolean;\n}"
|
|
13238
13251
|
},
|
|
13239
13252
|
{
|
|
13240
13253
|
"name": "viteLeakGuard",
|