@nifrajs/cli 2.13.0 → 3.1.0

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.
Files changed (114) hide show
  1. package/dist/capabilities-tool.d.ts +54 -1
  2. package/dist/capabilities-tool.d.ts.map +1 -1
  3. package/dist/capabilities-tool.js +146 -18
  4. package/dist/capabilities-tool.js.map +1 -1
  5. package/dist/check.d.ts +11 -11
  6. package/dist/check.d.ts.map +1 -1
  7. package/dist/check.js +260 -49
  8. package/dist/check.js.map +1 -1
  9. package/dist/cli.d.ts +11 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +130 -414
  12. package/dist/cli.js.map +1 -1
  13. package/dist/command-catalog.d.ts +250 -0
  14. package/dist/command-catalog.d.ts.map +1 -0
  15. package/dist/command-catalog.js +1032 -0
  16. package/dist/command-catalog.js.map +1 -0
  17. package/dist/contracts.d.ts +9 -0
  18. package/dist/contracts.d.ts.map +1 -1
  19. package/dist/contracts.js +22 -6
  20. package/dist/contracts.js.map +1 -1
  21. package/dist/doctor.d.ts +55 -0
  22. package/dist/doctor.d.ts.map +1 -1
  23. package/dist/doctor.js +82 -9
  24. package/dist/doctor.js.map +1 -1
  25. package/dist/env-file.d.ts +17 -0
  26. package/dist/env-file.d.ts.map +1 -0
  27. package/dist/env-file.js +113 -0
  28. package/dist/env-file.js.map +1 -0
  29. package/dist/fix-recipes.d.ts.map +1 -1
  30. package/dist/fix-recipes.js +91 -15
  31. package/dist/fix-recipes.js.map +1 -1
  32. package/dist/internal/reserved-segment-codemod.d.ts +36 -0
  33. package/dist/internal/reserved-segment-codemod.d.ts.map +1 -0
  34. package/dist/internal/reserved-segment-codemod.js +134 -0
  35. package/dist/internal/reserved-segment-codemod.js.map +1 -0
  36. package/dist/internal/typescript-import.d.ts +1 -1
  37. package/dist/internal/typescript-import.d.ts.map +1 -1
  38. package/dist/internal/typescript-import.js +62 -11
  39. package/dist/internal/typescript-import.js.map +1 -1
  40. package/dist/introspect.d.ts +26 -1
  41. package/dist/introspect.d.ts.map +1 -1
  42. package/dist/introspect.js +74 -24
  43. package/dist/introspect.js.map +1 -1
  44. package/dist/load.d.ts.map +1 -1
  45. package/dist/load.js +22 -5
  46. package/dist/load.js.map +1 -1
  47. package/dist/manifest-tool.d.ts +15 -1
  48. package/dist/manifest-tool.d.ts.map +1 -1
  49. package/dist/manifest-tool.js +23 -9
  50. package/dist/manifest-tool.js.map +1 -1
  51. package/dist/mcp-http.js +1 -1
  52. package/dist/mcp-http.js.map +1 -1
  53. package/dist/mcp.d.ts +16 -0
  54. package/dist/mcp.d.ts.map +1 -1
  55. package/dist/mcp.js +127 -355
  56. package/dist/mcp.js.map +1 -1
  57. package/dist/project-facts.d.ts +40 -0
  58. package/dist/project-facts.d.ts.map +1 -0
  59. package/dist/project-facts.js +36 -0
  60. package/dist/project-facts.js.map +1 -0
  61. package/dist/recipes/3.0.0.d.ts +10 -0
  62. package/dist/recipes/3.0.0.d.ts.map +1 -0
  63. package/dist/recipes/3.0.0.js +23 -0
  64. package/dist/recipes/3.0.0.js.map +1 -0
  65. package/dist/recipes/index.d.ts.map +1 -1
  66. package/dist/recipes/index.js +2 -0
  67. package/dist/recipes/index.js.map +1 -1
  68. package/dist/release-verification.d.ts.map +1 -1
  69. package/dist/release-verification.js +15 -0
  70. package/dist/release-verification.js.map +1 -1
  71. package/dist/rules/comment-markers.d.ts +8 -0
  72. package/dist/rules/comment-markers.d.ts.map +1 -1
  73. package/dist/rules/comment-markers.js +36 -0
  74. package/dist/rules/comment-markers.js.map +1 -1
  75. package/dist/rules/index.d.ts +2 -3
  76. package/dist/rules/index.d.ts.map +1 -1
  77. package/dist/rules/index.js.map +1 -1
  78. package/dist/rules/routes.d.ts.map +1 -1
  79. package/dist/rules/routes.js +29 -44
  80. package/dist/rules/routes.js.map +1 -1
  81. package/dist/rules/security.js +14 -14
  82. package/dist/rules/security.js.map +1 -1
  83. package/dist/workspace-link.d.ts +37 -0
  84. package/dist/workspace-link.d.ts.map +1 -0
  85. package/dist/workspace-link.js +72 -0
  86. package/dist/workspace-link.js.map +1 -0
  87. package/docs/examples.json +1 -1
  88. package/docs/llms-full.txt +362 -20
  89. package/docs/types.json +956 -56
  90. package/package.json +9 -9
  91. package/src/capabilities-tool.ts +229 -21
  92. package/src/check.ts +312 -65
  93. package/src/cli.ts +140 -405
  94. package/src/command-catalog.ts +1435 -0
  95. package/src/contracts.ts +28 -7
  96. package/src/doctor.ts +134 -12
  97. package/src/env-file.ts +121 -0
  98. package/src/fix-recipes.ts +101 -15
  99. package/src/internal/reserved-segment-codemod.ts +150 -0
  100. package/src/internal/typescript-import.ts +61 -11
  101. package/src/introspect.ts +82 -21
  102. package/src/load.ts +25 -6
  103. package/src/manifest-tool.ts +43 -12
  104. package/src/mcp-http.ts +1 -1
  105. package/src/mcp.ts +163 -420
  106. package/src/project-facts.ts +86 -0
  107. package/src/recipes/3.0.0.ts +24 -0
  108. package/src/recipes/index.ts +2 -0
  109. package/src/release-verification.ts +17 -0
  110. package/src/rules/comment-markers.ts +36 -0
  111. package/src/rules/index.ts +3 -4
  112. package/src/rules/routes.ts +30 -44
  113. package/src/rules/security.ts +14 -14
  114. package/src/workspace-link.ts +80 -0
package/docs/types.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "kind": "type",
5
5
  "package": "@nifrajs/web",
6
6
  "signature": "export type Action = (ctx: LoaderContext) => unknown | Promise<unknown>;",
7
- "doc": "/**\n * A route's optional mutation, run on POST. Shares the loader context (params/request/api);\n * read the form/JSON body off `request`. Returns either a `Response` (e.g. a redirect -\n * passed straight through) or data, surfaced to the page component as `actionData`.\n */"
7
+ "doc": "/**\n * A route's optional mutation, run on POST. Shares the loader context (params/request/api);\n * read the form/JSON body off `request`. Returns either a control-flow value (a `redirect()`, a\n * `status(...)` render, or a hand-rolled `Response` - all passed straight through) or data,\n * surfaced to the page component as `actionData`.\n */"
8
8
  },
9
9
  {
10
10
  "name": "ACTION_GLOBAL",
@@ -546,6 +546,13 @@
546
546
  "signature": "export declare function assertSafeKey(key: string): void;",
547
547
  "doc": "/** Throw {@link StorageKeyError} unless `key` is a safe relative storage key. */"
548
548
  },
549
+ {
550
+ "name": "assertStaticBoundaryImports",
551
+ "kind": "function",
552
+ "package": "@nifrajs/web",
553
+ "signature": "export declare function assertStaticBoundaryImports(roots: readonly StaticBoundaryRoot[], edges: readonly StaticBoundaryImportEdge[], requestScopedModules: ReadonlySet<string>): void;",
554
+ "doc": "/**\n * Enforce the second half of the static-boundary safety boundary. A build adapter supplies the\n * transitive module graph and the modules it has classified as request-scoped; a static root that\n * reaches one fails before any shared shell is emitted. Keeping this check graph-shaped makes it\n * usable by Bun/Vite without making the neutral web runtime depend on either bundler.\n */"
555
+ },
549
556
  {
550
557
  "name": "assertStorageAdapterConformance",
551
558
  "kind": "function",
@@ -628,7 +635,7 @@
628
635
  "name": "AssuranceRouteSelector",
629
636
  "kind": "interface",
630
637
  "package": "@nifrajs/core",
631
- "signature": "export interface AssuranceRouteSelector {\n /** Omit for every method. */\n readonly methods?: readonly Method[];\n /** Absolute route globs. `*` matches one segment; final `**` matches zero or more. */\n readonly paths?: readonly string[];\n /** Restrict the rule to MCP tool routes (`true`) or non-tool routes (`false`). */\n readonly tools?: boolean;\n /**\n * Match routes declaring ANY of these capability tokens.\n *\n * Lets a policy be written about what a route DOES rather than where it lives: \"anything that writes\n * to the database must be authenticated\" survives a route being moved or renamed, which a path glob\n * does not. Reflection already carries the declared tokens, so this reads what the route said about\n * itself.\n *\n * Naming exact tokens is precise but closed: a rule listing `db.write` does not cover `storage.write`,\n * and a capability added next year escapes it in silence. Prefer `access`/`zone` for a rule that is\n * meant to hold for a CLASS of effect.\n */\n readonly capabilities?: readonly string[];\n /**\n * Match routes declaring any capability whose definition has this access.\n *\n * This is the selector to reach for when the rule is \"anything that writes must prove who asked\":\n * it is keyed on what the capability IS rather than what it is called, so a token introduced later\n * is covered the day it is declared instead of the day someone remembers to widen the rule.\n *\n * Requires capability definitions. A policy using it without them is refused rather than quietly\n * matching nothing - a selector that matches nothing lets the route fall through to a laxer rule.\n */\n readonly access?: CapabilityAccess;\n /**\n * Match routes declaring any capability in this zone. Combined with `access`, both must hold for the\n * SAME capability, so `{ access: \"write\", zone: \"domain\" }` is \"writes business state\" and does not\n * match a route that only writes an audit log.\n */\n readonly zone?: CapabilityZone;\n /** Match routes whose response classification is at least this sensitivity. */\n readonly classificationAtLeast?: DataClassification;\n}"
638
+ "signature": "export interface AssuranceRouteSelector {\n /** Omit for every method. */\n readonly methods?: readonly Method[];\n /** Absolute route globs. `*` matches one segment; final `**` matches zero or more. */\n readonly paths?: readonly string[];\n /** Restrict the rule to MCP tool routes (`true`) or non-tool routes (`false`). */\n readonly tools?: boolean;\n /**\n * Match routes declaring ANY of these capability tokens.\n *\n * Lets a policy be written about what a route DOES rather than where it lives: \"anything that writes\n * to the database must be authenticated\" survives a route being moved or renamed, which a path glob\n * does not. Reflection already carries the declared tokens, so this reads what the route said about\n * itself.\n *\n * Naming exact tokens is precise but closed: a rule listing `db.write` does not cover `storage.write`,\n * and a capability added next year escapes it in silence. Prefer `access`/`zone` for a rule that is\n * meant to hold for a CLASS of effect.\n */\n readonly capabilities?: readonly string[];\n /**\n * Match routes declaring any capability whose definition has this access.\n *\n * This is the selector to reach for when the rule is \"anything that writes must prove who asked\":\n * it is keyed on what the capability IS rather than what it is called, so a token introduced later\n * is covered the day it is declared instead of the day someone remembers to widen the rule.\n *\n * Requires capability definitions. A policy using it without them is refused rather than quietly\n * matching nothing - a selector that matches nothing lets the route fall through to a laxer rule.\n */\n readonly access?: CapabilityAccess;\n /**\n * Match routes declaring any capability in this zone. Combined with `access`, both must hold for the\n * SAME capability, so `{ access: \"write\", zone: \"domain\" }` is \"writes business state\" and does not\n * match a route that only writes an audit log.\n */\n readonly zone?: CapabilityZone;\n /** Match routes whose response classification is at least this sensitivity. */\n readonly classificationAtLeast?: DataClassification;\n /**\n * Match routes by whether they declare a request-body schema. `true` selects routes that parse a\n * body (the buffered-read surface F-001 is about); `false` selects bodyless routes. Reflection\n * already carries `schema.body`, so this reads what the route declared, not where it lives.\n */\n readonly hasBody?: boolean;\n /**\n * Match routes by their effective transport body policy. `\"unlimited\"` is the explicit\n * streaming/upload exemption; `\"bounded\"` is any finite cap (an explicit number or the inherited\n * server default); `\"unset\"` is a route that declared no `bodyLimit` at all. Lets a baseline say\n * \"a body-schema route may never be unlimited\" as a first-class, movable invariant rather than a\n * path list. A route with no schema reports `\"unset\"` unless it names a limit.\n */\n readonly bodyLimit?: \"bounded\" | \"unlimited\" | \"unset\";\n}"
632
639
  },
633
640
  {
634
641
  "name": "AssuranceRule",
@@ -705,7 +712,7 @@
705
712
  "name": "attachWebSocket",
706
713
  "kind": "function",
707
714
  "package": "@nifrajs/core",
708
- "signature": "export declare function attachWebSocket(socket: StandardWebSocket, handler: WebSocketHandler, data: unknown, options: {\n openNow: boolean;\n pubsub: TopicRegistry;\n maxPayloadBytes?: number;\n}): NifraWebSocket;",
715
+ "signature": "export declare function attachWebSocket<Data = unknown, Env = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined>(socket: StandardWebSocket, handler: WebSocketHandler<Data, Env, Schema, Send>, data: unknown, options: {\n openNow: boolean;\n pubsub: TopicRegistry;\n maxPayloadBytes?: number;\n}): NifraWebSocket<Data>;",
709
716
  "doc": "/**\n * Wire a standard server-side `WebSocket` to a nifra {@link WebSocketHandler}, returning the portable\n * {@link NifraWebSocket}. Shared by the Deno and Workers bridges. `openNow` fires `open` immediately\n * (Workers, where the socket is already open after `accept()`); otherwise `open` waits for the socket's\n * `open` event (Deno). Lifecycle callbacks are error-isolated - a throw (or async rejection) routes to\n * `error()` and never tears the process down; binary frames are normalized to `Uint8Array`.\n */"
710
717
  },
711
718
  {
@@ -733,7 +740,7 @@
733
740
  "kind": "interface",
734
741
  "package": "@nifrajs/auth",
735
742
  "signature": "export interface AuthorizationRequest<Subject = unknown, Resource = unknown> {\n readonly subject: Subject;\n readonly action: string;\n readonly resource?: Resource;\n}",
736
- "doc": "/**\n * Public authorization seam. Nifra supplies the control-flow contract; the application or data layer\n * supplies the actual policy. No subject/resource data is persisted or interpreted here.\n */"
743
+ "doc": "/** What a policy is asked to decide: this subject, doing this action, optionally to this resource. */"
737
744
  },
738
745
  {
739
746
  "name": "Authorizer",
@@ -843,6 +850,27 @@
843
850
  "signature": "export interface BakedCollection<Frontmatter> {\n readonly entries: ReadonlyArray<Entry<Frontmatter>>;\n}",
844
851
  "doc": "/**\n * A content collection baked to plain data - fs-free, so it works at the **edge** (Workers\n * request-time) where `defineCollection`'s `node:fs` reader can't run. Produce one at build/server time\n * with `bakeCollection`, JSON-serialize + ship it in the bundle, then rehydrate with `fromBaked`.\n */"
845
852
  },
853
+ {
854
+ "name": "BakedCollectionIndex",
855
+ "kind": "interface",
856
+ "package": "@nifrajs/content",
857
+ "signature": "export interface BakedCollectionIndex<Frontmatter extends Record<string, unknown>, By extends ContentFieldKey<Frontmatter>> {\n readonly entries: ReadonlyArray<Entry<Frontmatter>>;\n readonly by: By;\n readonly sort: IndexSort<Frontmatter>;\n /** Entry indexes in the default deterministic order. */\n readonly order: ReadonlyArray<number>;\n readonly buckets: ReadonlyArray<BakedIndexBucket>;\n}",
858
+ "doc": "/** JSON-safe index data. It contains no functions, Map, Set, filesystem handle, or request data. */"
859
+ },
860
+ {
861
+ "name": "BakedCollectionJoin",
862
+ "kind": "interface",
863
+ "package": "@nifrajs/content",
864
+ "signature": "export interface BakedCollectionJoin<Left extends Record<string, unknown>, Right extends Record<string, unknown>, On extends SharedKey<Left, Right>, Cardinality extends JoinCardinality> {\n readonly on: On;\n readonly cardinality: Cardinality;\n readonly rows: ReadonlyArray<JoinedRow<Left, Right, Cardinality>>;\n}",
865
+ "doc": "/** JSON-safe joined rows, ordered by the left index and then the right index. */"
866
+ },
867
+ {
868
+ "name": "BakedIndexBucket",
869
+ "kind": "interface",
870
+ "package": "@nifrajs/content",
871
+ "signature": "export interface BakedIndexBucket {\n readonly key: string;\n readonly entryIndexes: ReadonlyArray<number>;\n}",
872
+ "doc": "/** The JSON-safe lookup bucket stored in a baked index. */"
873
+ },
846
874
  {
847
875
  "name": "basicAuth",
848
876
  "kind": "function",
@@ -1108,6 +1136,85 @@
1108
1136
  "signature": "export declare function boolean(opts?: Base<boolean>): StandardSchemaV1<boolean>;",
1109
1137
  "doc": "/** A boolean: `true`/`1`/`yes`/`on` → true; `false`/`0`/`no`/`off`/empty → false (case-insensitive). */"
1110
1138
  },
1139
+ {
1140
+ "name": "Boundary",
1141
+ "kind": "type",
1142
+ "package": "@nifrajs/web",
1143
+ "signature": "export type Boundary<Data, UI> = StaticBoundary<Data, UI> | DynamicBoundary<Data, UI> | InterceptBoundary<Data, UI>;",
1144
+ "doc": "/** A discriminated union: the `mode` selects the context type accepted by `load`. */"
1145
+ },
1146
+ {
1147
+ "name": "BOUNDARY_GLOBAL",
1148
+ "kind": "const",
1149
+ "package": "@nifrajs/web",
1150
+ "signature": "export declare const BOUNDARY_GLOBAL = \"__NIFRA_BOUNDARIES__\";",
1151
+ "doc": "/** Dynamic-boundary states for hydration; absent when a route declares no boundaries. */"
1152
+ },
1153
+ {
1154
+ "name": "BoundaryDescriptor",
1155
+ "kind": "interface",
1156
+ "package": "@nifrajs/web",
1157
+ "signature": "export interface BoundaryDescriptor {\n readonly name: string;\n readonly mode: BoundaryMode;\n readonly hasLoad: boolean;\n readonly errorId?: string;\n}",
1158
+ "doc": "/** Neutral manifest descriptor: no framework component crosses the web core boundary. */"
1159
+ },
1160
+ {
1161
+ "name": "boundaryDescriptors",
1162
+ "kind": "function",
1163
+ "package": "@nifrajs/web",
1164
+ "signature": "export declare function boundaryDescriptors(boundaries: readonly BoundaryRegistration[]): ReadonlyArray<BoundaryDescriptor>;",
1165
+ "doc": "/** Validate and serialize the neutral boundary manifest. Duplicate names fail closed at startup. */"
1166
+ },
1167
+ {
1168
+ "name": "BoundaryError",
1169
+ "kind": "interface",
1170
+ "package": "@nifrajs/web",
1171
+ "signature": "export interface BoundaryError {\n readonly name: string;\n readonly message: string;\n}"
1172
+ },
1173
+ {
1174
+ "name": "BoundaryMode",
1175
+ "kind": "type",
1176
+ "package": "@nifrajs/web",
1177
+ "signature": "export type BoundaryMode = \"static\" | \"dynamic\" | {\n readonly intercept: string;\n};"
1178
+ },
1179
+ {
1180
+ "name": "boundaryModeKey",
1181
+ "kind": "function",
1182
+ "package": "@nifrajs/web",
1183
+ "signature": "export declare function boundaryModeKey(mode: BoundaryMode): string;",
1184
+ "doc": "/** Stable mode label for adapter registries and diagnostics. */"
1185
+ },
1186
+ {
1187
+ "name": "BoundaryRegistration",
1188
+ "kind": "type",
1189
+ "package": "@nifrajs/web",
1190
+ "signature": "export type BoundaryRegistration = (ErasedBoundaryBase & {\n readonly mode: \"static\";\n readonly load?: (ctx: StaticCtx) => unknown | Promise<unknown>;\n}) | (ErasedBoundaryBase & {\n readonly mode: \"dynamic\";\n readonly load?: (ctx: BoundaryRequestCtx) => unknown | Promise<unknown>;\n}) | (ErasedBoundaryBase & {\n readonly mode: {\n readonly intercept: string;\n };\n readonly load?: (ctx: BoundaryRequestCtx) => unknown | Promise<unknown>;\n});"
1191
+ },
1192
+ {
1193
+ "name": "BoundaryRequestCtx",
1194
+ "kind": "interface",
1195
+ "package": "@nifrajs/web",
1196
+ "signature": "export interface BoundaryRequestCtx {\n readonly request: Request;\n readonly params: Readonly<Record<string, string>>;\n readonly api: unknown;\n readonly env: unknown;\n readonly draft: boolean;\n readonly search: Readonly<Record<string, unknown>>;\n readonly signal: AbortSignal;\n}",
1197
+ "doc": "/** Request-scoped inputs available to dynamic and intercepting boundaries. */"
1198
+ },
1199
+ {
1200
+ "name": "BoundaryState",
1201
+ "kind": "interface",
1202
+ "package": "@nifrajs/web",
1203
+ "signature": "export interface BoundaryState {\n readonly name: string;\n readonly mode: BoundaryMode;\n readonly status: BoundaryStatus;\n readonly data?: unknown;\n readonly error?: BoundaryError;\n readonly errorId?: string;\n}",
1204
+ "doc": "/** Serializable boundary state passed to the adapter's render seam. */"
1205
+ },
1206
+ {
1207
+ "name": "BoundaryStates",
1208
+ "kind": "type",
1209
+ "package": "@nifrajs/web",
1210
+ "signature": "export type BoundaryStates = Readonly<Record<string, BoundaryState>>;"
1211
+ },
1212
+ {
1213
+ "name": "BoundaryStatus",
1214
+ "kind": "type",
1215
+ "package": "@nifrajs/web",
1216
+ "signature": "export type BoundaryStatus = \"unresolved\" | \"pending\" | \"ready\" | \"error\";"
1217
+ },
1111
1218
  {
1112
1219
  "name": "BoundDataPort",
1113
1220
  "kind": "interface",
@@ -2124,12 +2231,54 @@
2124
2231
  "signature": "export declare const CLIENT_ENTRY_PATH = \"/__nifra/client.js\";",
2125
2232
  "doc": "/**\n * The stable URL every SSR'd page points its client entry at.\n *\n * It has to be stable, and Bun's own URL is not: that one is a content hash over the entire client graph,\n * so it changes whenever anything the entry imports changes. This path redirects to whichever hashed\n * chunk Bun is serving at the moment the browser asks, which is the only formulation that stays correct\n * across a rebuild.\n */"
2126
2233
  },
2234
+ {
2235
+ "name": "ClientAction",
2236
+ "kind": "type",
2237
+ "package": "@nifrajs/web",
2238
+ "signature": "export type ClientAction = (args: ClientActionArgs) => ClientActionResult | void | Promise<ClientActionResult | void>;",
2239
+ "doc": "/** A client-only action wrapper; it never replaces the server action. */"
2240
+ },
2241
+ {
2242
+ "name": "ClientActionArgs",
2243
+ "kind": "interface",
2244
+ "package": "@nifrajs/web",
2245
+ "signature": "export interface ClientActionArgs extends ClientLoaderArgs {\n readonly body: ClientRequestBody;\n}",
2246
+ "doc": "/** Safe, client-visible context for a client action. No secrets or raw request headers cross this seam. */"
2247
+ },
2248
+ {
2249
+ "name": "ClientActionResult",
2250
+ "kind": "interface",
2251
+ "package": "@nifrajs/web",
2252
+ "signature": "export interface ClientActionResult {\n readonly body?: ClientRequestBody;\n readonly optimisticData?: unknown;\n}",
2253
+ "doc": "/** Client action preparation. `body` is sent as untrusted input; `optimisticData` is never sent. */"
2254
+ },
2255
+ {
2256
+ "name": "ClientLoader",
2257
+ "kind": "type",
2258
+ "package": "@nifrajs/web",
2259
+ "signature": "export type ClientLoader = (args: ClientLoaderArgs) => unknown | Promise<unknown>;",
2260
+ "doc": "/** A client-only post-hydration data loader. Its return value replaces the route's rendered data. */"
2261
+ },
2262
+ {
2263
+ "name": "ClientLoaderArgs",
2264
+ "kind": "interface",
2265
+ "package": "@nifrajs/web",
2266
+ "signature": "export interface ClientLoaderArgs {\n readonly url: string;\n readonly params: Readonly<Record<string, string>>;\n readonly signal: AbortSignal;\n /** Lazily obtains the server loader result; repeated calls share one per-navigation request. */\n readonly serverLoader: () => Promise<unknown>;\n}",
2267
+ "doc": "/** Safe, client-visible context for a client loader. It intentionally exposes no Request or headers. */"
2268
+ },
2127
2269
  {
2128
2270
  "name": "ClientOptions",
2129
2271
  "kind": "interface",
2130
2272
  "package": "@nifrajs/client",
2131
2273
  "signature": "export interface ClientOptions {\n /** Headers sent on every request (a per-call `headers` option is merged on top). */\n readonly headers?: Record<string, string>;\n /** Override the `fetch` implementation (tests, an in-process bridge, a custom agent, etc.). */\n readonly fetch?: FetchFn;\n /**\n * Runs before each request (including each retry). Return a header map to MERGE onto the outgoing\n * request - the place to inject a fresh auth token. `await`ed, so async token refresh works.\n */\n readonly onRequest?: (request: {\n readonly url: string;\n readonly method: string;\n readonly headers: Record<string, string>;\n readonly body: unknown;\n }) => MaybePromise<Record<string, string> | undefined>;\n /** Runs after a response arrives (once per call, on the final response). Observe-only. */\n readonly onResponse?: (response: {\n readonly url: string;\n readonly method: string;\n readonly response: Response;\n }) => MaybePromise<void>;\n /** Abort a call that takes longer than this many ms. Surfaces as `{ ok: false, status: 0 }` with a\n * `timeout` error, never a throw. Combined with a per-call `signal`. */\n readonly timeoutMs?: number;\n /** Enable safe automatic retries. See {@link ClientRetryOptions}. */\n readonly retry?: ClientRetryOptions;\n /**\n * Largest response body, in bytes, that will be DECODED into a value. Default 16 MB.\n *\n * Bounds the two paths that build something in memory - a JSON body becoming an object graph, a text\n * body becoming a string - and it bounds them while streaming, cancelling the read the moment the\n * total passes. A 2 GB string costs as much as a 2 GB object, so both answer to one number.\n *\n * A BINARY body is deliberately not bounded by this. That is a download, and a size limit on a\n * download is a bug rather than a defence - the caller asked for the file. Bound one at the call site\n * with a `signal`, or read `content-length` before deciding.\n *\n * This used to live at `transport.maxBytes`, where it could not be reached: `transport` requires a\n * `codec`, so raising your response limit meant opting into a versioned transport representation you\n * had not asked for. That spelling still works and still wins for the transport path.\n */\n readonly maxDecodedBytes?: number;\n /**\n * Opt into a versioned transport representation. Plain JSON remains the default. Responses are\n * decoded through the bounded registry, and WebSocket frames use the same codec.\n */\n readonly transport?: {\n readonly codec: TransportCodec;\n readonly registry?: TransportCodecRegistry;\n readonly maxBytes?: number;\n };\n}"
2132
2274
  },
2275
+ {
2276
+ "name": "ClientRequestBody",
2277
+ "kind": "type",
2278
+ "package": "@nifrajs/web",
2279
+ "signature": "export type ClientRequestBody = NonNullable<RequestInit[\"body\"]>;",
2280
+ "doc": "/** The body a client action may prepare for the server action. The server must validate it again. */"
2281
+ },
2133
2282
  {
2134
2283
  "name": "ClientRetryOptions",
2135
2284
  "kind": "interface",
@@ -2137,18 +2286,25 @@
2137
2286
  "signature": "export interface ClientRetryOptions {\n /** Max RETRIES after the first attempt. Default 2. */\n readonly attempts?: number;\n /** Response statuses to retry. Default `[502, 503, 504]`. 4xx/429 are never added by default. */\n readonly on?: readonly number[];\n /** Methods eligible for retry. Default the idempotent set `GET/HEAD/OPTIONS/PUT/DELETE`. */\n readonly methods?: readonly string[];\n /** Delay (ms) before retry `n` (1-based). Default exponential backoff with jitter, capped at 3s. */\n readonly backoff?: (attempt: number) => number;\n}",
2138
2287
  "doc": "/** Safe retry policy. Off unless `retry` is set; retries ONLY idempotent methods and transient 5xx -\n * never a 4xx/429 and never a non-idempotent method, so a retry can't double a side effect. */"
2139
2288
  },
2289
+ {
2290
+ "name": "ClientRouteHooks",
2291
+ "kind": "interface",
2292
+ "package": "@nifrajs/web",
2293
+ "signature": "export interface ClientRouteHooks {\n readonly clientLoader?: ClientLoader;\n readonly clientAction?: ClientAction;\n /** Neutral boundary descriptors needed for soft-navigation interception; no server loader crosses. */\n readonly boundaries?: readonly BoundaryDescriptor[];\n}",
2294
+ "doc": "/** Client hooks populated by the generated route entry after a route chunk loads. */"
2295
+ },
2140
2296
  {
2141
2297
  "name": "ClientRouter",
2142
2298
  "kind": "interface",
2143
2299
  "package": "@nifrajs/web",
2144
- "signature": "export interface ClientRouter {\n /** Current state; stable reference between transitions (so `useSyncExternalStore` can bail). */\n snapshot: () => RouterState;\n /** Subscribe to transitions; returns an unsubscribe fn. */\n subscribe: (listener: () => void) => () => void;\n /** Navigate to a path: match → fetch loader data → publish. No-op for an unmatched path. */\n navigate: (path: string) => Promise<void>;\n /**\n * Submit an action (POST `body` to `action` in data mode): a redirect becomes a client\n * navigation; otherwise the data return is published as `actionData` and the active route's\n * loader is revalidated so the mutation is reflected. Pass `{ revalidate: false }` to SKIP that\n * revalidation - keep the current `data` and just publish the action's `actionData` (useful when\n * the action already returned everything that changed, saving the extra round-trip). A redirect\n * always loads its target regardless. Rejects on failure (caller falls back).\n */\n submit: (action: string, body: NonNullable<RequestInit[\"body\"]>, opts?: SubmitOptions) => Promise<void>;\n /**\n * Mark cached route data stale and refresh the active view. With `paths`, target exactly those\n * (e.g. the routes a mutation changed); without, invalidate the whole cache. The active route\n * refreshes immediately - refetched + republished - whenever it's in scope (an explicit list that\n * includes it, or an invalidate-all); other stale entries refetch lazily when next read (a\n * fetcher, or the next navigation/access). Rejects if the active refetch fails (like `navigate`).\n * The keyed substrate for targeted revalidation (the `X-Nifra-Revalidate` header) and fetchers.\n */\n invalidate: (paths?: readonly string[]) => Promise<void>;\n /**\n * Warm a path's chunk + loader data into a bounded one-shot cache without publishing state -\n * a later `navigate` to it transitions with no network round-trip. Best-effort: failures and\n * unmatched paths are no-ops. Wired to link hover/focus by `installHistory`.\n */\n prefetch: (path: string) => Promise<void>;\n /**\n * Get (lazily creating) the stable {@link Fetcher} for `key` - an independent, concurrent\n * load/submit state machine for row-level mutations or side-channel loads that must not disturb\n * the active view. The same `key` always returns the same fetcher (so a binding can subscribe to a\n * stable store). Keys are app-chosen and typically stable (e.g. a row id).\n */\n fetcher: (key: string) => Fetcher;\n /** All live fetchers - for a global busy view (e.g. a `useFetchers` binding). */\n fetchers: () => readonly Fetcher[];\n /** Subscribe to any-fetcher-changed (a transition on any fetcher, or a new one created) - backs a\n * `useFetchers` binding; returns an unsubscribe fn. */\n subscribeFetchers: (listener: () => void) => () => void;\n /** Match a path against the manifest patterns (exposed for history/link wiring). */\n match: (path: string) => RouteMatch | null;\n}",
2300
+ "signature": "export interface ClientRouter {\n /** Current state; stable reference between transitions (so `useSyncExternalStore` can bail). */\n snapshot: () => RouterState;\n /** Subscribe to transitions; returns an unsubscribe fn. */\n subscribe: (listener: () => void) => () => void;\n /** Navigate to a path: match → fetch loader data → publish. No-op for an unmatched path. */\n navigate: (path: string) => Promise<void>;\n /**\n * Submit an action (POST `body` to `action` in data mode): a redirect becomes a client\n * navigation; otherwise the data return is published as `actionData` and the active route's\n * loader is revalidated so the mutation is reflected. Pass `{ revalidate: false }` to SKIP that\n * revalidation - keep the current `data` and just publish the action's `actionData` (useful when\n * the action already returned everything that changed, saving the extra round-trip). A redirect\n * always loads its target regardless. Rejects on failure (caller falls back).\n */\n submit: (action: string, body: NonNullable<RequestInit[\"body\"]>, opts?: SubmitOptions) => Promise<void>;\n /** Run the initial route's client loader after the adapter has hydrated the SSR markup. */\n hydrate: () => Promise<void>;\n /**\n * Mark cached route data stale and refresh the active view. With `paths`, target exactly those\n * (e.g. the routes a mutation changed); without, invalidate the whole cache. The active route\n * refreshes immediately - refetched + republished - whenever it's in scope (an explicit list that\n * includes it, or an invalidate-all); other stale entries refetch lazily when next read (a\n * fetcher, or the next navigation/access). Rejects if the active refetch fails (like `navigate`).\n * The keyed substrate for targeted revalidation (the `X-Nifra-Revalidate` header) and fetchers.\n */\n invalidate: (paths?: readonly string[]) => Promise<void>;\n /**\n * Warm a path's chunk + loader data into a bounded one-shot cache without publishing state -\n * a later `navigate` to it transitions with no network round-trip. Best-effort: failures and\n * unmatched paths are no-ops. Wired to link hover/focus by `installHistory`.\n */\n prefetch: (path: string) => Promise<void>;\n /**\n * Get (lazily creating) the stable {@link Fetcher} for `key` - an independent, concurrent\n * load/submit state machine for row-level mutations or side-channel loads that must not disturb\n * the active view. The same `key` always returns the same fetcher (so a binding can subscribe to a\n * stable store). Keys are app-chosen and typically stable (e.g. a row id).\n */\n fetcher: (key: string) => Fetcher;\n /** All live fetchers - for a global busy view (e.g. a `useFetchers` binding). */\n fetchers: () => readonly Fetcher[];\n /** Subscribe to any-fetcher-changed (a transition on any fetcher, or a new one created) - backs a\n * `useFetchers` binding; returns an unsubscribe fn. */\n subscribeFetchers: (listener: () => void) => () => void;\n /** Match a path against the manifest patterns (exposed for history/link wiring). */\n match: (path: string) => RouteMatch | null;\n}",
2145
2301
  "doc": "/** The agnostic router store consumed by per-adapter Router bindings. */"
2146
2302
  },
2147
2303
  {
2148
2304
  "name": "ClientRouterOptions",
2149
2305
  "kind": "interface",
2150
2306
  "package": "@nifrajs/web",
2151
- "signature": "export interface ClientRouterOptions {\n readonly patterns: readonly RoutePattern[];\n readonly initial: RouterState;\n /** Override the loader-data fetch (tests inject a stub; defaults to a same-origin JSON GET). */\n readonly fetchData?: FetchRouteData;\n /** Ensure a route's code chunk is loaded before rendering (code-splitting). Awaited in parallel\n * with the loader data, so `pending` covers both. Omit when the bundle isn't split. */\n readonly loadModule?: (routeId: string) => Promise<void>;\n /** Terminal status → client route id. Generated entries populate this from `_404` and\n * `_<status>` files so soft navigation renders the same boundary as a hard request. */\n readonly statusRoutes?: Readonly<Record<number, string>>;\n /** routeId → the route's client-only search keys (its `searchClientKeys` export). When a soft\n * navigation stays on the same route + pathname and changes ONLY these keys, `navigate` publishes the\n * new URL WITHOUT re-running the loader (re-render, not revalidate). Populated lazily by the generated\n * entry's `loadModule` (so a route's keys are present once it has been visited, which is exactly when a\n * same-route nav can consult them). Omit ⇒ every search change revalidates (the safe default). */\n readonly searchClientKeys?: Readonly<Record<string, readonly string[]>>;\n}"
2307
+ "signature": "export interface ClientRouterOptions {\n readonly patterns: readonly RoutePattern[];\n readonly initial: RouterState;\n /** Override the loader-data fetch (tests inject a stub; defaults to a same-origin JSON GET). */\n readonly fetchData?: FetchRouteData;\n /** Ensure a route's code chunk is loaded before rendering (code-splitting). Awaited in parallel\n * with the loader data, so `pending` covers both. Omit when the bundle isn't split. */\n readonly loadModule?: (routeId: string) => Promise<void>;\n /** Terminal status → client route id. Generated entries populate this from `_404` and\n * `_<status>` files so soft navigation renders the same boundary as a hard request. */\n readonly statusRoutes?: Readonly<Record<number, string>>;\n /** routeId → the route's client-only search keys (its `searchClientKeys` export). When a soft\n * navigation stays on the same route + pathname and changes ONLY these keys, `navigate` publishes the\n * new URL WITHOUT re-running the loader (re-render, not revalidate). Populated lazily by the generated\n * entry's `loadModule` (so a route's keys are present once it has been visited, which is exactly when a\n * same-route nav can consult them). Omit ⇒ every search change revalidates (the safe default). */\n readonly searchClientKeys?: Readonly<Record<string, readonly string[]>>;\n /** routeId → client-only loader/action hooks, populated by the generated route entry. */\n readonly routeHooks?: Readonly<Record<string, ClientRouteHooks | undefined>>;\n}"
2152
2308
  },
2153
2309
  {
2154
2310
  "name": "ClientServerFn",
@@ -2425,6 +2581,13 @@
2425
2581
  "package": "@nifrajs/image",
2426
2582
  "signature": "export declare const CONTENT_TYPE: Record<OutputFormat, string>;"
2427
2583
  },
2584
+ {
2585
+ "name": "ContentFieldKey",
2586
+ "kind": "type",
2587
+ "package": "@nifrajs/content",
2588
+ "signature": "export type ContentFieldKey<Frontmatter extends Record<string, unknown>> = Extract<keyof Frontmatter, string>;",
2589
+ "doc": "/** A string frontmatter field name accepted by the index APIs. */"
2590
+ },
2428
2591
  {
2429
2592
  "name": "ContentPreference",
2430
2593
  "kind": "interface",
@@ -3048,7 +3211,7 @@
3048
3211
  "name": "CreateWebAppOptions",
3049
3212
  "kind": "interface",
3050
3213
  "package": "@nifrajs/web",
3051
- "signature": "export interface CreateWebAppOptions<Env = unknown> {\n readonly adapter: RenderAdapter;\n readonly manifest: Manifest;\n /** URL of the built client entry (module script) injected into every page. */\n readonly clientEntry: string;\n /** Default document title for all pages. */\n readonly title?: string;\n /**\n * Options for the underlying `server()` - `requestTimeoutMs`, `admission`, `gracefulSignals`, and\n * the rest of {@link ServerOptions}.\n *\n * Needed because the `Server` is constructed in here, so a caller has no other way to reach its\n * constructor: a page app could set no request timeout and no capacity gate, which are exactly the\n * two knobs a production readiness check looks for. An SSR app wants them MORE than a backend does -\n * a render is slow and allocation-heavy, so a burst that a JSON API would absorb is the one that\n * exhausts the pod.\n *\n * Applies to the whole app, {@link mounts} and the {@link api} auto-mount included: the capacity gate\n * sits at the fetch entry, ahead of the request hooks those are dispatched from.\n */\n readonly server?: ServerOptions;\n /**\n * Runs against the app BEFORE any page route is registered - the seam for `securityHeaders()`,\n * `requestId()`, `logger()`, a rate limit, or anything else applied with `use`.\n *\n * ```ts\n * createWebApp({\n * …,\n * use: (app) => {\n * app.use(securityHeaders())\n * app.use(requestId())\n * },\n * })\n * ```\n *\n * A callback rather than an array because `use` is overloaded - `Middleware`, `IdentityPlugin`,\n * `ContextPlugin` - and only the real call site instantiates the right overload. The return value\n * is ignored: this is for cross-cutting concerns, not for declaring routes (declare those on the\n * returned app, where they get their types).\n *\n * **Why the timing matters.** `beforeHandle`, `afterHandle`, `around`, `derive`/`decorate`, and\n * `onError` are snapshotted into each route AS IT IS DECLARED, and `createWebApp` declares every\n * page (plus the `/*` catch-all) before it returns - so a caller's `app.use(…)` afterwards binds\n * them to nothing, silently. `requestId()` is exactly that case: it is a `derive`, so applied late\n * it leaves every page without `c.requestId`. Route assurance evidence is order-scoped the same\n * way, so a late `securityHeaders()` leaves the pages unable to PROVE the header to `nifra assure`\n * even though it does still set it.\n *\n * `onRequest`/`onResponse` (and the response header/body hooks) are app-global arrays read at\n * request time, so those alone DO work when added late. Using this seam for everything avoids\n * having to remember which is which.\n *\n * Runs ahead of the {@link mounts} / {@link api} request hooks, so an `onRequest` middleware guards\n * a mounted auth handler too.\n *\n * A `ContextPlugin` applied here takes runtime effect but cannot widen the declared return type of\n * this function, so `c.requestId` is not typed on routes you declare afterwards. Named plugins are\n * idempotent, so `app.use(requestId())` on the returned app recovers the TYPE without applying the\n * plugin a second time.\n */\n readonly use?: (app: ReturnType<typeof server<Env>>) => void;\n /** Injected into each loader's `ctx.api` - typically an `inProcessClient(app)` (typed\n * per-route via `@nifrajs/client`'s `createRoutes`). Opaque to the core.\n *\n * **Auto-mount.** Every `inProcessClient(backend)` exposes the symbol-keyed platform-aware backend\n * mount interface from `@nifrajs/core/mount`; `createWebApp` also serves that backend over HTTP at\n * {@link apiPrefix} (default `/api`): a request whose pathname starts with the prefix is dispatched\n * before page routing with the same `env`/`waitUntil` platform context, and the backend's `Response`\n * is returned untouched. The mount runs in `nifra dev` too. Pass `apiPrefix: \"\"` to disable it. */\n readonly api?: unknown;\n /** HTTP path prefix the {@link api} backend is auto-mounted at (default `\"/api\"`). A request whose\n * pathname is exactly the prefix or starts with `prefix + \"/\"` is dispatched to the backend before\n * page routing; the backend therefore defines its routes at the **full** path (`server().post(\"/api/\n * sync\", …)`), matching the in-process `inProcessClient` call sites. Set to `\"\"` to disable the\n * auto-mount entirely (the app serves pages only and `api` stays a loader-only `ctx.api`). Mounting\n * is also a no-op when `api` does not expose the symbol mount. */\n readonly apiPrefix?: string;\n /**\n * Strip {@link apiPrefix} from the pathname before dispatching to `api` (default `false`).\n *\n * The default suits a backend that declares FULL paths (`server().post(\"/api/sync\", …)`), which is\n * right when it is only ever mounted here. Set this when the backend declares its routes WITHOUT the\n * prefix because it also runs standalone behind its own shell, so its paths cannot carry a prefix that\n * only exists when it is mounted. Without it every request 404s inside the backend, and the workaround\n * is a `Proxy` that rewrites each URL.\n */\n readonly apiStrip?: boolean;\n /**\n * Sub-apps mounted ahead of page routing - an auth handler, a webhook receiver, a stack's routes.\n *\n * Structural on purpose: anything with `{ path, app: { fetch } }` fits, so a library that exposes its\n * routes as such a list mounts as `mounts: theirRoutes` without `@nifrajs/web` taking a dependency on\n * it. `better-auth` is the motivating case - it is not a `backend` route, so `/api/auth/*` used to 404\n * silently.\n *\n * Tried longest-path-first and BEFORE the `api` mount, so a mount at `/api/auth` wins over a backend\n * at `/api` no matter which was declared first. `stripPrefix` is the per-mount form of {@link apiStrip}:\n * leave it off to pass the full path through.\n */\n readonly mounts?: ReadonlyArray<{\n readonly path: string;\n readonly app: {\n fetch(request: Request): Response | Promise<Response>;\n };\n readonly stripPrefix?: boolean;\n }>;\n /** Secret for **draft / preview mode** (see `enableDraft`). When set, a request carrying a valid\n * signed `__nifra_draft` cookie gets `ctx.draft === true` in loaders/actions (else always `false`).\n * Pair with `withISR({ draftSecret })` so editors bypass the cache. Omit to disable draft mode. */\n readonly draftSecret?: string;\n /** Per-route chunk URLs (`buildClient`'s `BuildManifest.routes`) - `routeId → [layout chunks…, own\n * chunk]`. When present, each page `modulepreload`s its matched route's chunks alongside the entry,\n * so the route code downloads in parallel (no entry→route-chunk waterfall). Omit ⇒ entry-only. */\n readonly routePreload?: Readonly<Record<string, readonly string[]>>;\n /** The app's bundled stylesheet URLs (`buildClient`'s `BuildManifest.css`) - the aggregate, injected\n * as `<link rel=\"stylesheet\">` in a page's `<head>`. Used as the fallback for any route absent from\n * {@link routeStyles}. Omit ⇒ no links (dev, where Vite injects CSS, or a CSS-free app). */\n readonly styles?: readonly string[];\n /** Per-route stylesheet URLs (`buildClient`'s `BuildManifest.routeStyles`) - `routeId → [chain CSS]`.\n * When a matched route has an entry here, only those (its layout chain + own CSS) are linked instead\n * of the aggregate `styles`, so a page ships only the CSS it uses. An empty array ⇒ no `<link>` (the\n * page imports no CSS). Routes absent here fall back to `styles`. Omit ⇒ always use `styles`. */\n readonly routeStyles?: Readonly<Record<string, readonly string[]>>;\n /** SSG: the prerendered-path set (e.g. `enumerateStaticRoutes(routes).paths` or the build's\n * `prerendered.json`). Injected as `window.__NIFRA_PRERENDERED__` on every page so a client soft-nav\n * into a prerendered route fetches its static `_data.json` instead of hitting the worker. */\n readonly prerenderedPaths?: readonly string[];\n /** Publish the project's `AGENTS.md` inside `/llms.txt` and `/llms-full.txt`. **Off by default**:\n * those endpoints are public and unauthenticated, while `AGENTS.md` is a repo file written for the\n * team - unreleased feature names, internal hostnames, and \"don't touch X yet\" notes live there\n * routinely. Turn it on only for a repo whose guidelines you would publish as a page. */\n readonly publishLocalGuidelines?: boolean;\n /** SSG: per dynamic route pattern, its `getStaticPaths` `fallback` (from `enumerateStaticRoutes` or\n * the build's `prerendered.json`). A route mapped to `\"404\"` rejects any path NOT in\n * `prerenderedPaths` with the 404 page - the unlisted path simply doesn't exist. `\"ssr\"` (the\n * default for unmapped routes) renders unlisted paths on-demand. */\n readonly staticFallbacks?: Readonly<Record<string, \"ssr\" | \"404\">>;\n /** Observe every loader/action failure - for error-reporting plugins (Sentry-style). Called for\n * real throws (not control-flow `Response`s like `redirect`), **before** the nearest `_error`\n * boundary renders / a soft-nav 500 / a rethrow - so it sees errors that the boundary would\n * otherwise hide. Observation only; its own throws are swallowed so a faulty reporter can't break\n * rendering. (`beforeLoader` is intentionally omitted - the core HTTP hooks already cover\n * pre-request work.) */\n readonly onLoaderError?: (error: unknown, ctx: {\n readonly request: Request;\n readonly params: Readonly<Record<string, string>>;\n readonly route: string;\n }) => void;\n}"
3214
+ "signature": "export interface CreateWebAppOptions<Env = unknown> {\n readonly adapter: RenderAdapter;\n readonly manifest: Manifest;\n /** URL of the built client entry (module script) injected into every page. */\n readonly clientEntry: string;\n /** Default document title for all pages. */\n readonly title?: string;\n /**\n * Options for the underlying `server()` - `requestTimeoutMs`, `admission`, `gracefulSignals`, and\n * the rest of {@link ServerOptions}.\n *\n * Needed because the `Server` is constructed in here, so a caller has no other way to reach its\n * constructor: a page app could set no request timeout and no capacity gate, which are exactly the\n * two knobs a production readiness check looks for. An SSR app wants them MORE than a backend does -\n * a render is slow and allocation-heavy, so a burst that a JSON API would absorb is the one that\n * exhausts the pod.\n *\n * Applies to the whole app, {@link mounts} and the {@link api} auto-mount included: the capacity gate\n * sits at the fetch entry, ahead of the request hooks those are dispatched from.\n */\n readonly server?: ServerOptions;\n /**\n * Runs against the app BEFORE any page route is registered - the seam for `securityHeaders()`,\n * `requestId()`, `logger()`, a rate limit, or anything else applied with `use`.\n *\n * ```ts\n * createWebApp({\n * …,\n * use: (app) => {\n * app.use(securityHeaders())\n * app.use(requestId())\n * },\n * })\n * ```\n *\n * A callback rather than an array because `use` is overloaded - `Middleware`, `IdentityPlugin`,\n * `ContextPlugin` - and only the real call site instantiates the right overload. The return value\n * is ignored: this is for cross-cutting concerns, not for declaring routes (declare those on the\n * returned app, where they get their types).\n *\n * **Why the timing matters.** `beforeHandle`, `afterHandle`, `around`, `derive`/`decorate`, and\n * `onError` are snapshotted into each route AS IT IS DECLARED, and `createWebApp` declares every\n * page (plus the `/*` catch-all) before it returns - so a caller's `app.use(…)` afterwards binds\n * them to nothing, silently. `requestId()` is exactly that case: it is a `derive`, so applied late\n * it leaves every page without `c.requestId`. Route assurance evidence is order-scoped the same\n * way, so a late `securityHeaders()` leaves the pages unable to PROVE the header to `nifra assure`\n * even though it does still set it.\n *\n * `onRequest`/`onResponse` (and the response header/body hooks) are app-global arrays read at\n * request time, so those alone DO work when added late. Using this seam for everything avoids\n * having to remember which is which.\n *\n * Runs ahead of the {@link mounts} / {@link api} request hooks, so an `onRequest` middleware guards\n * a mounted auth handler too.\n *\n * A `ContextPlugin` applied here takes runtime effect but cannot widen the declared return type of\n * this function, so `c.requestId` is not typed on routes you declare afterwards. Named plugins are\n * idempotent, so `app.use(requestId())` on the returned app recovers the TYPE without applying the\n * plugin a second time.\n */\n readonly use?: (app: ReturnType<typeof server<Env>>) => void;\n /** Injected into each loader's `ctx.api` - typically an `inProcessClient(app)` (typed\n * per-route via `@nifrajs/client`'s `createRoutes`). Opaque to the core.\n *\n * **Auto-mount.** Every `inProcessClient(backend)` exposes the symbol-keyed platform-aware backend\n * mount interface from `@nifrajs/core/mount`; `createWebApp` also serves that backend over HTTP at\n * {@link apiPrefix} (default `/api`): a request whose pathname starts with the prefix is dispatched\n * before page routing with the same `env`/`waitUntil` platform context, and the backend's `Response`\n * is returned untouched. The mount runs in `nifra dev` too. Pass `apiPrefix: \"\"` to disable it. */\n readonly api?: unknown;\n /** HTTP path prefix the {@link api} backend is auto-mounted at (default `\"/api\"`). A request whose\n * pathname is exactly the prefix or starts with `prefix + \"/\"` is dispatched to the backend before\n * page routing; the backend therefore defines its routes at the **full** path (`server().post(\"/api/\n * sync\", …)`), matching the in-process `inProcessClient` call sites. Set to `\"\"` to disable the\n * auto-mount entirely (the app serves pages only and `api` stays a loader-only `ctx.api`). Mounting\n * is also a no-op when `api` does not expose the symbol mount. */\n readonly apiPrefix?: string;\n /**\n * Strip {@link apiPrefix} from the pathname before dispatching to `api` (default `false`).\n *\n * The default suits a backend that declares FULL paths (`server().post(\"/api/sync\", …)`), which is\n * right when it is only ever mounted here. Set this when the backend declares its routes WITHOUT the\n * prefix because it also runs standalone behind its own shell, so its paths cannot carry a prefix that\n * only exists when it is mounted. Without it every request 404s inside the backend, and the workaround\n * is a `Proxy` that rewrites each URL.\n */\n readonly apiStrip?: boolean;\n /**\n * Sub-apps mounted ahead of page routing - an auth handler, a webhook receiver, a stack's routes.\n *\n * Structural on purpose: anything with `{ path, app: { fetch } }` fits, so a library that exposes its\n * routes as such a list mounts as `mounts: theirRoutes` without `@nifrajs/web` taking a dependency on\n * it. `better-auth` is the motivating case - it is not a `backend` route, so `/api/auth/*` used to 404\n * silently.\n *\n * Tried longest-path-first and BEFORE the `api` mount, so a mount at `/api/auth` wins over a backend\n * at `/api` no matter which was declared first. `stripPrefix` is the per-mount form of {@link apiStrip}:\n * leave it off to pass the full path through.\n */\n readonly mounts?: ReadonlyArray<{\n readonly path: string;\n readonly app: {\n fetch(request: Request): Response | Promise<Response>;\n };\n readonly stripPrefix?: boolean;\n }>;\n /** Secret for **draft / preview mode** (see `enableDraft`). When set, a request carrying a valid\n * signed `__nifra_draft` cookie gets `ctx.draft === true` in loaders/actions (else always `false`).\n * Pair with `withISR({ draftSecret })` so editors bypass the cache. Omit to disable draft mode. */\n readonly draftSecret?: string;\n /** Per-route chunk URLs (`buildClient`'s `BuildManifest.routes`) - `routeId → [layout chunks…, own\n * chunk]`. When present, each page `modulepreload`s its matched route's chunks alongside the entry,\n * so the route code downloads in parallel (no entry→route-chunk waterfall). Omit ⇒ entry-only. */\n readonly routePreload?: Readonly<Record<string, readonly string[]>>;\n /** The app's bundled stylesheet URLs (`buildClient`'s `BuildManifest.css`) - the aggregate, injected\n * as `<link rel=\"stylesheet\">` in a page's `<head>`. Used as the fallback for any route absent from\n * {@link routeStyles}. Omit ⇒ no links (dev, where Vite injects CSS, or a CSS-free app). */\n readonly styles?: readonly string[];\n /** Per-route stylesheet URLs (`buildClient`'s `BuildManifest.routeStyles`) - `routeId → [chain CSS]`.\n * When a matched route has an entry here, only those (its layout chain + own CSS) are linked instead\n * of the aggregate `styles`, so a page ships only the CSS it uses. An empty array ⇒ no `<link>` (the\n * page imports no CSS). Routes absent here fall back to `styles`. Omit ⇒ always use `styles`. */\n readonly routeStyles?: Readonly<Record<string, readonly string[]>>;\n /** SSG: the prerendered-path set (e.g. `enumerateStaticRoutes(routes).paths` or the build's\n * `prerendered.json`). Injected as `window.__NIFRA_PRERENDERED__` on every page so a client soft-nav\n * into a prerendered route fetches its static `_data.json` instead of hitting the worker. */\n readonly prerenderedPaths?: readonly string[];\n /** Publish the project's `AGENTS.md` inside `/llms.txt` and `/llms-full.txt`. **Off by default**:\n * those endpoints are public and unauthenticated, while `AGENTS.md` is a repo file written for the\n * team - unreleased feature names, internal hostnames, and \"don't touch X yet\" notes live there\n * routinely. Turn it on only for a repo whose guidelines you would publish as a page. */\n readonly publishLocalGuidelines?: boolean;\n /** SSG: per dynamic route pattern, its `getStaticPaths` `fallback` (from `enumerateStaticRoutes` or\n * the build's `prerendered.json`). A route mapped to `\"404\"` rejects any path NOT in\n * `prerenderedPaths` with the 404 page - the unlisted path simply doesn't exist. `\"ssr\"` (the\n * default for unmapped routes) renders unlisted paths on-demand. */\n readonly staticFallbacks?: Readonly<Record<string, \"ssr\" | \"404\">>;\n /** In-memory reference cache for explicitly `static` boundary values. It never persists payloads\n * across processes; operated/durable cache implementations stay outside the public framework. */\n readonly staticBoundaryCache?: import(\"./boundary.js\").StaticBoundaryCache;\n /** Observe every loader/action failure - for error-reporting plugins (Sentry-style). Called for\n * real throws (not control-flow `Response`s like `redirect`), **before** the nearest `_error`\n * boundary renders / a soft-nav 500 / a rethrow - so it sees errors that the boundary would\n * otherwise hide. Observation only; its own throws are swallowed so a faulty reporter can't break\n * rendering. (`beforeLoader` is intentionally omitted - the core HTTP hooks already cover\n * pre-request work.) */\n readonly onLoaderError?: (error: unknown, ctx: {\n readonly request: Request;\n readonly params: Readonly<Record<string, string>>;\n readonly route: string;\n }) => void;\n}"
3052
3215
  },
3053
3216
  {
3054
3217
  "name": "createWebSocketHub",
@@ -3117,6 +3280,13 @@
3117
3280
  "signature": "export declare function cssModulesBunPlugin(generate: \"dom\" | \"ssr\"): BunPlugin;",
3118
3281
  "doc": "/**\n * The CSS Modules Bun plugin. `\"dom\"` → the `.module.css` import becomes the class map AND emits the\n * scoped stylesheet as a virtual `?nifra-css-module` module that `Bun.build`'s CSS bundler folds into\n * the app stylesheet. `\"ssr\"` → the class map only (no CSS; the scoped names match the client build).\n * Tolerates a trailing `?query` on the path (dev servers append one to bust Bun's import cache).\n */"
3119
3282
  },
3283
+ {
3284
+ "name": "CtxSet",
3285
+ "kind": "type",
3286
+ "package": "@nifrajs/core",
3287
+ "signature": "export type CtxSet = ResponseControls & {\n _headers?: Record<string, string>;\n /** Accumulated `Set-Cookie` values - a list, since a `Record` would collapse multiple cookies. */\n _cookies?: string[];\n};",
3288
+ "doc": "/** `ctx.set` carrying the lazy backings (`_headers`, `_cookies`) so `toResponse` can skip allocating\n * anything when no handler touched `c.set.*`. Server-internal. */"
3289
+ },
3120
3290
  {
3121
3291
  "name": "CURSOR_MCP_JSON_PATH",
3122
3292
  "kind": "const",
@@ -3984,6 +4154,46 @@
3984
4154
  "package": "@nifrajs/core",
3985
4155
  "signature": "export type DurableRecordKind = \"effect\" | \"approval\" | \"saga\";"
3986
4156
  },
4157
+ {
4158
+ "name": "DynamicBoundary",
4159
+ "kind": "type",
4160
+ "package": "@nifrajs/web",
4161
+ "signature": "export type DynamicBoundary<Data, UI> = BoundaryBase<Data, UI> & {\n readonly mode: \"dynamic\";\n readonly load?: (ctx: BoundaryRequestCtx) => Data | Promise<Data>;\n};"
4162
+ },
4163
+ {
4164
+ "name": "DynamicBoundaryBatch",
4165
+ "kind": "interface",
4166
+ "package": "@nifrajs/web",
4167
+ "signature": "export interface DynamicBoundaryBatch {\n readonly initial: BoundaryStates;\n readonly pending: ReadonlyArray<PendingBoundary>;\n /** Resolves to final per-boundary states for non-streaming consumers and tests. */\n readonly complete: Promise<BoundaryStates>;\n}",
4168
+ "doc": "/** Runtime handles for a concurrent boundary batch. `initial` is renderable immediately. */"
4169
+ },
4170
+ {
4171
+ "name": "EdgeContext",
4172
+ "kind": "interface",
4173
+ "package": "@nifrajs/edge",
4174
+ "signature": "export interface EdgeContext<Path extends string = string, Body = unknown> {\n /** The raw `Request`. */\n readonly request: Request;\n /** Path parameters, typed from the route pattern (`/users/:id` -> `{ id: string }`). */\n readonly params: Params<Path>;\n /** The parsed, schema-validated body, or `undefined` on a route with no body schema. */\n readonly body: Body;\n /** The query string parsed to an object, computed on demand. */\n query(): Record<string, QueryValue>;\n /** Read a request header (case-insensitive), or `null`. */\n header(name: string): string | null;\n}",
4175
+ "doc": "/** The request handed to a route. Compact by design: no cookies, no response builder - return a\n * value (rendered as JSON) or a `Response` for full control. */"
4176
+ },
4177
+ {
4178
+ "name": "EdgeHandler",
4179
+ "kind": "type",
4180
+ "package": "@nifrajs/edge",
4181
+ "signature": "export type EdgeHandler<Path extends string = string, Body = unknown> = (c: EdgeContext<Path, Body>) => unknown | Promise<unknown>;",
4182
+ "doc": "/** A route handler: returns a value (rendered as JSON), a `Response`, or a promise of either. A\n * thrown `Response` is sent as-is; any other throw becomes a `500`. */"
4183
+ },
4184
+ {
4185
+ "name": "EdgeOptions",
4186
+ "kind": "interface",
4187
+ "package": "@nifrajs/edge",
4188
+ "signature": "export interface EdgeOptions {\n /** Maximum request body size in bytes before a `413`. Defaults to 1 MB. */\n readonly maxBodyBytes?: number;\n /** Prototype-poisoning policy for JSON bodies. Defaults to `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n}",
4189
+ "doc": "/** Construction-time options. Both mirror `@nifrajs/core`'s `ServerOptions` defaults. */"
4190
+ },
4191
+ {
4192
+ "name": "EdgeServer",
4193
+ "kind": "class",
4194
+ "package": "@nifrajs/edge",
4195
+ "signature": "export declare class EdgeServer {\n #private;\n constructor(options?: EdgeOptions);\n get<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n head<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n options<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n post<const Path extends string, Body>(path: Path, schema: BodySchema<Body>, handler: EdgeHandler<Path, Body>): this;\n post<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n put<const Path extends string, Body>(path: Path, schema: BodySchema<Body>, handler: EdgeHandler<Path, Body>): this;\n put<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n patch<const Path extends string, Body>(path: Path, schema: BodySchema<Body>, handler: EdgeHandler<Path, Body>): this;\n patch<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n delete<const Path extends string, Body>(path: Path, schema: BodySchema<Body>, handler: EdgeHandler<Path, Body>): this;\n delete<const Path extends string>(path: Path, handler: EdgeHandler<Path>): this;\n /** The fetch handler. Not bound - use {@link toFetchHandler} (re-exported) or wrap it yourself. */\n fetch: (request: Request) => Promise<Response>;\n}"
4196
+ },
3987
4197
  {
3988
4198
  "name": "effect",
3989
4199
  "kind": "function",
@@ -4182,6 +4392,12 @@
4182
4392
  "package": "@nifrajs/core",
4183
4393
  "signature": "export declare const EMPTY_PARAMS: Record<string, string>;"
4184
4394
  },
4395
+ {
4396
+ "name": "EMPTY_RESPONSE_CONTROLS",
4397
+ "kind": "const",
4398
+ "package": "@nifrajs/core",
4399
+ "signature": "export declare const EMPTY_RESPONSE_CONTROLS: CtxSet;"
4400
+ },
4185
4401
  {
4186
4402
  "name": "enableDraft",
4187
4403
  "kind": "function",
@@ -4678,6 +4894,20 @@
4678
4894
  "signature": "export type FetchRouteData = (path: string, match: RouteMatch, signal?: AbortSignal, navigation?: {\n readonly from: string;\n readonly retain: readonly number[];\n}) => Promise<unknown>;",
4679
4895
  "doc": "/** How a router fetches a route's loader data on navigation. `signal` aborts a superseded fetch\n * (and its deferred stream). */"
4680
4896
  },
4897
+ {
4898
+ "name": "fetchTransport",
4899
+ "kind": "function",
4900
+ "package": "@nifrajs/proxy",
4901
+ "signature": "export declare function fetchTransport(options?: FetchTransportOptions): ProxyTransport;",
4902
+ "doc": "/**\n * Create the portable `fetch`-backed {@link ProxyTransport} - the default off Node, and the fallback\n * everywhere the undici transport cannot be used. `redirect: \"manual\"` is not a preference: following\n * an upstream redirect would let the upstream choose the proxy's next destination, so it is pinned\n * here and a 3xx is relayed to the caller untouched.\n *\n * Pass it explicitly only to tune {@link FetchTransportOptions.bodyTimeoutMs} or to pin the choice\n * on Node; leaving `transport` unset picks the right one per runtime.\n */"
4903
+ },
4904
+ {
4905
+ "name": "FetchTransportOptions",
4906
+ "kind": "interface",
4907
+ "package": "@nifrajs/proxy",
4908
+ "signature": "export interface FetchTransportOptions {\n /**\n * Milliseconds of silence tolerated *within* the response body before the relayed stream is\n * errored and the upstream read cancelled. `createProxy`'s own `timeoutMs` only covers the wait\n * for response headers - after the status is relayed a `504` is no longer sendable - so this is\n * what protects against a body that starts and then stalls. Default `30_000` (undici's\n * `bodyTimeout` default, so the choice of transport does not change the bound); `0` disables it.\n */\n readonly bodyTimeoutMs?: number;\n}",
4909
+ "doc": "/** Options for {@link fetchTransport}. */"
4910
+ },
4681
4911
  {
4682
4912
  "name": "FieldKey",
4683
4913
  "kind": "type",
@@ -4918,6 +5148,20 @@
4918
5148
  "signature": "export declare function fromBaked<Frontmatter>(baked: BakedCollection<Frontmatter>): StaticCollection<Frontmatter>;",
4919
5149
  "doc": "/**\n * Rehydrate a baked collection into a read-only `all()`/`get()` collection - fs-free, edge-safe. The\n * entries were validated when baked (build output, trusted), so they're served as-is. `get` is O(1).\n */"
4920
5150
  },
5151
+ {
5152
+ "name": "fromBakedIndex",
5153
+ "kind": "function",
5154
+ "package": "@nifrajs/content",
5155
+ "signature": "export declare function fromBakedIndex<Frontmatter extends Record<string, unknown>, By extends ContentFieldKey<Frontmatter>>(baked: BakedCollectionIndex<Frontmatter, By>): IndexedCollection<Frontmatter, By>;",
5156
+ "doc": "/** Rehydrate a JSON-serialized index at the edge without filesystem access. */"
5157
+ },
5158
+ {
5159
+ "name": "fromBakedJoin",
5160
+ "kind": "function",
5161
+ "package": "@nifrajs/content",
5162
+ "signature": "export declare function fromBakedJoin<Left extends Record<string, unknown>, Right extends Record<string, unknown>, On extends SharedKey<Left, Right>, Cardinality extends JoinCardinality>(baked: BakedCollectionJoin<Left, Right, On, Cardinality>): IndexedJoin<Left, Right, On, Cardinality>;",
5163
+ "doc": "/** Rehydrate a deterministic join artifact. */"
5164
+ },
4921
5165
  {
4922
5166
  "name": "fromTypeBox",
4923
5167
  "kind": "function",
@@ -4995,8 +5239,7 @@
4995
5239
  "name": "generateServerManifest",
4996
5240
  "kind": "function",
4997
5241
  "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 */"
5242
+ "signature": "export declare function generateServerManifest(manifest: Manifest, options: GenerateServerManifestOptions): string;"
5000
5243
  },
5001
5244
  {
5002
5245
  "name": "GenerateServerManifestOptions",
@@ -5462,6 +5705,13 @@
5462
5705
  "signature": "export declare const IDEMPOTENT_REPLAY_HEADER = \"x-nifra-idempotent-replay\";",
5463
5706
  "doc": "/** Header stamped on a replayed response so clients/proxies can tell a replay from a fresh run. */"
5464
5707
  },
5708
+ {
5709
+ "name": "IDENTITY_SENSITIVE_PACKAGES",
5710
+ "kind": "const",
5711
+ "package": "@nifrajs/core",
5712
+ "signature": "export declare const IDENTITY_SENSITIVE_PACKAGES: readonly string[];",
5713
+ "doc": "/**\n * Packages whose duplication is a defect rather than a waste. Each keeps module-scoped state that\n * every importer must share - a hook dispatcher, a renderer's options global, a class identity - so a\n * second physical copy breaks behaviour instead of merely costing bytes. Anything scoped `@nifrajs/`\n * qualifies for the same reason and is matched by pattern.\n */"
5714
+ },
5465
5715
  {
5466
5716
  "name": "identityLoader",
5467
5717
  "kind": "const",
@@ -5646,6 +5896,75 @@
5646
5896
  "package": "@nifrajs/testing",
5647
5897
  "signature": "export interface IncidentReplayResult {\n readonly reproduced: boolean;\n readonly status: number;\n readonly expectedStatus: number;\n readonly statusMatches: boolean;\n /** null when shape was not checked. */\n readonly shapeMatches: boolean | null;\n}"
5648
5898
  },
5899
+ {
5900
+ "name": "indexCollection",
5901
+ "kind": "function",
5902
+ "package": "@nifrajs/content",
5903
+ "signature": "export declare function indexCollection<Frontmatter extends Record<string, unknown>, By extends ContentFieldKey<Frontmatter>>(baked: BakedCollection<Frontmatter>, options: IndexOptions<Frontmatter, By>): IndexedCollection<Frontmatter, By>;",
5904
+ "doc": "/** Build a deterministic typed index from already validated baked entries. */"
5905
+ },
5906
+ {
5907
+ "name": "IndexedCollection",
5908
+ "kind": "interface",
5909
+ "package": "@nifrajs/content",
5910
+ "signature": "export interface IndexedCollection<Frontmatter extends Record<string, unknown>, By extends ContentFieldKey<Frontmatter>> {\n readonly entries: ReadonlyArray<Entry<Frontmatter>>;\n readonly by: By;\n readonly baked: BakedCollectionIndex<Frontmatter, By>;\n /** O(1) lookup after the build/rehydration map is constructed. Missing keys return no rows. */\n readonly lookup: (value: Frontmatter[By]) => ReadonlyArray<Entry<Frontmatter>>;\n /** All entries in the index's default stable order. */\n readonly all: () => ReadonlyArray<Entry<Frontmatter>>;\n readonly query: (options?: IndexQueryOptions<Frontmatter>) => IndexPage<Frontmatter>;\n}",
5911
+ "doc": "/** A build-time/runtime index over validated, baked entries. */"
5912
+ },
5913
+ {
5914
+ "name": "IndexedJoin",
5915
+ "kind": "interface",
5916
+ "package": "@nifrajs/content",
5917
+ "signature": "export interface IndexedJoin<Left extends Record<string, unknown>, Right extends Record<string, unknown>, On extends SharedKey<Left, Right>, Cardinality extends JoinCardinality> {\n readonly entries: ReadonlyArray<JoinedRow<Left, Right, Cardinality>>;\n readonly baked: BakedCollectionJoin<Left, Right, On, Cardinality>;\n}",
5918
+ "doc": "/** A deterministic cross-collection join. No database or network layer is involved. */"
5919
+ },
5920
+ {
5921
+ "name": "IndexOptions",
5922
+ "kind": "interface",
5923
+ "package": "@nifrajs/content",
5924
+ "signature": "export interface IndexOptions<Frontmatter extends Record<string, unknown>, By extends ContentFieldKey<Frontmatter>> {\n readonly by: By;\n readonly sort?: IndexSort<Frontmatter>;\n}"
5925
+ },
5926
+ {
5927
+ "name": "IndexPage",
5928
+ "kind": "interface",
5929
+ "package": "@nifrajs/content",
5930
+ "signature": "export interface IndexPage<Frontmatter extends Record<string, unknown>> {\n readonly items: ReadonlyArray<Entry<Frontmatter>>;\n readonly nextCursor?: string;\n}",
5931
+ "doc": "/** One page from an indexed collection. `nextCursor` is absent on the final page. */"
5932
+ },
5933
+ {
5934
+ "name": "IndexQueryOptions",
5935
+ "kind": "interface",
5936
+ "package": "@nifrajs/content",
5937
+ "signature": "export interface IndexQueryOptions<Frontmatter extends Record<string, unknown>> {\n readonly where?: IndexWhere<Frontmatter>;\n readonly range?: IndexRanges<Frontmatter>;\n readonly sort?: IndexSort<Frontmatter>;\n readonly cursor?: string;\n /** Defaults to 20; values above 100 are rejected to bound request-driven work. */\n readonly limit?: number;\n}",
5938
+ "doc": "/** A bounded, cursor-based index query. The cursor is opaque and tied to its filter + sort. */"
5939
+ },
5940
+ {
5941
+ "name": "IndexRange",
5942
+ "kind": "type",
5943
+ "package": "@nifrajs/content",
5944
+ "signature": "export type IndexRange<Value> = [Extract<Value, string | number>] extends [never] ? never : {\n readonly gt?: Extract<Value, string | number>;\n readonly gte?: Extract<Value, string | number>;\n readonly lt?: Extract<Value, string | number>;\n readonly lte?: Extract<Value, string | number>;\n};",
5945
+ "doc": "/** Range operators are available for string and number fields only. */"
5946
+ },
5947
+ {
5948
+ "name": "IndexRanges",
5949
+ "kind": "type",
5950
+ "package": "@nifrajs/content",
5951
+ "signature": "export type IndexRanges<Frontmatter extends Record<string, unknown>> = Partial<{\n [K in ContentFieldKey<Frontmatter>]: IndexRange<Frontmatter[K]>;\n}>;",
5952
+ "doc": "/** Typed range filters derived from the collection's frontmatter. */"
5953
+ },
5954
+ {
5955
+ "name": "IndexSort",
5956
+ "kind": "interface",
5957
+ "package": "@nifrajs/content",
5958
+ "signature": "export interface IndexSort<Frontmatter extends Record<string, unknown>> {\n readonly field: ContentFieldKey<Frontmatter>;\n readonly dir: \"asc\" | \"desc\";\n}",
5959
+ "doc": "/** A declared sort order. Ties are always broken by slug, then source order. */"
5960
+ },
5961
+ {
5962
+ "name": "IndexWhere",
5963
+ "kind": "type",
5964
+ "package": "@nifrajs/content",
5965
+ "signature": "export type IndexWhere<Frontmatter extends Record<string, unknown>> = Partial<{\n [K in ContentFieldKey<Frontmatter>]: Frontmatter[K];\n}>;",
5966
+ "doc": "/** Field-equality filters. Arbitrary predicates are intentionally not part of baked indexes. */"
5967
+ },
5649
5968
  {
5650
5969
  "name": "InertScriptType",
5651
5970
  "kind": "type",
@@ -5776,6 +6095,12 @@
5776
6095
  "package": "@nifrajs/web",
5777
6096
  "signature": "export interface InstallHistoryOptions {\n /** Full-page fallback when a client navigation can't proceed (default: `location.assign`). */\n readonly fallback?: (path: string) => void;\n}"
5778
6097
  },
6098
+ {
6099
+ "name": "InterceptBoundary",
6100
+ "kind": "type",
6101
+ "package": "@nifrajs/web",
6102
+ "signature": "export type InterceptBoundary<Data, UI> = BoundaryBase<Data, UI> & {\n readonly mode: {\n readonly intercept: string;\n };\n readonly load?: (ctx: BoundaryRequestCtx) => Data | Promise<Data>;\n};"
6103
+ },
5779
6104
  {
5780
6105
  "name": "InvariantExecutor",
5781
6106
  "kind": "type",
@@ -5904,12 +6229,26 @@
5904
6229
  "signature": "export declare function islandState(state: Record<string, unknown>): string;",
5905
6230
  "doc": "/**\n * Server-side helper: the value for a host's `data-island-state` attribute. Plain JSON - emit it\n * through an escaping renderer (`@nifrajs/web-vanilla`'s `html` escapes quotes in attributes), e.g.\n * `html\\`<div data-island=\"compare\" data-island-state=\"${islandState({ count })}\">…\\``.\n */"
5906
6231
  },
6232
+ {
6233
+ "name": "IslandStrategy",
6234
+ "kind": "type",
6235
+ "package": "@nifrajs/island-trigger",
6236
+ "signature": "export type IslandStrategy = \"load\" | \"idle\" | \"visible\" | {\n readonly media: string;\n};",
6237
+ "doc": "/** When an island's enhancer runs. An object strategy is intentionally limited to media queries. */"
6238
+ },
6239
+ {
6240
+ "name": "IslandStrategy",
6241
+ "kind": "type",
6242
+ "package": "@nifrajs/islets",
6243
+ "signature": "export type IslandStrategy = \"load\" | \"idle\" | \"visible\" | {\n readonly media: string;\n};",
6244
+ "doc": "/** When an island's enhancer runs. An object strategy is intentionally limited to media queries. */"
6245
+ },
5907
6246
  {
5908
6247
  "name": "IslandStrategy",
5909
6248
  "kind": "type",
5910
6249
  "package": "@nifrajs/web",
5911
- "signature": "export type IslandStrategy = \"load\" | \"idle\" | \"visible\";",
5912
- "doc": "/** When an island's enhancer runs. Default `load`. */"
6250
+ "signature": "export type IslandStrategy = \"load\" | \"idle\" | \"visible\" | {\n readonly media: string;\n};",
6251
+ "doc": "/** When an island's enhancer runs. An object strategy is intentionally limited to media queries. */"
5913
6252
  },
5914
6253
  {
5915
6254
  "name": "isManifestInSync",
@@ -5959,6 +6298,20 @@
5959
6298
  "signature": "export interface ISRPlatform {\n readonly waitUntil?: (promise: Promise<unknown>) => void;\n}",
5960
6299
  "doc": "/** Minimal platform shape `withISR` needs - just `waitUntil` (edge runtimes extend the response\n * lifetime so background regeneration finishes). Off-edge it's absent and regen runs fire-and-forget. */"
5961
6300
  },
6301
+ {
6302
+ "name": "isSameOriginPath",
6303
+ "kind": "function",
6304
+ "package": "@nifrajs/core",
6305
+ "signature": "export declare function isSameOriginPath(value: string): boolean;",
6306
+ "doc": "/**\n * Is `value` a destination that stays on this origin?\n *\n * True only for an absolute path: one leading `/`, never `//` (protocol-relative → another origin),\n * and free of any character a URL parser turns into an origin escape. A leading `/` alone is not\n * enough: under a special scheme `\\` parses as `/`, and tab/CR/LF are STRIPPED before parsing, so\n * `/\\evil.example` and `/<TAB>/evil.example` both resolve to the external host `evil.example` while\n * passing a `//` test. Rejecting CR/LF here also keeps a validated destination out of the\n * response-splitting sink it usually flows into.\n *\n * One implementation, because every caller is the same open-redirect gate: `redirect()` in\n * `@nifrajs/web`, the `redirectTo` of the `@nifrajs/auth` and `@nifrajs/better-auth` guards. Three\n * copies of a security predicate is three chances for one of them to be hardened alone.\n *\n * It answers about a PATH, not a URL: an absolute `https://this.host/x` is false even for the\n * current origin, because the whole point is that the value never got to name a host.\n */"
6307
+ },
6308
+ {
6309
+ "name": "isSameOriginPath",
6310
+ "kind": "function",
6311
+ "package": "nifra",
6312
+ "signature": "export declare function isSameOriginPath(value: string): boolean;",
6313
+ "doc": "/**\n * Is `value` a destination that stays on this origin?\n *\n * True only for an absolute path: one leading `/`, never `//` (protocol-relative → another origin),\n * and free of any character a URL parser turns into an origin escape. A leading `/` alone is not\n * enough: under a special scheme `\\` parses as `/`, and tab/CR/LF are STRIPPED before parsing, so\n * `/\\evil.example` and `/<TAB>/evil.example` both resolve to the external host `evil.example` while\n * passing a `//` test. Rejecting CR/LF here also keeps a validated destination out of the\n * response-splitting sink it usually flows into.\n *\n * One implementation, because every caller is the same open-redirect gate: `redirect()` in\n * `@nifrajs/web`, the `redirectTo` of the `@nifrajs/auth` and `@nifrajs/better-auth` guards. Three\n * copies of a security predicate is three chances for one of them to be hardened alone.\n *\n * It answers about a PATH, not a URL: an absolute `https://this.host/x` is false even for the\n * current origin, because the whole point is that the value never got to name a host.\n */"
6314
+ },
5962
6315
  {
5963
6316
  "name": "isSameOriginRequest",
5964
6317
  "kind": "function",
@@ -6034,6 +6387,12 @@
6034
6387
  "signature": "export declare class JobValidationError extends Error {\n readonly job: string;\n readonly issues: ReadonlyArray<{\n readonly message: string;\n }>;\n readonly name = \"JobValidationError\";\n constructor(job: string, issues: ReadonlyArray<{\n readonly message: string;\n }>);\n}",
6035
6388
  "doc": "/** Thrown by `enqueue` when the payload fails the job's `input` schema (validation at the trust boundary). */"
6036
6389
  },
6390
+ {
6391
+ "name": "JoinCardinality",
6392
+ "kind": "type",
6393
+ "package": "@nifrajs/content",
6394
+ "signature": "export type JoinCardinality = \"one-to-many\" | \"one-to-one\";"
6395
+ },
6037
6396
  {
6038
6397
  "name": "joinCausality",
6039
6398
  "kind": "function",
@@ -6041,11 +6400,23 @@
6041
6400
  "signature": "export declare function joinCausality(parents: readonly CausalityContext[], nodeKind: CausalityKind, id: string, options?: ContinueCausalityOptions): CausalityStep;",
6042
6401
  "doc": "/** Join several immediate parents. Cross-execution joins fail closed. */"
6043
6402
  },
6403
+ {
6404
+ "name": "joinCollections",
6405
+ "kind": "function",
6406
+ "package": "@nifrajs/content",
6407
+ "signature": "export declare function joinCollections<Left extends Record<string, unknown>, Right extends Record<string, unknown>, LeftBy extends ContentFieldKey<Left>, RightBy extends ContentFieldKey<Right>, On extends SharedKey<Left, Right>>(left: IndexedCollection<Left, LeftBy>, right: IndexedCollection<Right, RightBy>, on: On, options: {\n readonly cardinality: \"one-to-one\";\n}): IndexedJoin<Left, Right, On, \"one-to-one\">;"
6408
+ },
6409
+ {
6410
+ "name": "JoinedRow",
6411
+ "kind": "type",
6412
+ "package": "@nifrajs/content",
6413
+ "signature": "export type JoinedRow<Left extends Record<string, unknown>, Right extends Record<string, unknown>, Cardinality extends JoinCardinality> = {\n readonly left: Entry<Left>;\n readonly right: Cardinality extends \"one-to-one\" ? Entry<Right> | null : ReadonlyArray<Entry<Right>>;\n};"
6414
+ },
6044
6415
  {
6045
6416
  "name": "Jsonify",
6046
6417
  "kind": "type",
6047
6418
  "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;",
6419
+ "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
6420
  "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
6421
  },
6051
6422
  {
@@ -6338,7 +6709,7 @@
6338
6709
  "name": "LayoutEntry",
6339
6710
  "kind": "interface",
6340
6711
  "package": "@nifrajs/web",
6341
- "signature": "export interface LayoutEntry {\n readonly file: string;\n readonly load: () => Promise<{\n default: unknown;\n meta?: MetaInput;\n }>;\n}",
6712
+ "signature": "export interface LayoutEntry {\n readonly file: string;\n readonly load: () => Promise<RouteModule>;\n}",
6342
6713
  "doc": "/** A layout (or `_404`/`_error`) entry: its source file (for client codegen) + a lazy loader.\n *\n * A `_layout.tsx` may export `meta` (static {@link Meta} or a function of the loader data + params,\n * same shape as a route's) to contribute sitewide `<head>` tags - `hreflang`/`preconnect`/etc. that\n * belong on every page under the layout. The layout chain's heads merge with the page's: arrays\n * (`meta`/`link`) concatenate outermost→innermost→page; scalars (`title`) are nearest-wins (the page\n * overrides an inner layout, which overrides an outer one). See `mergeHeads` in `@nifrajs/web`. */"
6343
6714
  },
6344
6715
  {
@@ -6625,8 +6996,14 @@
6625
6996
  "name": "matchesAssuranceSelector",
6626
6997
  "kind": "function",
6627
6998
  "package": "@nifrajs/core",
6628
- "signature": "export declare function matchesAssuranceSelector(route: Pick<ReflectedRoute, \"method\" | \"path\" | \"tool\" | \"capabilities\" | \"classification\">, selector: AssuranceRouteSelector, definitions?: ReadonlyMap<string, CapabilityDefinition>): boolean;",
6629
- "doc": "/**\n * Shared selector semantics for policy rules and framework adapters.\n *\n * `definitions` is only consulted by the `access`/`zone` selectors; every other selector reads\n * reflection alone. A caller that omits it while the selector needs it gets no match, so callers that\n * accept user policy must reject that combination up front - `defineAssuranceConfig` does.\n */"
6999
+ "signature": "export declare function matchesAssuranceSelector(route: Pick<ReflectedRoute, \"method\" | \"path\" | \"tool\" | \"capabilities\" | \"classification\" | \"schema\">, selector: AssuranceRouteSelector, definitions?: ReadonlyMap<string, CapabilityDefinition>): boolean;"
7000
+ },
7001
+ {
7002
+ "name": "matchesSingleCopyDeclaration",
7003
+ "kind": "const",
7004
+ "package": "@nifrajs/core",
7005
+ "signature": "export declare const matchesSingleCopyDeclaration: (declared: readonly string[], name: string) => boolean;",
7006
+ "doc": "/**\n * Match a package name against a declaration entry: an exact name, or a `@scope/*` prefix.\n *\n * Exported because the enforcement and the CHECK must agree on it exactly. If `nifra check` decided\n * coverage by its own rule, a package could be reported as deduplicated while the plugin walked past\n * it - which is worse than no check at all, because it is a green light for a broken graph.\n */"
6630
7007
  },
6631
7008
  {
6632
7009
  "name": "matchRoutePattern",
@@ -6642,6 +7019,20 @@
6642
7019
  "signature": "export declare const MAX_COST_AXES = 8;",
6643
7020
  "doc": "/** Most cost axes one entry may carry. */"
6644
7021
  },
7022
+ {
7023
+ "name": "MAX_MEDIA_QUERY_LENGTH",
7024
+ "kind": "const",
7025
+ "package": "@nifrajs/island-trigger",
7026
+ "signature": "export declare const MAX_MEDIA_QUERY_LENGTH = 256;",
7027
+ "doc": "/** The maximum media-query length accepted from an HTML data attribute. */"
7028
+ },
7029
+ {
7030
+ "name": "MAX_MEDIA_QUERY_LENGTH",
7031
+ "kind": "const",
7032
+ "package": "@nifrajs/web",
7033
+ "signature": "export declare const MAX_MEDIA_QUERY_LENGTH = 256;",
7034
+ "doc": "/** The maximum media-query length accepted from an HTML data attribute. */"
7035
+ },
6645
7036
  {
6646
7037
  "name": "maxClassification",
6647
7038
  "kind": "function",
@@ -6649,6 +7040,12 @@
6649
7040
  "signature": "export declare function maxClassification(values: Iterable<DataClassification>): DataClassification;",
6650
7041
  "doc": "/** The most sensitive classification among the inputs; `\"public\"` when none are given. */"
6651
7042
  },
7043
+ {
7044
+ "name": "MaybePromise",
7045
+ "kind": "type",
7046
+ "package": "@nifrajs/core",
7047
+ "signature": "export type MaybePromise<T> = T | Promise<T>;"
7048
+ },
6652
7049
  {
6653
7050
  "name": "mcp",
6654
7051
  "kind": "function",
@@ -7056,6 +7453,12 @@
7056
7453
  "package": "@nifrajs/auth",
7057
7454
  "signature": "export interface MemorySessionStoreOptions {\n /** Allow the in-memory store in production. Off by default - per-instance sessions don't hold across\n * instances and are lost on restart. */\n readonly allowInProduction?: boolean;\n /** Hard cap on stored sessions; the oldest-inserted is evicted past it (default 10_000). */\n readonly max?: number;\n}"
7058
7455
  },
7456
+ {
7457
+ "name": "MemoryStaticBoundaryCache",
7458
+ "kind": "class",
7459
+ "package": "@nifrajs/web",
7460
+ "signature": "export declare class MemoryStaticBoundaryCache implements StaticBoundaryCache {\n #private;\n get(boundary: BoundaryRegistration): Promise<unknown> | undefined;\n set(boundary: BoundaryRegistration, value: Promise<unknown>): void;\n}"
7461
+ },
7059
7462
  {
7060
7463
  "name": "MemoryStorage",
7061
7464
  "kind": "class",
@@ -7135,6 +7538,12 @@
7135
7538
  "package": "@nifrajs/core",
7136
7539
  "signature": "export type Method = (typeof METHODS)[number];"
7137
7540
  },
7541
+ {
7542
+ "name": "Method",
7543
+ "kind": "type",
7544
+ "package": "@nifrajs/edge",
7545
+ "signature": "export type Method = (typeof METHODS)[number];"
7546
+ },
7138
7547
  {
7139
7548
  "name": "Method",
7140
7549
  "kind": "type",
@@ -7193,14 +7602,14 @@
7193
7602
  "kind": "interface",
7194
7603
  "package": "@nifrajs/core",
7195
7604
  "signature": "export interface Middleware {\n readonly name?: string;\n readonly onRequest?: (req: Request, platform?: Platform) => MaybePromise<OnRequestResult>;\n /** Allocation-light Node equivalent of `onRequest` for header-only hooks. */\n readonly onNodeRequest?: NodeRequestHook;\n readonly around?: <T>(context: Context, next: () => MaybePromise<T>) => MaybePromise<T>;\n readonly beforeHandle?: (context: Context) => MaybePromise<unknown>;\n readonly afterHandle?: (result: unknown, context: Context) => MaybePromise<unknown>;\n readonly onResponse?: (response: Response, req: Request) => MaybePromise<Response>;\n /**\n * Header-only equivalent of `onResponse` for the Node-direct serializer. It is used only when every\n * response hook in the app supplies this paired native implementation; arbitrary response transforms\n * continue through the Web Response path.\n */\n readonly onNodeResponse?: NodeResponseHook;\n /**\n * Response headers with NO per-request decision behind them. Declared here instead of written by a\n * hook, they are folded into response construction, so a bundle that only sets static headers does\n * not cost the app its fused/native lanes (see {@link Server.responseHeaders}). They are defaults:\n * anything the request produced wins. Reach for `onResponseHeaders` the moment a value depends on\n * the request, the route, or the response.\n */\n readonly responseHeaders?: Readonly<Record<string, string>>;\n /**\n * PORTABLE header-only response hook - the recommended shape when the middleware only reads or\n * writes headers. One implementation runs on every runtime: inside the Web `onResponse` walk\n * against the response's own `Headers`, and on Node as a self-paired native hook against the\n * outcome record - so it never forces the Node adapter off its direct writer. Use `onResponse` +\n * an optional `onNodeResponse` twin only when the hook must see a real `Response`.\n */\n readonly onResponseHeaders?: ResponseHeadersHook;\n /**\n * PORTABLE post-serialization body hook - the payload tier. Receives the final\n * framework-serialized bytes (already resident on every runtime; no stream is drained) plus the\n * header view and status, and may return replacement bytes. Raw handler-returned `Response`s\n * (proxies, SSE, streamed SSR) are skipped by contract - transforming those needs `onResponse`.\n */\n readonly onResponseBody?: ResponseBodyHook;\n /**\n * Response transform for untagged/raw responses (streams, proxied fetches, and framework errors).\n * Framework-serialized payloads use `onResponseBody` and remain on the Node direct lane.\n */\n readonly onResponseRaw?: (response: Response, req: Request) => MaybePromise<Response>;\n readonly onResponseFinalized?: (outcome: ResponseFinalization, req: Request) => MaybePromise<void>;\n readonly onError?: (error: unknown, context: Context) => MaybePromise<unknown>;\n}",
7196
- "doc": "/**\n * A bundle of lifecycle hooks applied together via {@link Server.use} - the unit\n * `@nifrajs/middleware` ships (cors, security headers, rate-limit). Every hook is\n * optional and wired to its lifecycle point. Middleware is context-agnostic (sees\n * the base `Context`); `use` does no context-type merging - the full type-merging\n * plugin system is deferred, and `.use` is reserved as its future entry point.\n */"
7605
+ "doc": "/**\n * A bundle of lifecycle hooks applied together via {@link Server.use} - the unit\n * `@nifrajs/middleware` ships (cors, security headers, rate-limit). Every hook is\n * optional and wired to its lifecycle point. Middleware carrying a portable response tier must be\n * marked with `withResponseObserver()` from `@nifrajs/core/response-observer`, or the server must\n * install `responseObserver()` before the bundle is applied. Middleware is context-agnostic (sees\n * the base `Context`); `use` does no context-type merging - the full type-merging\n * plugin system is deferred, and `.use` is reserved as its future entry point.\n */"
7197
7606
  },
7198
7607
  {
7199
7608
  "name": "Middleware",
7200
7609
  "kind": "interface",
7201
7610
  "package": "nifra",
7202
7611
  "signature": "export interface Middleware {\n readonly name?: string;\n readonly onRequest?: (req: Request, platform?: Platform) => MaybePromise<OnRequestResult>;\n /** Allocation-light Node equivalent of `onRequest` for header-only hooks. */\n readonly onNodeRequest?: NodeRequestHook;\n readonly around?: <T>(context: Context, next: () => MaybePromise<T>) => MaybePromise<T>;\n readonly beforeHandle?: (context: Context) => MaybePromise<unknown>;\n readonly afterHandle?: (result: unknown, context: Context) => MaybePromise<unknown>;\n readonly onResponse?: (response: Response, req: Request) => MaybePromise<Response>;\n /**\n * Header-only equivalent of `onResponse` for the Node-direct serializer. It is used only when every\n * response hook in the app supplies this paired native implementation; arbitrary response transforms\n * continue through the Web Response path.\n */\n readonly onNodeResponse?: NodeResponseHook;\n /**\n * Response headers with NO per-request decision behind them. Declared here instead of written by a\n * hook, they are folded into response construction, so a bundle that only sets static headers does\n * not cost the app its fused/native lanes (see {@link Server.responseHeaders}). They are defaults:\n * anything the request produced wins. Reach for `onResponseHeaders` the moment a value depends on\n * the request, the route, or the response.\n */\n readonly responseHeaders?: Readonly<Record<string, string>>;\n /**\n * PORTABLE header-only response hook - the recommended shape when the middleware only reads or\n * writes headers. One implementation runs on every runtime: inside the Web `onResponse` walk\n * against the response's own `Headers`, and on Node as a self-paired native hook against the\n * outcome record - so it never forces the Node adapter off its direct writer. Use `onResponse` +\n * an optional `onNodeResponse` twin only when the hook must see a real `Response`.\n */\n readonly onResponseHeaders?: ResponseHeadersHook;\n /**\n * PORTABLE post-serialization body hook - the payload tier. Receives the final\n * framework-serialized bytes (already resident on every runtime; no stream is drained) plus the\n * header view and status, and may return replacement bytes. Raw handler-returned `Response`s\n * (proxies, SSE, streamed SSR) are skipped by contract - transforming those needs `onResponse`.\n */\n readonly onResponseBody?: ResponseBodyHook;\n /**\n * Response transform for untagged/raw responses (streams, proxied fetches, and framework errors).\n * Framework-serialized payloads use `onResponseBody` and remain on the Node direct lane.\n */\n readonly onResponseRaw?: (response: Response, req: Request) => MaybePromise<Response>;\n readonly onResponseFinalized?: (outcome: ResponseFinalization, req: Request) => MaybePromise<void>;\n readonly onError?: (error: unknown, context: Context) => MaybePromise<unknown>;\n}",
7203
- "doc": "/**\n * A bundle of lifecycle hooks applied together via {@link Server.use} - the unit\n * `@nifrajs/middleware` ships (cors, security headers, rate-limit). Every hook is\n * optional and wired to its lifecycle point. Middleware is context-agnostic (sees\n * the base `Context`); `use` does no context-type merging - the full type-merging\n * plugin system is deferred, and `.use` is reserved as its future entry point.\n */"
7612
+ "doc": "/**\n * A bundle of lifecycle hooks applied together via {@link Server.use} - the unit\n * `@nifrajs/middleware` ships (cors, security headers, rate-limit). Every hook is\n * optional and wired to its lifecycle point. Middleware carrying a portable response tier must be\n * marked with `withResponseObserver()` from `@nifrajs/core/response-observer`, or the server must\n * install `responseObserver()` before the bundle is applied. Middleware is context-agnostic (sees\n * the base `Context`); `use` does no context-type merging - the full type-merging\n * plugin system is deferred, and `.use` is reserved as its future entry point.\n */"
7204
7613
  },
7205
7614
  {
7206
7615
  "name": "MIN_DIGEST_KEY_BYTES",
@@ -7263,11 +7672,17 @@
7263
7672
  "signature": "export declare function modernVersionOf(params: Record<string, unknown> | undefined): string | undefined;",
7264
7673
  "doc": "/** The protocol version a modern (2026-07-28+) request declares in `_meta`, or `undefined` for a legacy\n * request. Its presence is what puts the dispatch in modern mode for that one request. */"
7265
7674
  },
7675
+ {
7676
+ "name": "MountIslandOptions",
7677
+ "kind": "interface",
7678
+ "package": "@nifrajs/islets",
7679
+ "signature": "export interface MountIslandOptions {\n readonly root?: BindableRoot;\n}"
7680
+ },
7266
7681
  {
7267
7682
  "name": "mountIslands",
7268
7683
  "kind": "function",
7269
7684
  "package": "@nifrajs/islets",
7270
- "signature": "export declare function mountIslands(root?: BindableRoot): void;",
7685
+ "signature": "export declare function mountIslands(rootOrOptions?: BindableRoot | MountIslandOptions): () => void;",
7271
7686
  "doc": "/**\n * Mount every registered island under `root` (default: the document). Idempotent - a host is\n * marked once mounted, so calling again (e.g. after a soft navigation swapped content in) only\n * mounts new hosts. Unregistered island names are skipped silently: markup may ship ahead of\n * its script, and progressive enhancement means the static content is already correct.\n */"
7272
7687
  },
7273
7688
  {
@@ -7393,17 +7808,35 @@
7393
7808
  "doc": "/** Compose middleware/plugins into one idempotent named bundle. */"
7394
7809
  },
7395
7810
  {
7396
- "name": "NAV_FROM_HEADER",
7397
- "kind": "const",
7398
- "package": "@nifrajs/web",
7399
- "signature": "export declare const NAV_FROM_HEADER = \"x-nifra-from\";",
7400
- "doc": "/**\n * The path a client navigation is coming FROM, sent on the data-mode GET.\n *\n * Lets the SERVER decide which layout loaders to skip: it already knows each layout's scoped params\n * (derived at build time), so given both paths it can tell whether a layout's own prefix changed.\n * Doing it server-side means the client never needs the scope table, and the decision lives next to\n * the data it is about.\n *\n * Sent only when the client actually holds layout data to retain, so a request without it is simply\n * the full-chain case.\n */"
7811
+ "name": "NativeProxyTransport",
7812
+ "kind": "type",
7813
+ "package": "@nifrajs/proxy",
7814
+ "signature": "export type NativeProxyTransport = (target: URL, request: NativeProxyTransportRequest) => Promise<NativeProxyUpstreamResponse>;"
7401
7815
  },
7402
7816
  {
7403
- "name": "Navigate",
7404
- "kind": "function",
7405
- "package": "@nifrajs/web-react",
7406
- "signature": "export declare function Navigate({ to, replace }: NavigateProps): null;",
7817
+ "name": "NativeProxyTransportRequest",
7818
+ "kind": "interface",
7819
+ "package": "@nifrajs/proxy",
7820
+ "signature": "export interface NativeProxyTransportRequest {\n readonly method: string;\n /** Flat name/value pairs already sanitized by the proxy. */\n readonly headers: readonly string[];\n readonly body: unknown;\n readonly signal: AbortSignal;\n readonly headersTimeout: number;\n}"
7821
+ },
7822
+ {
7823
+ "name": "NativeProxyUpstreamResponse",
7824
+ "kind": "interface",
7825
+ "package": "@nifrajs/proxy",
7826
+ "signature": "export interface NativeProxyUpstreamResponse {\n readonly status: number;\n readonly headers: Readonly<Record<string, string | readonly string[] | undefined>>;\n readonly body: unknown;\n dump(): Promise<void>;\n}"
7827
+ },
7828
+ {
7829
+ "name": "NAV_FROM_HEADER",
7830
+ "kind": "const",
7831
+ "package": "@nifrajs/web",
7832
+ "signature": "export declare const NAV_FROM_HEADER = \"x-nifra-from\";",
7833
+ "doc": "/**\n * The path a client navigation is coming FROM, sent on the data-mode GET.\n *\n * Lets the SERVER decide which layout loaders to skip: it already knows each layout's scoped params\n * (derived at build time), so given both paths it can tell whether a layout's own prefix changed.\n * Doing it server-side means the client never needs the scope table, and the decision lives next to\n * the data it is about.\n *\n * Sent only when the client actually holds layout data to retain, so a request without it is simply\n * the full-chain case.\n */"
7834
+ },
7835
+ {
7836
+ "name": "Navigate",
7837
+ "kind": "function",
7838
+ "package": "@nifrajs/web-react",
7839
+ "signature": "export declare function Navigate({ to, replace }: NavigateProps): null;",
7407
7840
  "doc": "/**\n * Declaratively navigate on mount - the component analogue of `useNavigate` (e.g. a guard that renders\n * `<Navigate to=\"/login\" replace />`). Navigates in an effect, so it's a safe no-op during SSR (renders\n * `null`); the redirect happens once on the client after hydration.\n */"
7408
7841
  },
7409
7842
  {
@@ -7708,6 +8141,20 @@
7708
8141
  "signature": "export declare function nodeDirect(): IdentityPlugin;",
7709
8142
  "doc": "/** Enable `app.resolveNode()` for direct callers. Applying it twice is a no-op (named plugin dedupe). */"
7710
8143
  },
8144
+ {
8145
+ "name": "NodeNativeProxyRequest",
8146
+ "kind": "interface",
8147
+ "package": "@nifrajs/proxy",
8148
+ "signature": "export interface NodeNativeProxyRequest {\n readonly method: string;\n /** Absolute URL assembled by the Node adapter from its trusted protocol/host policy. */\n readonly url: string;\n readonly headers: Readonly<Record<string, string | readonly string[] | undefined>>;\n readonly raw: unknown;\n}",
8149
+ "doc": "/** Structural request view used only by the Node-native mount seam. The raw body stays the\n * IncomingMessage; no Web Request, Headers, or Web stream is created before the transport sees it. */"
8150
+ },
8151
+ {
8152
+ "name": "NodeNativeProxyResponse",
8153
+ "kind": "interface",
8154
+ "package": "@nifrajs/proxy",
8155
+ "signature": "export interface NodeNativeProxyResponse {\n readonly destroyed?: boolean;\n readonly writableEnded?: boolean;\n readonly writable?: boolean;\n readonly headersSent?: boolean;\n setHeader(name: string, value: string | readonly string[]): void;\n writeHead(status: number): void;\n end(body?: string | Uint8Array): void;\n once(event: string, listener: (...args: unknown[]) => void): unknown;\n removeListener(event: string, listener: (...args: unknown[]) => void): unknown;\n destroy(error?: unknown): unknown;\n}",
8156
+ "doc": "/** Structural response view used by the Node-native mount seam. */"
8157
+ },
7711
8158
  {
7712
8159
  "name": "NodeRequestContext",
7713
8160
  "kind": "interface",
@@ -8054,6 +8501,12 @@
8054
8501
  "package": "@nifrajs/core",
8055
8502
  "signature": "export type Params<Path extends string> = Prettify<RawParams<Path>>;"
8056
8503
  },
8504
+ {
8505
+ "name": "Params",
8506
+ "kind": "type",
8507
+ "package": "@nifrajs/edge",
8508
+ "signature": "export type Params<Path extends string> = Prettify<RawParams<Path>>;"
8509
+ },
8057
8510
  {
8058
8511
  "name": "Params",
8059
8512
  "kind": "type",
@@ -8196,8 +8649,8 @@
8196
8649
  "name": "parseManifestRouteFiles",
8197
8650
  "kind": "function",
8198
8651
  "package": "@nifrajs/web",
8199
- "signature": "export declare function parseManifestRouteFiles(source: string, routesPrefix?: string): string[];",
8200
- "doc": "/**\n * Extract the route-relative file list the committed server-manifest imports, normalized to the same\n * `routes/`-relative keys `discoverRoutes` produces (e.g. `docs/index.tsx`). `routesPrefix` is the\n * specifier prefix the manifest used for the routes dir (default `./routes/`, what `buildServer`'s\n * default `resolve` emits). Only import specifiers under that prefix are route files; the\n * `@nifrajs/web` import (and any other bare specifier) is ignored. Pure - operates on source text.\n */"
8652
+ "signature": "export declare function parseManifestRouteFiles(source: string, _routesPrefix?: string): string[];",
8653
+ "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
8654
  },
8202
8655
  {
8203
8656
  "name": "parseManifestRouteStyles",
@@ -8258,6 +8711,13 @@
8258
8711
  "package": "nifra",
8259
8712
  "signature": "export declare function pathnameOf(url: string): string;"
8260
8713
  },
8714
+ {
8715
+ "name": "PendingBoundary",
8716
+ "kind": "interface",
8717
+ "package": "@nifrajs/web",
8718
+ "signature": "export interface PendingBoundary {\n readonly name: string;\n readonly mode: BoundaryMode;\n readonly errorId?: string;\n readonly promise: Promise<unknown>;\n}",
8719
+ "doc": "/** A dynamic load that has started but is not part of the initial render barrier. */"
8720
+ },
8261
8721
  {
8262
8722
  "name": "pickLanguage",
8263
8723
  "kind": "function",
@@ -8272,18 +8732,53 @@
8272
8732
  "signature": "export declare function pipeWebBodyToNode(body: ReadableStream<Uint8Array> | null, res: NodeResLike): Promise<void>;",
8273
8733
  "doc": "/**\n * Stream a Web `Response` body to a Node response chunk-by-chunk. Buffering the whole body (e.g.\n * `arrayBuffer()`) waits for the stream to END - which an open-ended SSE (`text/event-stream`) body never\n * does, so it hung `nifra dev` (the Bun production server streamed it fine). This flushes each chunk as it\n * arrives and cancels the reader if the client disconnects; a finite body just streams its chunk(s) + ends.\n */"
8274
8734
  },
8735
+ {
8736
+ "name": "plainError",
8737
+ "kind": "function",
8738
+ "package": "@nifrajs/core",
8739
+ "signature": "export declare function plainError(status: number, error: string, headers?: Record<string, string>): ResponseResult;",
8740
+ "doc": "/**\n * The same envelope as {@link jsonError}, as plain data rather than a built `Response`.\n *\n * This is what the framework's own renders - 404, 405, 422, the body caps, the timeouts, 500 - answer\n * with wherever the value flows into a lane's response wrapper, so an error costs what a handler's\n * plain return costs. Building the `Response` was measured as the dominant cost of answering early\n * (see `PlainRender`), and on the Node lane an error `Response` is worse still: it is untagged, so\n * the adapter cannot recognize its body and drains it through a Web stream, which is also why an\n * error answered chunked while an ordinary return carries a `content-length`.\n *\n * `jsonError` stays for the callers that genuinely need a `Response` object (mount bridges, the\n * lanes' own typed returns).\n */"
8741
+ },
8275
8742
  {
8276
8743
  "name": "plainJsonCodec",
8277
8744
  "kind": "const",
8278
8745
  "package": "@nifrajs/core",
8279
8746
  "signature": "export declare const plainJsonCodec: TransportCodec;"
8280
8747
  },
8748
+ {
8749
+ "name": "PlainRender",
8750
+ "kind": "interface",
8751
+ "package": "@nifrajs/core",
8752
+ "signature": "export interface PlainRender {\n readonly status: number;\n /** Headers belonging to this render. They win over anything the request left in `c.set.headers`. */\n readonly headers?: Readonly<Record<string, string>>;\n /** The body as a value, serialized by the lane that renders it. `undefined` means no body. */\n readonly body: unknown;\n}",
8753
+ "doc": "/**\n * A response described as plain data - the status, any headers of its own, and a body still in value\n * form. A `ResponseResult` carrying one is rendered on the SAME lane a handler's plain return takes:\n * `JSON.stringify` straight into the node writer's `kind: \"json\"` outcome, or the web lane's prebuilt\n * JSON init. No `Response` is constructed anywhere on the node path.\n *\n * That matters because building one is the dominant cost of answering early. Measured on the rig, one\n * server per shape, all five answering the same 401: `c.set.status` + a plain object 82802 req/s,\n * `beforeHandle` returning that same object 81819, `return new Response(...)` 49668, `throw new\n * Response(...)` 47505, the same throw from a `derive` 48746. The `Response` costs 40%; the throw\n * around it costs another 4%; unwinding a lifecycle stage instead of a handler costs nothing\n * measurable. So the fix for a slow rejection is not a faster throw - it is not allocating the\n * `Response`.\n */"
8754
+ },
8755
+ {
8756
+ "name": "PlainRender",
8757
+ "kind": "interface",
8758
+ "package": "nifra",
8759
+ "signature": "export interface PlainRender {\n readonly status: number;\n /** Headers belonging to this render. They win over anything the request left in `c.set.headers`. */\n readonly headers?: Readonly<Record<string, string>>;\n /** The body as a value, serialized by the lane that renders it. `undefined` means no body. */\n readonly body: unknown;\n}",
8760
+ "doc": "/**\n * A response described as plain data - the status, any headers of its own, and a body still in value\n * form. A `ResponseResult` carrying one is rendered on the SAME lane a handler's plain return takes:\n * `JSON.stringify` straight into the node writer's `kind: \"json\"` outcome, or the web lane's prebuilt\n * JSON init. No `Response` is constructed anywhere on the node path.\n *\n * That matters because building one is the dominant cost of answering early. Measured on the rig, one\n * server per shape, all five answering the same 401: `c.set.status` + a plain object 82802 req/s,\n * `beforeHandle` returning that same object 81819, `return new Response(...)` 49668, `throw new\n * Response(...)` 47505, the same throw from a `derive` 48746. The `Response` costs 40%; the throw\n * around it costs another 4%; unwinding a lifecycle stage instead of a handler costs nothing\n * measurable. So the fix for a slow rejection is not a faster throw - it is not allocating the\n * `Response`.\n */"
8761
+ },
8762
+ {
8763
+ "name": "plainValidationError",
8764
+ "kind": "function",
8765
+ "package": "@nifrajs/core",
8766
+ "signature": "export declare function plainValidationError(issues: ReadonlyArray<StandardIssue>): ResponseResult;",
8767
+ "doc": "/** The 422 as plain data - the shape every lane's response wrapper takes, so a rejected body costs\n * what an accepted one costs: on Node it is written straight to the socket with a `content-length`\n * instead of being built as a `Response` and drained back out. */"
8768
+ },
8281
8769
  {
8282
8770
  "name": "planProofs",
8283
8771
  "kind": "function",
8284
8772
  "package": "@nifrajs/cli",
8285
8773
  "signature": "export declare function planProofs(graph: WorkGraph, impact: ImpactReport, targetLevel?: number): ProofPlan;"
8286
8774
  },
8775
+ {
8776
+ "name": "planSingleCopy",
8777
+ "kind": "function",
8778
+ "package": "@nifrajs/core",
8779
+ "signature": "export declare function planSingleCopy(options?: SingleCopyOptions): SingleCopyPlan;",
8780
+ "doc": "/**\n * Work out which foreign copies exist and which of them may be redirected.\n *\n * Pure discovery: it reads `package.json` files and symlink targets, never application source, and\n * never mutates anything. Both the plugin and `nifra check`'s verification are built on it, so the\n * enforcement and the report cannot drift apart.\n */"
8781
+ },
8287
8782
  {
8288
8783
  "name": "Platform",
8289
8784
  "kind": "interface",
@@ -8608,7 +9103,7 @@
8608
9103
  "name": "ProjectFacts",
8609
9104
  "kind": "interface",
8610
9105
  "package": "@nifrajs/cli",
8611
- "signature": "export interface ProjectFacts {\n readonly [key: string]: unknown;\n}"
9106
+ "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
9107
  },
8613
9108
  {
8614
9109
  "name": "ProjectWorkGraphResult",
@@ -8729,6 +9224,13 @@
8729
9224
  "signature": "export declare const PROTOCOL_VERSION = \"2025-06-18\";",
8730
9225
  "doc": "/** The protocol revision this server advertises by default. A handshake-era version - the HTTP transport\n * still uses `initialize`; current clients reach it through their backward-compatibility fallback.\n * `initialize` echoes the client's own requested version instead when it's one this server also speaks\n * ({@link SUPPORTED_PROTOCOL_VERSIONS}). */"
8731
9226
  },
9227
+ {
9228
+ "name": "ProtoPoisoning",
9229
+ "kind": "type",
9230
+ "package": "@nifrajs/core",
9231
+ "signature": "export type ProtoPoisoning = \"reject\" | \"strip\" | \"ignore\";",
9232
+ "doc": "/**\n * Prototype-poisoning guard for the JSON body lane - the check behind `c.boundedJson` and the\n * schema path. A single walk of the parsed value, never a reviver (a reviver taxes every key of\n * every parse, including the parses that carry no object at all).\n *\n * No raw-text pre-scan: the Fastify-style `text.includes('\"__proto__\"')` filter is a pessimization\n * on 2026 engines. A quoted-name search runs a general substring algorithm over the whole body,\n * while the walk only touches the nodes the parse already built. Measured on Node 26 and Bun 1.3,\n * three `includes()` calls cost 2-4x the walk on every body shape an API actually receives\n * (records, strings, nested objects); the scan only wins on a body that is mostly a flat array of\n * numbers, where it saves ~1.5us on a 9KB payload that spends 20us in `JSON.parse` regardless.\n * Dropping the tier also removes an escape-analysis obligation - the scan had to route every `\\u`\n * to the walk, because `_` spells `_`.\n */"
9233
+ },
8732
9234
  {
8733
9235
  "name": "proveIdempotency",
8734
9236
  "kind": "function",
@@ -8754,7 +9256,28 @@
8754
9256
  "name": "ProxyOptions",
8755
9257
  "kind": "interface",
8756
9258
  "package": "@nifrajs/proxy",
8757
- "signature": "export interface ProxyOptions {\n /**\n * The upstream to forward every request to, as a **bare origin** (`https://api.internal:8443`).\n * A path, query, fragment, or credentials in the URL throws at construction; only `http:` and\n * `https:` are accepted. The forwarded URL is this origin + the incoming path and query.\n */\n readonly upstream: string;\n /** Mount prefix to remove from the incoming path before forwarding (`/api` + request\n * `/api/users` → upstream `/users`). A path outside the prefix is forwarded unchanged. */\n readonly stripPrefix?: string;\n /**\n * Forward caller metadata upstream. Default **false**: `Forwarded` and `X-Forwarded-*` headers\n * are stripped, so a client-forged chain never reaches the upstream. When true, the inbound\n * `X-Forwarded-For` is kept with the observed caller IP appended (pass a `ProxyContext` so\n * `c.clientIp` - already filtered by the app's trust declaration - is what gets appended). With a\n * bare `Request`, forwarding metadata is suppressed rather than passed through.\n */\n readonly forwardClientIp?: boolean;\n /** Upstream response deadline in milliseconds. Default `30_000`; expiry answers `504`. */\n readonly timeoutMs?: number;\n /** Static headers to set on every forwarded request (after hygiene, so they always win). */\n readonly headers?: Readonly<Record<string, string>>;\n}"
9259
+ "signature": "export interface ProxyOptions {\n /**\n * The upstream to forward every request to, as a **bare origin** (`https://api.internal:8443`).\n * A path, query, fragment, or credentials in the URL throws at construction; only `http:` and\n * `https:` are accepted. The forwarded URL is this origin + the incoming path and query.\n */\n readonly upstream: string;\n /** Mount prefix to remove from the incoming path before forwarding (`/api` + request\n * `/api/users` → upstream `/users`). A path outside the prefix is forwarded unchanged. */\n readonly stripPrefix?: string;\n /**\n * Forward caller metadata upstream. Default **false**: `Forwarded` and `X-Forwarded-*` headers\n * are stripped, so a client-forged chain never reaches the upstream. When true, the observed caller\n * IP replaces inbound `X-Forwarded-For` by default (pass a `ProxyContext` so `c.clientIp` - already\n * filtered by the app's trust declaration - is the value emitted). With a bare `Request`, forwarding\n * metadata is suppressed rather than passed through.\n */\n readonly forwardClientIp?: boolean;\n /**\n * Preserve an inbound `X-Forwarded-For` chain before appending the observed caller IP. Set this only\n * when a proxy you operate has already stripped and rebuilt the inbound chain; otherwise a directly\n * reachable caller can forge the leading entries. Requires `forwardClientIp: true`.\n */\n readonly trustForwardedFor?: boolean;\n /**\n * Deadline in milliseconds for the upstream to *begin* answering. Default `30_000`; expiry\n * answers `504`. It covers up to the response headers, which is the only window in which a `504`\n * is still sendable - once the status has been relayed the exchange cannot be turned into one. A\n * body that starts and then stalls is the transport's timeout to enforce; both built-in transports\n * cap the idle gap between chunks at 30s (undici's `bodyTimeout`, and an equivalent per-chunk timer\n * on the portable one) and error the relayed stream past it. A custom transport owes the same\n * bound. Caller disconnect still tears the upstream down at any point.\n */\n readonly timeoutMs?: number;\n /** Static headers to set on every forwarded request (after hygiene, so they always win). */\n readonly headers?: Readonly<Record<string, string>>;\n /**\n * How to reach the upstream. Omit to use the default: the undici transport on Node when `undici`\n * is installed (the fast path there, resolved lazily so the base package stays dependency-free),\n * `fetch` on every other runtime and when `undici` is absent. See {@link ProxyTransport} - a\n * transport carries security obligations. Pass one explicitly to pin the choice or tune it (e.g.\n * `undiciTransport({ dispatcher })`).\n */\n readonly transport?: ProxyTransport;\n}"
9260
+ },
9261
+ {
9262
+ "name": "ProxyTransport",
9263
+ "kind": "type",
9264
+ "package": "@nifrajs/proxy",
9265
+ "signature": "export type ProxyTransport = (target: URL, request: ProxyUpstreamRequest) => Promise<ProxyUpstreamResponse>;",
9266
+ "doc": "/**\n * How the forwarded request reaches the upstream. Defaults to the undici transport on Node when\n * `undici` is installed (substantially faster there), and to `fetch` everywhere else.\n *\n * A transport is a security boundary, and swapping it moves three of this package's guarantees into\n * your implementation. It MUST dial exactly `target` and nothing else, MUST NOT follow redirects\n * (relay the 3xx as-is), and MUST leave TLS verification on. It MUST NOT add, drop, or rewrite the\n * headers it is handed - they have already been sanitised, and re-adding `host` or a forwarding\n * header undoes that work. If it does not decode `Content-Encoding`, it MUST set\n * {@link ProxyUpstreamResponse.bodyEncoded} so the encoding is relayed rather than stripped.\n *\n * `@nifrajs/proxy/undici` ships the one selected by default on Node.\n */"
9267
+ },
9268
+ {
9269
+ "name": "ProxyUpstreamRequest",
9270
+ "kind": "interface",
9271
+ "package": "@nifrajs/proxy",
9272
+ "signature": "export interface ProxyUpstreamRequest {\n readonly method: string;\n /** Already sanitised: hop-by-hop, Connection-nominated, `Proxy-*`, `host`, and (unless opted in)\n * forwarding headers are gone, and static `headers` have been applied. Send them as given. */\n readonly headers: Headers;\n readonly body: ReadableStream<Uint8Array> | null;\n /** Aborts on the deadline or on caller disconnect. A transport MUST honour it. */\n readonly signal: AbortSignal;\n}",
9273
+ "doc": "/** The forwarded request, after hygiene, as handed to a {@link ProxyTransport}. */"
9274
+ },
9275
+ {
9276
+ "name": "ProxyUpstreamResponse",
9277
+ "kind": "interface",
9278
+ "package": "@nifrajs/proxy",
9279
+ "signature": "export interface ProxyUpstreamResponse {\n readonly status: number;\n /** Empty string is fine - HTTP/2 has no reason phrase, and nothing downstream depends on it. */\n readonly statusText: string;\n readonly headers: Headers;\n readonly body: ReadableStream<Uint8Array> | null;\n /**\n * Whether `body` is still exactly the bytes the upstream sent, `Content-Encoding` intact. `fetch`\n * transparently decodes a compressed response, so its body is identity and the stored\n * `content-encoding`/`content-length` no longer describe it - both are dropped on relay (the\n * default when this is omitted). A transport that does NOT decode (undici's `request` does not)\n * MUST set this `true` so the encoding and length are relayed instead, letting the client decode\n * the bytes it actually receives. Getting this wrong ships a gzip body labelled identity.\n */\n readonly bodyEncoded?: boolean;\n}",
9280
+ "doc": "/** What a {@link ProxyTransport} returns. Header hygiene on the way back is the proxy's job. */"
8758
9281
  },
8759
9282
  {
8760
9283
  "name": "PublicDirCache",
@@ -8816,6 +9339,12 @@
8816
9339
  "package": "@nifrajs/cli",
8817
9340
  "signature": "export declare function queryImpact(graph: WorkGraph, changedFiles: readonly string[]): ImpactReport;"
8818
9341
  },
9342
+ {
9343
+ "name": "queryObjectOf",
9344
+ "kind": "function",
9345
+ "package": "@nifrajs/core",
9346
+ "signature": "export declare function queryObjectOf(search: string): Record<string, QueryValue>;"
9347
+ },
8819
9348
  {
8820
9349
  "name": "QueryOptions",
8821
9350
  "kind": "interface",
@@ -8844,6 +9373,20 @@
8844
9373
  "signature": "export type QueryStore<T> = Readable<QueryState<T>> & {\n /** Force a refetch (ignores `staleTime`). */\n readonly refetch: () => Promise<T>;\n};",
8845
9374
  "doc": "/** A query store: a `Readable<QueryState<T>>` (read via `$`) plus `refetch`. */"
8846
9375
  },
9376
+ {
9377
+ "name": "QueryValue",
9378
+ "kind": "type",
9379
+ "package": "@nifrajs/core",
9380
+ "signature": "export type QueryValue = string | string[];",
9381
+ "doc": "/** A query value: a single occurrence is a string; a repeated key promotes to a string[] so an\n * array query schema (`t.array(t.string())`) can validate `?tag=a&tag=b` - last-wins silently\n * dropped values before (audit 2026-06). Single-occurrence keys stay plain strings, so existing\n * `t.string()` schemas are untouched; a repeated key against a string schema now FAILS validation\n * (an explicit 400 beats silently picking one). */"
9382
+ },
9383
+ {
9384
+ "name": "QueryValue",
9385
+ "kind": "type",
9386
+ "package": "@nifrajs/edge",
9387
+ "signature": "export type QueryValue = string | string[];",
9388
+ "doc": "/** A query value: a single occurrence is a string; a repeated key promotes to a string[] so an\n * array query schema (`t.array(t.string())`) can validate `?tag=a&tag=b` - last-wins silently\n * dropped values before (audit 2026-06). Single-occurrence keys stay plain strings, so existing\n * `t.string()` schemas are untouched; a repeated key against a string schema now FAILS validation\n * (an explicit 400 beats silently picking one). */"
9389
+ },
8847
9390
  {
8848
9391
  "name": "Queue",
8849
9392
  "kind": "interface",
@@ -8922,6 +9465,13 @@
8922
9465
  "signature": "export interface RateLimitStore {\n hit(key: string, windowMs: number): Promise<RateLimitResult>;\n}",
8923
9466
  "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
9467
  },
9468
+ {
9469
+ "name": "raw",
9470
+ "kind": "function",
9471
+ "package": "@nifrajs/core",
9472
+ "signature": "export declare function raw<T>(response: Response): RawResponse<T>;",
9473
+ "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 */"
9474
+ },
8925
9475
  {
8926
9476
  "name": "raw",
8927
9477
  "kind": "function",
@@ -8936,6 +9486,13 @@
8936
9486
  "signature": "export declare class RawHtml {\n readonly value: string;\n constructor(value: string);\n}",
8937
9487
  "doc": "/** Branded wrapper marking a string as pre-trusted markup. Construct only via {@link raw}. */"
8938
9488
  },
9489
+ {
9490
+ "name": "RawResponse",
9491
+ "kind": "type",
9492
+ "package": "@nifrajs/core",
9493
+ "signature": "export type RawResponse<T> = Response & {\n readonly [NIFRA_RAW]: T;\n};",
9494
+ "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 */"
9495
+ },
8939
9496
  {
8940
9497
  "name": "reactAdapter",
8941
9498
  "kind": "const",
@@ -8962,6 +9519,13 @@
8962
9519
  "package": "@nifrajs/mcp",
8963
9520
  "signature": "export interface ReactWidgetOptions {\n /** The widget's `ui://` resource URI, e.g. `ui://orders/table`. */\n readonly uri: string;\n readonly name: string;\n readonly description?: string;\n readonly title?: string;\n /** Absolute path to a `.tsx`/`.jsx` module whose DEFAULT export is a React component. It receives the\n * tool's `structuredContent` as props. */\n readonly component: string;\n /** Extra `<head>` content (styles, fonts). The bridge + component bundle are injected for you. */\n readonly head?: string;\n /** Minify the client bundle (default true). */\n readonly minify?: boolean;\n}"
8964
9521
  },
9522
+ {
9523
+ "name": "readBodyFramed",
9524
+ "kind": "function",
9525
+ "package": "@nifrajs/core",
9526
+ "signature": "export declare function readBodyFramed<T>(source: RequestSource, maxBodyBytes: number, protoPoisoning: ProtoPoisoning, onParsed: (parsed: unknown) => MaybePromise<T>, wrapResponse: (response: Response | ResponseResult) => T, onError: (err: unknown) => MaybePromise<T>): Promise<T>;",
9527
+ "doc": "/**\n * The shared bounded body framing/parser: the single trust-boundary enforcement point every body\n * lane routes through. Content-type dispatch, the urlencoded-form cap, and the JSON path\n * (`Content-Length` pre-reject -> streaming cap -> prototype-poisoning guard, all inside\n * `readBoundedJsonSource`) live here so the fused body runner, the generic body-only lane, and a\n * compact edge entrypoint all enforce the same boundary from one definition. `protoPoisoning` is a\n * parameter, not read off a server instance, so this stays free of any dependency on the class.\n *\n * `onParsed` receives the decoded, guard-screened value; a framing rejection (`Content-Length` over\n * the cap, a lying length caught mid-stream, malformed JSON, an unsupported media type) is rendered\n * through `wrapResponse`; a read that never completed (client abort, socket error) reaches `onError`.\n */"
9528
+ },
8965
9529
  {
8966
9530
  "name": "readBoundedBytes",
8967
9531
  "kind": "function",
@@ -8983,6 +9547,20 @@
8983
9547
  "signature": "export declare function readImageDimensions(source: {\n arrayBuffer(): Promise<ArrayBuffer>;\n stream?: () => ReadableStream<Uint8Array>;\n}, maxBytes?: number): Promise<ImageInfo | null>;",
8984
9548
  "doc": "/**\n * Read just the leading bytes of an image file (via the platform `Bun.file`/`fetch` blob) and parse its\n * dimensions. Build-time tooling: pre-read dimensions into a manifest so `<Image>` is CLS-safe without\n * hardcoding sizes. Reads at most `maxBytes` (default 64 KB - enough for any header).\n */"
8985
9549
  },
9550
+ {
9551
+ "name": "readSingleCopyDeclaration",
9552
+ "kind": "function",
9553
+ "package": "@nifrajs/core",
9554
+ "signature": "export declare function readSingleCopyDeclaration(cwd: string): readonly string[] | undefined;",
9555
+ "doc": "/**\n * The declaration, read from `package.json` - deliberately NOT from `nifra.config.ts`.\n *\n * `nifra check` holds a pre-load invariant: it never imports the app's config, because importing is\n * executing. A dedupe claim has to be verifiable by a checker that refuses to run the app, so it lives\n * in the one file every tool already parses. `true` means the built-in identity-sensitive set.\n */"
9556
+ },
9557
+ {
9558
+ "name": "readSingleCopyRegistration",
9559
+ "kind": "function",
9560
+ "package": "@nifrajs/core",
9561
+ "signature": "export declare function readSingleCopyRegistration(cwd: string): SingleCopyRegistration;",
9562
+ "doc": "/**\n * Read the runtime proof out of `bunfig.toml`.\n *\n * Line-oriented on purpose: this runs inside `nifra check`, which must not execute or import anything\n * from the project, and the shape being read is a literal array of strings under a known key. A full\n * TOML parse would buy nothing here and would turn an unrelated syntax error elsewhere in the file\n * into a failure to answer this question.\n */"
9563
+ },
8986
9564
  {
8987
9565
  "name": "reconcileEffects",
8988
9566
  "kind": "function",
@@ -9114,8 +9692,8 @@
9114
9692
  "name": "redirect",
9115
9693
  "kind": "function",
9116
9694
  "package": "@nifrajs/web",
9117
- "signature": "export declare function redirect(location: string, options?: RedirectOptions): Response;",
9118
- "doc": "/**\n * Build a redirect `Response` - return it from a route `action` for the Post/Redirect/Get\n * pattern (POST mutates, 303 sends the browser to a fresh GET, so a reload doesn't re-submit).\n * Defaults to 303 (See Other); pass `{ status: 307 }` or `{ status: 308 }` to preserve the method.\n *\n * **Secure by default:** `location` must be a same-origin path (begins with `/`, not `//`). An\n * off-origin/absolute destination throws unless you pass `{ external: true }` - this closes the\n * open-redirect footgun of `return redirect(formData.get(\"next\"))` on the no-JS (native-form) path,\n * which returns the action's `Response` verbatim.\n *\n * @param options redirect status and whether an off-origin destination is intentional.\n */"
9695
+ "signature": "export declare function redirect(location: string, options?: RedirectOptions): ResponseResult;",
9696
+ "doc": "/**\n * Build a redirect - return it from a route `action` for the Post/Redirect/Get pattern (POST\n * mutates, 303 sends the browser to a fresh GET, so a reload doesn't re-submit). Defaults to 303\n * (See Other); pass `{ status: 307 }` or `{ status: 308 }` to preserve the method.\n *\n * **Secure by default:** `location` must be a same-origin path (begins with `/`, not `//`). An\n * off-origin/absolute destination throws unless you pass `{ external: true }` - this closes the\n * open-redirect footgun of `return redirect(formData.get(\"next\"))` on the no-JS (native-form) path,\n * which serves the action's control-flow value verbatim.\n *\n * Returns a plain render, not a `Response`. A redirect is a status line and one header - the most\n * body-less response there is - and building a `Response` for it costs the whole Web object plus, on\n * Node, a stream drained back out. As data it renders on the same lane a handler's return takes.\n * `redirect(...)` is still returned or thrown from exactly the same places; only `.status` /\n * `.headers` are gone from the value, replaced by `options.headers` and the request's `c.set`.\n *\n * @param options redirect status, extra headers, and whether an off-origin destination is intentional.\n */"
9119
9697
  },
9120
9698
  {
9121
9699
  "name": "REDIRECT_HEADER",
@@ -9128,7 +9706,7 @@
9128
9706
  "name": "RedirectOptions",
9129
9707
  "kind": "interface",
9130
9708
  "package": "@nifrajs/web",
9131
- "signature": "export interface RedirectOptions {\n /** HTTP status (default 303 See Other; pass 307/308 to preserve the method). */\n readonly status?: number;\n /** Allow an off-origin / absolute destination. Off by default: only a same-origin path (a single\n * leading `/`) is permitted, so an action can't be turned into an open redirect by passing\n * attacker-controlled input straight through. Set `true` for a deliberate external redirect. */\n readonly external?: boolean;\n}",
9709
+ "signature": "export interface RedirectOptions {\n /** HTTP status (default 303 See Other; pass 307/308 to preserve the method). */\n readonly status?: number;\n /** Allow an off-origin / absolute destination. Off by default: only a same-origin path (a single\n * leading `/`) is permitted, so an action can't be turned into an open redirect by passing\n * attacker-controlled input straight through. Set `true` for a deliberate external redirect. */\n readonly external?: boolean;\n /** Extra response headers. A redirect is no longer a `Response`, so there is no `.headers` to\n * mutate after the fact - name them here. Cookies still ride `c.set`, as on any other response. */\n readonly headers?: Readonly<Record<string, string>>;\n}",
9132
9710
  "doc": "/** Options for {@link redirect}. */"
9133
9711
  },
9134
9712
  {
@@ -9198,6 +9776,13 @@
9198
9776
  "signature": "export declare function registerFormat(name: string, validate: (value: string) => boolean): void;",
9199
9777
  "doc": "/** Register (or override) a string format usable as `t.string({ format: name })`. */"
9200
9778
  },
9779
+ {
9780
+ "name": "registerSingleCopy",
9781
+ "kind": "function",
9782
+ "package": "@nifrajs/core",
9783
+ "signature": "export declare function registerSingleCopy(options?: SingleCopyOptions): SingleCopyPlan;",
9784
+ "doc": "/**\n * Install the plugin into the Bun RUNTIME. Import `@nifrajs/core/single-copy/register` from a\n * `bunfig.toml` preload rather than calling this from application code: a resolver installed from\n * inside a module cannot affect the imports that module already resolved.\n */"
9785
+ },
9201
9786
  {
9202
9787
  "name": "Registry",
9203
9788
  "kind": "type",
@@ -9305,7 +9890,7 @@
9305
9890
  "name": "RenderPageOptions",
9306
9891
  "kind": "interface",
9307
9892
  "package": "@nifrajs/web",
9308
- "signature": "export interface RenderPageOptions {\n readonly adapter: RenderAdapter;\n /** The layout chain to render - outermost layout → page (opaque; the adapter renders it). */\n readonly chain: readonly unknown[];\n /** The loader output for this request. */\n readonly data: unknown;\n /** An action's data return (POST only) - surfaced to the page as `actionData` + serialized\n * for the client so post-POST hydration matches. Omit on GETs. */\n readonly actionData?: unknown;\n /**\n * URL of the built client entry (loaded as a module script).\n *\n * Optional ONLY on a `hydrate: false` page, where there is no client takeover to feed and this value\n * reaches no output at all. The union below is what enforces that: omitting it on a hydrating page\n * stays a compile error rather than rendering `src=\"\"`.\n */\n readonly clientEntry?: string;\n /** Chunk URLs for the **matched** route (its layout chain + own chunk) to `modulepreload` in the\n * shell - so the route code downloads in parallel with the entry instead of after it\n * (`buildClient`'s per-route map). Empty/omitted ⇒ only the entry is preloaded (unchanged). */\n readonly preload?: readonly string[];\n /** Stylesheet URLs for the **matched** route (its layout chain + own CSS, from `buildClient`'s\n * `BuildManifest.css`) - injected as `<link rel=\"stylesheet\">` in `<head>` so styles arrive with the\n * first paint (no FOUC). Rendered even on non-hydrated pages. Empty/omitted ⇒ none (unchanged). */\n readonly styles?: readonly string[];\n /** SSG: the prerendered-path set, serialized to `window.__NIFRA_PRERENDERED__` so the client fetches\n * a static `_data.json` on soft-nav into a prerendered route. Empty/omitted ⇒ not injected. */\n readonly prerenderedPaths?: readonly string[];\n /** ISR: route freshness in seconds, emitted as the `x-nifra-isr-revalidate` header for a `withISR`\n * wrapper to read. Omit ⇒ no header (the wrapper's default TTL applies). */\n readonly revalidate?: number;\n /** ISR invalidation tags emitted as a bounded `x-nifra-isr-tags` header. */\n readonly revalidateTags?: readonly string[];\n /** Matched route id; written to `window.__NIFRA_ROUTE__` so the client hydrates this chain. */\n readonly routeId?: string;\n /** The matched route's decoded path params - surfaced to the page as `params` (via {@link RenderProps})\n * so an adapter's `useParams` is SSR-correct. Omit ⇒ `{}` (a route with no dynamic segments, or an\n * error/404 render). */\n readonly params?: Readonly<Record<string, string>>;\n /** The request's `pathname + search` - surfaced as `path` (via {@link RenderProps}) so an adapter's\n * `useLocation`/`useSearchParams` render the right URL server-side and hydrate without drift. Omit ⇒\n * `\"\"`. */\n readonly path?: string;\n /** The route's validated search (`searchOf(mod.searchSchema, url.search)`, the same value handed to\n * the loader as `ctx.search`), surfaced as `search` (via {@link RenderProps}) so an adapter's\n * `useSearch` is SSR-correct. Omit ⇒ `{}` (a render with no search context). */\n readonly search?: Record<string, unknown>;\n /** Per-layout loader data, forwarded to the adapter as `RenderProps.layoutData`. Aligned with the\n * chain's layout prefix; omitted when no layout in the chain has a loader. */\n readonly layoutData?: readonly unknown[];\n /** HTTP status for the response (default 200; e.g. 404 for a not-found page). */\n readonly status?: number;\n /** Extra response headers - e.g. the `cache-control` a terminal status page wants. `content-type`\n * is ignored (the document is always HTML) and the ISR freshness header is applied after these,\n * so neither can be overridden from here. */\n readonly headers?: HeadersLike;\n /** Document title (fallback when `head.title` is unset). */\n readonly title?: string;\n /** Resolved route head - `title` overrides `title` above; `meta`/`link` render as managed\n * (`data-nifra`) tags the client updates on navigation.\n *\n * **Head contract (the layout chain contributes).** `createWebApp` resolves this via\n * {@link mergeHeads}: a route's head is its **layout chain's** `meta`/`head` exports merged with the\n * page's. A `_layout.tsx` may `export const meta` (or `export function meta(args)`) - its tags land\n * on every page below it (the home for `hreflang`, `preconnect`, a section-default `<title>`). The\n * merge is **nearest-wins for scalars** (the page's `title` overrides an inner layout's, which\n * overrides an outer one; an undefined page title keeps the layout's) and **concatenated for the\n * `meta`/`link` arrays** (outermost layout first, page last). `<meta>`/`<link>` attributes pass a\n * shared tag-specific allowlist (including inert `data-*` metadata) and values are escaped. */\n readonly head?: Meta;\n /** Id of the container wrapping the app markup (default `\"root\"`). A non-default id also gets\n * {@link ROOT_ATTRIBUTE}, which is how the generated client entry finds the container to hydrate -\n * the entry is built once and cannot know what a given render chose. */\n readonly rootId?: string;\n /** When `false`, emit a complete but **non-hydrated** document - no client entry script, data\n * globals, or modulepreloads. Used for server-rendered `_error` pages: a terminal state that needs no\n * client takeover, and it sidesteps an SSR/hydrate mismatch (the server rendered the boundary, not\n * the page the client manifest maps this route id to). Default `true`. */\n readonly hydrate?: boolean;\n /** Island client bundles (`@nifrajs/web/islands`) to load as `<script type=\"module\">` in the document\n * tail - emitted **regardless of `hydrate`**, so a static (`hydrate: false`) page can still mount\n * no-framework islands. URLs are attribute-escaped. Empty/omitted ⇒ none (unchanged output). */\n readonly islandScripts?: readonly string[];\n /** CSP nonce applied to every framework-owned executable script in this document. */\n readonly nonce?: string;\n /**\n * Advanced: a per-route slot the renderer fills with the request-invariant document pieces (shell\n * prefix/suffix, tail statics) on the first render and reuses afterwards, skipping their re-assembly.\n *\n * Only pass a cache when every shell-shaping input is IDENTICAL across the requests sharing it:\n * same `head` content (a static meta chain - never a `meta(data)` function), `title`, `styles`,\n * `preload`, `islandScripts`, `clientEntry`, `rootId`, `hydrate`, and `prerenderedPaths`. Per-request\n * values (`data`, `params`, `search`, `actionData`, `layoutData`, deferred state) are always assembled\n * fresh and safe. A per-request `nonce` disables the cache automatically. `createWebApp` wires this\n * per route, gated on the route + layout metas being static.\n */\n readonly assemblyCache?: RenderAssemblyCache;\n}"
9893
+ "signature": "export interface RenderPageOptions {\n readonly adapter: RenderAdapter;\n /** The layout chain to render - outermost layout → page (opaque; the adapter renders it). */\n readonly chain: readonly unknown[];\n /** The loader output for this request. */\n readonly data: unknown;\n /** An action's data return (POST only) - surfaced to the page as `actionData` + serialized\n * for the client so post-POST hydration matches. Omit on GETs. */\n readonly actionData?: unknown;\n /**\n * URL of the built client entry (loaded as a module script).\n *\n * Optional ONLY on a `hydrate: false` page, where there is no client takeover to feed and this value\n * reaches no output at all. The union below is what enforces that: omitting it on a hydrating page\n * stays a compile error rather than rendering `src=\"\"`.\n */\n readonly clientEntry?: string;\n /** Chunk URLs for the **matched** route (its layout chain + own chunk) to `modulepreload` in the\n * shell - so the route code downloads in parallel with the entry instead of after it\n * (`buildClient`'s per-route map). Empty/omitted ⇒ only the entry is preloaded (unchanged). */\n readonly preload?: readonly string[];\n /** Stylesheet URLs for the **matched** route (its layout chain + own CSS, from `buildClient`'s\n * `BuildManifest.css`) - injected as `<link rel=\"stylesheet\">` in `<head>` so styles arrive with the\n * first paint (no FOUC). Rendered even on non-hydrated pages. Empty/omitted ⇒ none (unchanged). */\n readonly styles?: readonly string[];\n /** SSG: the prerendered-path set, serialized to `window.__NIFRA_PRERENDERED__` so the client fetches\n * a static `_data.json` on soft-nav into a prerendered route. Empty/omitted ⇒ not injected. */\n readonly prerenderedPaths?: readonly string[];\n /** ISR: route freshness in seconds, emitted as the `x-nifra-isr-revalidate` header for a `withISR`\n * wrapper to read. Omit ⇒ no header (the wrapper's default TTL applies). */\n readonly revalidate?: number;\n /** ISR invalidation tags emitted as a bounded `x-nifra-isr-tags` header. */\n readonly revalidateTags?: readonly string[];\n /** Matched route id; written to `window.__NIFRA_ROUTE__` so the client hydrates this chain. */\n readonly routeId?: string;\n /** The matched route's decoded path params - surfaced to the page as `params` (via {@link RenderProps})\n * so an adapter's `useParams` is SSR-correct. Omit ⇒ `{}` (a route with no dynamic segments, or an\n * error/404 render). */\n readonly params?: Readonly<Record<string, string>>;\n /** The request's `pathname + search` - surfaced as `path` (via {@link RenderProps}) so an adapter's\n * `useLocation`/`useSearchParams` render the right URL server-side and hydrate without drift. Omit ⇒\n * `\"\"`. */\n readonly path?: string;\n /** The route's validated search (`searchOf(mod.searchSchema, url.search)`, the same value handed to\n * the loader as `ctx.search`), surfaced as `search` (via {@link RenderProps}) so an adapter's\n * `useSearch` is SSR-correct. Omit ⇒ `{}` (a render with no search context). */\n readonly search?: Record<string, unknown>;\n /** Per-layout loader data, forwarded to the adapter as `RenderProps.layoutData`. Aligned with the\n * chain's layout prefix; omitted when no layout in the chain has a loader. */\n readonly layoutData?: readonly unknown[];\n /** Dynamic-boundary states, forwarded to the adapter and serialized for hydration when present. */\n readonly boundaries?: BoundaryStates;\n /** HTTP status for the response (default 200; e.g. 404 for a not-found page). */\n readonly status?: number;\n /** Extra response headers - e.g. the `cache-control` a terminal status page wants. `content-type`\n * is ignored (the document is always HTML) and the ISR freshness header is applied after these,\n * so neither can be overridden from here. */\n readonly headers?: HeadersLike;\n /** Document title (fallback when `head.title` is unset). */\n readonly title?: string;\n /** Resolved route head - `title` overrides `title` above; `meta`/`link` render as managed\n * (`data-nifra`) tags the client updates on navigation.\n *\n * **Head contract (the layout chain contributes).** `createWebApp` resolves this via\n * {@link mergeHeads}: a route's head is its **layout chain's** `meta`/`head` exports merged with the\n * page's. A `_layout.tsx` may `export const meta` (or `export function meta(args)`) - its tags land\n * on every page below it (the home for `hreflang`, `preconnect`, a section-default `<title>`). The\n * merge is **nearest-wins for scalars** (the page's `title` overrides an inner layout's, which\n * overrides an outer one; an undefined page title keeps the layout's) and **concatenated for the\n * `meta`/`link` arrays** (outermost layout first, page last). `<meta>`/`<link>` attributes pass a\n * shared tag-specific allowlist (including inert `data-*` metadata) and values are escaped. */\n readonly head?: Meta;\n /** Id of the container wrapping the app markup (default `\"root\"`). A non-default id also gets\n * {@link ROOT_ATTRIBUTE}, which is how the generated client entry finds the container to hydrate -\n * the entry is built once and cannot know what a given render chose. */\n readonly rootId?: string;\n /** When `false`, emit a complete but **non-hydrated** document - no client entry script, data\n * globals, or modulepreloads. Used for server-rendered `_error` pages: a terminal state that needs no\n * client takeover, and it sidesteps an SSR/hydrate mismatch (the server rendered the boundary, not\n * the page the client manifest maps this route id to). Default `true`. */\n readonly hydrate?: boolean;\n /** Island client bundles (`@nifrajs/web/islands`) to load as `<script type=\"module\">` in the document\n * tail - emitted **regardless of `hydrate`**, so a static (`hydrate: false`) page can still mount\n * no-framework islands. URLs are attribute-escaped. Empty/omitted ⇒ none (unchanged output). */\n readonly islandScripts?: readonly string[];\n /** CSP nonce applied to every framework-owned executable script in this document. */\n readonly nonce?: string;\n /**\n * Advanced: a per-route slot the renderer fills with the request-invariant document pieces (shell\n * prefix/suffix, tail statics) on the first render and reuses afterwards, skipping their re-assembly.\n *\n * Only pass a cache when every shell-shaping input is IDENTICAL across the requests sharing it:\n * same `head` content (a static meta chain - never a `meta(data)` function), `title`, `styles`,\n * `preload`, `islandScripts`, `clientEntry`, `rootId`, `hydrate`, and `prerenderedPaths`. Per-request\n * values (`data`, `params`, `search`, `actionData`, `layoutData`, deferred state) are always assembled\n * fresh and safe. A per-request `nonce` disables the cache automatically. `createWebApp` wires this\n * per route, gated on the route + layout metas being static.\n */\n readonly assemblyCache?: RenderAssemblyCache;\n}"
9309
9894
  },
9310
9895
  {
9311
9896
  "name": "renderPageResult",
@@ -9317,7 +9902,7 @@
9317
9902
  "name": "RenderProps",
9318
9903
  "kind": "interface",
9319
9904
  "package": "@nifrajs/web",
9320
- "signature": "export interface RenderProps {\n readonly data: unknown;\n /** Per-layout loader data, aligned index-for-index with the layout prefix of `chain`. */\n readonly layoutData?: readonly unknown[];\n readonly actionData?: unknown;\n /** True while a client navigation or submit is in flight (client-only; absent/false on SSR). */\n readonly pending?: boolean;\n /** The path a client navigation is transitioning TO while `pending` (client-only; absent on SSR). */\n readonly pendingPath?: string;\n /** The in-flight client submit, for optimistic UI (client-only; absent on SSR). */\n readonly submission?: Submission;\n /** The matched route's decoded path params. */\n readonly params?: Readonly<Record<string, string>>;\n /** The current URL's `pathname + search` (no hash). */\n readonly path?: string;\n /** The route's typed, validated search params. */\n readonly search?: Record<string, unknown>;\n}",
9905
+ "signature": "export interface RenderProps {\n readonly data: unknown;\n /** Per-layout loader data, aligned index-for-index with the layout prefix of `chain`. */\n readonly layoutData?: readonly unknown[];\n readonly actionData?: unknown;\n /** True while a client navigation or submit is in flight (client-only; absent/false on SSR). */\n readonly pending?: boolean;\n /** The path a client navigation is transitioning TO while `pending` (client-only; absent on SSR). */\n readonly pendingPath?: string;\n /** The in-flight client submit, for optimistic UI (client-only; absent on SSR). */\n readonly submission?: Submission;\n /** The matched route's decoded path params. */\n readonly params?: Readonly<Record<string, string>>;\n /** The current URL's `pathname + search` (no hash). */\n readonly path?: string;\n /** The route's typed, validated search params. */\n readonly search?: Record<string, unknown>;\n /** Neutral named-boundary states; adapters choose how each boundary's `render` UI is mounted. */\n readonly boundaries?: BoundaryStates;\n}",
9321
9906
  "doc": "/** The data handed to a route component. */"
9322
9907
  },
9323
9908
  {
@@ -9438,6 +10023,13 @@
9438
10023
  "package": "@nifrajs/node",
9439
10024
  "signature": "export type RequestProtocolOption = RequestProtocol | ((request: IncomingMessage) => RequestProtocol);"
9440
10025
  },
10026
+ {
10027
+ "name": "RequestSource",
10028
+ "kind": "interface",
10029
+ "package": "@nifrajs/core",
10030
+ "signature": "export interface RequestSource {\n readonly method: string;\n readonly url: string;\n readonly headers: Headers;\n header?(name: string): string | null;\n /** Pre-split pathname/search, when the source already had the origin-form target (the Node lazy\n * sources do) - saves synthesizing an absolute URL only to scan it apart again. */\n readonly urlParts?: UrlParts;\n readonly body: ReadableStream<Uint8Array> | null;\n arrayBuffer(): Promise<ArrayBuffer>;\n json(): Promise<unknown>;\n /** Optional runtime-native exact-byte reader (Bun's Request.bytes, when available). */\n bytes?(): Promise<Uint8Array>;\n /** Present only when materializing a `Request` is non-trivial (the Node lazy source); for a real\n * `Request` passed as the source it's absent and {@link requestOf} returns the source itself. */\n readonly request?: Request;\n /** Optional pre-`Request` reader surface for the transport cap. A source that reads its own\n * transport bytes (the Node lazy source reads the socket) exposes them here so a capped direct\n * read (`c.req.json()`) buffers off the transport instead of routing through the deferred\n * `Request`. `body` must stay the live stream - the cap still guards a chunked body mid-flight. */\n rawBodyReaders?(): RawBodyReaders;\n}",
10031
+ "doc": "/**\n * Internal request view. A real Web `Request` already satisfies this shape, so Web/edge runtimes pass\n * their `Request` **directly** (zero wrapper allocation on the hot path - `request` is simply absent and\n * {@link requestOf} returns the source itself). Node's adapter passes a *lazy* source whose `request`\n * getter builds an undici `Request` only when user code reads `c.req`, an onRequest/onResponse hook\n * needs it, or a body helper consumes it - so the common Node request never pays for a `Request` build.\n */"
10032
+ },
9441
10033
  {
9442
10034
  "name": "RequestSpec",
9443
10035
  "kind": "interface",
@@ -9450,7 +10042,7 @@
9450
10042
  "kind": "function",
9451
10043
  "package": "@nifrajs/auth",
9452
10044
  "signature": "export declare function requireAuthorization<Subject, Resource>(authorizer: Authorizer<Subject, Resource>, request: AuthorizationRequest<Subject, Resource>): Promise<void>;",
9453
- "doc": "/** Require an application/data-layer policy to allow an action; denied requests throw a 403 Response. */"
10045
+ "doc": "/** Require an application/data-layer policy to allow an action. A denied request throws a plain\n * `status(403)` render - the same control-flow signal a guard throws, on the same rendering lane as a\n * returned one, so the denial never builds a `Response`. Like the guards, it throws because it is\n * called for effect from inside the work it protects; where the caller can return, return\n * `status(403, ...)` instead. */"
9454
10046
  },
9455
10047
  {
9456
10048
  "name": "requirePeer",
@@ -9464,21 +10056,21 @@
9464
10056
  "kind": "function",
9465
10057
  "package": "@nifrajs/better-auth",
9466
10058
  "signature": "export declare function requirePrincipal<A extends BetterAuthLike, const RequireTenant extends boolean = false>(auth: A, request: Request, options?: AuthedOptions<SessionUserOf<A>> & {\n readonly requireTenant?: RequireTenant;\n}): Promise<PrincipalFor<SessionUserOf<A>, RequireTenant>>;",
9467
- "doc": "/**\n * Resolve the better-auth session and map it to a {@link Principal}, or **throw a `Response`** so the\n * handler never runs unauthenticated:\n *\n * - No/invalid session -> `302` to `options.redirectTo` when set, else `401` JSON (`requireSession`).\n * - `requireTenant: true` and no tenant resolves -> `403` JSON (`{ ok: false, error: \"forbidden\" }`).\n *\n * nifra returns a thrown `Response` as-is (short-circuit), so this is the fail-closed guard used inline\n * or by {@link authed}. `tenantId` is a non-optional `string` in the return type when `requireTenant`.\n *\n * ```ts\n * const principal = await requirePrincipal(auth, c.req, { requireTenant: true })\n * // principal.userId / principal.tenantId are typed `string`, no null-check\n * ```\n */"
10059
+ "doc": "/**\n * Resolve the better-auth session and map it to a {@link Principal}, or **throw a Nifra `ResponseResult`** so the\n * handler never runs unauthenticated:\n *\n * - No/invalid session -> `302` to `options.redirectTo` when set, else `401` JSON (`requireSession`).\n * - `requireTenant: true` and no tenant resolves -> `403` JSON (`{ ok: false, error: \"forbidden\" }`).\n *\n * nifra handles the thrown control-flow value as a short-circuit, so this is the fail-closed guard used\n * inline or by {@link authed}. `tenantId` is a non-optional `string` in the return type when `requireTenant`.\n *\n * ```ts\n * const principal = await requirePrincipal(auth, c.req, { requireTenant: true })\n * // principal.userId / principal.tenantId are typed `string`, no null-check\n * ```\n */"
9468
10060
  },
9469
10061
  {
9470
10062
  "name": "requireSession",
9471
10063
  "kind": "function",
9472
10064
  "package": "@nifrajs/auth",
9473
10065
  "signature": "export declare function requireSession<Data extends Record<string, unknown>>(session: Session<Data>, options?: GuardOptions): Session<Data>;",
9474
- "doc": "/**\n * Require a non-empty session. Returns it when present; otherwise throws a `Response` (302/401). Use at\n * the top of a protected loader:\n * `const session = requireSession(await sessions.get(c), { redirectTo: \"/login\" })`.\n */"
10066
+ "doc": "/**\n * Require a non-empty session. Returns it when present; otherwise throws a `status(...)` render\n * (302/401) - control flow, not a `Response`; see the module docs above. Use at\n * the top of a protected loader:\n * `const session = requireSession(await sessions.get(c), { redirectTo: \"/login\" })`.\n */"
9475
10067
  },
9476
10068
  {
9477
10069
  "name": "requireSession",
9478
10070
  "kind": "function",
9479
10071
  "package": "@nifrajs/better-auth",
9480
10072
  "signature": "export declare function requireSession<A extends BetterAuthLike>(auth: A, request: Request, options?: RequireSessionOptions): Promise<SessionOf<A>>;",
9481
- "doc": "/**\n * Require an authenticated better-auth session at the top of a protected handler/loader/action.\n * Returns the (non-null) session when present; otherwise **throws a `Response`** (302/401) - nifra\n * returns a thrown `Response` as-is, short-circuiting the rest of the handler.\n *\n * ```ts\n * const { user } = await requireSession(auth, c.req, { redirectTo: \"/login\" })\n * ```\n */"
10073
+ "doc": "/**\n * Require an authenticated better-auth session at the top of a protected handler/loader/action.\n * Returns the (non-null) session when present; otherwise **throws a Nifra `ResponseResult`** (302/401).\n * Nifra handles the thrown control-flow value on the same rendering lane as `@nifrajs/auth`.\n *\n * ```ts\n * const { user } = await requireSession(auth, c.req, { redirectTo: \"/login\" })\n * ```\n */"
9482
10074
  },
9483
10075
  {
9484
10076
  "name": "RequireSessionOptions",
@@ -9494,6 +10086,34 @@
9494
10086
  "signature": "export declare function requireUser<Data extends Record<string, unknown>, K extends keyof Data>(session: Session<Data>, key: K, options?: GuardOptions): NonNullable<Data[K]>;",
9495
10087
  "doc": "/**\n * Require a specific session key (e.g. the `userId` a login set) to be present. Returns its value\n * (narrowed non-nullish); otherwise throws like {@link requireSession}. The common \"who is the user\"\n * guard: `const userId = requireUser(await sessions.get(c), \"userId\", { redirectTo: \"/login\" })`.\n */"
9496
10088
  },
10089
+ {
10090
+ "name": "RESERVED_EXACT_KEYS",
10091
+ "kind": "const",
10092
+ "package": "@nifrajs/client",
10093
+ "signature": "export declare const RESERVED_EXACT_KEYS: readonly [\"subscribe\", \"ws\", \"index\", \"then\"];",
10094
+ "doc": "/** Intercepted by exact match: `subscribe`/`ws` are transports, `index` is `/`, `then` is the await guard. */"
10095
+ },
10096
+ {
10097
+ "name": "RESERVED_KEY_READOUT",
10098
+ "kind": "const",
10099
+ "package": "@nifrajs/client",
10100
+ "signature": "export declare const RESERVED_KEY_READOUT: string;",
10101
+ "doc": "/** Human-readable readout of the closed set, for diagnostics that have to teach it. */"
10102
+ },
10103
+ {
10104
+ "name": "RESERVED_VERB_KEYS",
10105
+ "kind": "const",
10106
+ "package": "@nifrajs/client",
10107
+ "signature": "export declare const RESERVED_VERB_KEYS: readonly [\"get\", \"post\", \"put\", \"patch\", \"delete\", \"head\", \"options\"];",
10108
+ "doc": "/** Intercepted case-insensitively: `/api/Delete` collides just as `/api/delete` does. */"
10109
+ },
10110
+ {
10111
+ "name": "reservedKeyFor",
10112
+ "kind": "function",
10113
+ "package": "@nifrajs/client",
10114
+ "signature": "export declare function reservedKeyFor(segment: string): string | undefined;",
10115
+ "doc": "/**\n * The reserved key a static path segment collides with, or undefined. Params (`:id`) and wildcards\n * (`*rest`) never collide - they are not spelled as property accesses.\n */"
10116
+ },
9497
10117
  {
9498
10118
  "name": "ResizeInput",
9499
10119
  "kind": "interface",
@@ -9518,6 +10138,13 @@
9518
10138
  "package": "@nifrajs/i18n",
9519
10139
  "signature": "export interface ResolvedLocale {\n /** Always a member of `locales` (or `defaultLocale`) - never raw request input. */\n readonly locale: Locale;\n readonly source: LocaleSource;\n /** The supported locale the request's cookie currently resolves to, when\n * {@link NegotiateOptions.cookie} is configured and the cookie holds a valid value. Lets a caller\n * persist a new choice only when it actually differs. */\n readonly cookie?: Locale;\n}"
9520
10140
  },
10141
+ {
10142
+ "name": "resolveDynamicBoundaries",
10143
+ "kind": "function",
10144
+ "package": "@nifrajs/web",
10145
+ "signature": "export declare function resolveDynamicBoundaries(boundaries: readonly BoundaryRegistration[], context: BoundaryRequestCtx): Promise<BoundaryStates>;",
10146
+ "doc": "/**\n * Resolve all dynamic boundaries concurrently. Each receives a fresh frozen context object; one\n * failure becomes that boundary's error state and never rejects a sibling or exposes sibling data.\n * Static/intercepting modes remain `unresolved` until their phase-specific runtime owns them.\n */"
10147
+ },
9521
10148
  {
9522
10149
  "name": "resolveImage",
9523
10150
  "kind": "function",
@@ -9560,6 +10187,13 @@
9560
10187
  "signature": "export declare function resolveRouteFile(path: string, routes: readonly RouteLocation[]): string | undefined;",
9561
10188
  "doc": "/**\n * Resolve a route path literal to the first route whose pattern matches it. Query/hash are ignored\n * (a link's `?tab=x` does not change which route file serves it). Returns the route's `file`, or\n * undefined when the value is not a path or matches no route.\n */"
9562
10189
  },
10190
+ {
10191
+ "name": "resolveStaticBoundaries",
10192
+ "kind": "function",
10193
+ "package": "@nifrajs/web",
10194
+ "signature": "export declare function resolveStaticBoundaries(boundaries: readonly BoundaryRegistration[], context: StaticCtx, cache?: StaticBoundaryCache): Promise<BoundaryStates>;",
10195
+ "doc": "/**\n * Resolve only explicitly annotated static boundaries with a request-free build context. Dynamic\n * and intercepting boundaries remain unresolved. Values are cached by boundary object identity in\n * the supplied in-memory cache, so a worker instance does not repeat a build-safe computation per\n * request. A rejected static load becomes that slot's error state; it never fabricates shared data.\n */"
10196
+ },
9563
10197
  {
9564
10198
  "name": "respondMcpHttp",
9565
10199
  "kind": "function",
@@ -9726,6 +10360,51 @@
9726
10360
  "signature": "export interface ResponseHeadersView {\n get(name: string): string | null;\n has(name: string): boolean;\n set(name: string, value: string): void;\n append(name: string, value: string): void;\n delete(name: string): void;\n}",
9727
10361
  "doc": "/**\n * The mutable, case-insensitive header surface a portable {@link ResponseHeadersHook} writes\n * through. Deliberately the subset of the Web `Headers` interface every runtime can satisfy\n * natively: on the Web paths the hook receives the response's own `Headers` object directly (which\n * structurally implements this), and on the Node direct-writer path it receives a thin view over\n * the outcome's plain header record - so ONE hook implementation is fast everywhere.\n */"
9728
10362
  },
10363
+ {
10364
+ "name": "responseObserver",
10365
+ "kind": "function",
10366
+ "package": "@nifrajs/core",
10367
+ "signature": "export declare function responseObserver(): ResponseObserverPlugin;",
10368
+ "doc": "/**\n * Enable the response observation methods on a server.\n *\n * The default server does not carry the header, body, or raw-response observation adapters. Apply\n * this plugin before using those methods:\n *\n * ```ts\n * import { responseObserver } from \"@nifrajs/core/response-observer\"\n * const app = server().use(responseObserver()).onResponseHeaders((headers) => {\n * headers.set(\"cache-control\", \"no-store\")\n * })\n * ```\n */"
10369
+ },
10370
+ {
10371
+ "name": "ResponseObserverMethods",
10372
+ "kind": "interface",
10373
+ "package": "@nifrajs/core",
10374
+ "signature": "export interface ResponseObserverMethods {\n onResponseHeaders(fn: ResponseHeadersHook): this;\n onResponseBody(fn: ResponseBodyHook): this;\n onResponseRaw(fn: (response: Response, req: Request) => MaybePromise<Response>): this;\n}"
10375
+ },
10376
+ {
10377
+ "name": "ResponseObserverPlugin",
10378
+ "kind": "type",
10379
+ "package": "@nifrajs/core",
10380
+ "signature": "export type ResponseObserverPlugin = (<S extends AnyServer>(app: S) => ResponseObserverServer<S>) & {\n readonly pluginName?: string;\n};",
10381
+ "doc": "/** A plugin that enables response header, body, and raw-response observation methods. */"
10382
+ },
10383
+ {
10384
+ "name": "ResponseObserverRuntime",
10385
+ "kind": "interface",
10386
+ "package": "@nifrajs/core",
10387
+ "signature": "export interface ResponseObserverRuntime {\n install(host: ResponseObserverHost): ResponseObserverMethods;\n}"
10388
+ },
10389
+ {
10390
+ "name": "ResponseObserverServer",
10391
+ "kind": "type",
10392
+ "package": "@nifrajs/core",
10393
+ "signature": "export type ResponseObserverServer<S extends AnyServer> = S & import(\"./server/response-observer-runtime.js\").ResponseObserverMethods;",
10394
+ "doc": "/** A server shape with the opt-in response observation methods installed. */"
10395
+ },
10396
+ {
10397
+ "name": "ResponseResult",
10398
+ "kind": "interface",
10399
+ "package": "@nifrajs/core",
10400
+ "signature": "export interface ResponseResult {\n readonly [RESPONSE_RESULT]: true;\n toResponse(): Response;\n toNodeBody?(): {\n readonly status: number;\n readonly headers: Readonly<Record<string, string | readonly string[]>> | undefined;\n readonly body: string | Uint8Array;\n };\n /** Present when this result can be rendered as plain data - see {@link PlainRender}. Every lane\n * checks it before `toNodeBody`/`toResponse`, so a carrier that has one never builds a `Response`. */\n readonly plain?: PlainRender;\n}"
10401
+ },
10402
+ {
10403
+ "name": "ResponseResult",
10404
+ "kind": "interface",
10405
+ "package": "nifra",
10406
+ "signature": "export interface ResponseResult {\n readonly [RESPONSE_RESULT]: true;\n toResponse(): Response;\n toNodeBody?(): {\n readonly status: number;\n readonly headers: Readonly<Record<string, string | readonly string[]>> | undefined;\n readonly body: string | Uint8Array;\n };\n /** Present when this result can be rendered as plain data - see {@link PlainRender}. Every lane\n * checks it before `toNodeBody`/`toResponse`, so a carrier that has one never builds a `Response`. */\n readonly plain?: PlainRender;\n}"
10407
+ },
9729
10408
  {
9730
10409
  "name": "ResponseStream",
9731
10410
  "kind": "interface",
@@ -9930,14 +10609,14 @@
9930
10609
  "name": "RouteConfigErrorCode",
9931
10610
  "kind": "type",
9932
10611
  "package": "@nifrajs/core",
9933
- "signature": "export type RouteConfigErrorCode = \"DUPLICATE_ROUTE\" | \"DUPLICATE_PARAM\" | \"PARAM_NAME_CONFLICT\" | \"INVALID_PATH\" | \"INVALID_PARAM_NAME\" | \"WILDCARD_NOT_LAST\" | \"INVALID_METHOD\" | \"INVALID_ASSURANCE\" | \"INVALID_IDEMPOTENCY\" | \"INVALID_BODY_LIMIT\";",
10612
+ "signature": "export type RouteConfigErrorCode = \"DUPLICATE_ROUTE\" | \"DUPLICATE_PARAM\" | \"PARAM_NAME_CONFLICT\" | \"INVALID_PATH\" | \"INVALID_PARAM_NAME\" | \"WILDCARD_NOT_LAST\" | \"INVALID_METHOD\" | \"INVALID_ASSURANCE\" | \"INVALID_IDEMPOTENCY\" | \"INVALID_WS_SEND_VALIDATION\" | \"INVALID_BODY_LIMIT\";",
9934
10613
  "doc": "/** Stable codes for boot-time (L2) route configuration failures. */"
9935
10614
  },
9936
10615
  {
9937
10616
  "name": "RouteConfigErrorCode",
9938
10617
  "kind": "type",
9939
10618
  "package": "nifra",
9940
- "signature": "export type RouteConfigErrorCode = \"DUPLICATE_ROUTE\" | \"DUPLICATE_PARAM\" | \"PARAM_NAME_CONFLICT\" | \"INVALID_PATH\" | \"INVALID_PARAM_NAME\" | \"WILDCARD_NOT_LAST\" | \"INVALID_METHOD\" | \"INVALID_ASSURANCE\" | \"INVALID_IDEMPOTENCY\" | \"INVALID_BODY_LIMIT\";",
10619
+ "signature": "export type RouteConfigErrorCode = \"DUPLICATE_ROUTE\" | \"DUPLICATE_PARAM\" | \"PARAM_NAME_CONFLICT\" | \"INVALID_PATH\" | \"INVALID_PARAM_NAME\" | \"WILDCARD_NOT_LAST\" | \"INVALID_METHOD\" | \"INVALID_ASSURANCE\" | \"INVALID_IDEMPOTENCY\" | \"INVALID_WS_SEND_VALIDATION\" | \"INVALID_BODY_LIMIT\";",
9941
10620
  "doc": "/** Stable codes for boot-time (L2) route configuration failures. */"
9942
10621
  },
9943
10622
  {
@@ -10021,7 +10700,7 @@
10021
10700
  "name": "RouteModule",
10022
10701
  "kind": "interface",
10023
10702
  "package": "@nifrajs/web",
10024
- "signature": "export interface RouteModule {\n readonly default: unknown;\n readonly loader?: Loader;\n readonly action?: Action;\n /** A Standard Schema validating this route's URL search params. When present, `ctx.search` is parsed +\n * validated against it (failing closed to the schema's defaults on invalid input); type it into the\n * loader with `LoaderArgs<Api, Env, typeof searchSchema>`. */\n readonly searchSchema?: StandardSchemaV1<unknown, Record<string, unknown>>;\n /** Search keys that are purely client-side UI (`\"tab\"`, a client-side `\"sort\"`, `\"modal\"`) and do NOT\n * affect this route's loader. When a client navigation stays on the same route + pathname and changes\n * ONLY these keys, the router updates the URL (so `useSearch` re-renders) WITHOUT re-running the loader.\n * Any other key change revalidates as usual - so omitting a data-affecting key here can never serve\n * stale data, it only forgoes the optimization. Client-only: the server always renders fresh. */\n readonly searchClientKeys?: readonly string[];\n readonly meta?: MetaInput;\n /**\n * Opt this route out of nifra's full-document client hydration. The server still renders the full\n * HTML document, loaders/actions still run, and native links/forms still work; the generated app\n * client, route chunks, and loader globals are omitted for hard navigations. Intended for static or\n * island-hydrated pages where interactivity is mounted by smaller, explicit client entries.\n */\n readonly hydrate?: boolean;\n /**\n * Opt a **static** route (no `:param`/`*`) into build-time prerendering (SSG): `prerenderRoutes`\n * (from `@nifrajs/web/build`) renders it to a static `index.html` at build. The loader runs at build\n * with the in-process `api` (build-safe data only - no per-request cookies/secrets); `defer()` on a\n * prerendered route resolves at build. For **dynamic** routes use {@link getStaticPaths} instead.\n */\n readonly prerender?: boolean;\n /**\n * Enumerate the concrete params to prerender for a **dynamic** (`:param`) route - the SSG path list\n * (blogs/docs/etc.). Runs at build; `prerenderRoutes` renders one `index.html` per returned path.\n */\n readonly getStaticPaths?: GetStaticPaths;\n /**\n * ISR freshness for this route, in **seconds**. `createWebApp` emits it as an\n * `x-nifra-isr-revalidate` response header that `withISR` reads to set the page's cache TTL\n * (overriding the wrapper's default). Older-than-`revalidate` cached pages are served stale while\n * regenerating. (Distinct from the action-revalidation `x-nifra-revalidate` header - a CSV path\n * list the client parses to refetch - so the two channels never alias.)\n */\n readonly revalidate?: number;\n /** Optional bounded tags used by ISR on-demand invalidation (`?tag=...`). */\n readonly revalidateTags?: readonly string[];\n /**\n * No-framework island bundles (`@nifrajs/web/islands`) to load on this route, as `<script\n * type=\"module\">` in the document tail. Loaded **regardless of `hydrate`** - pair with\n * `export const hydrate = false` for a static page that ships zero framework JS and mounts\n * interactivity through `<Island>` markers + `mountIslands` enhancers instead.\n */\n readonly islandScripts?: readonly string[];\n}",
10703
+ "signature": "export interface RouteModule {\n readonly default: unknown;\n readonly loader?: Loader;\n readonly action?: Action;\n /** Optional client-only loader. It runs after hydration and on client navigations. */\n readonly clientLoader?: ClientLoader;\n /** Optional client-only submit wrapper. The server action remains mandatory for mutations. */\n readonly clientAction?: ClientAction;\n /** Named async boundaries owned by this route. The adapter renders their neutral state seam. */\n readonly boundaries?: readonly BoundaryRegistration[];\n /** A Standard Schema validating this route's URL search params. When present, `ctx.search` is parsed +\n * validated against it (failing closed to the schema's defaults on invalid input); type it into the\n * loader with `LoaderArgs<Api, Env, typeof searchSchema>`. */\n readonly searchSchema?: StandardSchemaV1<unknown, Record<string, unknown>>;\n /** Search keys that are purely client-side UI (`\"tab\"`, a client-side `\"sort\"`, `\"modal\"`) and do NOT\n * affect this route's loader. When a client navigation stays on the same route + pathname and changes\n * ONLY these keys, the router updates the URL (so `useSearch` re-renders) WITHOUT re-running the loader.\n * Any other key change revalidates as usual - so omitting a data-affecting key here can never serve\n * stale data, it only forgoes the optimization. Client-only: the server always renders fresh. */\n readonly searchClientKeys?: readonly string[];\n readonly meta?: MetaInput;\n /**\n * Opt this route out of nifra's full-document client hydration. The server still renders the full\n * HTML document, loaders/actions still run, and native links/forms still work; the generated app\n * client, route chunks, and loader globals are omitted for hard navigations. Intended for static or\n * island-hydrated pages where interactivity is mounted by smaller, explicit client entries.\n */\n readonly hydrate?: boolean;\n /**\n * Opt a **static** route (no `:param`/`*`) into build-time prerendering (SSG): `prerenderRoutes`\n * (from `@nifrajs/web/build`) renders it to a static `index.html` at build. The loader runs at build\n * with the in-process `api` (build-safe data only - no per-request cookies/secrets); `defer()` on a\n * prerendered route resolves at build. For **dynamic** routes use {@link getStaticPaths} instead.\n */\n readonly prerender?: boolean;\n /**\n * Enumerate the concrete params to prerender for a **dynamic** (`:param`) route - the SSG path list\n * (blogs/docs/etc.). Runs at build; `prerenderRoutes` renders one `index.html` per returned path.\n */\n readonly getStaticPaths?: GetStaticPaths;\n /**\n * ISR freshness for this route, in **seconds**. `createWebApp` emits it as an\n * `x-nifra-isr-revalidate` response header that `withISR` reads to set the page's cache TTL\n * (overriding the wrapper's default). Older-than-`revalidate` cached pages are served stale while\n * regenerating. (Distinct from the action-revalidation `x-nifra-revalidate` header - a CSV path\n * list the client parses to refetch - so the two channels never alias.)\n */\n readonly revalidate?: number;\n /** Optional bounded tags used by ISR on-demand invalidation (`?tag=...`). */\n readonly revalidateTags?: readonly string[];\n /**\n * No-framework island bundles (`@nifrajs/web/islands`) to load on this route, as `<script\n * type=\"module\">` in the document tail. Loaded **regardless of `hydrate`** - pair with\n * `export const hydrate = false` for a static page that ships zero framework JS and mounts\n * interactivity through `<Island>` markers + `mountIslands` enhancers instead.\n */\n readonly islandScripts?: readonly string[];\n}",
10025
10704
  "doc": "/** A route module - the default component + optional loader / action / meta. */"
10026
10705
  },
10027
10706
  {
@@ -10095,21 +10774,21 @@
10095
10774
  "name": "RouterState",
10096
10775
  "kind": "interface",
10097
10776
  "package": "@nifrajs/web",
10098
- "signature": "export interface RouterState {\n readonly routeId: string;\n readonly params: Record<string, string>;\n /** The current URL path (used to revalidate the active loader after an action). */\n readonly path: string;\n readonly data: unknown;\n /** Per-layout loader data, aligned with the matched chain's leading layout prefix. Absent when no\n * layout in that chain has a loader. */\n readonly layoutData?: readonly unknown[] | undefined;\n /** An action's data return after a client-side submit (cleared on navigation). */\n readonly actionData?: unknown;\n /** True while a navigation or submit is in flight (drives loading UI). */\n readonly pending: boolean;\n /** The path a navigation is transitioning TO while `pending` (cleared when it settles). Lets a\n * `NavLink` know whether its own `to` is the one loading; `undefined` when idle. */\n readonly pendingPath?: string | undefined;\n /** The in-flight submit (set during a `submit`, cleared when it settles) - for optimistic UI. */\n readonly submission?: Submission;\n}",
10777
+ "signature": "export interface RouterState {\n readonly routeId: string;\n readonly params: Record<string, string>;\n /** The current URL path (used to revalidate the active loader after an action). */\n readonly path: string;\n readonly data: unknown;\n /** Per-layout loader data, aligned with the matched chain's leading layout prefix. Absent when no\n * layout in that chain has a loader. */\n readonly layoutData?: readonly unknown[] | undefined;\n /** Neutral named-boundary states for the active route. */\n readonly boundaries?: BoundaryStates;\n /** An action's data return after a client-side submit (cleared on navigation). */\n readonly actionData?: unknown;\n /** True while a navigation or submit is in flight (drives loading UI). */\n readonly pending: boolean;\n /** The path a navigation is transitioning TO while `pending` (cleared when it settles). Lets a\n * `NavLink` know whether its own `to` is the one loading; `undefined` when idle. */\n readonly pendingPath?: string | undefined;\n /** The in-flight submit (set during a `submit`, cleared when it settles) - for optimistic UI. */\n readonly submission?: Submission;\n}",
10099
10778
  "doc": "/** The router's observable state. A new object is published on every transition. */"
10100
10779
  },
10101
10780
  {
10102
10781
  "name": "RouteSchema",
10103
10782
  "kind": "interface",
10104
10783
  "package": "@nifrajs/core",
10105
- "signature": "export interface RouteSchema {\n /** Transport body cap for this route. Defaults to the server's maxBodyBytes. Use a finite\n * smaller/larger limit for a specific endpoint. The 'unlimited' value is an explicit\n * streaming/upload exemption and requires a non-empty bodyLimitReason for auditability. */\n readonly bodyLimit?: number | \"unlimited\";\n /** Required explanation when bodyLimit is 'unlimited' (for example, a streaming upload is\n * bounded by an upstream object-store protocol). */\n readonly bodyLimitReason?: string;\n /** Declared effect tokens. Reflected for assurance; never read by validation or serialization. */\n readonly capabilities?: readonly string[];\n /**\n * Dedupe retries of this (mutating) route on an `Idempotency-Key` header. The first request runs and\n * its response is stored; a retry with the same key replays that response without re-running the\n * handler, and a key reused with a different body is rejected (409). A missing key on an\n * idempotency-required route fails closed (400). Off the hot path - routes without it are unchanged.\n */\n readonly idempotency?: IdempotencyConfig;\n /**\n * Highest data-sensitivity this route's response body carries (`public` | `pii` | `secret`). A\n * declarative, compile-time + introspection fact - never validated at runtime. Reflected for tooling,\n * recorded in the capability lockfile (so a route that starts returning PII is a reviewable change),\n * and read by downstream policy (e.g. a partner-API surface refusing to expose `pii`/`secret`).\n */\n readonly classification?: DataClassification;\n /**\n * Inline **route-assurance evidence**: the enforcement posture this route carries, declared adjacent to\n * the handler (e.g. `[NIFRA_ASSURANCE.AUTHENTICATED]`). Each id becomes route-scoped `declared` evidence\n * in reflection, so a `nifra.assurance.ts` policy `require:` clause is satisfiable WITHOUT rewriting an\n * in-handler guard into a `withRouteAssurance`-marked middleware. Ids are lowercase dot/dash segments\n * (invalid ids throw at registration). Reflected for the assurance gate; never read on the hot path.\n *\n * This is an author ASSERTION (recorded as `source: \"declared\"`), not runtime proof - like every\n * assurance marker it is trusted by the static gate, which matches on the evidence id, not its source.\n * Declare an id only on a route whose guard actually enforces it; a false declaration silently satisfies\n * the policy. (`source` is retained in reflection, so a stricter policy or reviewer can still tell\n * declared evidence from enforcement-module evidence.)\n */\n readonly assurance?: readonly string[];\n /**\n * Mark this route a **dynamic route family**: a template (`/api/:slug/:resource`) whose concrete\n * resources are resolved at runtime (auto-CRUD over tenant-defined tables, a catch-all dispatcher).\n * Purely declarative - it does not change dispatch. It surfaces in reflection so the assurance gate and\n * tooling treat the one templated route as a deliberate family whose evidence covers every runtime-\n * resolved resource, instead of reading it as a single forgotten route.\n */\n readonly family?: boolean;\n /** Optional **path-params schema**. Path params arrive as strings (`/users/:id` -> `c.params.id`);\n * declaring a schema validates them at the boundary (a malformed `:id` is a `422` before the handler,\n * like `body`/`query`) and can coerce them (use `t.query({ id: t.integer() })` for a numeric param).\n * The schema must cover every path param; with the strict default an undeclared path param is rejected.\n * When omitted, `c.params` stays the path-inferred `Record<name, string>`. */\n readonly params?: StandardSchemaV1;\n /** Optional request-header schema. Header names are normalized to lower-case and the validated\n * output is exposed as `c.headers`; use lower-case keys because HTTP header names are\n * case-insensitive. */\n readonly headers?: StandardSchemaV1;\n readonly body?: StandardSchemaV1;\n readonly query?: StandardSchemaV1;\n /** Optional **response contract**. When declared: the handler's return is type-checked against it\n * (the implementation can't drift from the contract), the typed client sees THIS as the response type\n * (the contract - not the handler's incidental return), and it's emitted into OpenAPI/JSON-Schema so\n * tooling and coding agents can read the exact shape. It is **not** validated at runtime (zero\n * hot-path cost) - purely a compile-time + introspection contract. */\n readonly response?: StandardSchemaV1;\n /**\n * Optional **error-response contract**: a map of HTTP status code → the Standard Schema of that error's\n * body. Declares a route's failure modes so they flow into OpenAPI (as non-2xx `responses`), the\n * `/llms.txt` context, and other introspection - the whole contract, not just the happy path, is legible\n * to tooling and coding agents. Like `response`, it is **not** validated at runtime (zero hot-path cost);\n * it's a compile-time + introspection contract. Example: `{ 404: NotFound, 409: Conflict }`. */\n readonly errors?: Readonly<Record<number, StandardSchemaV1>>;\n /**\n * Optional **SSE event contract**: the Standard Schema of each event's `data` payload on a\n * streaming route (declared via `app.sse()`). Marks the route as a typed event stream - the\n * typed client grows a `.subscribe()` for it, and the schema flows into reflection. Like\n * `response`, it is **not** validated at runtime (zero hot-path cost); the server-side\n * `stream.send()` is compile-time-checked against it instead.\n */\n readonly sse?: StandardSchemaV1;\n /**\n * Hook fired when the request fails `headers`/`params`/`body`/`query` validation, before the handler\n * runs. `kind` says which input failed. Its return value selects one of three outcomes (may be async):\n * - a **`Response`** → returned as-is, short-circuiting the route (custom error envelope, redirect, …).\n * - **any other value** → treated as a repaired payload and **re-validated once** against the same\n * schema. If it now passes, the handler runs with it; if it still fails, the original `422` stands.\n * Re-validation means a bad return can't bypass the schema - the trust boundary holds.\n * - **`undefined`** → give up; the original validation `422` is returned unchanged.\n * A route hook **overrides** the app-wide default set via `server({ onValidationError })`; return\n * `undefined` to fall through to the plain `422` even when an app default exists. Typical uses: a custom\n * error envelope, coercing the input, or prompting an LLM to repair the payload (re-validated, so it can't\n * bypass the schema).\n */\n readonly onValidationError?: (issues: ReadonlyArray<StandardIssue>, ctx: Context, kind: \"body\" | \"query\" | \"params\" | \"headers\") => Response | unknown | Promise<Response | unknown>;\n}",
10784
+ "signature": "export interface RouteSchema {\n /** Transport body cap for this route. Defaults to the server's maxBodyBytes. Use a finite\n * smaller/larger limit for a specific endpoint. The 'unlimited' value is an explicit\n * streaming/upload exemption and requires a non-empty bodyLimitReason for auditability.\n *\n * 'unlimited' is legal only for schema-less streaming/upload routes. It is rejected with `body` or\n * `idempotency`, because those lanes buffer the body before user code can apply a protocol-specific\n * bound. Read an unlimited route from `c.req.body` as a stream and bound it by the protocol it speaks;\n * `nifra.body-bounded` is deliberately NOT published for an unlimited route. */\n readonly bodyLimit?: number | \"unlimited\";\n /** Required explanation when bodyLimit is 'unlimited' (for example, a streaming upload is\n * bounded by an upstream object-store protocol). */\n readonly bodyLimitReason?: string;\n /** Declared effect tokens. Reflected for assurance; never read by validation or serialization. */\n readonly capabilities?: readonly string[];\n /**\n * Dedupe retries of this (mutating) route on an `Idempotency-Key` header. The first request runs and\n * its response is stored; a retry with the same key replays that response without re-running the\n * handler, and a key reused with a different body is rejected (409). A missing key on an\n * idempotency-required route fails closed (400). Off the hot path - routes without it are unchanged.\n */\n readonly idempotency?: IdempotencyConfig;\n /**\n * Highest data-sensitivity this route's response body carries (`public` | `pii` | `secret`). A\n * declarative, compile-time + introspection fact - never validated at runtime. Reflected for tooling,\n * recorded in the capability lockfile (so a route that starts returning PII is a reviewable change),\n * and read by downstream policy (e.g. a partner-API surface refusing to expose `pii`/`secret`).\n */\n readonly classification?: DataClassification;\n /**\n * Inline **route-assurance evidence**: the enforcement posture this route carries, declared adjacent to\n * the handler (e.g. `[NIFRA_ASSURANCE.AUTHENTICATED]`). Each id becomes route-scoped `declared` evidence\n * in reflection, so a `nifra.assurance.ts` policy `require:` clause is satisfiable WITHOUT rewriting an\n * in-handler guard into a `withRouteAssurance`-marked middleware. Ids are lowercase dot/dash segments\n * (invalid ids throw at registration). Reflected for the assurance gate; never read on the hot path.\n *\n * This is an author ASSERTION (recorded as `source: \"declared\"`), not runtime proof - like every\n * assurance marker it is trusted by the static gate, which matches on the evidence id, not its source.\n * Declare an id only on a route whose guard actually enforces it; a false declaration silently satisfies\n * the policy. (`source` is retained in reflection, so a stricter policy or reviewer can still tell\n * declared evidence from enforcement-module evidence.)\n */\n readonly assurance?: readonly string[];\n /**\n * Mark this route a **dynamic route family**: a template (`/api/:slug/:resource`) whose concrete\n * resources are resolved at runtime (auto-CRUD over tenant-defined tables, a catch-all dispatcher).\n * Purely declarative - it does not change dispatch. It surfaces in reflection so the assurance gate and\n * tooling treat the one templated route as a deliberate family whose evidence covers every runtime-\n * resolved resource, instead of reading it as a single forgotten route.\n */\n readonly family?: boolean;\n /** Optional **path-params schema**. Path params arrive as strings (`/users/:id` -> `c.params.id`);\n * declaring a schema validates them at the boundary (a malformed `:id` is a `422` before the handler,\n * like `body`/`query`) and can coerce them (use `t.query({ id: t.integer() })` for a numeric param).\n * The schema must cover every path param; with the strict default an undeclared path param is rejected.\n * When omitted, `c.params` stays the path-inferred `Record<name, string>`. */\n readonly params?: StandardSchemaV1;\n /** Optional request-header schema. Header names are normalized to lower-case and the validated\n * output is exposed as `c.headers`; use lower-case keys because HTTP header names are\n * case-insensitive. */\n readonly headers?: StandardSchemaV1;\n readonly body?: StandardSchemaV1;\n readonly query?: StandardSchemaV1;\n /** Optional **response contract**. When declared: the handler's return is type-checked against it\n * (the implementation can't drift from the contract), the typed client sees THIS as the response type\n * (the contract - not the handler's incidental return), and it's emitted into OpenAPI/JSON-Schema so\n * tooling and coding agents can read the exact shape. It is **not** validated at runtime (zero\n * hot-path cost) - purely a compile-time + introspection contract. */\n readonly response?: StandardSchemaV1;\n /**\n * Optional **error-response contract**: a map of HTTP status code → the Standard Schema of that error's\n * body. Declares a route's failure modes so they flow into OpenAPI (as non-2xx `responses`), the\n * `/llms.txt` context, and other introspection - the whole contract, not just the happy path, is legible\n * to tooling and coding agents. Like `response`, it is **not** validated at runtime (zero hot-path cost);\n * it's a compile-time + introspection contract. Example: `{ 404: NotFound, 409: Conflict }`. */\n readonly errors?: Readonly<Record<number, StandardSchemaV1>>;\n /**\n * Optional **SSE event contract**: the Standard Schema of each event's `data` payload on a\n * streaming route (declared via `app.sse()`). Marks the route as a typed event stream - the\n * typed client grows a `.subscribe()` for it, and the schema flows into reflection. Like\n * `response`, it is **not** validated at runtime (zero hot-path cost); the server-side\n * `stream.send()` is compile-time-checked against it instead.\n */\n readonly sse?: StandardSchemaV1;\n /**\n * Hook fired when the request fails `headers`/`params`/`body`/`query` validation, before the handler\n * runs. `kind` says which input failed. Its return value selects one of three outcomes (may be async):\n * - a **`Response`** → returned as-is, short-circuiting the route (custom error envelope, redirect, …).\n * - **any other value** → treated as a repaired payload and **re-validated once** against the same\n * schema. If it now passes, the handler runs with it; if it still fails, the original `422` stands.\n * Re-validation means a bad return can't bypass the schema - the trust boundary holds.\n * - **`undefined`** → give up; the original validation `422` is returned unchanged.\n * A route hook **overrides** the app-wide default set via `server({ onValidationError })`; return\n * `undefined` to fall through to the plain `422` even when an app default exists. Typical uses: a custom\n * error envelope, coercing the input, or prompting an LLM to repair the payload (re-validated, so it can't\n * bypass the schema).\n */\n readonly onValidationError?: (issues: ReadonlyArray<StandardIssue>, ctx: Context, kind: \"body\" | \"query\" | \"params\" | \"headers\") => Response | unknown | Promise<Response | unknown>;\n}",
10106
10785
  "doc": "/** Per-route input schemas. Each is any Standard Schema (zod/valibot/arktype/…). */"
10107
10786
  },
10108
10787
  {
10109
10788
  "name": "RouteSchema",
10110
10789
  "kind": "interface",
10111
10790
  "package": "nifra",
10112
- "signature": "export interface RouteSchema {\n /** Transport body cap for this route. Defaults to the server's maxBodyBytes. Use a finite\n * smaller/larger limit for a specific endpoint. The 'unlimited' value is an explicit\n * streaming/upload exemption and requires a non-empty bodyLimitReason for auditability. */\n readonly bodyLimit?: number | \"unlimited\";\n /** Required explanation when bodyLimit is 'unlimited' (for example, a streaming upload is\n * bounded by an upstream object-store protocol). */\n readonly bodyLimitReason?: string;\n /** Declared effect tokens. Reflected for assurance; never read by validation or serialization. */\n readonly capabilities?: readonly string[];\n /**\n * Dedupe retries of this (mutating) route on an `Idempotency-Key` header. The first request runs and\n * its response is stored; a retry with the same key replays that response without re-running the\n * handler, and a key reused with a different body is rejected (409). A missing key on an\n * idempotency-required route fails closed (400). Off the hot path - routes without it are unchanged.\n */\n readonly idempotency?: IdempotencyConfig;\n /**\n * Highest data-sensitivity this route's response body carries (`public` | `pii` | `secret`). A\n * declarative, compile-time + introspection fact - never validated at runtime. Reflected for tooling,\n * recorded in the capability lockfile (so a route that starts returning PII is a reviewable change),\n * and read by downstream policy (e.g. a partner-API surface refusing to expose `pii`/`secret`).\n */\n readonly classification?: DataClassification;\n /**\n * Inline **route-assurance evidence**: the enforcement posture this route carries, declared adjacent to\n * the handler (e.g. `[NIFRA_ASSURANCE.AUTHENTICATED]`). Each id becomes route-scoped `declared` evidence\n * in reflection, so a `nifra.assurance.ts` policy `require:` clause is satisfiable WITHOUT rewriting an\n * in-handler guard into a `withRouteAssurance`-marked middleware. Ids are lowercase dot/dash segments\n * (invalid ids throw at registration). Reflected for the assurance gate; never read on the hot path.\n *\n * This is an author ASSERTION (recorded as `source: \"declared\"`), not runtime proof - like every\n * assurance marker it is trusted by the static gate, which matches on the evidence id, not its source.\n * Declare an id only on a route whose guard actually enforces it; a false declaration silently satisfies\n * the policy. (`source` is retained in reflection, so a stricter policy or reviewer can still tell\n * declared evidence from enforcement-module evidence.)\n */\n readonly assurance?: readonly string[];\n /**\n * Mark this route a **dynamic route family**: a template (`/api/:slug/:resource`) whose concrete\n * resources are resolved at runtime (auto-CRUD over tenant-defined tables, a catch-all dispatcher).\n * Purely declarative - it does not change dispatch. It surfaces in reflection so the assurance gate and\n * tooling treat the one templated route as a deliberate family whose evidence covers every runtime-\n * resolved resource, instead of reading it as a single forgotten route.\n */\n readonly family?: boolean;\n /** Optional **path-params schema**. Path params arrive as strings (`/users/:id` -> `c.params.id`);\n * declaring a schema validates them at the boundary (a malformed `:id` is a `422` before the handler,\n * like `body`/`query`) and can coerce them (use `t.query({ id: t.integer() })` for a numeric param).\n * The schema must cover every path param; with the strict default an undeclared path param is rejected.\n * When omitted, `c.params` stays the path-inferred `Record<name, string>`. */\n readonly params?: StandardSchemaV1;\n /** Optional request-header schema. Header names are normalized to lower-case and the validated\n * output is exposed as `c.headers`; use lower-case keys because HTTP header names are\n * case-insensitive. */\n readonly headers?: StandardSchemaV1;\n readonly body?: StandardSchemaV1;\n readonly query?: StandardSchemaV1;\n /** Optional **response contract**. When declared: the handler's return is type-checked against it\n * (the implementation can't drift from the contract), the typed client sees THIS as the response type\n * (the contract - not the handler's incidental return), and it's emitted into OpenAPI/JSON-Schema so\n * tooling and coding agents can read the exact shape. It is **not** validated at runtime (zero\n * hot-path cost) - purely a compile-time + introspection contract. */\n readonly response?: StandardSchemaV1;\n /**\n * Optional **error-response contract**: a map of HTTP status code → the Standard Schema of that error's\n * body. Declares a route's failure modes so they flow into OpenAPI (as non-2xx `responses`), the\n * `/llms.txt` context, and other introspection - the whole contract, not just the happy path, is legible\n * to tooling and coding agents. Like `response`, it is **not** validated at runtime (zero hot-path cost);\n * it's a compile-time + introspection contract. Example: `{ 404: NotFound, 409: Conflict }`. */\n readonly errors?: Readonly<Record<number, StandardSchemaV1>>;\n /**\n * Optional **SSE event contract**: the Standard Schema of each event's `data` payload on a\n * streaming route (declared via `app.sse()`). Marks the route as a typed event stream - the\n * typed client grows a `.subscribe()` for it, and the schema flows into reflection. Like\n * `response`, it is **not** validated at runtime (zero hot-path cost); the server-side\n * `stream.send()` is compile-time-checked against it instead.\n */\n readonly sse?: StandardSchemaV1;\n /**\n * Hook fired when the request fails `headers`/`params`/`body`/`query` validation, before the handler\n * runs. `kind` says which input failed. Its return value selects one of three outcomes (may be async):\n * - a **`Response`** → returned as-is, short-circuiting the route (custom error envelope, redirect, …).\n * - **any other value** → treated as a repaired payload and **re-validated once** against the same\n * schema. If it now passes, the handler runs with it; if it still fails, the original `422` stands.\n * Re-validation means a bad return can't bypass the schema - the trust boundary holds.\n * - **`undefined`** → give up; the original validation `422` is returned unchanged.\n * A route hook **overrides** the app-wide default set via `server({ onValidationError })`; return\n * `undefined` to fall through to the plain `422` even when an app default exists. Typical uses: a custom\n * error envelope, coercing the input, or prompting an LLM to repair the payload (re-validated, so it can't\n * bypass the schema).\n */\n readonly onValidationError?: (issues: ReadonlyArray<StandardIssue>, ctx: Context, kind: \"body\" | \"query\" | \"params\" | \"headers\") => Response | unknown | Promise<Response | unknown>;\n}",
10791
+ "signature": "export interface RouteSchema {\n /** Transport body cap for this route. Defaults to the server's maxBodyBytes. Use a finite\n * smaller/larger limit for a specific endpoint. The 'unlimited' value is an explicit\n * streaming/upload exemption and requires a non-empty bodyLimitReason for auditability.\n *\n * 'unlimited' is legal only for schema-less streaming/upload routes. It is rejected with `body` or\n * `idempotency`, because those lanes buffer the body before user code can apply a protocol-specific\n * bound. Read an unlimited route from `c.req.body` as a stream and bound it by the protocol it speaks;\n * `nifra.body-bounded` is deliberately NOT published for an unlimited route. */\n readonly bodyLimit?: number | \"unlimited\";\n /** Required explanation when bodyLimit is 'unlimited' (for example, a streaming upload is\n * bounded by an upstream object-store protocol). */\n readonly bodyLimitReason?: string;\n /** Declared effect tokens. Reflected for assurance; never read by validation or serialization. */\n readonly capabilities?: readonly string[];\n /**\n * Dedupe retries of this (mutating) route on an `Idempotency-Key` header. The first request runs and\n * its response is stored; a retry with the same key replays that response without re-running the\n * handler, and a key reused with a different body is rejected (409). A missing key on an\n * idempotency-required route fails closed (400). Off the hot path - routes without it are unchanged.\n */\n readonly idempotency?: IdempotencyConfig;\n /**\n * Highest data-sensitivity this route's response body carries (`public` | `pii` | `secret`). A\n * declarative, compile-time + introspection fact - never validated at runtime. Reflected for tooling,\n * recorded in the capability lockfile (so a route that starts returning PII is a reviewable change),\n * and read by downstream policy (e.g. a partner-API surface refusing to expose `pii`/`secret`).\n */\n readonly classification?: DataClassification;\n /**\n * Inline **route-assurance evidence**: the enforcement posture this route carries, declared adjacent to\n * the handler (e.g. `[NIFRA_ASSURANCE.AUTHENTICATED]`). Each id becomes route-scoped `declared` evidence\n * in reflection, so a `nifra.assurance.ts` policy `require:` clause is satisfiable WITHOUT rewriting an\n * in-handler guard into a `withRouteAssurance`-marked middleware. Ids are lowercase dot/dash segments\n * (invalid ids throw at registration). Reflected for the assurance gate; never read on the hot path.\n *\n * This is an author ASSERTION (recorded as `source: \"declared\"`), not runtime proof - like every\n * assurance marker it is trusted by the static gate, which matches on the evidence id, not its source.\n * Declare an id only on a route whose guard actually enforces it; a false declaration silently satisfies\n * the policy. (`source` is retained in reflection, so a stricter policy or reviewer can still tell\n * declared evidence from enforcement-module evidence.)\n */\n readonly assurance?: readonly string[];\n /**\n * Mark this route a **dynamic route family**: a template (`/api/:slug/:resource`) whose concrete\n * resources are resolved at runtime (auto-CRUD over tenant-defined tables, a catch-all dispatcher).\n * Purely declarative - it does not change dispatch. It surfaces in reflection so the assurance gate and\n * tooling treat the one templated route as a deliberate family whose evidence covers every runtime-\n * resolved resource, instead of reading it as a single forgotten route.\n */\n readonly family?: boolean;\n /** Optional **path-params schema**. Path params arrive as strings (`/users/:id` -> `c.params.id`);\n * declaring a schema validates them at the boundary (a malformed `:id` is a `422` before the handler,\n * like `body`/`query`) and can coerce them (use `t.query({ id: t.integer() })` for a numeric param).\n * The schema must cover every path param; with the strict default an undeclared path param is rejected.\n * When omitted, `c.params` stays the path-inferred `Record<name, string>`. */\n readonly params?: StandardSchemaV1;\n /** Optional request-header schema. Header names are normalized to lower-case and the validated\n * output is exposed as `c.headers`; use lower-case keys because HTTP header names are\n * case-insensitive. */\n readonly headers?: StandardSchemaV1;\n readonly body?: StandardSchemaV1;\n readonly query?: StandardSchemaV1;\n /** Optional **response contract**. When declared: the handler's return is type-checked against it\n * (the implementation can't drift from the contract), the typed client sees THIS as the response type\n * (the contract - not the handler's incidental return), and it's emitted into OpenAPI/JSON-Schema so\n * tooling and coding agents can read the exact shape. It is **not** validated at runtime (zero\n * hot-path cost) - purely a compile-time + introspection contract. */\n readonly response?: StandardSchemaV1;\n /**\n * Optional **error-response contract**: a map of HTTP status code → the Standard Schema of that error's\n * body. Declares a route's failure modes so they flow into OpenAPI (as non-2xx `responses`), the\n * `/llms.txt` context, and other introspection - the whole contract, not just the happy path, is legible\n * to tooling and coding agents. Like `response`, it is **not** validated at runtime (zero hot-path cost);\n * it's a compile-time + introspection contract. Example: `{ 404: NotFound, 409: Conflict }`. */\n readonly errors?: Readonly<Record<number, StandardSchemaV1>>;\n /**\n * Optional **SSE event contract**: the Standard Schema of each event's `data` payload on a\n * streaming route (declared via `app.sse()`). Marks the route as a typed event stream - the\n * typed client grows a `.subscribe()` for it, and the schema flows into reflection. Like\n * `response`, it is **not** validated at runtime (zero hot-path cost); the server-side\n * `stream.send()` is compile-time-checked against it instead.\n */\n readonly sse?: StandardSchemaV1;\n /**\n * Hook fired when the request fails `headers`/`params`/`body`/`query` validation, before the handler\n * runs. `kind` says which input failed. Its return value selects one of three outcomes (may be async):\n * - a **`Response`** → returned as-is, short-circuiting the route (custom error envelope, redirect, …).\n * - **any other value** → treated as a repaired payload and **re-validated once** against the same\n * schema. If it now passes, the handler runs with it; if it still fails, the original `422` stands.\n * Re-validation means a bad return can't bypass the schema - the trust boundary holds.\n * - **`undefined`** → give up; the original validation `422` is returned unchanged.\n * A route hook **overrides** the app-wide default set via `server({ onValidationError })`; return\n * `undefined` to fall through to the plain `422` even when an app default exists. Typical uses: a custom\n * error envelope, coercing the input, or prompting an LLM to repair the payload (re-validated, so it can't\n * bypass the schema).\n */\n readonly onValidationError?: (issues: ReadonlyArray<StandardIssue>, ctx: Context, kind: \"body\" | \"query\" | \"params\" | \"headers\") => Response | unknown | Promise<Response | unknown>;\n}",
10113
10792
  "doc": "/** Per-route input schemas. Each is any Standard Schema (zod/valibot/arktype/…). */"
10114
10793
  },
10115
10794
  {
@@ -10466,6 +11145,20 @@
10466
11145
  "package": "@nifrajs/cron",
10467
11146
  "signature": "export interface SchedulerOptions {\n /** Called when a job handler throws/rejects. Default: `console.error`. A throwing onError is swallowed. */\n readonly onError?: (error: unknown, jobName: string) => void;\n /** Injectable clock (tests). Default `() => new Date()`. */\n readonly now?: () => Date;\n}"
10468
11147
  },
11148
+ {
11149
+ "name": "scheduleTrigger",
11150
+ "kind": "function",
11151
+ "package": "@nifrajs/island-trigger",
11152
+ "signature": "export declare function scheduleTrigger(strategy: IslandStrategy, run: () => void, options?: TriggerOptions): () => void;",
11153
+ "doc": "/**\n * Schedule an island trigger and return a disposer. Every successful trigger is one-shot: a late\n * media/visibility/idle event cannot run an enhancer twice. Invalid media strategies remain inert,\n * which keeps malformed untrusted HTML fail-closed while leaving its server-rendered content usable.\n */"
11154
+ },
11155
+ {
11156
+ "name": "scheduleTrigger",
11157
+ "kind": "function",
11158
+ "package": "@nifrajs/web",
11159
+ "signature": "export declare function scheduleTrigger(strategy: IslandStrategy, run: () => void, options?: TriggerOptions): () => void;",
11160
+ "doc": "/**\n * Schedule an island trigger and return a disposer. Every successful trigger is one-shot: a late\n * media/visibility/idle event cannot run an enhancer twice. Invalid media strategies remain inert,\n * which keeps malformed untrusted HTML fail-closed while leaving its server-rendered content usable.\n */"
11161
+ },
10469
11162
  {
10470
11163
  "name": "SchemaReflection",
10471
11164
  "kind": "interface",
@@ -10525,6 +11218,12 @@
10525
11218
  "package": "@nifrajs/web-solid",
10526
11219
  "signature": "export declare const SearchContext: Context<Accessor<Record<string, unknown>> | undefined>;"
10527
11220
  },
11221
+ {
11222
+ "name": "searchOf",
11223
+ "kind": "function",
11224
+ "package": "@nifrajs/core",
11225
+ "signature": "export declare function searchOf(url: string): string;"
11226
+ },
10528
11227
  {
10529
11228
  "name": "searchOf",
10530
11229
  "kind": "function",
@@ -10560,6 +11259,27 @@
10560
11259
  "signature": "export declare const SearchProvider: import(\"vue\").DefineComponent<import(\"vue\").ExtractPropTypes<{\n value: {\n type: ObjectConstructor;\n required: true;\n };\n}>, () => import(\"vue\").VNode<import(\"vue\").RendererNode, import(\"vue\").RendererElement, {\n [key: string]: any;\n}>[] | undefined, {}, {}, {}, import(\"vue\").ComponentOptionsMixin, import(\"vue\").ComponentOptionsMixin, {}, string, import(\"vue\").PublicProps, Readonly<import(\"vue\").ExtractPropTypes<{\n value: {\n type: ObjectConstructor;\n required: true;\n };\n}>> & Readonly<{}>, {}, {}, {}, {}, string, import(\"vue\").ComponentProvideOptions, true, {}, any>;",
10561
11260
  "doc": "/**\n * The provider `compose` wraps the layout tree in. It `provide`s a `computed` view of its `value` prop,\n * so as the mount re-renders with each navigation's search the injected ref updates reactively (setup\n * runs once, but the computed keeps tracking the prop). Renders its default slot (the folded chain).\n */"
10562
11261
  },
11262
+ {
11263
+ "name": "securityBaseline",
11264
+ "kind": "function",
11265
+ "package": "@nifrajs/core",
11266
+ "signature": "export declare function securityBaseline(options?: SecurityBaselineOptions): AssurancePolicy;",
11267
+ "doc": "/**\n * A first-match-wins security policy that turns the recurring audit finding classes into machine\n * checked route invariants. Composed only from the public assurance engine, so it inherits its\n * fail-closed evaluation, provenance checks, and selector validation - no bespoke evaluator.\n *\n * The rules are ordered most-specific-first because assurance evaluation is first-match-wins: each\n * route is owned by exactly one rule, so that rule carries the FULL requirement bundle for its class\n * (a body-carrying mutation proves bounded-body AND CSRF in one rule, not two). Raising the `level`\n * widens those bundles; it never reorders them.\n *\n * Coverage by level (see {@link SecurityBaselineLevel} for the rationale):\n *\n * | invariant | essential | standard | strict |\n * | --- | :-: | :-: | :-: |\n * | unlimited body can never be \"bounded\" (F-001) | ✓ | ✓ | ✓ |\n * | every body read is bounded | ✓ | ✓ | ✓ |\n * | agent tool ingress is bounded | ✓ | ✓ | ✓ |\n * | authenticated mutation proves CSRF | ✓ | ✓ | ✓ |\n * | pii+ route is authenticated | | ✓ | ✓ |\n * | every route carries a response contract | | | ✓ |\n * | every read carries security headers | | | ✓ |\n * | every mutation is rate limited | | | ✓ |\n *\n * The baseline deliberately does not select on `access`/`zone` capabilities: those selectors require\n * capability definitions and would make the preset refuse an app that declares none. Extend the\n * returned policy's `rules` for capability- or path-specific requirements; put more specific rules\n * before these so they own their routes first.\n */"
11268
+ },
11269
+ {
11270
+ "name": "SecurityBaselineLevel",
11271
+ "kind": "type",
11272
+ "package": "@nifrajs/core",
11273
+ "signature": "export type SecurityBaselineLevel = \"essential\" | \"standard\" | \"strict\";",
11274
+ "doc": "/**\n * How much a {@link securityBaseline} demands. Each level is a superset of the one before it, so\n * raising the level only ever adds findings.\n *\n * - `\"essential\"` - the invariants that hold for ANY app and never false-positive on a reasonable\n * one: a body read must be bounded, an unlimited body may never claim to be bounded, an agent tool\n * ingress must be bounded, and an authenticated state change must prove CSRF. Every required piece\n * of evidence here is either published by the core from the route schema or only demanded when the\n * route already opted into the risk (CSRF is required only where authentication is present). Safe to\n * adopt on day one.\n * - `\"standard\"` (default) - essential, plus: a route the app itself classified as `pii` or higher\n * must be authenticated, whether it reads or writes. High signal, low noise - it fires only on\n * routes the application already labelled sensitive.\n * - `\"strict\"` - standard, plus the opinionated, higher-friction requirements: every route must carry\n * a response contract, every read must carry security headers, and every mutation must be rate\n * limited. These need middleware the app has to install, so they are opt-in rather than default.\n */"
11275
+ },
11276
+ {
11277
+ "name": "SecurityBaselineOptions",
11278
+ "kind": "interface",
11279
+ "package": "@nifrajs/core",
11280
+ "signature": "export interface SecurityBaselineOptions {\n /** How much the baseline demands. Default `\"standard\"`. See {@link SecurityBaselineLevel}. */\n readonly level?: SecurityBaselineLevel;\n /**\n * How to treat a route no rule matched. Default `\"ignore\"` so the baseline is purely additive - it\n * asserts the invariants below and stays silent on everything else, which lets a project adopt it\n * without first classifying its whole route table. Set `\"error\"` to make an unclassified route a\n * finding, turning the baseline into a closed allow-list (recommended once the table is covered).\n */\n readonly unmatched?: \"error\" | \"ignore\";\n /**\n * Require that a matched route's evidence was installed by runtime enforcement (middleware/plugin\n * or framework policy) rather than asserted inline on `schema.assurance`. Default `true`: an author\n * label is not proof, and a security baseline that accepts labels is theater. Set `false` only to\n * stage adoption before guards emit runtime evidence.\n */\n readonly requireRuntimeProvenance?: boolean;\n}",
11281
+ "doc": "/** Tuning for {@link securityBaseline}. Every knob only ever tightens the policy. */"
11282
+ },
10563
11283
  {
10564
11284
  "name": "securityHeaders",
10565
11285
  "kind": "function",
@@ -10714,6 +11434,13 @@
10714
11434
  "signature": "export declare function server<Env = unknown>(options?: ServerOptions): Server<EmptyRegistry, {\n readonly env: Env;\n}>;",
10715
11435
  "doc": "/**\n * Create a new {@link Server}. Pass an `Env` to type the platform bindings - `server<Env>()` makes\n * `c.env: Env` in every handler + middleware, and types the `env` argument of `app.fetch` /\n * `toFetchHandler`. Omit it and `c.env` is `unknown` (validate/cast before use).\n */"
10716
11436
  },
11437
+ {
11438
+ "name": "server",
11439
+ "kind": "function",
11440
+ "package": "@nifrajs/edge",
11441
+ "signature": "export declare function server(options?: EdgeOptions): EdgeServer;",
11442
+ "doc": "/** Create a compact edge server. */"
11443
+ },
10717
11444
  {
10718
11445
  "name": "server",
10719
11446
  "kind": "function",
@@ -10725,14 +11452,14 @@
10725
11452
  "name": "Server",
10726
11453
  "kind": "class",
10727
11454
  "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}",
11455
+ "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 * Returning a `status(...)` (or a `Response`) instead of an extension ends the request there - the\n * guard shape, and the cheap one: it renders as plain data on the same lane a handler's return\n * takes, where `throw new Response(...)` pays ~40% of the rejection lane to build the object. That\n * branch is control flow, so it does not widen the derived context type.\n */\n derive<D extends object>(fn: (context: Context & Ctx) => MaybePromise<D | ResponseResult | Response>): 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 private responseObserverMethods;\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 /** Enable the opt-in portable response observer methods. */\n use(plugin: ResponseObserverPlugin): this & ResponseObserverMethods;\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 response observer plugin. */\n [INSTALL_RESPONSE_OBSERVER](runtime: ResponseObserverRuntime): ResponseObserverMethods;\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 * Select a mounted handler's native Node lane without materializing a Web Request. This is an\n * adapter seam, not a second lifecycle: any app-wide behavior that the ordinary mount path would\n * run makes the capability ineligible and the caller falls back to `resolveNodeSource`. Typed\n * routes keep precedence exactly as `routeAndRun` does, including the existing mount behavior for\n * a path whose registered route rejects this method.\n */\n [RESOLVE_NODE_MOUNT](source: RequestSource): NativeMountSelection | undefined;\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 /** 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 /** Synchronous by design, and `MaybePromise` rather than `Promise` for the same reason: control flow\n * out of a lifecycle stage must not cost a promise. An `async` method allocates one and defers the\n * result a microtask even when every branch it takes returns immediately, which is the common case\n * here - a thrown `status(...)`/`Response`, or a route with no `onError` hook at all. Only the hook\n * loop, which may await, drops into {@link runErrorHooks}. */\n private handleLifecycleError;\n /** The `onError` chain, split off {@link handleLifecycleError} so its `await` costs only the routes\n * that registered a hook. A hook may return a custom response; otherwise the default 500 stands. */\n private runErrorHooks;\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
11456
  "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
11457
  },
10731
11458
  {
10732
11459
  "name": "Server",
10733
11460
  "kind": "class",
10734
11461
  "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}",
11462
+ "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 * Returning a `status(...)` (or a `Response`) instead of an extension ends the request there - the\n * guard shape, and the cheap one: it renders as plain data on the same lane a handler's return\n * takes, where `throw new Response(...)` pays ~40% of the rejection lane to build the object. That\n * branch is control flow, so it does not widen the derived context type.\n */\n derive<D extends object>(fn: (context: Context & Ctx) => MaybePromise<D | ResponseResult | Response>): 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 private responseObserverMethods;\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 /** Enable the opt-in portable response observer methods. */\n use(plugin: ResponseObserverPlugin): this & ResponseObserverMethods;\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 response observer plugin. */\n [INSTALL_RESPONSE_OBSERVER](runtime: ResponseObserverRuntime): ResponseObserverMethods;\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 * Select a mounted handler's native Node lane without materializing a Web Request. This is an\n * adapter seam, not a second lifecycle: any app-wide behavior that the ordinary mount path would\n * run makes the capability ineligible and the caller falls back to `resolveNodeSource`. Typed\n * routes keep precedence exactly as `routeAndRun` does, including the existing mount behavior for\n * a path whose registered route rejects this method.\n */\n [RESOLVE_NODE_MOUNT](source: RequestSource): NativeMountSelection | undefined;\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 /** 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 /** Synchronous by design, and `MaybePromise` rather than `Promise` for the same reason: control flow\n * out of a lifecycle stage must not cost a promise. An `async` method allocates one and defers the\n * result a microtask even when every branch it takes returns immediately, which is the common case\n * here - a thrown `status(...)`/`Response`, or a route with no `onError` hook at all. Only the hook\n * loop, which may await, drops into {@link runErrorHooks}. */\n private handleLifecycleError;\n /** The `onError` chain, split off {@link handleLifecycleError} so its `await` costs only the routes\n * that registered a hook. A hook may return a custom response; otherwise the default 500 stands. */\n private runErrorHooks;\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
11463
  "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
11464
  },
10738
11465
  {
@@ -10893,7 +11620,7 @@
10893
11620
  "name": "serverFunctions",
10894
11621
  "kind": "function",
10895
11622
  "package": "@nifrajs/web",
10896
- "signature": "export declare function serverFunctions<S extends ServerFnHost>(namespace: string, module: ServerFnModule): (app: S) => S;",
11623
+ "signature": "export declare function serverFunctions(namespace: string, module: ServerFnModule): IdentityPlugin;",
10897
11624
  "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
11625
  },
10899
11626
  {
@@ -10928,13 +11655,13 @@
10928
11655
  "name": "ServerOptions",
10929
11656
  "kind": "interface",
10930
11657
  "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}"
11658
+ "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
11659
  },
10933
11660
  {
10934
11661
  "name": "ServerOptions",
10935
11662
  "kind": "interface",
10936
11663
  "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}"
11664
+ "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
11665
  },
10939
11666
  {
10940
11667
  "name": "ServeStaticOptions",
@@ -11113,6 +11840,13 @@
11113
11840
  "signature": "export declare function shapeOf(value: unknown): unknown;",
11114
11841
  "doc": "/** A stable structural fingerprint: keys + value *types*, not values. Used for the optional shape check. */"
11115
11842
  },
11843
+ {
11844
+ "name": "SharedKey",
11845
+ "kind": "type",
11846
+ "package": "@nifrajs/content",
11847
+ "signature": "export type SharedKey<Left extends Record<string, unknown>, Right extends Record<string, unknown>> = {\n [K in ContentFieldKey<Left> & ContentFieldKey<Right>]: [Left[K]] extends [Right[K]] ? [Right[K]] extends [Left[K]] ? K : never : never;\n}[ContentFieldKey<Left> & ContentFieldKey<Right>];",
11848
+ "doc": "/** Keys whose frontmatter value types are identical on both sides of a join. */"
11849
+ },
11116
11850
  {
11117
11851
  "name": "sharpImageBackend",
11118
11852
  "kind": "function",
@@ -11223,6 +11957,73 @@
11223
11957
  "signature": "export declare const silentLogger: Logger;",
11224
11958
  "doc": "/** Discards everything - for tests, or when log output is handled elsewhere. */"
11225
11959
  },
11960
+ {
11961
+ "name": "SINGLE_COPY_ACTIVE",
11962
+ "kind": "const",
11963
+ "package": "@nifrajs/core",
11964
+ "signature": "export declare const SINGLE_COPY_ACTIVE: unique symbol;",
11965
+ "doc": "/** Set once the runtime plugin is installed, so a checker can tell \"one copy\" from \"deduplicated\". */"
11966
+ },
11967
+ {
11968
+ "name": "SINGLE_COPY_REGISTER_SPECIFIER",
11969
+ "kind": "const",
11970
+ "package": "@nifrajs/core",
11971
+ "signature": "export declare const SINGLE_COPY_REGISTER_SPECIFIER = \"@nifrajs/core/single-copy/register\";",
11972
+ "doc": "/** The public specifier a `bunfig.toml` preload must name to arm the runtime. */"
11973
+ },
11974
+ {
11975
+ "name": "SingleCopyOptions",
11976
+ "kind": "interface",
11977
+ "package": "@nifrajs/core",
11978
+ "signature": "export interface SingleCopyOptions {\n /** The app root whose copy wins. Defaults to `process.cwd()`. */\n readonly cwd?: string;\n /** Package names or `@scope/*` patterns. Defaults to the `nifra.singleCopy` declaration. */\n readonly packages?: readonly string[];\n}"
11979
+ },
11980
+ {
11981
+ "name": "SingleCopyPlan",
11982
+ "kind": "interface",
11983
+ "package": "@nifrajs/core",
11984
+ "signature": "export interface SingleCopyPlan {\n /** The app root whose installed copy wins. */\n readonly root: string;\n /** Declared package names and patterns, as written. */\n readonly declared: readonly string[];\n readonly redirects: readonly SingleCopyRedirect[];\n readonly skipped: readonly SingleCopySkip[];\n}"
11985
+ },
11986
+ {
11987
+ "name": "singleCopyPlugin",
11988
+ "kind": "function",
11989
+ "package": "@nifrajs/core",
11990
+ "signature": "export declare function singleCopyPlugin(options?: SingleCopyOptions): SingleCopyPlugin;",
11991
+ "doc": "/**\n * Pin every declared package to the app's copy.\n *\n * Two hooks, because the two phases resolve differently. `onResolve` is the direct statement of the\n * rule and it is what a BUNDLER honours - it sees every bare specifier. The runtime does not deliver\n * bare specifiers to it at all, so the `onLoad` arm intercepts the foreign file itself and hands back\n * a re-export of the counterpart in the winning copy. The importer gets the same function objects and\n * therefore the same module state, which is the entire requirement.\n */"
11992
+ },
11993
+ {
11994
+ "name": "SingleCopyPlugin",
11995
+ "kind": "interface",
11996
+ "package": "@nifrajs/core",
11997
+ "signature": "export interface SingleCopyPlugin extends BunPlugin {\n /** What it will do, computed once at construction. Exposed so a caller can report it. */\n readonly plan: SingleCopyPlan;\n}",
11998
+ "doc": "/** A Bun plugin - `Bun.plugin(...)` for the runtime, or a `plugins:` entry for `Bun.build`. */"
11999
+ },
12000
+ {
12001
+ "name": "SingleCopyRedirect",
12002
+ "kind": "interface",
12003
+ "package": "@nifrajs/core",
12004
+ "signature": "export interface SingleCopyRedirect {\n readonly package: string;\n /** Absolute realpath of the copy that loses - the one a linked package would otherwise load. */\n readonly from: string;\n /** Absolute realpath of the copy that wins - the one resolvable from the app root. */\n readonly to: string;\n readonly version: string;\n}",
12005
+ "doc": "/** One foreign copy that will be redirected into the app's copy. */"
12006
+ },
12007
+ {
12008
+ "name": "SingleCopyRegistration",
12009
+ "kind": "interface",
12010
+ "package": "@nifrajs/core",
12011
+ "signature": "export interface SingleCopyRegistration {\n /** `preload` at the top level: covers `bun run` and anything that loads app sources directly. */\n readonly run: boolean;\n /** `[test] preload`: covers `bun test`, the surface that runs app sources unbundled. */\n readonly test: boolean;\n /** The `bunfig.toml` that was read, if one exists. */\n readonly config?: string;\n}",
12012
+ "doc": "/** Which unbundled phases have the resolver preloaded. Bundled phases never need it - nifra's build\n * injects the plugin itself. */"
12013
+ },
12014
+ {
12015
+ "name": "SingleCopySkip",
12016
+ "kind": "interface",
12017
+ "package": "@nifrajs/core",
12018
+ "signature": "export interface SingleCopySkip {\n readonly package: string;\n readonly from: string;\n readonly reason: SingleCopySkipReason;\n readonly detail: string;\n}",
12019
+ "doc": "/** A foreign copy deliberately left alone, and why - never silently dropped. */"
12020
+ },
12021
+ {
12022
+ "name": "SingleCopySkipReason",
12023
+ "kind": "type",
12024
+ "package": "@nifrajs/core",
12025
+ "signature": "export type SingleCopySkipReason = \"version-skew\" | \"no-counterpart\";"
12026
+ },
11226
12027
  {
11227
12028
  "name": "sitemap",
11228
12029
  "kind": "function",
@@ -11549,6 +12350,13 @@
11549
12350
  "signature": "export interface StandardSchemaV1<Input = unknown, Output = Input> {\n readonly \"~standard\": StandardSchemaProps<Input, Output>;\n}",
11550
12351
  "doc": "/**\n * The Standard Schema v1 interface (https://standardschema.dev), vendored as\n * types + a tiny runtime helper so any compliant validator - zod, valibot,\n * arktype, … - validates requests without coupling the framework to one lib.\n * The spec is MIT-licensed and explicitly designed to be copied.\n */"
11551
12352
  },
12353
+ {
12354
+ "name": "StandardSchemaV1",
12355
+ "kind": "interface",
12356
+ "package": "@nifrajs/edge",
12357
+ "signature": "export interface StandardSchemaV1<Input = unknown, Output = Input> {\n readonly \"~standard\": StandardSchemaProps<Input, Output>;\n}",
12358
+ "doc": "/**\n * The Standard Schema v1 interface (https://standardschema.dev), vendored as\n * types + a tiny runtime helper so any compliant validator - zod, valibot,\n * arktype, … - validates requests without coupling the framework to one lib.\n * The spec is MIT-licensed and explicitly designed to be copied.\n */"
12359
+ },
11552
12360
  {
11553
12361
  "name": "StandardSchemaV1",
11554
12362
  "kind": "interface",
@@ -11621,12 +12429,44 @@
11621
12429
  "package": "@nifrajs/core",
11622
12430
  "signature": "export interface StartCausalityOptions {\n /** Stable graph identity. Generate once at the ingress boundary, then propagate it. */\n readonly executionId: string;\n /** Epoch milliseconds. Injectable for deterministic tests. Default `Date.now()`. */\n readonly at?: number;\n /** Observation opened for this exact node. */\n readonly trace?: CausalityTrace;\n}"
11623
12431
  },
12432
+ {
12433
+ "name": "startDynamicBoundaries",
12434
+ "kind": "function",
12435
+ "package": "@nifrajs/web",
12436
+ "signature": "export declare function startDynamicBoundaries(boundaries: readonly BoundaryRegistration[], context: BoundaryRequestCtx): DynamicBoundaryBatch;",
12437
+ "doc": "/**\n * Start all dynamic boundary loads at once without making the page wait for the slowest sibling.\n * The initial states contain `status: \"pending\"`; callers that support deferred values can attach\n * each `pending.promise` to its own slot. `complete` still provides settled, isolated states to\n * non-streaming callers, preserving the simple reference API.\n */"
12438
+ },
11624
12439
  {
11625
12440
  "name": "StartObservation",
11626
12441
  "kind": "interface",
11627
12442
  "package": "@nifrajs/otel",
11628
12443
  "signature": "export interface StartObservation {\n readonly name: string;\n /** Explicit parent. `null` forces a root span; `undefined` falls back to `traceparent`. */\n readonly parent?: ObservationParent | null;\n /** Inbound W3C header used when `parent` is undefined. */\n readonly traceparent?: string | null;\n readonly attributes?: Readonly<Record<string, AttributeValue>>;\n /** Non-parent causal relationships, for example an outbox event that resumed this workflow. */\n readonly links?: readonly ObservationLink[];\n}"
11629
12444
  },
12445
+ {
12446
+ "name": "StaticBoundary",
12447
+ "kind": "type",
12448
+ "package": "@nifrajs/web",
12449
+ "signature": "export type StaticBoundary<Data, UI> = BoundaryBase<Data, UI> & {\n readonly mode: \"static\";\n readonly load?: (ctx: StaticCtx) => Data | Promise<Data>;\n};"
12450
+ },
12451
+ {
12452
+ "name": "StaticBoundaryCache",
12453
+ "kind": "interface",
12454
+ "package": "@nifrajs/web",
12455
+ "signature": "export interface StaticBoundaryCache {\n get(boundary: BoundaryRegistration): Promise<unknown> | undefined;\n set(boundary: BoundaryRegistration, value: Promise<unknown>): void;\n}",
12456
+ "doc": "/** Public in-memory reference cache for build-safe static boundary values. It holds no payload outside\n * the process and is intentionally not a durable or tenant-aware cache implementation. */"
12457
+ },
12458
+ {
12459
+ "name": "StaticBoundaryImportEdge",
12460
+ "kind": "interface",
12461
+ "package": "@nifrajs/web",
12462
+ "signature": "export interface StaticBoundaryImportEdge {\n readonly from: string;\n readonly to: string;\n}"
12463
+ },
12464
+ {
12465
+ "name": "StaticBoundaryRoot",
12466
+ "kind": "interface",
12467
+ "package": "@nifrajs/web",
12468
+ "signature": "export interface StaticBoundaryRoot {\n readonly name: string;\n readonly module: string;\n}"
12469
+ },
11630
12470
  {
11631
12471
  "name": "StaticCollection",
11632
12472
  "kind": "interface",
@@ -11634,6 +12474,13 @@
11634
12474
  "signature": "export interface StaticCollection<Frontmatter> {\n all(): Promise<ReadonlyArray<Entry<Frontmatter>>>;\n get(slug: string): Promise<Entry<Frontmatter> | null>;\n}",
11635
12475
  "doc": "/** Read-only collection surface (`all()`/`get()`) - structurally compatible with `defineCollection`'s\n * `Collection`, but with no filesystem access. */"
11636
12476
  },
12477
+ {
12478
+ "name": "StaticCtx",
12479
+ "kind": "interface",
12480
+ "package": "@nifrajs/web",
12481
+ "signature": "export interface StaticCtx {\n readonly phase: \"build\";\n readonly origin?: string;\n}",
12482
+ "doc": "/** Build-safe inputs available to a static boundary. It intentionally has no request/session/params API. */"
12483
+ },
11637
12484
  {
11638
12485
  "name": "StaticPath",
11639
12486
  "kind": "interface",
@@ -11655,6 +12502,20 @@
11655
12502
  "signature": "export interface StaticRoutes {\n /** Concrete prerendered paths - static `prerender` routes + each `getStaticPaths` entry. */\n readonly paths: string[];\n /** Per dynamic route pattern, its `getStaticPaths` `fallback` (`\"ssr\"` default). `createWebApp` uses\n * `\"404\"` to reject an unlisted path under that route at runtime (the path simply doesn't exist). */\n readonly fallbacks: Record<string, \"ssr\" | \"404\">;\n}",
11656
12503
  "doc": "/** The static-routing facts a server needs from the route modules: which concrete paths are\n * prerendered, plus each dynamic route's `getStaticPaths` fallback policy. */"
11657
12504
  },
12505
+ {
12506
+ "name": "status",
12507
+ "kind": "function",
12508
+ "package": "@nifrajs/core",
12509
+ "signature": "export declare function status(code: number, body?: unknown, init?: {\n readonly headers?: Readonly<Record<string, string>>;\n}): ResponseResult;",
12510
+ "doc": "/**\n * Finish the request here, with this status and body, without building a `Response`.\n *\n * Returned or thrown, from a handler or from any lifecycle stage:\n *\n * ```ts\n * app.derive((c) => {\n * const user = sessionOf(c)\n * if (user === undefined) return status(401, { error: \"unauthorized\" })\n * return { user }\n * })\n * ```\n *\n * A `derive` is the reason this exists as a value rather than as a rule about `beforeHandle`: a\n * `beforeHandle` already short-circuits by returning a value, but a `derive`'s return IS the context\n * extension, so before this its only exit was `throw new Response(...)` - the most expensive way to\n * say 401 (see {@link PlainRender} for the measurements). Returning it is preferred; throwing it\n * carries the same cost as any other throw and stays supported so a guard helper called for effect\n * (`requireSession(c)`) can still end the request from inside a call it makes.\n *\n * The body is serialized by the lane that renders it, exactly like a handler's plain return, so the\n * response carries a `content-length` rather than falling to chunked, and queued cookies still apply.\n */"
12511
+ },
12512
+ {
12513
+ "name": "status",
12514
+ "kind": "function",
12515
+ "package": "nifra",
12516
+ "signature": "export declare function status(code: number, body?: unknown, init?: {\n readonly headers?: Readonly<Record<string, string>>;\n}): ResponseResult;",
12517
+ "doc": "/**\n * Finish the request here, with this status and body, without building a `Response`.\n *\n * Returned or thrown, from a handler or from any lifecycle stage:\n *\n * ```ts\n * app.derive((c) => {\n * const user = sessionOf(c)\n * if (user === undefined) return status(401, { error: \"unauthorized\" })\n * return { user }\n * })\n * ```\n *\n * A `derive` is the reason this exists as a value rather than as a rule about `beforeHandle`: a\n * `beforeHandle` already short-circuits by returning a value, but a `derive`'s return IS the context\n * extension, so before this its only exit was `throw new Response(...)` - the most expensive way to\n * say 401 (see {@link PlainRender} for the measurements). Returning it is preferred; throwing it\n * carries the same cost as any other throw and stays supported so a guard helper called for effect\n * (`requireSession(c)`) can still end the request from inside a call it makes.\n *\n * The body is serialized by the lane that renders it, exactly like a handler's plain return, so the\n * response carries a `content-length` rather than falling to chunked, and queued cookies still apply.\n */"
12518
+ },
11658
12519
  {
11659
12520
  "name": "STATUS_HEADER",
11660
12521
  "kind": "const",
@@ -12075,6 +12936,13 @@
12075
12936
  "signature": "export declare function toFetchHandler<Env = unknown>(app: {\n fetch(request: Request, platform?: Platform<Env>): MaybePromise<Response>;\n resolveWebSocketUpgrade?(request: Request, platform?: Platform<Env>): MaybePromise<WebSocketUpgradeOutcome>;\n}, options?: {\n scheduled?: ScheduledHandler<Env>;\n /**\n * Route WebSocket upgrades to a Durable Object that holds the connections and runs the app's\n * pub/sub - enabling cross-connection broadcast (`app.publish`) on Cloudflare Workers, where a\n * stateless isolate can't. Pass the DO namespace binding from `env`; pair with `@nifrajs/workers`'\n * `createWebSocketHub(app)` (the DO class) + a `wrangler.toml` binding. Without this, WS upgrades use\n * a per-connection `WebSocketPair` (no broadcast).\n */\n webSocketHub?: (env: Env) => DurableObjectNamespaceLike;\n}): {\n fetch(request: Request, env: Env, ctx: ExecutionContext): MaybePromise<Response>;\n scheduled?(controller: ScheduledController, env: Env, ctx: ExecutionContext): MaybePromise<void>;\n};",
12076
12937
  "doc": "/**\n * Adapt a nifra app to an edge \"ExportedHandler\" - use it as a Cloudflare Workers (or any\n * `fetch(request, env, ctx)` runtime) default export. It threads `env` + `ctx.waitUntil` into the\n * nifra Context, so handlers read `c.env` and schedule background work via `c.waitUntil`:\n *\n * export default toFetchHandler(app)\n *\n * Pass `{ scheduled }` to also export a Workers cron handler (for a `[triggers]` schedule) - it\n * receives the platform controller plus the same typed `env`/`waitUntil`:\n *\n * export default toFetchHandler(app, {\n * scheduled: (controller, { env, waitUntil }) =>\n * waitUntil(env.KV.put(\"last-run\", String(controller.scheduledTime))),\n * })\n *\n * No Workers-only deps - `app.fetch` stays a portable Web-standard handler; this is the thin\n * shim from the platform's 3-arg `fetch`/`scheduled` to it.\n */"
12077
12938
  },
12939
+ {
12940
+ "name": "toFetchHandler",
12941
+ "kind": "function",
12942
+ "package": "@nifrajs/edge",
12943
+ "signature": "export declare function toFetchHandler<Env = unknown>(app: {\n fetch(request: Request, platform?: Platform<Env>): MaybePromise<Response>;\n resolveWebSocketUpgrade?(request: Request, platform?: Platform<Env>): MaybePromise<WebSocketUpgradeOutcome>;\n}, options?: {\n scheduled?: ScheduledHandler<Env>;\n /**\n * Route WebSocket upgrades to a Durable Object that holds the connections and runs the app's\n * pub/sub - enabling cross-connection broadcast (`app.publish`) on Cloudflare Workers, where a\n * stateless isolate can't. Pass the DO namespace binding from `env`; pair with `@nifrajs/workers`'\n * `createWebSocketHub(app)` (the DO class) + a `wrangler.toml` binding. Without this, WS upgrades use\n * a per-connection `WebSocketPair` (no broadcast).\n */\n webSocketHub?: (env: Env) => DurableObjectNamespaceLike;\n}): {\n fetch(request: Request, env: Env, ctx: ExecutionContext): MaybePromise<Response>;\n scheduled?(controller: ScheduledController, env: Env, ctx: ExecutionContext): MaybePromise<void>;\n};",
12944
+ "doc": "/**\n * Adapt a nifra app to an edge \"ExportedHandler\" - use it as a Cloudflare Workers (or any\n * `fetch(request, env, ctx)` runtime) default export. It threads `env` + `ctx.waitUntil` into the\n * nifra Context, so handlers read `c.env` and schedule background work via `c.waitUntil`:\n *\n * export default toFetchHandler(app)\n *\n * Pass `{ scheduled }` to also export a Workers cron handler (for a `[triggers]` schedule) - it\n * receives the platform controller plus the same typed `env`/`waitUntil`:\n *\n * export default toFetchHandler(app, {\n * scheduled: (controller, { env, waitUntil }) =>\n * waitUntil(env.KV.put(\"last-run\", String(controller.scheduledTime))),\n * })\n *\n * No Workers-only deps - `app.fetch` stays a portable Web-standard handler; this is the thin\n * shim from the platform's 3-arg `fetch`/`scheduled` to it.\n */"
12945
+ },
12078
12946
  {
12079
12947
  "name": "toFetchHandler",
12080
12948
  "kind": "function",
@@ -12322,6 +13190,12 @@
12322
13190
  "signature": "export declare function topUserFrame(frames: readonly DiagnosticFrame[], root: string | undefined): DiagnosticFrame | undefined;",
12323
13191
  "doc": "/** The first frame that points at the user's own source - what the codeframe should show. */"
12324
13192
  },
13193
+ {
13194
+ "name": "toResponse",
13195
+ "kind": "function",
13196
+ "package": "@nifrajs/core",
13197
+ "signature": "export declare function toResponse(result: HandlerResult, set: CtxSet, tagResponseBody?: ResponseBodyTagOption, statics?: StaticResponseHeaders): Response;"
13198
+ },
12325
13199
  {
12326
13200
  "name": "toVercelHandler",
12327
13201
  "kind": "function",
@@ -12463,6 +13337,12 @@
12463
13337
  "signature": "export type TreatyFromRegistry<R> = TreatyNode<R, \"\"> & RootIndex<R>;",
12464
13338
  "doc": "/**\n * The Eden-style proxy type for a route registry - the shared core used by both\n * `Treaty<App>` (coupled, from `typeof app`) and `client(contract, url)`\n * (decoupled, from a contract's `RegistryFor`).\n */"
12465
13339
  },
13340
+ {
13341
+ "name": "TriggerOptions",
13342
+ "kind": "interface",
13343
+ "package": "@nifrajs/island-trigger",
13344
+ "signature": "export interface TriggerOptions {\n /** Target used by the `visible` strategy. Missing targets degrade to immediate activation. */\n readonly target?: object;\n}"
13345
+ },
12466
13346
  {
12467
13347
  "name": "trimTrailingSlash",
12468
13348
  "kind": "function",
@@ -12551,6 +13431,19 @@
12551
13431
  "signature": "export declare const UNBOUNDED_DEADLINE: number;",
12552
13432
  "doc": "/** Sentinel used only for an unbounded local budget. It is never written to the wire. */"
12553
13433
  },
13434
+ {
13435
+ "name": "undiciTransport",
13436
+ "kind": "function",
13437
+ "package": "@nifrajs/proxy",
13438
+ "signature": "export declare function undiciTransport(options?: UndiciTransportOptions): ProxyTransport;",
13439
+ "doc": "/** Create an undici-backed {@link ProxyTransport}. */"
13440
+ },
13441
+ {
13442
+ "name": "UndiciTransportOptions",
13443
+ "kind": "interface",
13444
+ "package": "@nifrajs/proxy",
13445
+ "signature": "export interface UndiciTransportOptions {\n /**\n * Connection pool to dial through - an undici `Agent`, `Pool`, or any other `Dispatcher`. Omit to\n * use undici's global dispatcher. Supply one to tune `connections` per origin, which is the knob\n * that matters under load. It must not compose a redirect interceptor: this proxy relays 3xx\n * rather than following it, and a dispatcher that follows would hand the upstream the next hop.\n */\n readonly dispatcher?: Dispatcher;\n /**\n * Milliseconds of silence tolerated *within* the response body before undici destroys it.\n * `createProxy`'s own `timeoutMs` only covers the wait for response headers - after the status is\n * relayed a `504` is no longer sendable - so this is what protects against a body that starts and\n * then stalls. Default `30_000`; `0` disables it.\n */\n readonly bodyTimeoutMs?: number;\n}"
13446
+ },
12554
13447
  {
12555
13448
  "name": "unsafeInlineScript",
12556
13449
  "kind": "function",
@@ -13207,14 +14100,14 @@
13207
14100
  "name": "VERSION",
13208
14101
  "kind": "const",
13209
14102
  "package": "@nifrajs/core",
13210
- "signature": "export declare const VERSION: \"2.13.0\";",
14103
+ "signature": "export declare const VERSION: \"3.1.0\";",
13211
14104
  "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
14105
  },
13213
14106
  {
13214
14107
  "name": "VERSION",
13215
14108
  "kind": "const",
13216
14109
  "package": "nifra",
13217
- "signature": "export declare const VERSION: \"2.13.0\";",
14110
+ "signature": "export declare const VERSION: \"3.1.0\";",
13218
14111
  "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
14112
  },
13220
14113
  {
@@ -13234,7 +14127,7 @@
13234
14127
  "name": "ViteDevServerOptions",
13235
14128
  "kind": "interface",
13236
14129
  "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}"
14130
+ "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
14131
  },
13239
14132
  {
13240
14133
  "name": "viteLeakGuard",
@@ -13357,14 +14250,14 @@
13357
14250
  "name": "WebSocketHandler",
13358
14251
  "kind": "interface",
13359
14252
  "package": "@nifrajs/core",
13360
- "signature": "export interface WebSocketHandler<Data = unknown, Env = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined> {\n /**\n * Cross-site WebSocket hijacking (CSWSH) guard - checked BEFORE `upgrade()`. A browser does not\n * apply CORS to WebSocket handshakes and DOES send the page's cookies, so without an Origin check\n * any site can open an authenticated socket to your app. Set this to lock the route to known\n * origins: a string allow-list (exact `Origin` header match) or a predicate. A request whose\n * `Origin` doesn't match (or is absent, for the allow-list form) is rejected with `403` before any\n * per-connection work.\n *\n * **When omitted, the default is same-origin:** a cross-origin BROWSER handshake (an `Origin` header\n * whose host differs from the request's) is rejected with `403`. Non-browser clients (no `Origin`) and\n * same-origin browsers pass. Set this to allow specific cross-origin clients, or `() => true` for a\n * genuinely public socket. Non-browser clients can spoof `Origin`, so this is a browser-CSWSH defense,\n * not authentication - pair it with auth in `upgrade()`.\n */\n allowedOrigins?: ReadonlyArray<string> | ((origin: string | null) => boolean);\n /**\n * Runs in the HTTP request context **before** the upgrade (and after {@link allowedOrigins}) - the\n * place to authenticate or rate-limit. Return the initial per-connection `data` (→ `ws.data`), or a\n * `Response` to **reject** the upgrade (the client never connects). Omit to accept with\n * `data: undefined`. A thrown error rejects with a flat 500.\n */\n upgrade?(c: WebSocketContext<Env>): MaybePromise<Data | Response>;\n /**\n * Contract-first messages: a Standard Schema (`t`, zod, valibot, …) validating each **inbound** frame.\n * Text frames are parsed as JSON first. When set, `message` receives the validated, typed value; a\n * non-JSON or schema-invalid frame is routed to `onInvalidMessage` (or dropped if that's omitted).\n */\n messageSchema?: Schema;\n /**\n * The **outbound** frame contract (server → client), a Standard Schema. Purely type-level: it types\n * the frames the typed client's `.ws()` handle receives, and documents what this route pushes. The\n * server does NOT runtime-validate its own sends - the inbound `messageSchema` guards the trust\n * boundary; outbound honesty is the handler author's code, checked by tests.\n */\n sendSchema?: Send;\n /** Decode versioned transport frames before inbound schema validation. Omit for legacy JSON. */\n transport?: {\n readonly registry: TransportCodecRegistry;\n readonly maxBytes?: number;\n };\n open?(ws: NifraWebSocket<Data>): MaybePromise<void>;\n message?(ws: NifraWebSocket<Data>, data: WsMessageInput<Schema>): MaybePromise<void>;\n /** Inbound frame that failed JSON parse or `messageSchema` validation (only fires when a schema is\n * set). `raw` is the original frame; `issues` are the Standard Schema issues (one synthetic issue for\n * a JSON parse failure). Omit to silently drop invalid frames. */\n onInvalidMessage?(ws: NifraWebSocket<Data>, issues: ReadonlyArray<StandardIssue>, raw: WebSocketData): MaybePromise<void>;\n close?(ws: NifraWebSocket<Data>, code: number, reason: string): MaybePromise<void>;\n error?(ws: NifraWebSocket<Data>, error: unknown): MaybePromise<void>;\n}",
14253
+ "signature": "export interface WebSocketHandler<Data = unknown, Env = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined> {\n /**\n * Cross-site WebSocket hijacking (CSWSH) guard - checked BEFORE `upgrade()`. A browser does not\n * apply CORS to WebSocket handshakes and DOES send the page's cookies, so without an Origin check\n * any site can open an authenticated socket to your app. Set this to lock the route to known\n * origins: a string allow-list (exact `Origin` header match) or a predicate. A request whose\n * `Origin` doesn't match (or is absent, for the allow-list form) is rejected with `403` before any\n * per-connection work.\n *\n * **When omitted, the default is same-origin:** a cross-origin BROWSER handshake (an `Origin` header\n * whose host differs from the request's) is rejected with `403`. Non-browser clients (no `Origin`) and\n * same-origin browsers pass. Set this to allow specific cross-origin clients, or `() => true` for a\n * genuinely public socket. Non-browser clients can spoof `Origin`, so this is a browser-CSWSH defense,\n * not authentication - pair it with auth in `upgrade()`.\n */\n allowedOrigins?: ReadonlyArray<string> | ((origin: string | null) => boolean);\n /**\n * Runs in the HTTP request context **before** the upgrade (and after {@link allowedOrigins}) - the\n * place to authenticate or rate-limit. Return the initial per-connection `data` (→ `ws.data`), or a\n * `Response` to **reject** the upgrade (the client never connects). Omit to accept with\n * `data: undefined`. A thrown error rejects with a flat 500.\n */\n upgrade?(c: WebSocketContext<Env>): MaybePromise<Data | Response>;\n /**\n * Contract-first messages: a Standard Schema (`t`, zod, valibot, …) validating each **inbound** frame.\n * Text frames are parsed as JSON first. When set, `message` receives the validated, typed value; a\n * non-JSON or schema-invalid frame is routed to `onInvalidMessage` (or dropped if that's omitted).\n */\n messageSchema?: Schema;\n /**\n * The **outbound** frame contract (server → client), a Standard Schema. Purely type-level: it types\n * the frames the typed client's `.ws()` handle receives, and documents what this route pushes. The\n * server does NOT runtime-validate its own sends by default - the inbound `messageSchema` guards the\n * trust boundary; outbound honesty is the handler author's code. Set {@link validateSend} to opt into\n * a synchronous runtime check of JSON text/UTF-8 binary frames.\n */\n sendSchema?: Send;\n /**\n * Opt-in runtime enforcement for {@link sendSchema}. Invalid JSON, schema failures, and async\n * validators are dropped before the native socket's `send()` runs and reported to `error()` when it\n * exists. This is a development/contract check for the server's own output, not an inbound security\n * boundary. It is off by default and requires `sendSchema` at registration.\n */\n validateSend?: boolean;\n /** Decode versioned transport frames before inbound schema validation. Omit for legacy JSON. */\n transport?: {\n readonly registry: TransportCodecRegistry;\n readonly maxBytes?: number;\n };\n open?(ws: NifraWebSocket<Data>): MaybePromise<void>;\n message?(ws: NifraWebSocket<Data>, data: WsMessageInput<Schema>): MaybePromise<void>;\n /** Inbound frame that failed JSON parse or `messageSchema` validation (only fires when a schema is\n * set). `raw` is the original frame; `issues` are the Standard Schema issues (one synthetic issue for\n * a JSON parse failure). Omit to silently drop invalid frames. */\n onInvalidMessage?(ws: NifraWebSocket<Data>, issues: ReadonlyArray<StandardIssue>, raw: WebSocketData): MaybePromise<void>;\n close?(ws: NifraWebSocket<Data>, code: number, reason: string): MaybePromise<void>;\n error?(ws: NifraWebSocket<Data>, error: unknown): MaybePromise<void>;\n}",
13361
14254
  "doc": "/** A WebSocket route's lifecycle. All callbacks optional; only `message` is needed for an echo. */"
13362
14255
  },
13363
14256
  {
13364
14257
  "name": "WebSocketHandler",
13365
14258
  "kind": "interface",
13366
14259
  "package": "nifra",
13367
- "signature": "export interface WebSocketHandler<Data = unknown, Env = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined> {\n /**\n * Cross-site WebSocket hijacking (CSWSH) guard - checked BEFORE `upgrade()`. A browser does not\n * apply CORS to WebSocket handshakes and DOES send the page's cookies, so without an Origin check\n * any site can open an authenticated socket to your app. Set this to lock the route to known\n * origins: a string allow-list (exact `Origin` header match) or a predicate. A request whose\n * `Origin` doesn't match (or is absent, for the allow-list form) is rejected with `403` before any\n * per-connection work.\n *\n * **When omitted, the default is same-origin:** a cross-origin BROWSER handshake (an `Origin` header\n * whose host differs from the request's) is rejected with `403`. Non-browser clients (no `Origin`) and\n * same-origin browsers pass. Set this to allow specific cross-origin clients, or `() => true` for a\n * genuinely public socket. Non-browser clients can spoof `Origin`, so this is a browser-CSWSH defense,\n * not authentication - pair it with auth in `upgrade()`.\n */\n allowedOrigins?: ReadonlyArray<string> | ((origin: string | null) => boolean);\n /**\n * Runs in the HTTP request context **before** the upgrade (and after {@link allowedOrigins}) - the\n * place to authenticate or rate-limit. Return the initial per-connection `data` (→ `ws.data`), or a\n * `Response` to **reject** the upgrade (the client never connects). Omit to accept with\n * `data: undefined`. A thrown error rejects with a flat 500.\n */\n upgrade?(c: WebSocketContext<Env>): MaybePromise<Data | Response>;\n /**\n * Contract-first messages: a Standard Schema (`t`, zod, valibot, …) validating each **inbound** frame.\n * Text frames are parsed as JSON first. When set, `message` receives the validated, typed value; a\n * non-JSON or schema-invalid frame is routed to `onInvalidMessage` (or dropped if that's omitted).\n */\n messageSchema?: Schema;\n /**\n * The **outbound** frame contract (server → client), a Standard Schema. Purely type-level: it types\n * the frames the typed client's `.ws()` handle receives, and documents what this route pushes. The\n * server does NOT runtime-validate its own sends - the inbound `messageSchema` guards the trust\n * boundary; outbound honesty is the handler author's code, checked by tests.\n */\n sendSchema?: Send;\n /** Decode versioned transport frames before inbound schema validation. Omit for legacy JSON. */\n transport?: {\n readonly registry: TransportCodecRegistry;\n readonly maxBytes?: number;\n };\n open?(ws: NifraWebSocket<Data>): MaybePromise<void>;\n message?(ws: NifraWebSocket<Data>, data: WsMessageInput<Schema>): MaybePromise<void>;\n /** Inbound frame that failed JSON parse or `messageSchema` validation (only fires when a schema is\n * set). `raw` is the original frame; `issues` are the Standard Schema issues (one synthetic issue for\n * a JSON parse failure). Omit to silently drop invalid frames. */\n onInvalidMessage?(ws: NifraWebSocket<Data>, issues: ReadonlyArray<StandardIssue>, raw: WebSocketData): MaybePromise<void>;\n close?(ws: NifraWebSocket<Data>, code: number, reason: string): MaybePromise<void>;\n error?(ws: NifraWebSocket<Data>, error: unknown): MaybePromise<void>;\n}",
14260
+ "signature": "export interface WebSocketHandler<Data = unknown, Env = unknown, Schema extends StandardSchemaV1 | undefined = undefined, Send extends StandardSchemaV1 | undefined = undefined> {\n /**\n * Cross-site WebSocket hijacking (CSWSH) guard - checked BEFORE `upgrade()`. A browser does not\n * apply CORS to WebSocket handshakes and DOES send the page's cookies, so without an Origin check\n * any site can open an authenticated socket to your app. Set this to lock the route to known\n * origins: a string allow-list (exact `Origin` header match) or a predicate. A request whose\n * `Origin` doesn't match (or is absent, for the allow-list form) is rejected with `403` before any\n * per-connection work.\n *\n * **When omitted, the default is same-origin:** a cross-origin BROWSER handshake (an `Origin` header\n * whose host differs from the request's) is rejected with `403`. Non-browser clients (no `Origin`) and\n * same-origin browsers pass. Set this to allow specific cross-origin clients, or `() => true` for a\n * genuinely public socket. Non-browser clients can spoof `Origin`, so this is a browser-CSWSH defense,\n * not authentication - pair it with auth in `upgrade()`.\n */\n allowedOrigins?: ReadonlyArray<string> | ((origin: string | null) => boolean);\n /**\n * Runs in the HTTP request context **before** the upgrade (and after {@link allowedOrigins}) - the\n * place to authenticate or rate-limit. Return the initial per-connection `data` (→ `ws.data`), or a\n * `Response` to **reject** the upgrade (the client never connects). Omit to accept with\n * `data: undefined`. A thrown error rejects with a flat 500.\n */\n upgrade?(c: WebSocketContext<Env>): MaybePromise<Data | Response>;\n /**\n * Contract-first messages: a Standard Schema (`t`, zod, valibot, …) validating each **inbound** frame.\n * Text frames are parsed as JSON first. When set, `message` receives the validated, typed value; a\n * non-JSON or schema-invalid frame is routed to `onInvalidMessage` (or dropped if that's omitted).\n */\n messageSchema?: Schema;\n /**\n * The **outbound** frame contract (server → client), a Standard Schema. Purely type-level: it types\n * the frames the typed client's `.ws()` handle receives, and documents what this route pushes. The\n * server does NOT runtime-validate its own sends by default - the inbound `messageSchema` guards the\n * trust boundary; outbound honesty is the handler author's code. Set {@link validateSend} to opt into\n * a synchronous runtime check of JSON text/UTF-8 binary frames.\n */\n sendSchema?: Send;\n /**\n * Opt-in runtime enforcement for {@link sendSchema}. Invalid JSON, schema failures, and async\n * validators are dropped before the native socket's `send()` runs and reported to `error()` when it\n * exists. This is a development/contract check for the server's own output, not an inbound security\n * boundary. It is off by default and requires `sendSchema` at registration.\n */\n validateSend?: boolean;\n /** Decode versioned transport frames before inbound schema validation. Omit for legacy JSON. */\n transport?: {\n readonly registry: TransportCodecRegistry;\n readonly maxBytes?: number;\n };\n open?(ws: NifraWebSocket<Data>): MaybePromise<void>;\n message?(ws: NifraWebSocket<Data>, data: WsMessageInput<Schema>): MaybePromise<void>;\n /** Inbound frame that failed JSON parse or `messageSchema` validation (only fires when a schema is\n * set). `raw` is the original frame; `issues` are the Standard Schema issues (one synthetic issue for\n * a JSON parse failure). Omit to silently drop invalid frames. */\n onInvalidMessage?(ws: NifraWebSocket<Data>, issues: ReadonlyArray<StandardIssue>, raw: WebSocketData): MaybePromise<void>;\n close?(ws: NifraWebSocket<Data>, code: number, reason: string): MaybePromise<void>;\n error?(ws: NifraWebSocket<Data>, error: unknown): MaybePromise<void>;\n}",
13368
14261
  "doc": "/** A WebSocket route's lifecycle. All callbacks optional; only `message` is needed for an echo. */"
13369
14262
  },
13370
14263
  {
@@ -13458,6 +14351,13 @@
13458
14351
  "signature": "export type WithPrincipal<S extends AnyServer, P> = S extends Server<infer R, infer C> ? Server<R, C & {\n principal: P;\n}> : never;",
13459
14352
  "doc": "/** Add `{ principal: P }` to a server's context while preserving its route registry `R` (no collapse to\n * `any`). This is the type that makes `.use(authed(auth))` thread a NON-NULL `c.principal`. */"
13460
14353
  },
14354
+ {
14355
+ "name": "withResponseObserver",
14356
+ "kind": "function",
14357
+ "package": "@nifrajs/core",
14358
+ "signature": "export declare function withResponseObserver<T extends object>(middleware: T): T;",
14359
+ "doc": "/** Attach the opt-in observer runtime to a middleware bundle that uses response observation. */"
14360
+ },
13461
14361
  {
13462
14362
  "name": "withRouteAssurance",
13463
14363
  "kind": "function",