@nifrajs/cli 5.0.0 → 5.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 (202) hide show
  1. package/README.md +7 -2
  2. package/dist/assure-hydration.d.ts.map +1 -1
  3. package/dist/assure-hydration.js +4 -2
  4. package/dist/assure-hydration.js.map +1 -1
  5. package/dist/assure.d.ts +12 -2
  6. package/dist/assure.d.ts.map +1 -1
  7. package/dist/assure.js +59 -8
  8. package/dist/assure.js.map +1 -1
  9. package/dist/capabilities-tool.d.ts.map +1 -1
  10. package/dist/capabilities-tool.js +24 -7
  11. package/dist/capabilities-tool.js.map +1 -1
  12. package/dist/check-diagnostics.d.ts +2 -0
  13. package/dist/check-diagnostics.d.ts.map +1 -1
  14. package/dist/check-diagnostics.js.map +1 -1
  15. package/dist/check-scan.d.ts +8 -2
  16. package/dist/check-scan.d.ts.map +1 -1
  17. package/dist/check-scan.js +43 -10
  18. package/dist/check-scan.js.map +1 -1
  19. package/dist/check.d.ts.map +1 -1
  20. package/dist/check.js +39 -33
  21. package/dist/check.js.map +1 -1
  22. package/dist/cli.d.ts +2 -0
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js +106 -48
  25. package/dist/cli.js.map +1 -1
  26. package/dist/client-module.d.ts +5 -3
  27. package/dist/client-module.d.ts.map +1 -1
  28. package/dist/client-module.js +34 -10
  29. package/dist/client-module.js.map +1 -1
  30. package/dist/command-catalog.d.ts +9 -1
  31. package/dist/command-catalog.d.ts.map +1 -1
  32. package/dist/command-catalog.js +67 -22
  33. package/dist/command-catalog.js.map +1 -1
  34. package/dist/dev-feed-tool.d.ts +18 -1
  35. package/dist/dev-feed-tool.d.ts.map +1 -1
  36. package/dist/dev-feed-tool.js +93 -0
  37. package/dist/dev-feed-tool.js.map +1 -1
  38. package/dist/fix-recipes.d.ts +2 -0
  39. package/dist/fix-recipes.d.ts.map +1 -1
  40. package/dist/fix-recipes.js +93 -12
  41. package/dist/fix-recipes.js.map +1 -1
  42. package/dist/init-agents.d.ts +16 -0
  43. package/dist/init-agents.d.ts.map +1 -1
  44. package/dist/init-agents.js +3 -2
  45. package/dist/init-agents.js.map +1 -1
  46. package/dist/internal/config-paths.d.ts +16 -0
  47. package/dist/internal/config-paths.d.ts.map +1 -0
  48. package/dist/internal/config-paths.js +124 -0
  49. package/dist/internal/config-paths.js.map +1 -0
  50. package/dist/internal/installed-package.d.ts +4 -0
  51. package/dist/internal/installed-package.d.ts.map +1 -0
  52. package/dist/internal/installed-package.js +17 -0
  53. package/dist/internal/installed-package.js.map +1 -0
  54. package/dist/internal/project-specifiers.d.ts +14 -1
  55. package/dist/internal/project-specifiers.d.ts.map +1 -1
  56. package/dist/internal/project-specifiers.js +54 -15
  57. package/dist/internal/project-specifiers.js.map +1 -1
  58. package/dist/internal/source-facts.d.ts +6 -1
  59. package/dist/internal/source-facts.d.ts.map +1 -1
  60. package/dist/internal/source-facts.js +11 -5
  61. package/dist/internal/source-facts.js.map +1 -1
  62. package/dist/internal/typescript-import.d.ts.map +1 -1
  63. package/dist/internal/typescript-import.js +5 -3
  64. package/dist/internal/typescript-import.js.map +1 -1
  65. package/dist/introspect.d.ts +9 -0
  66. package/dist/introspect.d.ts.map +1 -1
  67. package/dist/introspect.js +32 -1
  68. package/dist/introspect.js.map +1 -1
  69. package/dist/levels-tool.d.ts.map +1 -1
  70. package/dist/levels-tool.js +5 -8
  71. package/dist/levels-tool.js.map +1 -1
  72. package/dist/load.d.ts +2 -2
  73. package/dist/load.d.ts.map +1 -1
  74. package/dist/load.js +23 -3
  75. package/dist/load.js.map +1 -1
  76. package/dist/mcp-context.d.ts.map +1 -1
  77. package/dist/mcp-context.js +6 -21
  78. package/dist/mcp-context.js.map +1 -1
  79. package/dist/mcp-delegate.d.ts +2 -2
  80. package/dist/mcp-delegate.d.ts.map +1 -1
  81. package/dist/mcp-delegate.js +19 -7
  82. package/dist/mcp-delegate.js.map +1 -1
  83. package/dist/mcp-exec.d.ts +1 -0
  84. package/dist/mcp-exec.d.ts.map +1 -1
  85. package/dist/mcp-exec.js +8 -3
  86. package/dist/mcp-exec.js.map +1 -1
  87. package/dist/mcp-http.js +1 -1
  88. package/dist/mcp-io.d.ts +13 -0
  89. package/dist/mcp-io.d.ts.map +1 -1
  90. package/dist/mcp-io.js +23 -0
  91. package/dist/mcp-io.js.map +1 -1
  92. package/dist/mcp-path.d.ts +2 -1
  93. package/dist/mcp-path.d.ts.map +1 -1
  94. package/dist/mcp-path.js +9 -24
  95. package/dist/mcp-path.js.map +1 -1
  96. package/dist/mcp.d.ts.map +1 -1
  97. package/dist/mcp.js +40 -17
  98. package/dist/mcp.js.map +1 -1
  99. package/dist/migrate-layout.d.ts +40 -1
  100. package/dist/migrate-layout.d.ts.map +1 -1
  101. package/dist/migrate-layout.js +1316 -228
  102. package/dist/migrate-layout.js.map +1 -1
  103. package/dist/output-schemas.d.ts +34 -0
  104. package/dist/output-schemas.d.ts.map +1 -1
  105. package/dist/output-schemas.js +132 -21
  106. package/dist/output-schemas.js.map +1 -1
  107. package/dist/project-path.d.ts +6 -0
  108. package/dist/project-path.d.ts.map +1 -1
  109. package/dist/project-path.js +48 -14
  110. package/dist/project-path.js.map +1 -1
  111. package/dist/release-verification.d.ts +5 -0
  112. package/dist/release-verification.d.ts.map +1 -1
  113. package/dist/release-verification.js +14 -0
  114. package/dist/release-verification.js.map +1 -1
  115. package/dist/review.d.ts.map +1 -1
  116. package/dist/review.js +5 -0
  117. package/dist/review.js.map +1 -1
  118. package/dist/rules/codes.d.ts +3 -1
  119. package/dist/rules/codes.d.ts.map +1 -1
  120. package/dist/rules/codes.js +3 -1
  121. package/dist/rules/codes.js.map +1 -1
  122. package/dist/rules/data-guard.d.ts +6 -0
  123. package/dist/rules/data-guard.d.ts.map +1 -1
  124. package/dist/rules/data-guard.js +37 -0
  125. package/dist/rules/data-guard.js.map +1 -1
  126. package/dist/rules/legacy.d.ts.map +1 -1
  127. package/dist/rules/legacy.js +20 -1
  128. package/dist/rules/legacy.js.map +1 -1
  129. package/dist/rules/pages.d.ts +29 -3
  130. package/dist/rules/pages.d.ts.map +1 -1
  131. package/dist/rules/pages.js +236 -22
  132. package/dist/rules/pages.js.map +1 -1
  133. package/dist/rules/security.d.ts +3 -2
  134. package/dist/rules/security.d.ts.map +1 -1
  135. package/dist/rules/security.js +42 -11
  136. package/dist/rules/security.js.map +1 -1
  137. package/dist/rules/zones.d.ts.map +1 -1
  138. package/dist/rules/zones.js +31 -9
  139. package/dist/rules/zones.js.map +1 -1
  140. package/dist/stylex-migrate.d.ts.map +1 -1
  141. package/dist/stylex-migrate.js +127 -17
  142. package/dist/stylex-migrate.js.map +1 -1
  143. package/dist/test-tool.d.ts.map +1 -1
  144. package/dist/test-tool.js +3 -9
  145. package/dist/test-tool.js.map +1 -1
  146. package/dist/upgrade.d.ts +20 -5
  147. package/dist/upgrade.d.ts.map +1 -1
  148. package/dist/upgrade.js +86 -9
  149. package/dist/upgrade.js.map +1 -1
  150. package/dist/verification-plan.d.ts.map +1 -1
  151. package/dist/verification-plan.js +5 -2
  152. package/dist/verification-plan.js.map +1 -1
  153. package/dist/version-drift.d.ts.map +1 -1
  154. package/dist/version-drift.js +55 -3
  155. package/dist/version-drift.js.map +1 -1
  156. package/docs/examples.json +2 -2
  157. package/docs/llms-full.txt +481 -61
  158. package/docs/types.json +147 -70
  159. package/package.json +11 -11
  160. package/src/assure-hydration.ts +4 -1
  161. package/src/assure.ts +88 -10
  162. package/src/capabilities-tool.ts +33 -7
  163. package/src/check-diagnostics.ts +2 -0
  164. package/src/check-scan.ts +56 -9
  165. package/src/check.ts +55 -39
  166. package/src/cli.ts +104 -35
  167. package/src/client-module.ts +45 -9
  168. package/src/command-catalog.ts +77 -21
  169. package/src/dev-feed-tool.ts +112 -1
  170. package/src/fix-recipes.ts +101 -10
  171. package/src/init-agents.ts +4 -3
  172. package/src/internal/config-paths.ts +154 -0
  173. package/src/internal/installed-package.ts +15 -0
  174. package/src/internal/project-specifiers.ts +69 -16
  175. package/src/internal/source-facts.ts +23 -5
  176. package/src/internal/typescript-import.ts +5 -3
  177. package/src/introspect.ts +39 -1
  178. package/src/levels-tool.ts +7 -9
  179. package/src/load.ts +29 -3
  180. package/src/mcp-context.ts +5 -18
  181. package/src/mcp-delegate.ts +22 -10
  182. package/src/mcp-exec.ts +9 -2
  183. package/src/mcp-http.ts +1 -1
  184. package/src/mcp-io.ts +33 -0
  185. package/src/mcp-path.ts +8 -22
  186. package/src/mcp.ts +48 -19
  187. package/src/migrate-layout.ts +1496 -237
  188. package/src/output-schemas.ts +179 -23
  189. package/src/project-path.ts +44 -13
  190. package/src/release-verification.ts +20 -0
  191. package/src/review.ts +5 -0
  192. package/src/rules/codes.ts +3 -1
  193. package/src/rules/data-guard.ts +40 -0
  194. package/src/rules/legacy.ts +22 -1
  195. package/src/rules/pages.ts +266 -24
  196. package/src/rules/security.ts +49 -11
  197. package/src/rules/zones.ts +30 -7
  198. package/src/stylex-migrate.ts +117 -17
  199. package/src/test-tool.ts +3 -9
  200. package/src/upgrade.ts +96 -8
  201. package/src/verification-plan.ts +9 -2
  202. package/src/version-drift.ts +53 -2
package/docs/types.json CHANGED
@@ -117,6 +117,13 @@
117
117
  "signature": "export declare const AGENT_PROTOCOL_VERSION: 1;",
118
118
  "doc": "/**\n * Backend-neutral protocol for local coding-agent hosts.\n *\n * This package deliberately has no runtime dependencies. A Pi adapter, a Nifra-native backend,\n * the CLI, and the Workbench can all implement or consume these contracts without pulling any\n * framework, model provider, or UI code into an application.\n */"
119
119
  },
120
+ {
121
+ "name": "APPROVAL_NEVER_EXPIRES_AT",
122
+ "kind": "const",
123
+ "package": "@nifrajs/coding-agent",
124
+ "signature": "export declare const APPROVAL_NEVER_EXPIRES_AT = 8640000000000000;",
125
+ "doc": "/**\n * The `expiresAt` of an approval that never times out: the largest epoch-ms a `Date` holds\n * (+275760-09-13). It survives JSON, unlike `Infinity`, and `new Date(expiresAt)` stays valid.\n */"
126
+ },
120
127
  {
121
128
  "name": "AcpBackend",
122
129
  "kind": "class",
@@ -718,7 +725,7 @@
718
725
  "name": "AgentPorts",
719
726
  "kind": "interface",
720
727
  "package": "@nifrajs/agent",
721
- "signature": "export interface AgentPorts {\n readonly model: AgentModelPort;\n readonly capabilities: readonly string[];\n readonly budget?: ToolBudget;\n /** Wall-clock budget shared with the parent request. Distinct from `budget`, which is cost. */\n readonly deadline?: RequestBudget;\n readonly idempotency?: ToolIdempotencyStore;\n readonly state?: AgentStateStore;\n readonly approval?: AgentApprovalPort;\n /**\n * Who decides a step that suspended for approval when the run resumes. `\"caller\"` (the default)\n * takes `resume.approval` as the decision. `\"port\"` asks `approval` again and hands it the caller's\n * decision as `callerDecision`; set it when the resuming caller is the party asking for the tool,\n * as under A2A or a public AG-UI route, so it cannot approve its own call.\n */\n readonly resumeApproval?: \"caller\" | \"port\";\n readonly telemetry?: AgentTelemetryPort;\n /** Receives model deltas when the model port streams. Transient - nothing here is persisted. */\n readonly deltas?: AgentDeltaSink;\n readonly clock?: () => number;\n /** Adapter used to satisfy execution policies declared by tool contracts. */\n readonly executionPolicy?: ExecutionPolicyAdapter;\n /** Injectable token generator for deterministic replay and tests. */\n readonly idFactory?: () => string;\n readonly signal?: AbortSignal;\n /** Replay mode skips every tool executor and marks the call dry-run. */\n readonly dryRun?: boolean;\n}"
728
+ "signature": "export interface AgentPorts {\n readonly model: AgentModelPort;\n readonly capabilities: readonly string[];\n readonly budget?: ToolBudget;\n /** Wall-clock budget shared with the parent request. Distinct from `budget`, which is cost. */\n readonly deadline?: RequestBudget;\n readonly idempotency?: ToolIdempotencyStore;\n readonly state?: AgentStateStore;\n readonly approval?: AgentApprovalPort;\n /**\n * Who decides a step that suspended for approval when the run resumes. `\"caller\"` (the default)\n * takes `resume.approval` as the decision. `\"port\"` asks `approval` again and hands it the caller's\n * decision as `callerDecision`; set it when the resuming caller is the party asking for the tool,\n * as on a public AG-UI route, so it cannot approve its own call. `mountA2A` defaults to `\"port\"`.\n */\n readonly resumeApproval?: \"caller\" | \"port\";\n readonly telemetry?: AgentTelemetryPort;\n /** Receives model deltas when the model port streams. Transient - nothing here is persisted. */\n readonly deltas?: AgentDeltaSink;\n readonly clock?: () => number;\n /** Adapter used to satisfy execution policies declared by tool contracts. */\n readonly executionPolicy?: ExecutionPolicyAdapter;\n /** Injectable token generator for deterministic replay and tests. */\n readonly idFactory?: () => string;\n readonly signal?: AbortSignal;\n /** Replay mode skips every tool executor and marks the call dry-run. */\n readonly dryRun?: boolean;\n}"
722
729
  },
723
730
  {
724
731
  "name": "AgentPreset",
@@ -1186,14 +1193,14 @@
1186
1193
  "name": "ApprovalManager",
1187
1194
  "kind": "class",
1188
1195
  "package": "@nifrajs/coding-agent",
1189
- "signature": "export declare class ApprovalManager {\n private readonly options;\n private readonly pendingApprovals;\n constructor(options?: ApprovalManagerOptions);\n get pending(): readonly ApprovalRequest[];\n /** Convert a streamed backend approval event into a resolvable pending request. */\n observe(event: AgentApprovalRequiredEvent): Promise<ApprovalRequest | undefined>;\n /**\n * Publish a pending approval without waiting for its decision (useful for transports). Returns\n * `undefined` when the broker is full or an approval with the same id is still pending.\n */\n offer(input: Omit<ApprovalRequest, \"createdAt\" | \"expiresAt\">): Promise<ApprovalRequest | undefined>;\n /**\n * Create a host-owned approval that can be awaited by a workflow or extension. Resolves `false`\n * when the broker is full or an approval with the same id is still pending.\n */\n request(input: Omit<ApprovalRequest, \"createdAt\" | \"expiresAt\">): Promise<boolean>;\n /**\n * Resolve an approval that was opened with a {@link DecisionCoordinate}, admitting the decision only\n * when it matches the live boundary and is still fresh. Every failure is content-free and fails\n * closed: an unknown id, a coordinate-less approval, a mismatched or superseded coordinate, or an\n * expired boundary resumes no work. This adds a typed path alongside the untyped {@link resolve}; it\n * never loosens it.\n */\n resolveMatched(coordinate: DecisionCoordinate, approved: boolean, now?: number): ApprovalMatchResult;\n /**\n * Settle a pending approval by id. An approval opened with a coordinate is approved only through\n * {@link resolveMatched}; this untyped path can still deny it, and returns `undefined` for an\n * approve.\n */\n resolve(approvalId: string, approved: boolean, reason?: string): ApprovalDecision | undefined;\n close(): void;\n private settle;\n private create;\n}",
1196
+ "signature": "export declare class ApprovalManager {\n private readonly options;\n private readonly pendingApprovals;\n constructor(options?: ApprovalManagerOptions);\n /** The configured timeout, for {@link approvalRequestFromEvent}. */\n get timeoutMs(): ApprovalTimeout;\n get pending(): readonly ApprovalRequest[];\n /** Convert a streamed backend approval event into a resolvable pending request. */\n observe(event: AgentApprovalRequiredEvent): Promise<ApprovalRequest | undefined>;\n /**\n * Publish a pending approval without waiting for its decision (useful for transports). Returns\n * `undefined` when the broker is full or an approval with the same id is still pending.\n */\n offer(input: Omit<ApprovalRequest, \"createdAt\" | \"expiresAt\">): Promise<ApprovalRequest | undefined>;\n /**\n * Create a host-owned approval that can be awaited by a workflow or extension. Resolves `false`\n * when the broker is full or an approval with the same id is still pending.\n */\n request(input: Omit<ApprovalRequest, \"createdAt\" | \"expiresAt\">): Promise<boolean>;\n /**\n * Resolve an approval that was opened with a {@link DecisionCoordinate}, admitting the decision only\n * when it matches the live boundary and is still fresh. Every failure is content-free and fails\n * closed: an unknown id, a coordinate-less approval, a mismatched or superseded coordinate, or an\n * expired boundary resumes no work. This adds a typed path alongside the untyped {@link resolve}; it\n * never loosens it.\n */\n resolveMatched(coordinate: DecisionCoordinate, approved: boolean, now?: number): ApprovalMatchResult;\n /**\n * Settle a pending approval by id. An approval opened with a coordinate is approved only through\n * {@link resolveMatched}; this untyped path can still deny it, and returns `undefined` for an\n * approve.\n */\n resolve(approvalId: string, approved: boolean, reason?: string): ApprovalDecision | undefined;\n close(): void;\n private settle;\n private create;\n}",
1190
1197
  "doc": "/**\n * Small approval broker shared by RPC, Workbench, and workflow extensions.\n *\n * Approval state is deliberately bounded and expires closed (denied) by default. It is a policy\n * seam, not a security boundary: filesystem/process isolation still belongs to the host or OS.\n */"
1191
1198
  },
1192
1199
  {
1193
1200
  "name": "ApprovalManagerOptions",
1194
1201
  "kind": "interface",
1195
1202
  "package": "@nifrajs/coding-agent",
1196
- "signature": "export interface ApprovalManagerOptions {\n readonly maxPending?: number;\n readonly timeoutMs?: number;\n readonly onRequired?: (request: ApprovalRequest) => void | PromiseLike<void>;\n readonly onResolved?: (decision: ApprovalDecision) => void | PromiseLike<void>;\n}"
1203
+ "signature": "export interface ApprovalManagerOptions {\n readonly maxPending?: number;\n /**\n * How long an approval waits before it is denied as timed out (default 5 minutes, at most 24 h).\n * `\"never\"` removes the timer; `maxPending` still bounds how many approvals can wait.\n */\n readonly timeoutMs?: ApprovalTimeout;\n readonly onRequired?: (request: ApprovalRequest) => void | PromiseLike<void>;\n readonly onResolved?: (decision: ApprovalDecision) => void | PromiseLike<void>;\n}"
1197
1204
  },
1198
1205
  {
1199
1206
  "name": "ApprovalMatchRejection",
@@ -1224,7 +1231,7 @@
1224
1231
  "name": "ApprovalRequest",
1225
1232
  "kind": "interface",
1226
1233
  "package": "@nifrajs/coding-agent",
1227
- "signature": "export interface ApprovalRequest {\n readonly id: string;\n readonly sessionId: string;\n readonly turnId?: string;\n readonly action: string;\n readonly capability: string;\n readonly reason?: string;\n /**\n * Optional decision-boundary coordinate. When present, {@link ApprovalManager.resolveMatched}\n * admits a decision only if it names this exact run, node, capability, request id, and vector, and\n * arrives before expiry. Coordinate-less approvals keep their original untyped {@link resolve} path.\n */\n readonly coordinate?: DecisionCoordinate;\n readonly createdAt: number;\n readonly expiresAt: number;\n}"
1234
+ "signature": "export interface ApprovalRequest {\n readonly id: string;\n readonly sessionId: string;\n readonly turnId?: string;\n readonly action: string;\n readonly capability: string;\n readonly reason?: string;\n /**\n * Optional decision-boundary coordinate. When present, {@link ApprovalManager.resolveMatched}\n * admits a decision only if it names this exact run, node, capability, request id, and vector, and\n * arrives before expiry. Coordinate-less approvals keep their original untyped {@link resolve} path.\n */\n readonly coordinate?: DecisionCoordinate;\n readonly createdAt: number;\n /**\n * Absolute epoch-ms after which the approval is denied as timed out. An approval opened with a\n * `\"never\"` timeout reports {@link APPROVAL_NEVER_EXPIRES_AT}, so `now < expiresAt` keeps treating\n * it as live.\n */\n readonly expiresAt: number;\n}"
1228
1235
  },
1229
1236
  {
1230
1237
  "name": "ApprovalRequiredError",
@@ -1256,6 +1263,13 @@
1256
1263
  "package": "@nifrajs/core",
1257
1264
  "signature": "export interface ApprovalStore {\n readonly durability?: \"memory\" | \"durable\";\n create(record: ApprovalRecord): boolean | Promise<boolean>;\n get(approvalId: string): ApprovalRecord | undefined | Promise<ApprovalRecord | undefined>;\n decide(input: {\n readonly approvalId: string;\n readonly tenantId: string;\n readonly decision: \"approved\" | \"denied\";\n readonly decidedBy: string;\n readonly now: number;\n }): boolean | Promise<boolean>;\n /**\n * Atomically validate binding/token/state and change `approved` to `consumed`. Two concurrent\n * callers with one token must yield exactly one `consumed` and one `replay` result.\n */\n consume(input: {\n readonly approvalId: string;\n readonly tenantId: string;\n readonly principalId: string;\n readonly capability: string;\n readonly target?: string;\n readonly digest?: string;\n readonly tokenHash: string;\n readonly now: number;\n }): ApprovalConsumeResult | Promise<ApprovalConsumeResult>;\n}"
1258
1265
  },
1266
+ {
1267
+ "name": "ApprovalTimeout",
1268
+ "kind": "type",
1269
+ "package": "@nifrajs/coding-agent",
1270
+ "signature": "export type ApprovalTimeout = number | \"never\";",
1271
+ "doc": "/**\n * How long an approval may wait: whole milliseconds from 1 ms to 24 h, or `\"never\"` for no timer. A\n * `\"never\"` approval still settles on an answer, a cancel, the end of its turn, and close.\n */"
1272
+ },
1259
1273
  {
1260
1274
  "name": "ApprovalTokenExpiredError",
1261
1275
  "kind": "class",
@@ -1385,7 +1399,7 @@
1385
1399
  "name": "AssurancePolicy",
1386
1400
  "kind": "interface",
1387
1401
  "package": "@nifrajs/core",
1388
- "signature": "export interface AssurancePolicy {\n /** First matching rule owns a route. Put exceptions before broad defaults. */\n readonly rules: readonly AssuranceRule[];\n /** Default `error`: an unclassified route fails closed. */\n readonly unmatched?: \"error\" | \"ignore\";\n /** Default false: reject an empty reflected source so a wrong import cannot pass CI silently. */\n readonly allowEmpty?: boolean;\n /**\n * Default false. When true, a route matched by a **pure-classification** rule (no `require`, no `forbid`)\n * that carries NO enforcement evidence is reported (`classified-no-evidence`). This surfaces the gap the\n * feedback flagged: a classification-only policy silently degrades \"proof\" to a \"label\". Opt-in, because\n * a genuinely public route legitimately carries no evidence; enable it once your guards emit evidence\n * (inline `schema.assurance` or a `withRouteAssurance` middleware) to keep classification honest.\n */\n readonly flagClassifiedWithoutEvidence?: boolean;\n}"
1402
+ "signature": "export interface AssurancePolicy {\n /** First matching rule owns a route. Put exceptions before broad defaults. */\n readonly rules: readonly AssuranceRule[];\n /**\n * Rules checked on EVERY route they match, in addition to the first-match rule that owns it - for a\n * requirement that holds across classes (\"every route declaring a response enforces it\"), which\n * first-match-wins would otherwise make you repeat in each rule. A baseline rule does not classify a\n * route: one no `rules` entry matches is still unclassified. Names share one namespace with `rules`.\n */\n readonly baseline?: readonly AssuranceRule[];\n /** Default `error`: an unclassified route fails closed. */\n readonly unmatched?: \"error\" | \"ignore\";\n /** Default false: reject an empty reflected source so a wrong import cannot pass CI silently. */\n readonly allowEmpty?: boolean;\n /**\n * Default false. When true, a route matched by a **pure-classification** rule (no `require`, no `forbid`)\n * that carries NO enforcement evidence is reported (`classified-no-evidence`). This surfaces the gap the\n * feedback flagged: a classification-only policy silently degrades \"proof\" to a \"label\". Opt-in, because\n * a genuinely public route legitimately carries no evidence; enable it once your guards emit evidence\n * (inline `schema.assurance` or a `withRouteAssurance` middleware) to keep classification honest.\n */\n readonly flagClassifiedWithoutEvidence?: boolean;\n}"
1389
1403
  },
1390
1404
  {
1391
1405
  "name": "AssuranceReport",
@@ -1397,7 +1411,7 @@
1397
1411
  "name": "AssuranceRouteSelector",
1398
1412
  "kind": "interface",
1399
1413
  "package": "@nifrajs/core",
1400
- "signature": "export interface AssuranceRouteSelector {\n /** Omit for every method. `\"WS\"` selects WebSocket routes. */\n readonly methods?: readonly (Method | \"WS\")[];\n /**\n * Skip routes under these methods; `\"WS\"` skips WebSocket routes. Every other method matches, a\n * custom one such as `PURGE` included, so `[\"GET\", \"HEAD\", \"OPTIONS\", \"WS\"]` selects every route\n * that can change state.\n */\n readonly exceptMethods?: readonly (Method | \"WS\")[];\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}"
1414
+ "signature": "export interface AssuranceRouteSelector {\n /** Omit for every method. `\"WS\"` selects WebSocket routes. */\n readonly methods?: readonly (Method | \"WS\")[];\n /**\n * Skip routes under these methods; `\"WS\"` skips WebSocket routes. Every other method matches, a\n * custom one such as `PURGE` included, so `[\"GET\", \"HEAD\", \"OPTIONS\", \"WS\"]` selects every route\n * that can change state.\n */\n readonly exceptMethods?: readonly (Method | \"WS\")[];\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 whether they declare a success `response` schema - the routes a response contract\n * can hold to anything. Pair it with `require: [\"nifra.response-contract\"]` to say \"every route\n * that declares a response enforces it\" without listing the routes that declare none.\n */\n readonly hasResponse?: 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}"
1401
1415
  },
1402
1416
  {
1403
1417
  "name": "AssuranceRule",
@@ -3238,7 +3252,7 @@
3238
3252
  "name": "Classification",
3239
3253
  "kind": "type",
3240
3254
  "package": "@nifrajs/web",
3241
- "signature": "export type Classification = {\n readonly zone: Zone;\n /** The package a `library` file belongs to. */\n readonly packageName?: string;\n /** A `library` package's own declaration, when it made one. */\n readonly declared?: PackageEnvironment;\n /** A third-party file's path inside `node_modules`: `drizzle-orm/node-postgres/index.js`. */\n readonly modulePath?: string;\n} | {\n readonly zone: \"error\";\n readonly reason: string;\n /** The undeclared package this error is about: every file in it shares the one fix. */\n readonly package?: string;\n};"
3255
+ "signature": "export type Classification = {\n readonly zone: Zone;\n /** The package a `library` file belongs to. */\n readonly packageName?: string;\n /** A `library` package's own declaration, when it made one. */\n readonly declared?: PackageEnvironment;\n /** A third-party file's path inside `node_modules`: `drizzle-orm/node-postgres/index.js`. */\n readonly modulePath?: string;\n /** The export subpath (`\"./react\"`) whose own declared side decided this import. */\n readonly entry?: string;\n} | {\n readonly zone: \"error\";\n readonly reason: string;\n /** The undeclared package this error is about: every file in it shares the one fix. */\n readonly package?: string;\n /** The export subpath the import named, when the package's map gives it no side. */\n readonly entry?: string;\n};"
3242
3256
  },
3243
3257
  {
3244
3258
  "name": "ClassifiedSchema",
@@ -3414,7 +3428,7 @@
3414
3428
  "name": "CodingAgentRpcServerOptions",
3415
3429
  "kind": "interface",
3416
3430
  "package": "@nifrajs/coding-agent",
3417
- "signature": "export interface CodingAgentRpcServerOptions {\n readonly backend: AgentBackend;\n readonly cwd: string;\n readonly hostname?: string;\n /** Remote binding is opt-in; the default only permits loopback hosts. */\n readonly allowRemote?: boolean;\n readonly port?: number;\n /** A random token is generated when omitted. Use an explicit token only for managed local launchers. */\n readonly authToken?: string;\n /** Include bounded exception stacks in RPC failures only for trusted loopback debugging. */\n readonly exposeErrorStacks?: boolean;\n readonly maxBodyBytes?: number;\n /** Maximum UTF-8 bytes in one non-streaming JSON response. Defaults to 4 MiB. */\n readonly maxResponseBytes?: number;\n readonly sessionStore?: SessionStore;\n readonly contextWindow?: ContextWindowOptions;\n readonly extensions?: ExtensionHost;\n readonly ui?: UiExtensionHost;\n readonly verifyAfterTurn?: readonly (\"check\" | \"assure\" | \"test\")[];\n readonly maxRepairAttempts?: number;\n readonly verification?: CodingAgentHostOptions[\"verification\"];\n readonly extensionEvents?: CodingAgentHostOptions[\"extensionEvents\"];\n /**\n * Keep a `turn.send` running when its client disconnects, and let a client that comes back read\n * what it missed with `turn.attach` (an `afterSeq` cursor, or `Last-Event-ID`). The newest\n * `replayEvents` frames, up to `replayBytes`, are held (defaults 1024 and 8 MiB); a turn no client\n * has followed for `detachedTimeoutMs` (default 2 minutes) is cancelled. A client that stops reading\n * is dropped once it falls `replayBytes` behind what is held, and can attach again from its cursor.\n */\n readonly resumableTurns?: boolean | {\n readonly replayEvents?: number;\n readonly replayBytes?: number;\n readonly detachedTimeoutMs?: number;\n };\n}"
3431
+ "signature": "export interface CodingAgentRpcServerOptions {\n readonly backend: AgentBackend;\n readonly cwd: string;\n readonly hostname?: string;\n /** Remote binding is opt-in; the default only permits loopback hosts. */\n readonly allowRemote?: boolean;\n readonly port?: number;\n /** A random token is generated when omitted. Use an explicit token only for managed local launchers. */\n readonly authToken?: string;\n /** Include bounded exception stacks in RPC failures only for trusted loopback debugging. */\n readonly exposeErrorStacks?: boolean;\n readonly maxBodyBytes?: number;\n /** Maximum UTF-8 bytes in one non-streaming JSON response. Defaults to 4 MiB. */\n readonly maxResponseBytes?: number;\n readonly sessionStore?: SessionStore;\n readonly contextWindow?: ContextWindowOptions;\n readonly extensions?: ExtensionHost;\n readonly ui?: UiExtensionHost;\n readonly verifyAfterTurn?: readonly (\"check\" | \"assure\" | \"test\")[];\n readonly maxRepairAttempts?: number;\n readonly verification?: CodingAgentHostOptions[\"verification\"];\n readonly extensionEvents?: CodingAgentHostOptions[\"extensionEvents\"];\n /**\n * The host's approval broker: how long an approval or a tool's question waits for its answer\n * (`timeoutMs`, default 5 minutes, or `\"never\"`), how many may wait (`maxPending`, default 32),\n * and its `onRequired`/`onResolved` hooks.\n */\n readonly approvals?: CodingAgentHostOptions[\"approvals\"];\n /**\n * Keep a `turn.send` running when its client disconnects, and let a client that comes back read\n * what it missed with `turn.attach` (an `afterSeq` cursor, or `Last-Event-ID`). The newest\n * `replayEvents` frames, up to `replayBytes`, are held (defaults 1024 and 8 MiB); a turn no client\n * has followed for `detachedTimeoutMs` (default 2 minutes) is cancelled. A client that stops reading\n * is dropped once it falls `replayBytes` behind what is held, and can attach again from its cursor.\n */\n readonly resumableTurns?: boolean | {\n readonly replayEvents?: number;\n readonly replayBytes?: number;\n readonly detachedTimeoutMs?: number;\n };\n}"
3418
3432
  },
3419
3433
  {
3420
3434
  "name": "Collection",
@@ -3989,7 +4003,7 @@
3989
4003
  "name": "CreateMcpServerOptions",
3990
4004
  "kind": "interface",
3991
4005
  "package": "@nifrajs/mcp",
3992
- "signature": "export interface CreateMcpServerOptions {\n readonly name: string;\n readonly version: string;\n readonly tools?: readonly McpTool[];\n /** MCP Apps widgets - their resources are registered and the UI capability is advertised. */\n readonly widgets?: readonly McpWidget[];\n /** Extra (non-widget) resources to expose. */\n readonly resources?: readonly McpResource[];\n readonly prompts?: readonly McpPrompt[];\n /** GET health-page text. */\n readonly health?: string;\n /** Max JSON-RPC body size in bytes (default 1 MB). */\n readonly maxBodyBytes?: number;\n /** Max serialized JSON-RPC response or SSE frame size (default 1 MB). */\n readonly maxResponseBytes?: number;\n /** Max bytes an SSE stream queues for a client that is not reading (default 4 MiB). */\n readonly maxPendingBytes?: number;\n /** Natural-language guidance for LLMs, surfaced in the modern `server/discover` result (2026-07-28). */\n readonly instructions?: string;\n /** Explicitly allow browser clients from any origin. Omit for the secure same-origin default. */\n readonly allowAnyOrigin?: boolean;\n /** Origin allowlist for the DNS-rebinding guard. Set it to permit exact cross-origin clients. */\n readonly allowedOrigins?: readonly string[];\n /** Host allowlist; set it for a server on localhost or a private network. See {@link McpHttpOptions}. */\n readonly allowedHosts?: readonly string[];\n /** Shared state for one authenticated MCP session; prefer `resolveState` for multi-session hosts. */\n readonly state?: McpProtocolState;\n /** Resolve a session-scoped request registry after per-message authorization. */\n readonly resolveState?: McpHttpOptions[\"resolveState\"];\n /**\n * Per-message authorization, applied after the message parses and before any tool runs. Return\n * `false` to answer 403 with a JSON-RPC `unauthorized` error (`MCP_ERROR.UNAUTHORIZED`) and no result.\n *\n * This is the seam for \"this caller may list tools but may not call the write ones\" - the HTTP\n * layer above only sees one opaque POST, so a route guard cannot make that distinction.\n * `fetch(request, { authorizeMessage })` overrides it per request when the decision depends on\n * something the surrounding handler resolved (a session, a tenant).\n */\n readonly authorizeMessage?: (message: JsonRpcRequest, request: Request) => boolean | Promise<boolean>;\n}"
4006
+ "signature": "export interface CreateMcpServerOptions {\n readonly name: string;\n readonly version: string;\n readonly tools?: readonly McpTool[];\n /** MCP Apps widgets - their resources are registered and the UI capability is advertised. */\n readonly widgets?: readonly McpWidget[];\n /** Extra (non-widget) resources to expose. */\n readonly resources?: readonly McpResource[];\n readonly prompts?: readonly McpPrompt[];\n /** GET health-page text. */\n readonly health?: string;\n /** Max JSON-RPC body size in bytes (default 1 MB). */\n readonly maxBodyBytes?: number;\n /** Max serialized JSON-RPC response or SSE frame size (default 1 MB). */\n readonly maxResponseBytes?: number;\n /** Max bytes an SSE stream queues for a client that is not reading (default 4 MiB). */\n readonly maxPendingBytes?: number;\n /** Natural-language guidance for LLMs, surfaced in the modern `server/discover` result (2026-07-28). */\n readonly instructions?: string;\n /** Explicitly allow browser clients from any origin. Omit for the secure same-origin default. */\n readonly allowAnyOrigin?: boolean;\n /** Origin allowlist for the DNS-rebinding guard. Set it to permit exact cross-origin clients. */\n readonly allowedOrigins?: readonly string[];\n /** Host allowlist; set it for a server on localhost or a private network. See {@link McpHttpOptions}. */\n readonly allowedHosts?: readonly string[];\n /** Shared state for one authenticated MCP session; prefer `resolveState` for multi-session hosts. */\n readonly state?: McpProtocolState;\n /** Resolve a session-scoped request registry after per-message authorization. */\n readonly resolveState?: McpHttpOptions[\"resolveState\"];\n /**\n * Per-message authorization, applied after the message parses and before any tool runs. Return\n * `false` to answer 403 with a JSON-RPC `unauthorized` error (`MCP_ERROR.UNAUTHORIZED`) and no result.\n *\n * This is the seam for \"this caller may list tools but may not call the write ones\" - the HTTP\n * layer above only sees one opaque POST, so a route guard cannot make that distinction.\n * `fetch(request, { authorizeMessage })` overrides it per request when the decision depends on\n * something the surrounding handler resolved (a session, a tenant). With it set, a GET for the\n * server-message stream is answered `405`, since that stream has no message to authorize.\n */\n readonly authorizeMessage?: (message: JsonRpcRequest, request: Request) => boolean | Promise<boolean>;\n}"
3993
4007
  },
3994
4008
  {
3995
4009
  "name": "CreateNonceResolverOptions",
@@ -4044,7 +4058,7 @@
4044
4058
  "name": "CreateWebAppOptions",
4045
4059
  "kind": "interface",
4046
4060
  "package": "@nifrajs/web",
4047
- "signature": "export interface CreateWebAppOptions<Env = unknown> {\n readonly serverComponents?: import(\"../server-components/types.js\").ServerComponentRuntime;\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 * Resolve a fresh CSP nonce for each document request. The value is applied to every\n * framework-owned executable script; return `undefined` to keep the default nonce-free output.\n * Nonce-bearing documents are marked `private, no-store` so the request-specific value is not\n * replayed by browser, CDN, or ISR caches. The resolver does not declare a CSP header because the\n * policy's allowed sources are app-specific.\n */\n readonly nonce?: NonceResolver<Env>;\n /**\n * A hash-based Content-Security-Policy from `createCspPolicy`, instead of `nonce`. A document then\n * carries a nonce only when it needs one (it `defer()`s a value, or `meta` names the nonce in\n * `unsafeInlineScript`); every other page is nonce-free, gets the same CSP header on every request,\n * and stays cacheable by `withISR` or a CDN. `meta` still receives a nonce to name.\n */\n readonly csp?: CspPolicy;\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 would\n * bind them to no page, and outside production it throws (`HOOK_AFTER_PAGES`). `requestId()` is\n * exactly that case: it is a `derive`, so applied late it would leave every page without\n * `c.requestId`. A `group()` is its own scope and stays allowed. 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`; given an {@link apiPrefix}, `createWebApp` also serves\n * that backend over HTTP there: a request whose pathname starts with the prefix is dispatched before\n * page routing with the same `env`/`waitUntil` platform context, and the backend's `Response` is\n * returned untouched. The mount runs in `nifra dev` too. Without `apiPrefix` the backend is\n * loader-only.\n *\n * **Request-scoped loader calls.** While a page renders, its loaders, actions and boundaries get a\n * `ctx.api` bound to that request's platform identity: a backend handler reached through it sees the\n * visitor's `c.clientIp` (derived under this app's `server.clientIp` trust declaration), `c.env` and\n * `c.waitUntil`, so a per-caller rate limit or audit field keys on the real visitor. `c.clientIp` is\n * the supported way to read the caller - identity travels in the platform, so rebuilding a `Request`\n * does not lose it. Headers do NOT travel: the page request's `cookie` and `authorization` are never\n * copied, so a loader call is anonymous unless the loader passes headers on the call itself. */\n readonly api?: unknown;\n /** HTTP path prefix the {@link api} backend is mounted at, such as `\"/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. Unset or `\"\"`, nothing is\n * mounted: the app serves pages only and `api` stays a loader-only `ctx.api`. Mounting is also a\n * no-op when `api` does not expose the symbol mount.\n *\n * A page file under the prefix (`routes/api/report.tsx`) could never render - the backend answers\n * first and its 404 is final - so `createWebApp` throws, naming the file. The same holds for every\n * other pre-route 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. `opaque` states why a mount whose routes nifra cannot\n * read (better-auth's handler) is outside assurance; it is then listed as a known gap, with any\n * routes it declares reported as declared.\n */\n readonly mounts?: ReadonlyArray<{\n readonly path: string;\n readonly app: MountableApp<Env>;\n readonly stripPrefix?: boolean;\n readonly priority?: number;\n readonly fallbackOn?: 404;\n readonly opaque?: MountOptions<Env>[\"opaque\"];\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 /**\n * Activation policy for framework-owned stylesheet links (default `\"blocking\"`). `\"deferred\"`\n * emits `media=\"print\"` links; the generated client waits for them and switches them to `all` before\n * mounting. Pair with an aggregate Vite stylesheet (`cssCodeSplit: false`) to prevent lazy-prefetch\n * CSS insertion. Non-hydrated pages always keep their stylesheet links blocking.\n */\n readonly cssLoading?: CssLoadingMode;\n /** SSG: the prerendered-path set (e.g. `enumerateStaticRoutes(routes).paths` or the build's\n * `prerendered.json`). Handed over 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. A set over\n * 4 KB of JSON is served once from `/__nifra/prerendered.json?v=<version>`, cacheable for good, and\n * pages hand over only that URL; `prerenderRoutes` writes the file into a static output. */\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 /** Serve `/llms.txt` and `/llms-full.txt` (default `true`): the page routes, and the backend routes\n * when the backend is mounted over HTTP at {@link apiPrefix}. `false` registers neither path. */\n readonly llmsTxt?: 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. A failure a boundary answers is also written to the\n * server's `logger` (under its `errorLogDetail`) whether or not this is set, exactly as an unhandled\n * error is. 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}"
4061
+ "signature": "export interface CreateWebAppOptions<Env = unknown> {\n readonly serverComponents?: import(\"../server-components/types.js\").ServerComponentRuntime;\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 * Resolve a fresh CSP nonce for each document request. The value is applied to every\n * framework-owned executable script; return `undefined` to keep the default nonce-free output.\n * Nonce-bearing documents are marked `private, no-store` so the request-specific value is not\n * replayed by browser, CDN, or ISR caches. The resolver does not declare a CSP header because the\n * policy's allowed sources are app-specific.\n */\n readonly nonce?: NonceResolver<Env>;\n /**\n * A hash-based Content-Security-Policy from `createCspPolicy`, instead of `nonce`. A document then\n * carries a nonce only when it needs one (it `defer()`s a value, or `meta` names the nonce in\n * `unsafeInlineScript`); every other page is nonce-free, gets the same CSP header on every request,\n * and stays cacheable by `withISR` or a CDN. `meta` still receives a nonce to name.\n */\n readonly csp?: CspPolicy;\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 would\n * bind them to no page, and outside production it throws (`HOOK_AFTER_PAGES`). `requestId()` is\n * exactly that case: it is a `derive`, so applied late it would leave every page without\n * `c.requestId`. A `group()` is its own scope and stays allowed. 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`; given an {@link apiPrefix}, `createWebApp` also serves\n * that backend over HTTP there: a request whose pathname starts with the prefix is dispatched before\n * page routing with the same `env`/`waitUntil` platform context, and the backend's `Response` is\n * returned untouched. The mount runs in `nifra dev` too. Without `apiPrefix` the backend is\n * loader-only.\n *\n * **Request-scoped loader calls.** While a page renders, its loaders, actions and boundaries get a\n * `ctx.api` bound to that request's platform identity: a backend handler reached through it sees the\n * visitor's `c.clientIp` (derived under this app's `server.clientIp` trust declaration), `c.env` and\n * `c.waitUntil`, so a per-caller rate limit or audit field keys on the real visitor. `c.clientIp` is\n * the supported way to read the caller - identity travels in the platform, so rebuilding a `Request`\n * does not lose it. Headers do NOT travel: the page request's `cookie` and `authorization` are never\n * copied, so a loader call is anonymous unless the loader passes headers on the call itself. */\n readonly api?: unknown;\n /** HTTP path prefix the {@link api} backend is mounted at, such as `\"/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. Unset or `\"\"`, nothing is\n * mounted: the app serves pages only and `api` stays a loader-only `ctx.api`. Mounting is also a\n * no-op when `api` does not expose the symbol mount.\n *\n * A page file under the prefix (`routes/api/report.tsx`) could never render - the backend answers\n * first and its 404 is final - so `createWebApp` throws, naming the file. The same holds for every\n * other pre-route 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. `opaque` states why a mount whose routes nifra cannot\n * read (better-auth's handler) is outside assurance; it is then listed as a known gap, with any\n * routes it declares reported as declared.\n */\n readonly mounts?: ReadonlyArray<{\n readonly path: string;\n readonly app: MountableApp<Env>;\n readonly stripPrefix?: boolean;\n readonly priority?: number;\n readonly fallbackOn?: 404;\n readonly opaque?: MountOptions<Env>[\"opaque\"];\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 /**\n * Activation policy for framework-owned stylesheet links (default `\"blocking\"`). `\"deferred\"`\n * emits `media=\"print\"` links; the generated client waits for them and switches them to `all` before\n * mounting. Pair with an aggregate Vite stylesheet (`cssCodeSplit: false`) to prevent lazy-prefetch\n * CSS insertion. Non-hydrated pages always keep their stylesheet links blocking.\n */\n readonly cssLoading?: CssLoadingMode;\n /** SSG: the prerendered-path set (e.g. `enumerateStaticRoutes(routes).paths` or the build's\n * `prerendered.json`). Handed over 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. A set over\n * 4 KB of JSON is served once from `/__nifra/prerendered.json?v=<version>`, cacheable for good, and\n * pages hand over only that URL; `prerenderRoutes` writes the file into a static output. */\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 /** Serve `/llms.txt` and `/llms-full.txt`: the page routes, and the backend routes when the backend\n * is mounted over HTTP at {@link apiPrefix}, with their request and response schemas in the full\n * text. **Off by default**: both are public and unauthenticated, and they list every route, admin\n * and internal ones included. Turn it on for an app whose whole surface you would publish. */\n readonly llmsTxt?: 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. A failure a boundary answers is also written to the\n * server's `logger` (under its `errorLogDetail`) whether or not this is set, exactly as an unhandled\n * error is. 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}"
4048
4062
  },
4049
4063
  {
4050
4064
  "name": "CronError",
@@ -4058,7 +4072,7 @@
4058
4072
  "kind": "interface",
4059
4073
  "package": "@nifrajs/cron",
4060
4074
  "signature": "export interface CronFields {\n readonly minute: ReadonlySet<number>;\n readonly hour: ReadonlySet<number>;\n readonly dom: ReadonlySet<number>;\n readonly month: ReadonlySet<number>;\n readonly dow: ReadonlySet<number>;\n readonly domRestricted: boolean;\n readonly dowRestricted: boolean;\n}",
4061
- "doc": "/** A parsed expression: one allowed-values Set per field, + whether dom/dow were restricted (for\n * the standard OR rule). */"
4075
+ "doc": "/** A parsed expression: one allowed-values Set per field, + whether dom/dow were restricted (for\n * the standard OR rule). A field led by a star, a star-step included, is not restricted. */"
4062
4076
  },
4063
4077
  {
4064
4078
  "name": "CronHandler",
@@ -5120,6 +5134,13 @@
5120
5134
  "package": "@nifrajs/coding-agent",
5121
5135
  "signature": "export interface DispatchWriteResult {\n readonly ok: boolean;\n readonly code: DispatchResultCode;\n}"
5122
5136
  },
5137
+ {
5138
+ "name": "DocumentParts",
5139
+ "kind": "interface",
5140
+ "package": "@nifrajs/web",
5141
+ "signature": "export interface DocumentParts {\n /** Placed at the end of `<head>`. Svelte's `<svelte:head>` lands here. */\n head: string;\n /** Placed first in `<body>`, before the app root. Vue's `<Teleport to=\"body\">` lands here. */\n body: string;\n}",
5142
+ "doc": "/**\n * Markup a render produced for outside the app root, which an adapter that sets\n * {@link RenderAdapter.documentParts} appends to. Each part must be complete before the render\n * settles: `renderToString` resolving, or `renderToStream` returning its stream.\n */"
5143
+ },
5123
5144
  {
5124
5145
  "name": "DraftCookieControls",
5125
5146
  "kind": "interface",
@@ -5323,7 +5344,7 @@
5323
5344
  "name": "EdgeOptions",
5324
5345
  "kind": "interface",
5325
5346
  "package": "@nifrajs/edge",
5326
- "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 /** Answers a request no route matched, in place of the default `404` body. Build it with\n * {@link notFound}: `server({ notFound: notFound(handler) })`. */\n readonly notFound?: EdgeNotFound;\n}",
5347
+ "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 /** Other sites whose HTML forms may post to a body-schema route. A form body whose `Origin` is\n * another site's, and not listed, is refused with `403`. */\n readonly formOrigins?: FormOrigins;\n /** Answers a request no route matched, in place of the default `404` body. Build it with\n * {@link notFound}: `server({ notFound: notFound(handler) })`. */\n readonly notFound?: EdgeNotFound;\n}",
5327
5348
  "doc": "/** Construction-time options. The defaults mirror `@nifrajs/core`'s `ServerOptions`. */"
5328
5349
  },
5329
5350
  {
@@ -6154,7 +6175,7 @@
6154
6175
  "name": "FixRecipe",
6155
6176
  "kind": "interface",
6156
6177
  "package": "@nifrajs/cli",
6157
- "signature": "export interface FixRecipe {\n readonly id: string;\n readonly description: string;\n apply(root: string, diagnostic: Diagnostic): Promise<readonly string[]>;\n readonly verify: string;\n}"
6178
+ "signature": "export interface FixRecipe {\n readonly id: string;\n readonly description: string;\n /** Run only by `nifra fix --code <code>`: the change it makes is a decision a person reviews first. */\n readonly onlyWhenNamed?: true;\n apply(root: string, diagnostic: Diagnostic): Promise<readonly string[]>;\n readonly verify: string;\n}"
6158
6179
  },
6159
6180
  {
6160
6181
  "name": "FontAsset",
@@ -6219,6 +6240,13 @@
6219
6240
  "signature": "export interface FormOptions extends MultipartLimits {\n /** Accept fields the form does not declare. Defaults to `false`: an undeclared field fails validation. */\n readonly additionalProperties?: boolean;\n readonly title?: string;\n readonly description?: string;\n}",
6220
6241
  "doc": "/**\n * The multipart limits (`maxFields`, `maxFiles`, `maxFieldBytes`, `maxFileBytes`) bound what the body\n * may carry before any of it is validated; a request over one is answered `413`.\n */"
6221
6242
  },
6243
+ {
6244
+ "name": "FormOrigins",
6245
+ "kind": "type",
6246
+ "package": "@nifrajs/core",
6247
+ "signature": "export type FormOrigins = ReadonlyArray<string> | ((origin: string) => boolean);",
6248
+ "doc": "/**\n * Origins besides the request's own whose HTML forms may post a body: exact origins, or a function\n * that receives the request's `Origin`.\n */"
6249
+ },
6222
6250
  {
6223
6251
  "name": "Formatter",
6224
6252
  "kind": "interface",
@@ -6267,7 +6295,7 @@
6267
6295
  "name": "GateResult",
6268
6296
  "kind": "interface",
6269
6297
  "package": "@nifrajs/cli",
6270
- "signature": "export interface GateResult {\n readonly gate: \"check\" | \"doctor\" | \"render\" | \"hydration\" | \"contracts\" | \"size\" | \"tests\" | string;\n readonly status: \"pass\" | \"fail\" | \"skip\";\n readonly skipReason?: string;\n readonly durationMs: number;\n readonly diagnostics: readonly Diagnostic[];\n readonly replay?: string;\n}"
6298
+ "signature": "export interface GateResult {\n readonly gate: \"check\" | \"assurance\" | \"doctor\" | \"render\" | \"hydration\" | \"contracts\" | \"size\" | \"tests\" | string;\n readonly status: \"pass\" | \"fail\" | \"skip\";\n readonly skipReason?: string;\n readonly durationMs: number;\n readonly diagnostics: readonly Diagnostic[];\n readonly replay?: string;\n}"
6271
6299
  },
6272
6300
  {
6273
6301
  "name": "Gauge",
@@ -6332,7 +6360,7 @@
6332
6360
  "name": "GraphqlHttpOptions",
6333
6361
  "kind": "interface",
6334
6362
  "package": "@nifrajs/graphql",
6335
- "signature": "export interface GraphqlHttpOptions<Context = unknown, Env = unknown> {\n /** The executable schema (types + resolvers), e.g. from `graphql`'s `buildSchema` or a schema builder. */\n readonly schema: GraphQLSchema;\n /** Build the resolver `contextValue` from the request (and nifra context when mounted). */\n readonly context?: GraphqlContextBuilder<Context, Env>;\n /** The nifra route context, when the caller has one (supplied by `mountGraphql`). */\n readonly nifra?: NifraContextLike<Env>;\n /** Maximum request body size in bytes. Default 1 MB. Rejected bodies answer 413. */\n readonly maxBodyBytes?: number;\n /** Maximum UTF-8 query size. Default 64 KiB, applied to POST and GET. */\n readonly maxQueryBytes?: number;\n /** Maximum UTF-8 serialized variables size. Default 256 KiB. */\n readonly maxVariablesBytes?: number;\n /** Maximum expanded field depth. Default 20. */\n readonly maxDepth?: number;\n /** Maximum aliases in one document. Default 100. */\n readonly maxAliases?: number;\n /** Maximum simple field complexity in one document. Default 1,000. */\n readonly maxComplexity?: number;\n /** Maximum operation definitions in one document. Default 10. */\n readonly maxOperations?: number;\n /**\n * Maximum pairs of fields sharing a response name in one selection set, counted through fragments.\n * Validation compares every such pair, so this bounds its cost. Default 2,000.\n */\n readonly maxFieldOverlaps?: number;\n /**\n * Maximum asynchronous resolver execution time. Default 10 seconds. The execution's abort signal,\n * which a resolver reads through `info.getAbortSignal()`, is aborted at this deadline and when the\n * request itself is aborted.\n */\n readonly executionTimeoutMs?: number;\n /** Prototype-pollution policy for the parsed JSON body. Default `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n /** Optional root value passed to the executor. */\n readonly rootValue?: unknown;\n /**\n * Origin allowlist for the CORS `access-control-allow-origin` header. Omit to reflect any origin\n * (`*`) - correct for a public API; set it to lock the browser callers down.\n */\n readonly allowedOrigins?: readonly string[];\n /**\n * Per-request authorization, run after the origin check and before the body is read or parsed; a\n * CORS preflight (`OPTIONS`) skips it. Return `false` to answer `401` with a GraphQL error envelope.\n */\n readonly authorize?: (request: Request) => boolean | Promise<boolean>;\n /** Emit the legacy always-200 `application/json` response shape instead of `application/graphql-response+json`. */\n readonly legacyJsonResponse?: boolean;\n /** Format request/execution errors. The default masks resolver messages and preserves request errors. */\n readonly formatError?: (error: GraphQLError, phase: \"request\" | \"execution\") => unknown;\n}"
6363
+ "signature": "export interface GraphqlHttpOptions<Context = unknown, Env = unknown> {\n /** The executable schema (types + resolvers), e.g. from `graphql`'s `buildSchema` or a schema builder. */\n readonly schema: GraphQLSchema;\n /** Build the resolver `contextValue` from the request (and nifra context when mounted). */\n readonly context?: GraphqlContextBuilder<Context, Env>;\n /** The nifra route context, when the caller has one (supplied by `mountGraphql`). */\n readonly nifra?: NifraContextLike<Env>;\n /** Maximum request body size in bytes. Default 1 MB. Rejected bodies answer 413. */\n readonly maxBodyBytes?: number;\n /** Maximum UTF-8 query size. Default 64 KiB, applied to POST and GET. */\n readonly maxQueryBytes?: number;\n /** Maximum UTF-8 serialized variables size. Default 256 KiB. */\n readonly maxVariablesBytes?: number;\n /** Maximum expanded field depth. Default 20. */\n readonly maxDepth?: number;\n /** Maximum aliases in one document. Default 100. */\n readonly maxAliases?: number;\n /** Maximum simple field complexity in one document. Default 1,000. */\n readonly maxComplexity?: number;\n /** Maximum operation definitions in one document. Default 10. */\n readonly maxOperations?: number;\n /**\n * Maximum pairs of fields sharing a response name in one selection set, counted through fragments.\n * Validation compares every such pair, so this bounds its cost. Default 2,000.\n */\n readonly maxFieldOverlaps?: number;\n /**\n * Maximum asynchronous resolver execution time. Default 10 seconds. The execution's abort signal,\n * which a resolver reads through `info.getAbortSignal()`, is aborted at this deadline and when the\n * request itself is aborted.\n */\n readonly executionTimeoutMs?: number;\n /** Prototype-pollution policy for the parsed JSON body. Default `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n /**\n * Answer introspection queries (`__schema`, `__type`). Default `true`. Set `false` to refuse them\n * as a validation error (400); `__typename` still resolves. Shared with `subscriptions`.\n */\n readonly introspection?: boolean;\n /** Optional root value passed to the executor. */\n readonly rootValue?: unknown;\n /**\n * Origin allowlist for the CORS `access-control-allow-origin` header. Omit to reflect any origin\n * (`*`) - correct for a public API; set it to lock the browser callers down.\n */\n readonly allowedOrigins?: readonly string[];\n /**\n * Per-request authorization, run after the origin check and before the body is read or parsed; a\n * CORS preflight (`OPTIONS`) skips it. Return `false` to answer `401` with a GraphQL error envelope.\n */\n readonly authorize?: (request: Request) => boolean | Promise<boolean>;\n /** Emit the legacy always-200 `application/json` response shape instead of `application/graphql-response+json`. */\n readonly legacyJsonResponse?: boolean;\n /** Format request/execution errors. The default masks resolver messages and preserves request errors. */\n readonly formatError?: (error: GraphQLError, phase: \"request\" | \"execution\") => unknown;\n}"
6336
6364
  },
6337
6365
  {
6338
6366
  "name": "GraphqlPubSub",
@@ -6357,7 +6385,7 @@
6357
6385
  "name": "GraphqlWsOptions",
6358
6386
  "kind": "interface",
6359
6387
  "package": "@nifrajs/graphql",
6360
- "signature": "export interface GraphqlWsOptions<Context extends Record<string, unknown> = Record<string, unknown>> {\n /** The executable schema. */\n readonly schema: GraphQLSchema;\n /** Build the resolver `contextValue` from the upgrade request. Shared with the HTTP transport. */\n readonly context?: GraphqlContextBuilder<Context>;\n /**\n * Admit a socket from its upgrade request, before {@link onConnect}; return `false` (or throw) to\n * reject the connection. `mountGraphql({ subscriptions: true })` passes its HTTP `authorize` here.\n */\n readonly authorize?: (request: Request) => boolean | Promise<boolean>;\n /**\n * Called once per connection with the client's `connection_init` payload; return `false` (or throw)\n * to reject the connection. The seam for authenticating a socket from an init token.\n */\n readonly onConnect?: (payload: ConnectionInitMessage[\"payload\"], request: Request) => boolean | Promise<boolean>;\n /** Additional raw `graphql-ws` server options merged last (advanced escape hatch). */\n readonly serverOptions?: Partial<ServerOptions>;\n /** Same query/complexity limits as the HTTP transport. */\n readonly maxQueryBytes?: number;\n readonly maxVariablesBytes?: number;\n readonly maxDepth?: number;\n readonly maxAliases?: number;\n readonly maxComplexity?: number;\n readonly maxOperations?: number;\n readonly maxFieldOverlaps?: number;\n /** Maximum concurrent subscription operation ids per connection. Default 20. */\n readonly maxSubscriptions?: number;\n /**\n * Maximum time for initial execute/subscribe setup. Default 10 seconds. Each operation's abort\n * signal, which a resolver reads through `info.getAbortSignal()`, is aborted at this deadline, when\n * the client completes the operation, and when the socket closes.\n */\n readonly executionTimeoutMs?: number;\n}"
6388
+ "signature": "export interface GraphqlWsOptions<Context extends Record<string, unknown> = Record<string, unknown>> {\n /** The executable schema. */\n readonly schema: GraphQLSchema;\n /** Build the resolver `contextValue` from the upgrade request. Shared with the HTTP transport. */\n readonly context?: GraphqlContextBuilder<Context>;\n /**\n * Admit a socket from its upgrade request, before {@link onConnect}; return `false` (or throw) to\n * reject the connection. `mountGraphql({ subscriptions: true })` passes its HTTP `authorize` here.\n */\n readonly authorize?: (request: Request) => boolean | Promise<boolean>;\n /**\n * Called once per connection with the client's `connection_init` payload; return `false` (or throw)\n * to reject the connection. The seam for authenticating a socket from an init token.\n */\n readonly onConnect?: (payload: ConnectionInitMessage[\"payload\"], request: Request) => boolean | Promise<boolean>;\n /** Additional raw `graphql-ws` server options merged last (advanced escape hatch). */\n readonly serverOptions?: Partial<ServerOptions>;\n /** Same query/complexity limits as the HTTP transport. */\n readonly maxQueryBytes?: number;\n readonly maxVariablesBytes?: number;\n readonly maxDepth?: number;\n readonly maxAliases?: number;\n readonly maxComplexity?: number;\n readonly maxOperations?: number;\n readonly maxFieldOverlaps?: number;\n /** Maximum concurrent subscription operation ids per connection. Default 20. */\n readonly maxSubscriptions?: number;\n /**\n * Answer introspection (`__schema`, `__type`). Default `true`. Set `false` to refuse such an\n * operation with an `error` frame; `__typename` still resolves.\n */\n readonly introspection?: boolean;\n /**\n * Maximum time for initial execute/subscribe setup. Default 10 seconds. Each operation's abort\n * signal, which a resolver reads through `info.getAbortSignal()`, is aborted at this deadline, when\n * the client completes the operation, and when the socket closes.\n */\n readonly executionTimeoutMs?: number;\n}"
6361
6389
  },
6362
6390
  {
6363
6391
  "name": "GuardOptions",
@@ -6797,7 +6825,7 @@
6797
6825
  "name": "IdempotencyRecord",
6798
6826
  "kind": "interface",
6799
6827
  "package": "@nifrajs/middleware",
6800
- "signature": "export interface IdempotencyRecord {\n readonly status: number;\n /** Response headers, **excluding `Set-Cookie`** (cookies are session-specific - see {@link idempotency}). */\n readonly headers: ReadonlyArray<readonly [string, string]>;\n /** Response body, base64-encoded. */\n readonly body: string;\n}",
6828
+ "signature": "export interface IdempotencyRecord {\n readonly status: number;\n /** Response headers, **excluding `Set-Cookie`** (cookies are session-specific - see {@link idempotency}). */\n readonly headers: ReadonlyArray<readonly [string, string]>;\n /** Response body, base64-encoded. */\n readonly body: string;\n /**\n * The response came from a route this middleware's `beforeHandle` covers, so a retry is replayed\n * from there - after the route's authentication, validation and earlier guards accept it again. A\n * record without it (a route declared before `.use(idempotency())`) is replayed in `onRequest`.\n */\n readonly recheck?: boolean;\n}",
6801
6829
  "doc": "/** A captured response, replayed verbatim on a retry. Body is base64 (binary-safe + JSON-serializable). */"
6802
6830
  },
6803
6831
  {
@@ -7387,7 +7415,7 @@
7387
7415
  "name": "JobDefinition",
7388
7416
  "kind": "interface",
7389
7417
  "package": "@nifrajs/jobs",
7390
- "signature": "export interface JobDefinition<Payload> {\n readonly handler: JobHandler<Payload>;\n /** Optional Standard Schema - validates the payload at `enqueue` (the trust boundary); a failure throws. */\n readonly input?: StandardSchemaV1<Payload>;\n /** `number` is shorthand for `{ attempts }`. */\n readonly retries?: number | RetryPolicy;\n /**\n * Fail an attempt that has not settled after this many ms: it is retried or dead-lettered like a\n * throw, its worker slot frees, and `ctx.signal` aborts. A handler that ignores the signal keeps\n * running unobserved. Keep it below the worker's `leaseMs`, after which the job can be leased again.\n */\n readonly timeoutMs?: number;\n}",
7418
+ "signature": "export interface JobDefinition<Payload> {\n readonly handler: JobHandler<Payload>;\n /** Optional Standard Schema - validates the payload at `enqueue` (the trust boundary); a failure throws. */\n readonly input?: StandardSchemaV1<Payload>;\n /** `number` is shorthand for `{ attempts }`. */\n readonly retries?: number | RetryPolicy;\n /**\n * Fail an attempt that has not settled after this many ms: it is retried or dead-lettered like a\n * throw, its worker slot frees, and `ctx.signal` aborts. A handler that ignores the signal keeps\n * running unobserved. It must be below the worker's `leaseMs`: `start()` throws otherwise.\n */\n readonly timeoutMs?: number;\n}",
7391
7419
  "doc": "/** A job definition registered on a queue. */"
7392
7420
  },
7393
7421
  {
@@ -7436,7 +7464,7 @@
7436
7464
  "name": "JobStore",
7437
7465
  "kind": "interface",
7438
7466
  "package": "@nifrajs/jobs",
7439
- "signature": "export interface JobStore {\n /** Persist a new job; return its id. Hand `traceparent` back on {@link StoredJob} when present. */\n enqueue(job: {\n name: string;\n payload: unknown;\n runAt: number;\n maxAttempts: number;\n traceparent?: string;\n }): string | Promise<string>;\n /** Atomically claim up to `limit` jobs due at/before `now`, hiding them for `leaseMs`. */\n lease(now: number, limit: number, leaseMs: number): StoredJob[] | Promise<StoredJob[]>;\n /** A job finished successfully - remove it. */\n complete(id: string): void | Promise<void>;\n /** A job failed but has attempts left - bump its attempt count and reschedule for `runAt`. */\n retry(id: string, runAt: number): void | Promise<void>;\n /** A job exhausted its attempts - move it to the dead-letter set with the last error. */\n deadLetter(id: string, error: string): void | Promise<void>;\n /** Snapshot counts (observability + tests). */\n counts(): JobCounts | Promise<JobCounts>;\n}",
7467
+ "signature": "export interface JobStore {\n /** Persist a new job; return its id. Hand `traceparent` back on {@link StoredJob} when present. */\n enqueue(job: {\n name: string;\n payload: unknown;\n runAt: number;\n maxAttempts: number;\n traceparent?: string;\n }): string | Promise<string>;\n /** Atomically claim up to `limit` jobs due at/before `now`, hiding them for `leaseMs`. */\n lease(now: number, limit: number, leaseMs: number): StoredJob[] | Promise<StoredJob[]>;\n /** A job finished successfully - remove it. `lease` is the {@link StoredJob.lease} it ran under:\n * a store that issues tokens ignores a call whose token is no longer the job's current one. */\n complete(id: string, lease?: string): void | Promise<void>;\n /** A job failed but has attempts left - bump its attempt count and reschedule for `runAt`. */\n retry(id: string, runAt: number, lease?: string): void | Promise<void>;\n /** A job exhausted its attempts - move it to the dead-letter set with the last error. */\n deadLetter(id: string, error: string, lease?: string): void | Promise<void>;\n /**\n * Optional: keep a leased job hidden until `until`. The queue calls it about three times per\n * `leaseMs` while the handler runs, so a long job is not leased again mid-run. Without it a job\n * that outruns `leaseMs` can be delivered to another worker while the first still runs.\n */\n renew?(id: string, until: number, lease?: string): void | Promise<void>;\n /** Snapshot counts (observability + tests). */\n counts(): JobCounts | Promise<JobCounts>;\n}",
7440
7468
  "doc": "/**\n * Persistence + leasing for the queue. The default {@link MemoryJobStore} is single-process (dev / a\n * single long-running server); implement this over Redis/Postgres/etc. for durability or multiple\n * workers. All methods may be sync or async - the queue awaits them.\n */"
7441
7469
  },
7442
7470
  {
@@ -7561,7 +7589,7 @@
7561
7589
  "name": "JwksOptions",
7562
7590
  "kind": "interface",
7563
7591
  "package": "@nifrajs/middleware",
7564
- "signature": "export interface JwksOptions {\n readonly url: string | URL;\n readonly fetch?: typeof fetch;\n readonly cacheMs?: number;\n /**\n * Extra time to keep using the last successful key set past `cacheMs`. Inside it a request is\n * answered from that set at once while one refresh runs behind it, so a slow or failing identity\n * provider holds no request. Defaults to one cache window; set `0` to wait for every refresh and\n * fail closed on refresh errors.\n */\n readonly staleMs?: number;\n readonly timeoutMs?: number;\n readonly maxBytes?: number;\n /**\n * Least time (ms) between the refreshes a token with a `kid` the cached set lacks may start, so a\n * newly rotated key is picked up without made-up `kid`s turning every request into a fetch.\n * Default 30 s.\n */\n readonly cooldownMs?: number;\n}"
7592
+ "signature": "export interface JwksOptions {\n readonly url: string | URL;\n readonly fetch?: typeof fetch;\n readonly cacheMs?: number;\n /**\n * Extra time to keep using the last successful key set past `cacheMs`. Inside it a request is\n * answered from that set at once while one refresh runs behind it, so a slow or failing identity\n * provider holds no request. Defaults to one cache window; set `0` to wait for every refresh and\n * fail closed on refresh errors.\n */\n readonly staleMs?: number;\n readonly timeoutMs?: number;\n readonly maxBytes?: number;\n /**\n * Least time (ms) between the refreshes a token with a `kid` the cached set lacks may start, so a\n * newly rotated key is picked up without made-up `kid`s turning every request into a fetch.\n * Default 30 s.\n */\n readonly cooldownMs?: number;\n /**\n * Least time (ms) between fetches after one that failed or returned no keys. Inside it a request\n * that needs the set gets that outcome again at once (the same error, or no key) instead of\n * waiting up to `timeoutMs` on a fetch of its own, so an identity provider outage does not hold\n * every request. Default 5 s; `0` fetches again for every such request.\n */\n readonly failureCooldownMs?: number;\n}"
7565
7593
  },
7566
7594
  {
7567
7595
  "name": "JwtAlgorithm",
@@ -7790,7 +7818,7 @@
7790
7818
  "name": "LeakGuardPlugin",
7791
7819
  "kind": "interface",
7792
7820
  "package": "@nifrajs/web",
7793
- "signature": "export interface LeakGuardPlugin {\n readonly name: string;\n /**\n * The finding that failed the build, or `undefined` when the bundle was clean.\n *\n * Recorded as well as thrown because the throw does not reliably survive. A plugin error is handed to\n * the bundler, which builds its own error to report it, and on some Bun + rolldown combinations that\n * construction itself fails (`Error.captureStackTrace` rejecting a non-Error) - so what surfaces is an\n * internal complaint naming neither the leaked module nor its import chain. A caller that owns the\n * build can read this afterwards and raise the real message from its own code, where nothing can\n * rewrite it. A leak is the one failure that must stay legible: the whole point is naming what\n * reached the browser.\n */\n leak?: string;\n generateBundle(this: RollupPluginContext, options: unknown, bundle: RollupBundleLike): void;\n}",
7821
+ "signature": "export interface LeakGuardPlugin {\n readonly name: string;\n /**\n * The finding that failed the build, or `undefined` when the bundle was clean.\n *\n * Recorded as well as thrown because the throw does not reliably survive. A plugin error is handed to\n * the bundler, which builds its own error to report it, and on some Bun + rolldown combinations that\n * construction itself fails (`Error.captureStackTrace` rejecting a non-Error) - so what surfaces is an\n * internal complaint naming neither the leaked module nor its import chain. A caller that owns the\n * build can read this afterwards and raise the real message from its own code, where nothing can\n * rewrite it. A leak is the one failure that must stay legible: the whole point is naming what\n * reached the browser.\n */\n leak?: string;\n buildStart(): void;\n /** Ordered first: the bundler's own resolver answers before a plugin listed after it is asked. */\n readonly resolveId: {\n readonly order: \"pre\";\n handler(this: ResolveContext, source: string, importer: string | undefined, options?: Readonly<Record<string, unknown>>): Promise<null>;\n };\n generateBundle(this: RollupPluginContext, options: unknown, bundle: RollupBundleLike): void;\n}",
7794
7822
  "doc": "/** The minimal Rollup plugin shape this returns - `generateBundle` bound to the plugin context. */"
7795
7823
  },
7796
7824
  {
@@ -8320,13 +8348,13 @@
8320
8348
  "name": "McpHttpOptions",
8321
8349
  "kind": "interface",
8322
8350
  "package": "@nifrajs/cli",
8323
- "signature": "export interface McpHttpOptions {\n /** Maximum JSON-RPC request body size in bytes. Default 1 MB. */\n readonly maxBodyBytes?: number;\n /** Maximum serialized JSON-RPC response or SSE frame size. Default 1 MB. */\n readonly maxResponseBytes?: number;\n /**\n * Maximum bytes an SSE stream queues for a client that is not reading. Past it the stream is\n * dropped and the tool call it carries is cancelled. Default 4 MiB.\n */\n readonly maxPendingBytes?: number | undefined;\n /** Resources / prompts / the MCP Apps UI extension served alongside the tools. */\n readonly features?: McpServerFeatures;\n /** Shown on the GET health page so each host can describe itself. */\n readonly health?: string;\n /** Explicitly expose a secret-free, unauthenticated server to browser clients from any origin. */\n readonly allowAnyOrigin?: boolean;\n /** Origin allowlist for the DNS-rebinding guard. When set, only exact origins are accepted. */\n readonly allowedOrigins?: readonly string[];\n /**\n * Host allowlist - the DNS-rebinding guard for a server on localhost or a private network. A rebound\n * page reaches the server under the attacker's hostname with a matching Origin, so the Origin check\n * alone cannot stop it. Entries are `host[:port]`; without a port they match any port. Every request,\n * with or without an Origin, whose Host is not listed gets 403. Example: `[\"localhost\", \"127.0.0.1\"]`.\n */\n readonly allowedHosts?: readonly string[];\n /**\n * Shared request registry for one authenticated MCP session. Pass the same state to the\n * request that starts a tool call and its `notifications/cancelled` request. Do not share one\n * state across unrelated callers unless the surrounding authorization boundary makes their\n * request-id namespace exclusive.\n */\n readonly state?: McpProtocolState;\n /**\n * Resolve a session-scoped request registry after authorization. This is the preferred seam for\n * multi-user HTTP hosts: bind the returned state to the authenticated caller/session and return\n * `undefined` for stateless requests. A resolver failure fails closed with a generic denial.\n */\n readonly resolveState?: (request: Request, message: JsonRpcRequest) => McpProtocolState | undefined | Promise<McpProtocolState | undefined>;\n /**\n * Optional authorization, run once per request against the parsed message - after the body has been\n * read under the size cap, so it never costs a second read of the stream. Returning `false` answers\n * `403` with a JSON-RPC error (`MCP_ERROR.UNAUTHORIZED`) and the handler never sees the message.\n */\n readonly authorizeMessage?: (message: JsonRpcRequest, request: Request) => boolean | Promise<boolean>;\n}"
8351
+ "signature": "export interface McpHttpOptions {\n /** Maximum JSON-RPC request body size in bytes. Default 1 MB. */\n readonly maxBodyBytes?: number;\n /** Maximum serialized JSON-RPC response or SSE frame size. Default 1 MB. */\n readonly maxResponseBytes?: number;\n /**\n * Maximum bytes an SSE stream queues for a client that is not reading. Past it the stream is\n * dropped and the tool call it carries is cancelled. Default 4 MiB.\n */\n readonly maxPendingBytes?: number | undefined;\n /** Resources / prompts / the MCP Apps UI extension served alongside the tools. */\n readonly features?: McpServerFeatures;\n /** Shown on the GET health page so each host can describe itself. */\n readonly health?: string;\n /** Explicitly expose a secret-free, unauthenticated server to browser clients from any origin. */\n readonly allowAnyOrigin?: boolean;\n /** Origin allowlist for the DNS-rebinding guard. When set, only exact origins are accepted. */\n readonly allowedOrigins?: readonly string[];\n /**\n * Host allowlist - the DNS-rebinding guard for a server on localhost or a private network. A rebound\n * page reaches the server under the attacker's hostname with a matching Origin, so the Origin check\n * alone cannot stop it. Entries are `host[:port]`; without a port they match any port. Every request,\n * with or without an Origin, whose Host is not listed gets 403. Example: `[\"localhost\", \"127.0.0.1\"]`.\n */\n readonly allowedHosts?: readonly string[];\n /**\n * Shared request registry for one authenticated MCP session. Pass the same state to the\n * request that starts a tool call and its `notifications/cancelled` request. Do not share one\n * state across unrelated callers unless the surrounding authorization boundary makes their\n * request-id namespace exclusive.\n */\n readonly state?: McpProtocolState;\n /**\n * Resolve a session-scoped request registry after authorization. This is the preferred seam for\n * multi-user HTTP hosts: bind the returned state to the authenticated caller/session and return\n * `undefined` for stateless requests. A resolver failure fails closed with a generic denial.\n */\n readonly resolveState?: (request: Request, message: JsonRpcRequest) => McpProtocolState | undefined | Promise<McpProtocolState | undefined>;\n /**\n * Optional authorization, run once per request against the parsed message - after the body has been\n * read under the size cap, so it never costs a second read of the stream. Returning `false` answers\n * `403` with a JSON-RPC error (`MCP_ERROR.UNAUTHORIZED`) and the handler never sees the message.\n * A GET for the server-message stream carries no message to authorize, so with this set it is\n * answered `405` (no stream offered) instead.\n */\n readonly authorizeMessage?: (message: JsonRpcRequest, request: Request) => boolean | Promise<boolean>;\n}"
8324
8352
  },
8325
8353
  {
8326
8354
  "name": "McpHttpOptions",
8327
8355
  "kind": "interface",
8328
8356
  "package": "@nifrajs/mcp",
8329
- "signature": "export interface McpHttpOptions {\n /** Maximum JSON-RPC request body size in bytes. Default 1 MB. */\n readonly maxBodyBytes?: number;\n /** Maximum serialized JSON-RPC response or SSE frame size. Default 1 MB. */\n readonly maxResponseBytes?: number;\n /**\n * Maximum bytes an SSE stream queues for a client that is not reading. Past it the stream is\n * dropped and the tool call it carries is cancelled. Default 4 MiB.\n */\n readonly maxPendingBytes?: number | undefined;\n /** Resources / prompts / the MCP Apps UI extension served alongside the tools. */\n readonly features?: McpServerFeatures;\n /** Shown on the GET health page so each host can describe itself. */\n readonly health?: string;\n /** Explicitly expose a secret-free, unauthenticated server to browser clients from any origin. */\n readonly allowAnyOrigin?: boolean;\n /** Origin allowlist for the DNS-rebinding guard. When set, only exact origins are accepted. */\n readonly allowedOrigins?: readonly string[];\n /**\n * Host allowlist - the DNS-rebinding guard for a server on localhost or a private network. A rebound\n * page reaches the server under the attacker's hostname with a matching Origin, so the Origin check\n * alone cannot stop it. Entries are `host[:port]`; without a port they match any port. Every request,\n * with or without an Origin, whose Host is not listed gets 403. Example: `[\"localhost\", \"127.0.0.1\"]`.\n */\n readonly allowedHosts?: readonly string[];\n /**\n * Shared request registry for one authenticated MCP session. Pass the same state to the\n * request that starts a tool call and its `notifications/cancelled` request. Do not share one\n * state across unrelated callers unless the surrounding authorization boundary makes their\n * request-id namespace exclusive.\n */\n readonly state?: McpProtocolState;\n /**\n * Resolve a session-scoped request registry after authorization. This is the preferred seam for\n * multi-user HTTP hosts: bind the returned state to the authenticated caller/session and return\n * `undefined` for stateless requests. A resolver failure fails closed with a generic denial.\n */\n readonly resolveState?: (request: Request, message: JsonRpcRequest) => McpProtocolState | undefined | Promise<McpProtocolState | undefined>;\n /**\n * Optional authorization, run once per request against the parsed message - after the body has been\n * read under the size cap, so it never costs a second read of the stream. Returning `false` answers\n * `403` with a JSON-RPC error (`MCP_ERROR.UNAUTHORIZED`) and the handler never sees the message.\n */\n readonly authorizeMessage?: (message: JsonRpcRequest, request: Request) => boolean | Promise<boolean>;\n}"
8357
+ "signature": "export interface McpHttpOptions {\n /** Maximum JSON-RPC request body size in bytes. Default 1 MB. */\n readonly maxBodyBytes?: number;\n /** Maximum serialized JSON-RPC response or SSE frame size. Default 1 MB. */\n readonly maxResponseBytes?: number;\n /**\n * Maximum bytes an SSE stream queues for a client that is not reading. Past it the stream is\n * dropped and the tool call it carries is cancelled. Default 4 MiB.\n */\n readonly maxPendingBytes?: number | undefined;\n /** Resources / prompts / the MCP Apps UI extension served alongside the tools. */\n readonly features?: McpServerFeatures;\n /** Shown on the GET health page so each host can describe itself. */\n readonly health?: string;\n /** Explicitly expose a secret-free, unauthenticated server to browser clients from any origin. */\n readonly allowAnyOrigin?: boolean;\n /** Origin allowlist for the DNS-rebinding guard. When set, only exact origins are accepted. */\n readonly allowedOrigins?: readonly string[];\n /**\n * Host allowlist - the DNS-rebinding guard for a server on localhost or a private network. A rebound\n * page reaches the server under the attacker's hostname with a matching Origin, so the Origin check\n * alone cannot stop it. Entries are `host[:port]`; without a port they match any port. Every request,\n * with or without an Origin, whose Host is not listed gets 403. Example: `[\"localhost\", \"127.0.0.1\"]`.\n */\n readonly allowedHosts?: readonly string[];\n /**\n * Shared request registry for one authenticated MCP session. Pass the same state to the\n * request that starts a tool call and its `notifications/cancelled` request. Do not share one\n * state across unrelated callers unless the surrounding authorization boundary makes their\n * request-id namespace exclusive.\n */\n readonly state?: McpProtocolState;\n /**\n * Resolve a session-scoped request registry after authorization. This is the preferred seam for\n * multi-user HTTP hosts: bind the returned state to the authenticated caller/session and return\n * `undefined` for stateless requests. A resolver failure fails closed with a generic denial.\n */\n readonly resolveState?: (request: Request, message: JsonRpcRequest) => McpProtocolState | undefined | Promise<McpProtocolState | undefined>;\n /**\n * Optional authorization, run once per request against the parsed message - after the body has been\n * read under the size cap, so it never costs a second read of the stream. Returning `false` answers\n * `403` with a JSON-RPC error (`MCP_ERROR.UNAUTHORIZED`) and the handler never sees the message.\n * A GET for the server-message stream carries no message to authorize, so with this set it is\n * answered `405` (no stream offered) instead.\n */\n readonly authorizeMessage?: (message: JsonRpcRequest, request: Request) => boolean | Promise<boolean>;\n}"
8330
8358
  },
8331
8359
  {
8332
8360
  "name": "McpPrompt",
@@ -8601,7 +8629,7 @@
8601
8629
  "name": "MemoryJobStore",
8602
8630
  "kind": "class",
8603
8631
  "package": "@nifrajs/jobs",
8604
- "signature": "export declare class MemoryJobStore implements JobStore {\n private readonly jobs;\n private readonly dead;\n private seq;\n private readonly idFor;\n constructor(options?: {\n idFor?: () => string;\n });\n enqueue(job: {\n name: string;\n payload: unknown;\n runAt: number;\n maxAttempts: number;\n traceparent?: string;\n }): string;\n lease(now: number, limit: number, leaseMs: number): StoredJob[];\n complete(id: string): void;\n retry(id: string, runAt: number): void;\n deadLetter(id: string, error: string): void;\n counts(now?: number): JobCounts;\n /** The dead-letter queue - inspect/requeue failed jobs (not part of the {@link JobStore} contract). */\n deadLetters(): DeadRecord[];\n}",
8632
+ "signature": "export declare class MemoryJobStore implements JobStore {\n private readonly jobs;\n private readonly dead;\n private seq;\n private leaseSeq;\n private readonly idFor;\n constructor(options?: {\n idFor?: () => string;\n });\n enqueue(job: {\n name: string;\n payload: unknown;\n runAt: number;\n maxAttempts: number;\n traceparent?: string;\n }): string;\n lease(now: number, limit: number, leaseMs: number): StoredJob[];\n /** The job, when a call made under `lease` may still act on it (no token: any caller may). */\n private held;\n complete(id: string, lease?: string): void;\n retry(id: string, runAt: number, lease?: string): void;\n deadLetter(id: string, error: string, lease?: string): void;\n renew(id: string, until: number, lease?: string): void;\n counts(now?: number): JobCounts;\n /** The dead-letter queue - inspect/requeue failed jobs (not part of the {@link JobStore} contract). */\n deadLetters(): DeadRecord[];\n}",
8605
8633
  "doc": "/** Construct an in-memory job store. `idFor` is injectable for deterministic tests. */"
8606
8634
  },
8607
8635
  {
@@ -8997,13 +9025,13 @@
8997
9025
  "name": "MountAgUIOptions",
8998
9026
  "kind": "interface",
8999
9027
  "package": "@nifrajs/ag-ui",
9000
- "signature": "export interface MountAgUIOptions<InputSchema extends StandardSchemaV1, OutputSchema extends StandardSchemaV1> {\n readonly agent: AgentDefinition<InputSchema, OutputSchema>;\n /** Endpoint path. Default `/agui`. */\n readonly path?: string;\n /** Bounded run length passed to the runner. */\n readonly maxTurns?: number;\n /** Maximum request body size in bytes. Default 1_000_000. */\n readonly maxBodyBytes?: number;\n /** Prototype-poisoning policy for the framing lane. Default `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n /** Maximum total UTF-8 bytes emitted by one SSE response. Default 4 MiB. */\n readonly maxOutputBytes?: number;\n /**\n * Build the ports for one request - the model, durable state store, approval transport,\n * capabilities, and budgets. Receives the route context so the caller can scope every port to\n * the request subject, and the run context carrying the turn id and the shared UI state channel.\n */\n readonly ports: (c: AgUIRouteContext, run: AgUIRunContext) => AgentPorts | Promise<AgentPorts>;\n /**\n * Evidence log making the SSE stream resumable via `Last-Event-ID`. The in-memory reference\n * (`createMemoryAgentEvidenceLog`) is single-process; a durable log is an adapter concern.\n */\n readonly evidenceLog?: AgentEvidenceLog;\n /**\n * Who a turn's recorded events belong to - the caller's user or tenant id. Turns are recorded and\n * replayed under it, so a reconnect or a reused run id from another caller finds nothing of this\n * caller's turns. It runs before a replay is served; throw to refuse the request.\n */\n readonly evidenceOwner?: (c: AgUIRouteContext) => string | Promise<string>;\n /**\n * Emit a `MESSAGES_SNAPSHOT` (the request's `messages` plus the assistant output message)\n * before `RUN_FINISHED` on a successful completion. Default `false`: the snapshot echoes\n * client-sent message payloads, and terminal events are persisted to the evidence log when one\n * is configured - leave it off unless the client relies on an authoritative snapshot.\n */\n readonly emitMessagesSnapshot?: boolean;\n}"
9028
+ "signature": "export interface MountAgUIOptions<InputSchema extends StandardSchemaV1, OutputSchema extends StandardSchemaV1> {\n readonly agent: AgentDefinition<InputSchema, OutputSchema>;\n /** Endpoint path. Default `/agui`. */\n readonly path?: string;\n /** Bounded run length passed to the runner. */\n readonly maxTurns?: number;\n /** Maximum request body size in bytes. Default 1_000_000. */\n readonly maxBodyBytes?: number;\n /** Prototype-poisoning policy for the framing lane. Default `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n /** Maximum total UTF-8 bytes emitted by one SSE response. Default 4 MiB. */\n readonly maxOutputBytes?: number;\n /**\n * Build the ports for one request - the model, durable state store, approval transport,\n * capabilities, and budgets. Receives the route context so the caller can scope every port to\n * the request subject, and the run context carrying the turn id and the shared UI state channel.\n * Throw a `Response` (a 401 with its challenge, a 403) to answer the request with it; any other\n * throw is a fault and reaches the app's error handling.\n */\n readonly ports: (c: AgUIRouteContext, run: AgUIRunContext) => AgentPorts | Promise<AgentPorts>;\n /**\n * Evidence log making the SSE stream resumable via `Last-Event-ID`. The in-memory reference\n * (`createMemoryAgentEvidenceLog`) is single-process; a durable log is an adapter concern.\n */\n readonly evidenceLog?: AgentEvidenceLog;\n /**\n * Who a turn's recorded events belong to - the caller's user or tenant id. Turns are recorded and\n * replayed under it, so a reconnect or a reused run id from another caller finds nothing of this\n * caller's turns. It runs before a replay is served; throw to refuse the request with\n * `403 { error: \"forbidden\" }`, or throw a `Response` to answer with it instead.\n */\n readonly evidenceOwner?: (c: AgUIRouteContext) => string | Promise<string>;\n /**\n * Emit a `MESSAGES_SNAPSHOT` (the request's `messages` plus the assistant output message)\n * before `RUN_FINISHED` on a successful completion. Default `false`: the snapshot echoes\n * client-sent message payloads, and terminal events are persisted to the evidence log when one\n * is configured - leave it off unless the client relies on an authoritative snapshot.\n */\n readonly emitMessagesSnapshot?: boolean;\n}"
9001
9029
  },
9002
9030
  {
9003
9031
  "name": "MountAgentOptions",
9004
9032
  "kind": "interface",
9005
9033
  "package": "@nifrajs/agent",
9006
- "signature": "export interface MountAgentOptions<InputSchema extends StandardSchemaV1, OutputSchema extends StandardSchemaV1> {\n readonly agent: AgentDefinition<InputSchema, OutputSchema>;\n /** Endpoint path. Default `/agent`. */\n readonly path?: string;\n /** Bounded run length passed to {@link runAgent}. */\n readonly maxTurns?: number;\n /** Maximum request body size in bytes. Default 1_000_000. */\n readonly maxBodyBytes?: number;\n /** Prototype-poisoning policy for the framing lane. Default `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n /**\n * Maximum total UTF-8 bytes one SSE response emits. Default 4 MiB. Past it the response ends with an\n * `error` frame (`output_limit`); with an `evidenceLog` the run keeps recording and a reconnect with\n * `Last-Event-ID` reads on from where this response stopped, otherwise the run is cancelled.\n */\n readonly maxOutputBytes?: number;\n /**\n * Build the ports for one request - the model, durable state store, approval transport, capabilities,\n * and budgets. Receives the route context so the caller can scope every port to the request subject.\n */\n readonly ports: (c: AgentRouteContext) => AgentPorts | Promise<AgentPorts>;\n /**\n * Evidence log making the SSE stream resumable via `Last-Event-ID`. The in-memory reference\n * (`createMemoryAgentEvidenceLog`) is single-process; a durable log is an adapter concern.\n */\n readonly evidenceLog?: AgentEvidenceLog;\n /**\n * Who a turn's recorded evidence belongs to - the caller's user or tenant id. Turns are recorded and\n * replayed under it, so a reconnect or a reused `turnId` from another caller finds nothing of this\n * caller's turns. It runs before a replay is served; throw to refuse the request.\n */\n readonly evidenceOwner?: (c: AgentRouteContext) => string | Promise<string>;\n}"
9034
+ "signature": "export interface MountAgentOptions<InputSchema extends StandardSchemaV1, OutputSchema extends StandardSchemaV1> {\n readonly agent: AgentDefinition<InputSchema, OutputSchema>;\n /** Endpoint path. Default `/agent`. */\n readonly path?: string;\n /** Bounded run length passed to {@link runAgent}. */\n readonly maxTurns?: number;\n /** Maximum request body size in bytes. Default 1_000_000. */\n readonly maxBodyBytes?: number;\n /** Prototype-poisoning policy for the framing lane. Default `\"reject\"`. */\n readonly protoPoisoning?: ProtoPoisoning;\n /**\n * Maximum total UTF-8 bytes one SSE response emits. Default 4 MiB. Past it the response ends with an\n * `error` frame (`output_limit`); with an `evidenceLog` the run keeps recording and a reconnect with\n * `Last-Event-ID` reads on from where this response stopped, otherwise the run is cancelled.\n */\n readonly maxOutputBytes?: number;\n /**\n * Build the ports for one request - the model, durable state store, approval transport, capabilities,\n * and budgets. Receives the route context so the caller can scope every port to the request subject.\n * Throw a `Response` (a 401 with its challenge, a 403) to answer the request with it; any other throw\n * is a fault and reaches the app's error handling.\n */\n readonly ports: (c: AgentRouteContext) => AgentPorts | Promise<AgentPorts>;\n /**\n * Evidence log making the SSE stream resumable via `Last-Event-ID`. The in-memory reference\n * (`createMemoryAgentEvidenceLog`) is single-process; a durable log is an adapter concern.\n */\n readonly evidenceLog?: AgentEvidenceLog;\n /**\n * Who a turn's recorded evidence belongs to - the caller's user or tenant id. Turns are recorded and\n * replayed under it, so a reconnect or a reused `turnId` from another caller finds nothing of this\n * caller's turns. It runs before a replay is served; throw to refuse the request with\n * `403 { error: \"forbidden\" }`, or throw a `Response` to answer with it instead.\n */\n readonly evidenceOwner?: (c: AgentRouteContext) => string | Promise<string>;\n}"
9007
9035
  },
9008
9036
  {
9009
9037
  "name": "MountFetchOptions",
@@ -9471,7 +9499,7 @@
9471
9499
  "name": "NifraBackendOptions",
9472
9500
  "kind": "interface",
9473
9501
  "package": "@nifrajs/coding-agent",
9474
- "signature": "export interface NifraBackendOptions {\n readonly model: NativeModelPort;\n readonly tools?: readonly NativeTool[];\n readonly approval?: NativeApprovalPort;\n /** Maximum time a protocol-visible native approval may remain unresolved. */\n readonly approvalTimeoutMs?: number;\n readonly maxSteps?: number;\n /** Longest message `send` accepts (default 64 KiB). */\n readonly maxMessageChars?: number;\n /**\n * Longest reply the model may give in one turn (default 1 MiB); past it the reply is cut with\n * a marker. A reply longer than one event's text travels as consecutive `assistant.message`\n * events, and the model's history keeps it whole.\n */\n readonly maxReplyChars?: number;\n /**\n * Character budget for the conversation a session sends to the model (default 1 MiB). Past it,\n * whole earlier turns are dropped, oldest first; the current turn is always sent in full.\n */\n readonly maxHistoryChars?: number;\n readonly now?: () => number;\n}"
9502
+ "signature": "export interface NifraBackendOptions {\n readonly model: NativeModelPort;\n readonly tools?: readonly NativeTool[];\n readonly approval?: NativeApprovalPort;\n /**\n * Maximum time a protocol-visible native approval may remain unresolved (default 5 minutes, at\n * most 24 h). `\"never\"` removes the timer: the approval waits for an answer, a cancel, the end of\n * its turn, or session close.\n */\n readonly approvalTimeoutMs?: ApprovalTimeout;\n readonly maxSteps?: number;\n /** Longest message `send` accepts (default 64 KiB). */\n readonly maxMessageChars?: number;\n /**\n * Longest reply the model may give in one turn (default 1 MiB); past it the reply is cut with\n * a marker. A reply longer than one event's text travels as consecutive `assistant.message`\n * events, and the model's history keeps it whole.\n */\n readonly maxReplyChars?: number;\n /**\n * Character budget for the conversation a session sends to the model (default 1 MiB). Past it,\n * whole earlier turns are dropped, oldest first; the current turn is always sent in full.\n */\n readonly maxHistoryChars?: number;\n readonly now?: () => number;\n}"
9475
9503
  },
9476
9504
  {
9477
9505
  "name": "NifraContextLike",
@@ -9968,7 +9996,7 @@
9968
9996
  "name": "OpenApiUiOptions",
9969
9997
  "kind": "interface",
9970
9998
  "package": "@nifrajs/middleware",
9971
- "signature": "export interface OpenApiUiOptions {\n /** Where to serve the UI page. Default `\"/reference\"`. */\n readonly path?: string;\n /** Page title. Defaults to `info.title`. */\n readonly title?: string;\n /** The Scalar script URL (loaded from a CDN). Default jsDelivr's `@scalar/api-reference`. */\n readonly cdn?: string;\n}",
9999
+ "signature": "export interface OpenApiUiOptions {\n /** Where to serve the UI page. Default `\"/reference\"`. */\n readonly path?: string;\n /** Page title. Defaults to `info.title`. */\n readonly title?: string;\n /**\n * The Scalar script URL. Default: `@scalar/api-reference` 1.72.1's standalone build on jsDelivr,\n * pinned by {@link integrity}. Point it at a copy you serve yourself (no third-party origin to\n * allow in a `script-src` policy, nothing to trust but your own deploy).\n */\n readonly cdn?: string;\n /**\n * The script's Subresource Integrity hash (`sha384-...`), which makes the browser refuse a script\n * whose bytes differ. Default: the default build's hash when `cdn` is unset, none when it is set.\n * Pass the hash of your own copy, or `false` to send none.\n */\n readonly integrity?: string | false;\n}",
9972
10000
  "doc": "/** Scalar API-reference UI options. */"
9973
10001
  },
9974
10002
  {
@@ -11073,7 +11101,7 @@
11073
11101
  "name": "QueueOptions",
11074
11102
  "kind": "interface",
11075
11103
  "package": "@nifrajs/jobs",
11076
- "signature": "export interface QueueOptions {\n /** Persistence. Default: a fresh {@link MemoryJobStore} (single-process). */\n readonly store?: JobStore;\n /** Called when a handler throws (before retry/dead-letter). Default: `console.error`. A throwing handler here is swallowed. */\n readonly onError?: (error: unknown, jobName: string) => void;\n /** Injectable clock (tests). Default `() => Date.now()`. */\n readonly now?: () => number;\n /** Default attempts for jobs that don't set `retries`. Default 3. */\n readonly defaultAttempts?: number;\n /** Default backoff for jobs that don't set one. Default {@link exponentialBackoff}. */\n readonly backoff?: Backoff;\n /**\n * Make `enqueue` produce capability evidence:\n *\n * import { useCapability } from \"@nifrajs/core/capabilities\"\n * const queue = createQueue({ beacon: useCapability })\n * await indexNote.for(c).enqueue({ id })\n */\n readonly beacon?: CapabilityBeacon;\n /** Override the announced token. Default `jobs.enqueue`. */\n readonly capabilities?: {\n readonly enqueue?: string;\n };\n /**\n * Around-hooks for each enqueue and each attempt - pass `jobTracing()` from `@nifrajs/otel/jobs` for a\n * `send <job>` producer span and a `process <job>` consumer span per attempt.\n */\n readonly instrument?: QueueInstrument;\n}"
11104
+ "signature": "export interface QueueOptions {\n /** Persistence. Default: a fresh {@link MemoryJobStore} (single-process). */\n readonly store?: JobStore;\n /** Called when a handler throws (before retry/dead-letter). Default: `console.error`. A throwing handler here is swallowed. */\n readonly onError?: (error: unknown, jobName: string) => void;\n /** Injectable clock (tests). Default `() => Date.now()`. */\n readonly now?: () => number;\n /** Default attempts for jobs that don't set `retries`: a whole number (below 1 counts as 1).\n * Default 3. `createQueue` throws a `RangeError` on anything else. */\n readonly defaultAttempts?: number;\n /** Default backoff for jobs that don't set one. Default {@link exponentialBackoff}. */\n readonly backoff?: Backoff;\n /**\n * Make `enqueue` produce capability evidence:\n *\n * import { useCapability } from \"@nifrajs/core/capabilities\"\n * const queue = createQueue({ beacon: useCapability })\n * await indexNote.for(c).enqueue({ id })\n */\n readonly beacon?: CapabilityBeacon;\n /** Override the announced token. Default `jobs.enqueue`. */\n readonly capabilities?: {\n readonly enqueue?: string;\n };\n /**\n * Around-hooks for each enqueue and each attempt - pass `jobTracing()` from `@nifrajs/otel/jobs` for a\n * `send <job>` producer span and a `process <job>` consumer span per attempt.\n */\n readonly instrument?: QueueInstrument;\n}"
11077
11105
  },
11078
11106
  {
11079
11107
  "name": "R2BucketLike",
@@ -11136,6 +11164,13 @@
11136
11164
  "signature": "export declare const RESERVED_VERB_KEYS: readonly [\"get\", \"post\", \"put\", \"patch\", \"delete\", \"head\", \"options\"];",
11137
11165
  "doc": "/** Intercepted case-insensitively: `/api/Delete` collides just as `/api/delete` does. */"
11138
11166
  },
11167
+ {
11168
+ "name": "RESPONSE_CONTRACT_BASELINE_HINT",
11169
+ "kind": "const",
11170
+ "package": "@nifrajs/cli",
11171
+ "signature": "export declare const RESPONSE_CONTRACT_BASELINE_HINT = \"to fail route assurance on these, add baseline: [{ name: \\\"response-contract\\\", match: { hasResponse: true }, require: [\\\"nifra.response-contract\\\"] }] to the policy\";",
11172
+ "doc": "/** The policy line that turns an unenforced contract into a route-assurance failure. */"
11173
+ },
11139
11174
  {
11140
11175
  "name": "RETAIN_HEADER",
11141
11176
  "kind": "const",
@@ -11624,7 +11659,7 @@
11624
11659
  "name": "RenderAdapter",
11625
11660
  "kind": "interface",
11626
11661
  "package": "@nifrajs/web",
11627
- "signature": "export interface RenderAdapter {\n /**\n * Render a route's layout `chain` (outermost layout → page) to a Web stream of HTML bytes,\n * including the framework's hydration markers. When `options.nonce` is set, every executable\n * `<script>` the framework streams (out-of-order Suspense runtimes, serialized resources) must\n * carry it, or a nonce-based Content-Security-Policy blocks it and the boundary never resolves.\n */\n renderToStream(chain: readonly unknown[], props: RenderProps, options?: RenderStreamOptions): ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>;\n /** Render the chain to a complete HTML string when no content is deferred. */\n renderToString?(chain: readonly unknown[], props: RenderProps): string | Promise<string>;\n /** Per-document bootstrap markup injected into `<head>` for client hydration. */\n hydrationHead(nonce?: string): string;\n}",
11662
+ "signature": "export interface RenderAdapter {\n /**\n * Render a route's layout `chain` (outermost layout → page) to a Web stream of HTML bytes,\n * including the framework's hydration markers. When `options.nonce` is set, every executable\n * `<script>` the framework streams (out-of-order Suspense runtimes, serialized resources) must\n * carry it, or a nonce-based Content-Security-Policy blocks it and the boundary never resolves.\n */\n renderToStream(chain: readonly unknown[], props: RenderProps, options?: RenderStreamOptions): ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>;\n /**\n * Render the chain to a complete HTML string when no content is deferred. `options.nonce` is the\n * document's CSP nonce, for any inline script the renderer emits (Solid's hydration data).\n */\n renderToString?(chain: readonly unknown[], props: RenderProps, options?: RenderStreamOptions): string | Promise<string>;\n /** Per-document bootstrap markup injected into `<head>` for client hydration. */\n hydrationHead(nonce?: string): string;\n /**\n * Set when a render can produce markup that belongs outside the app root. Every render is then\n * passed `options.parts` to fill; an adapter without it never is, and pays nothing for the seam.\n */\n readonly documentParts?: boolean;\n}",
11628
11663
  "doc": "/**\n * The seam every render adapter implements. New adapters should prove these invariants with\n * `assertRenderAdapterConformance`; framework-specific behavior remains locally tested.\n */"
11629
11664
  },
11630
11665
  {
@@ -11645,7 +11680,7 @@
11645
11680
  "name": "RenderAssemblyCache",
11646
11681
  "kind": "interface",
11647
11682
  "package": "@nifrajs/web",
11648
- "signature": "export interface RenderAssemblyCache {\n /** Shell up to (not including) the deferred-runtime insertion point. */\n shellPre?: string;\n /** Shell from after the deferred-runtime insertion point through the open `#root` container. */\n shellPost?: string;\n /** Tail opener: the handover script open tag + the data member's key. */\n tailPre?: string;\n /** Tail from after the per-request handover members (the route id, prerendered paths, the handover\n * close) through `</html>`. */\n tailPost?: string;\n}",
11683
+ "signature": "export interface RenderAssemblyCache {\n /** Shell up to (not including) the deferred-runtime insertion point. */\n shellPre?: string;\n /** Shell from after the deferred-runtime insertion point through `<body>`. */\n shellPost?: string;\n /** The open `#root` container. */\n rootOpen?: string;\n /** Tail opener: the handover script open tag + the data member's key. */\n tailPre?: string;\n /** Tail from after the per-request handover members (the route id, prerendered paths, the handover\n * close) through `</html>`. */\n tailPost?: string;\n}",
11649
11684
  "doc": "/** The mutable per-route slot {@link RenderPageOptions.assemblyCache} fills. Opaque - create as `{}`. */"
11650
11685
  },
11651
11686
  {
@@ -11698,7 +11733,7 @@
11698
11733
  "name": "RenderStreamOptions",
11699
11734
  "kind": "interface",
11700
11735
  "package": "@nifrajs/web",
11701
- "signature": "export interface RenderStreamOptions {\n /** The document's CSP nonce, for every executable `<script>` the framework streams. */\n readonly nonce?: string;\n}",
11736
+ "signature": "export interface RenderStreamOptions {\n /** The document's CSP nonce, for every executable `<script>` the framework streams. */\n readonly nonce?: string;\n /** Present only for an adapter that sets {@link RenderAdapter.documentParts}. */\n readonly parts?: DocumentParts;\n}",
11702
11737
  "doc": "/** Per-document options for {@link RenderAdapter.renderToStream}. */"
11703
11738
  },
11704
11739
  {
@@ -11956,6 +11991,13 @@
11956
11991
  "signature": "export interface ResponseContractDefinition {\n readonly response?: StandardSchemaV1;\n readonly errors?: Readonly<Record<number, StandardSchemaV1>>;\n}",
11957
11992
  "doc": "/** Success and status-specific error schemas captured by one route at registration time. */"
11958
11993
  },
11994
+ {
11995
+ "name": "ResponseContractGaps",
11996
+ "kind": "interface",
11997
+ "package": "@nifrajs/cli",
11998
+ "signature": "export interface ResponseContractGaps {\n readonly typedOnly: readonly string[];\n readonly warnOnly: readonly string[];\n readonly typedOnlyReason: string | undefined;\n readonly warnOnlyReason: string | undefined;\n}",
11999
+ "doc": "/** Why declared response/error schemas go unenforced, phrased for the server that has to change. */"
12000
+ },
11959
12001
  {
11960
12002
  "name": "ResponseContractMode",
11961
12003
  "kind": "type",
@@ -11963,6 +12005,12 @@
11963
12005
  "signature": "export type ResponseContractMode = \"warn\" | \"enforce\";",
11964
12006
  "doc": "/**\n * How hard a declared `response` schema is held.\n *\n * - `warn` - check and log; the response is sent UNCHANGED, so enabling it cannot break anything.\n * - `enforce` - serialize the validated value, so undeclared data cannot reach the wire.\n *\n * There is no `off`: not installing the plugin IS off, and that is what keeps this module out of an\n * app's bundle entirely rather than shipping a disabled branch to everyone.\n */"
11965
12007
  },
12008
+ {
12009
+ "name": "ResponseContractOptions",
12010
+ "kind": "interface",
12011
+ "package": "@nifrajs/core",
12012
+ "signature": "export interface ResponseContractOptions {\n /**\n * Fields the schema does not declare. `\"reject\"` (the default) leaves them to the validator: a\n * closed `t.object` reports them, so an enforced response becomes a 500 and the log names them.\n * `\"strip\"` drops them first, for any schema exposing its JSON Schema as `jsonSchema` (every\n * `@nifrajs/schema` `t` schema) - nested objects, arrays and records included. A union is projected\n * only when exactly one branch can hold an object. Schemas without `jsonSchema` (zod, valibot) are\n * unaffected: they already strip or reject by their own rules.\n */\n readonly extra?: \"reject\" | \"strip\";\n}"
12013
+ },
11966
12014
  {
11967
12015
  "name": "ResponseContractOutcome",
11968
12016
  "kind": "type",
@@ -12142,7 +12190,7 @@
12142
12190
  "name": "RetryPolicy",
12143
12191
  "kind": "interface",
12144
12192
  "package": "@nifrajs/jobs",
12145
- "signature": "export interface RetryPolicy {\n /** Total attempts before dead-lettering (incl. the first). Default 3. `1` = no retries. */\n readonly attempts: number;\n /** Delay before each retry. Default {@link exponentialBackoff}. */\n readonly backoff?: Backoff;\n}"
12193
+ "signature": "export interface RetryPolicy {\n /** Total attempts before dead-lettering (incl. the first): a whole number, below 1 counting as 1.\n * Default 3. `1` = no retries. `define` throws a `RangeError` on `NaN`, `Infinity` or a fraction. */\n readonly attempts: number;\n /** Delay before each retry. Default {@link exponentialBackoff}. */\n readonly backoff?: Backoff;\n}"
12146
12194
  },
12147
12195
  {
12148
12196
  "name": "RevalidateEndpointOptions",
@@ -12473,7 +12521,7 @@
12473
12521
  "name": "RouteCapabilityEvidence",
12474
12522
  "kind": "interface",
12475
12523
  "package": "@nifrajs/core",
12476
- "signature": "export interface RouteCapabilityEvidence {\n readonly method: string;\n readonly path: string;\n /** True only when the route's reachable module graph was actually scanned. */\n readonly covered: boolean;\n readonly evidence: readonly CapabilityEvidence[];\n}"
12524
+ "signature": "export interface RouteCapabilityEvidence {\n readonly method: string;\n readonly path: string;\n /** True only when the route's reachable module graph was actually scanned. */\n readonly covered: boolean;\n readonly evidence: readonly CapabilityEvidence[];\n /** The probable cause of an uncovered route, when the collector can tell. */\n readonly uncoveredReason?: string;\n}"
12477
12525
  },
12478
12526
  {
12479
12527
  "name": "RouteChange",
@@ -12639,7 +12687,7 @@
12639
12687
  "name": "RouteModule",
12640
12688
  "kind": "interface",
12641
12689
  "package": "@nifrajs/web",
12642
- "signature": "export interface RouteModule {\n readonly default: unknown;\n readonly loader?: Loader;\n /** Layout loader that must run before actions and is not retained across the action's render. */\n readonly gate?: boolean;\n readonly action?: Action;\n /**\n * Backend half only: the schema of what {@link loader} sends to the browser. Required whenever the\n * loader returns data. Keys it does not declare are dropped before the page renders; a declared\n * field of the wrong shape fails the request with a 500 naming the field's path.\n */\n readonly loaderOutput?: StandardSchemaV1;\n /** Backend half only: the schema of what {@link action} sends back, held to the same rule. */\n readonly actionOutput?: StandardSchemaV1;\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. A\n * boundary's `load` comes from {@link boundaryLoaders} in the route's backend half; the frontend\n * file declares only how it renders. */\n readonly boundaries?: readonly BoundaryRegistration[];\n /** Backend half only: each boundary's server loader, keyed by boundary name. */\n readonly boundaryLoaders?: Readonly<Record<string, BoundaryLoaderEntry>>;\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 * `false` renders this route's component in the browser only. The server still matches the route,\n * runs its gates and loaders, renders the layouts around it and embeds the data - it skips the\n * component alone, putting {@link HydrateFallback} (or nothing) in the page slot. The browser\n * hydrates against that, then renders the component. For a component that cannot render on a\n * server: one that reads `window` or a browser-only API while it renders.\n *\n * The module itself is still imported on the server, for its loader and options - so an import\n * that needs a browser at load time belongs inside the component (a dynamic `import()`), not at the\n * top of the file. Cannot be combined with `hydrate = false`: nothing would ever render the page.\n */\n readonly ssr?: boolean;\n /**\n * What the server renders in the page slot of an `ssr = false` route, and what the browser hydrates\n * before the component takes over - a skeleton, a spinner. Receives the same props as the\n * component, loader `data` included. Omitted ⇒ the slot is empty until the component renders.\n */\n readonly HydrateFallback?: unknown;\n /**\n * Any value to report through `useMatches` - a breadcrumb label, a render function, a flag a layout\n * reads about the page inside it. Layouts, pages, and status pages may export one. It is read from\n * the module on the server and in the browser, so it must be the same value on both.\n */\n readonly handle?: unknown;\n /**\n * On a root status page (`_404.tsx`, `_<status>.tsx`) or an `_error.tsx`. By default (`true`) the\n * page renders inside the layouts above it with their loader data and `meta`, as a nested `_404`\n * renders. When those layouts cannot render it - a loader throws, a gate or the middleware refuses -\n * a root status page renders alone and an `_error` inside its layouts without their data, with the\n * same status. `false` always renders them that way, and runs no layout loader for them.\n */\n readonly inLayouts?: 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 /**\n * Bounded tags ISR on-demand invalidation (`?tag=...`) and a CDN purge reach this page by. A list, or\n * a function of the route's params and URL (`({ params }) => [\\`product:${params.id}\\`]`) for tags\n * per page. Tags travel to the CDN and reach anyone reading the origin: never put personal data in one.\n */\n readonly revalidateTags?: RevalidateTags;\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}",
12690
+ "signature": "export interface RouteModule {\n readonly default: unknown;\n readonly loader?: Loader;\n /** Layout loader that must run before actions and is not retained across the action's render. */\n readonly gate?: boolean;\n readonly action?: Action;\n /**\n * Backend half only: which browser origins may POST to {@link action}. When omitted, a request\n * whose `Origin` is another site's is refused with 403 before middleware, gates or the action run;\n * requests without an `Origin` (non-browser clients) pass. An array allows exactly those origins\n * (and refuses a request without one); a function decides, receiving `null` when there is none.\n * Use it for a callback a third party posts to, such as an identity provider's `form_post`.\n * `Origin` is browser-enforced, not authentication: keep the action's own auth checks.\n */\n readonly allowedOrigins?: ReadonlyArray<string> | ((origin: string | null) => boolean);\n /**\n * Backend half only: the schema of what {@link loader} sends to the browser. Required whenever the\n * loader returns data. Keys it does not declare are dropped before the page renders; a declared\n * field of the wrong shape fails the request with a 500 naming the field's path.\n */\n readonly loaderOutput?: StandardSchemaV1;\n /** Backend half only: the schema of what {@link action} sends back, held to the same rule. */\n readonly actionOutput?: StandardSchemaV1;\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. A\n * boundary's `load` comes from {@link boundaryLoaders} in the route's backend half; the frontend\n * file declares only how it renders. */\n readonly boundaries?: readonly BoundaryRegistration[];\n /** Backend half only: each boundary's server loader, keyed by boundary name. */\n readonly boundaryLoaders?: Readonly<Record<string, BoundaryLoaderEntry>>;\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 * `false` renders this route's component in the browser only. The server still matches the route,\n * runs its gates and loaders, renders the layouts around it and embeds the data - it skips the\n * component alone, putting {@link HydrateFallback} (or nothing) in the page slot. The browser\n * hydrates against that, then renders the component. For a component that cannot render on a\n * server: one that reads `window` or a browser-only API while it renders.\n *\n * The module itself is still imported on the server, for its loader and options - so an import\n * that needs a browser at load time belongs inside the component (a dynamic `import()`), not at the\n * top of the file. Cannot be combined with `hydrate = false`: nothing would ever render the page.\n */\n readonly ssr?: boolean;\n /**\n * What the server renders in the page slot of an `ssr = false` route, and what the browser hydrates\n * before the component takes over - a skeleton, a spinner. Receives the same props as the\n * component, loader `data` included. Omitted ⇒ the slot is empty until the component renders.\n */\n readonly HydrateFallback?: unknown;\n /**\n * Any value to report through `useMatches` - a breadcrumb label, a render function, a flag a layout\n * reads about the page inside it. Layouts, pages, and status pages may export one. It is read from\n * the module on the server and in the browser, so it must be the same value on both.\n */\n readonly handle?: unknown;\n /**\n * On a root status page (`_404.tsx`, `_<status>.tsx`) or an `_error.tsx`. By default (`true`) the\n * page renders inside the layouts above it with their loader data and `meta`, as a nested `_404`\n * renders. When those layouts cannot render it - a loader throws, a gate or the middleware refuses -\n * a root status page renders alone and an `_error` inside its layouts without their data, with the\n * same status. `false` always renders them that way, and runs no layout loader for them.\n */\n readonly inLayouts?: 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 /**\n * Bounded tags ISR on-demand invalidation (`?tag=...`) and a CDN purge reach this page by. A list, or\n * a function of the route's params and URL (`({ params }) => [\\`product:${params.id}\\`]`) for tags\n * per page. Tags travel to the CDN and reach anyone reading the origin: never put personal data in one.\n */\n readonly revalidateTags?: RevalidateTags;\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}",
12643
12691
  "doc": "/** A route module - the default component + optional loader / action / meta. */"
12644
12692
  },
12645
12693
  {
@@ -13794,14 +13842,14 @@
13794
13842
  "name": "Server",
13795
13843
  "kind": "class",
13796
13844
  "package": "@nifrajs/core",
13797
- "signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext, HookOutput = never> {\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 /** Each socket path, its declared capabilities, the evidence declarations its handshake captured\n * and the chain it runs; reflection reads it. */\n private readonly wsRoutes;\n /** `wsChanges` when `wsMountsLive` was last worked out; -1 until then. */\n private wsMountsCheckedAt;\n /** Whether an app mounted here takes WebSocket upgrades, as of `wsMountsCheckedAt`. */\n private wsMountsLive;\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 /** True once any `app.ws()` route sets `validateSend: true` - the one case where a broadcast frame\n * is validated (and possibly dropped) per socket, so `app.publish` must stay on the JS registry loop\n * rather than delegate to Bun's native `server.publish`. */\n private wsHasValidatedSend;\n /** Bun's native topic broadcast, bound by `listen()` in native-pubsub mode; `app.publish` uses it\n * instead of the JS registry. `undefined` off Bun, before `listen()`, with a validated-send route,\n * or when a mounted app takes upgrades. */\n private nativePublish;\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 private readonly wsUpgradeTimeoutMs;\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 private mountOrder;\n /** Number of composed mounts that must run before the parent route table. Keeps legacy mounts off the hot path. */\n private preRouteMountCount;\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 answer for a request no route matched; `undefined` (the plain 404) until `.use(notFound())`. */\n private notFoundLane;\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 /** Dedicated authentication stages captured by subsequent routes. */\n private readonly authStages;\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 /** True when every request hook is safe to skip on a Bun native route. */\n private bunNativeRequestHooksSafe;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /** True when every response hook only mutates headers and can run after a Bun fused response. */\n private bunNativeResponseHeadersOnly;\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 /** A group's view of the static headers its enclosing scopes declared before it was created. */\n private inheritedStatics;\n /** A group's view of the plugins its enclosing scopes applied before it was created; unset while\n * a plugin applies, so its own dependency `use()` shares the parent's copy. */\n private inheritedPlugins;\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 /** A request the WebSocket handshake check ran the onRequest hooks on and then passed to HTTP →\n * what the hooks returned, so `fetch` routes that instead of running the hooks a second time. */\n private wsHookedPasses;\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 /** Plugins/middleware already applied via `use`, by name - 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 /** Kept so a {@link group} scope is built with exactly this server's settings: fused lanes read\n * several of them at request time, so a group route must never run under different ones. */\n private readonly options;\n /** Static prefix joined onto every route this server registers; non-empty only on a group scope. */\n private routePrefix;\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 * Compose a child fetch app under a literal path prefix.\n *\n * Composed mounts run after the app-global request phase and before the parent's route table. This\n * makes them safe to use in an SSR shell whose `/*` page route would otherwise swallow an API mount.\n * If the child exposes `resolveWebSocketUpgrade`, the same mount also participates in adapter-owned\n * WebSocket upgrades; the serving adapter still upgrades its original socket, while the child sees\n * the mounted request path (stripped when requested).\n *\n * `fallbackOn: 404` is deliberately limited to GET/HEAD/OPTIONS at dispatch time. Those methods are\n * replayable without buffering an untrusted request body; POST/PUT/PATCH and streaming requests\n * never get retried after a child has had a chance to consume them.\n */\n mount(options: MountOptions<EnvOf<Ctx>>): 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx & ContextExtensionOf<ReturnType<H>>, HookOutput | StatusResponseOf<Awaited<ReturnType<H>>>>;\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 /**\n * Register a dedicated authentication stage for subsequent routes.\n *\n * Unlike `derive`, this stage receives a body-blind authentication capsule and is compiled before\n * route validation. Keeping it separate prevents an unrelated derive from accidentally becoming a\n * security gate and lets the route compiler retain a protected fast lane.\n */\n authenticate<Principal>(stage: AuthenticationStage<Principal, EnvOf<Ctx>>): Server<R, Ctx & {\n readonly principal: Principal;\n }, HookOutput>;\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>, HookOutput>;\n /**\n * Run before routing on the raw request. Return a `Response` or a `status()` result to\n * short-circuit, or a replacement `Request` to continue routing with a rewritten method/URL/headers.\n * 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (context: Context & Ctx, next: () => MaybePromise<unknown>) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (result: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (error: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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. In a group, a name the group declares replaces the value its\n * enclosing scopes declared before the group, on the group's routes. 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 /**\n * Apply `all()` or `method()` from `@nifrajs/core/methods`: one handler registered under several\n * methods, or under a method outside the standard seven. The standard methods join the registry.\n *\n * Declared first on purpose. The plugin's handler is typed against this app's context, which\n * TypeScript reads from the first overload it tries.\n */\n use<M extends string, Path extends string, S extends RouteSchema, Output>(plugin: MethodRoutesPlugin<M, Path, S, Output, Ctx>): Server<WithMethodRoutes<R, M, Path, S, Output, HookOutput>, Ctx, HookOutput>;\n /** Enable the opt-in portable response observer methods. */\n use(plugin: ResponseObserverPlugin): this & ResponseObserverMethods;\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, HookOutput>;\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<AddedHookOutput = never>(plugin: IdentityPlugin<AddedHookOutput>): Server<R, Ctx, HookOutput | AddedHookOutput>;\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), however it was configured,\n * so a plugin meant to stack - a second, stricter guard - needs a name of its own per instance.\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<M extends Middleware>(mw: M): Server<R, Ctx, HookOutput | MiddlewareOutputOf<M>>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\n /**\n * Register a **typed SSE route** - an endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. It is a GET route, or a POST route when the schema\n * declares a `body` (a GET carries none): the body validates as on any POST, and the client sends\n * it with `.subscribe(onEvent, { body })` - the shape of a chat stream that posts its prompt. 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`, `maxBufferedBytes`,\n * extra headers). The connection closes when the handler resolves, `stream.close()` runs, or the\n * client disconnects (`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, SseMethodOf<S>, Path, RouteInfoFor<Path, S, Response, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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, HookOutput>;\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, HookOutput>;\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 handshake runs the chain an HTTP `GET` registered here would: the\n * `authenticate()` stages, `derive`s and `beforeHandle`s added before this call, then the optional\n * `handler.upgrade(c)`. Any of them may reject (a `Response`, a `status(...)`, a failed auth stage);\n * `upgrade()` may seed per-connection `ws.data`. To keep a socket public, register it before the\n * guard. 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, Ctx>): string extends Path ? Server<R, Ctx, HookOutput> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx, HookOutput>;\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: string, 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 *\n * A path ending in optional parameters (`/users/:id?`) is one catalog route per concrete pattern,\n * so reflection, OpenAPI, evidence and the typed client all see ordinary routes. */\n registerBatch(routes: readonly {\n readonly method: string;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n /** Join a group scope's prefix BEFORE compilation, so the pattern, the reflected descriptor, the\n * capability guard, the ledger record, and assurance path matching all see the one served path. */\n private prefixed;\n private prepareRoute;\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 `notFound()` plugin. Off the public typed surface. */\n [INSTALL_NOT_FOUND](lane: NotFoundLane): 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 An adapter reports a failure no response hook saw (a hook that threw past `fetch`, a\n * response the runtime refused to write), logged as Bun's `listen()` logs one. */\n [REPORT_ERROR](error: unknown): 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 * @internal The runtime Bun serves this app's WebSocket upgrades with, asked by `listen()` and by a\n * parent that mounts this app: `undefined` while nothing here can take one, `null` when something\n * can but no runtime is at hand. A mounted Nifra app answers through this same seam, so mounting an\n * app without a WebSocket route needs no runtime; a resolver without the seam cannot say, so it\n * counts. `seen` ends a mount cycle (an app mounted under itself to alias a prefix).\n */\n [GET_WS_RUNTIME](seen?: Set<unknown>): WsRuntime | null | undefined;\n /** The `[GET_WS_RUNTIME]` answer for the apps mounted here alone, whatever this app's own routes. */\n private mountedWsRuntime;\n /** Whether an app mounted here takes WebSocket upgrades. Worked out again only after a `ws()` or a\n * `mount()` somewhere, so the upgrade check on a plain request costs one comparison. */\n private mountsTakeUpgrades;\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, and for an `OPTIONS` preflight to a path they serve (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 or mounts is refused\n * (register those on the parent).\n */\n merge<R2 extends Registry, Ctx2, HookOutput2>(other: Server<R2, Ctx2, HookOutput2>): Server<R & R2, Ctx, HookOutput>;\n /**\n * Declare routes under a static path prefix, with the prefix in the typed client, `routes()`,\n * OpenAPI, capability events, and the effect ledger - the counterpart of Hono's `route()`,\n * Elysia's `group()`, and Fastify's `register({ prefix })`.\n *\n * app\n * .derive(session)\n * .group(\"/admin\", (admin) =>\n * admin.beforeHandle(requireAdmin).get(\"/users\", listUsers).get(\"/users/:id\", getUser),\n * )\n * .get(\"/\", home) // not covered by requireAdmin\n *\n * The builder receives a scope that INHERITS this server's route chain as it stands at the call\n * (`derive`/`decorate`/`authenticate`/`beforeHandle`/`afterHandle`/`onError`/`around`, assurance,\n * capability interceptors, installed runtimes, applied plugins), exactly as a route declared here\n * would. A plugin this server already applied is in effect for the group: the group's `use()` of\n * that same instance does nothing, and its `use()` of another instance under the same name throws a\n * `RouteConfigError` (`PLUGIN_RECONFIGURED`), because that instance could never replace the parent's.\n * A plugin the group applies still shares the parent's copy of a dependency it `use()`s itself.\n * What it adds stays in the group: its chain additions apply only to its own routes, and its\n * request/response hooks (`onRequest`, `onResponse`, `responseHeaders`, `onResponseFinalized`, and\n * middleware bundles that use them) run only for requests whose path is the prefix or below it.\n * Per-route authorization belongs in `authenticate`/`beforeHandle`, which are compiled into each\n * route; request hooks are path prefilters.\n *\n * The prefix is static text - `\"/api\"`, `\"/api/v1\"` - validated when declared: no params,\n * wildcards, empty or dot segments, percent-escapes, or trailing slash. A group's `\"/\"` route\n * serves the prefix itself. Groups nest (`\"/api\"` then `\"/v1\"` serves `/api/v1/...`).\n *\n * Fail closed: the builder must synchronously return the scope it was given; a collision with an\n * existing route throws `RouteConfigError` and adds none of the group's routes; `.ws()`, mounts,\n * MCP `.tool()`s, and `merge()` inside a group are refused (register them on the parent). Once the\n * builder returns, the scope is closed - a leaked reference cannot add routes later.\n */\n group<const P extends string, R2 extends Registry, Ctx2, HookOutput2>(prefix: P, build: (group: Server<EmptyRegistry, Ctx, HookOutput>) => Server<R2, Ctx2, HookOutput2>): Server<R & PrefixRegistry<P, R2>, Ctx, HookOutput>;\n /**\n * Take over another server's routes and hooks - the shared core of {@link merge} and {@link group}.\n * `prefix` selects group semantics: hooks are scoped to requests under the prefix (response hooks\n * included), and the source's global assurance past `inheritedGlobal` (what it copied from this\n * server) is folded into its routes. Without a prefix, merge semantics: request hooks are scoped to\n * the source's routes when it has any, response hooks are appended app-wide.\n */\n private adopt;\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 private firstMountUnder;\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 private runWebSocketRequestHooks;\n private continueWebSocketRequestHooks;\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 trustedPlatform;\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 compiled route program, 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 same error boundary as the compiled route program (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 the compiled route program'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 /** A fused Web lane's render in an async continuation, where a result that cannot be rendered\n * must fail like a handler throw; a synchronous render throw reaches {@link runMatchedLanes}. */\n private respondFused;\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 /**\n * Compile a route's `derive + before` lifecycle to a single closure: the per-request walk through\n * `runSync` → `runHooksSync` is a stack of 3 frames and 2 `Object.assign`s for what is by far the\n * most common middleware shape (auth/trace/id derivation, an auth/policy `beforeHandle`). Folding\n * the same steps into one closure hits the same monomorphic inline-cache site as `buildFusedWeb`,\n * and `Object.assign(ctx, deriveResult)` becomes one extra property write on the context's already\n * hot hidden class. Behavior is byte-identical to the compiled route program: the same thrown-value\n * contract (`Response` is control flow, anything else logs + 500), the same `c.set` semantics, the\n * same `fusedRespond` for the rendered body. The `LifecycleExecutionLane` guarantee\n * (`schema.params === undefined && schema.headers === undefined && derives === 1 &&\n * beforeHandle === 1 && afterHandle === 0 && onError === 0 && !hasResponseContract &&\n * !hasDecorations`) is enforced by `selectRouteLanes`; this lane is selected ONLY when all of those\n * hold. A `query` schema (the route declares `{ query }` alongside the hooks) is validated FIRST,\n * mirroring the compiled route program's stage order; the fused builder runs validate → derive →\n * before → handler in one frame.\n */\n private buildFusedDeriveBefore;\n private buildFusedDeriveBeforeAfter;\n /**\n * Body + lifecycle hooks fused: parse → validate → derive → before → handler → (after) in one\n * closure, the same win `buildFusedBodyRunner` gives for the no-hooks body shape. The shape is\n * `lifecycleHookLane` PLUS a body schema with no other validation conflicts; the lane is selected\n * ONLY when `schema.body !== undefined && schema.query/params/headers === undefined &&\n * schema.onValidationError === undefined && !defaultOnValidationError && !hasIdempotency &&\n * !hasLedger && derives === 1 && beforeHandle === 1 && afterHandle <= 1 && onError === 0 &&\n * !hasResponseContract && !hasDecorations && around === 0`. The same single `querySchema === undefined`\n * trick used in the no-body lane lets the build path stay simple: a query + body route falls back\n * to the generic program (this is rare in practice - validated query + validated body is usually a\n * \"search results\" route with a middleware chain on top, and the generic lane is fine there).\n */\n private buildFusedBodyDeriveBeforeAfter;\n /**\n * Generic (finalize/wrapResponse-parameterized) fused runner for the derive-before(-after) lane:\n * the Node-direct counterpart of `buildFusedDeriveBefore` / `buildFusedDeriveBeforeAfter`.\n *\n * The Web fused builders above return a `Response`, so the Node dispatcher (`webFast === false`)\n * cannot use them and a derive+before route falls back to the generic route program there - two\n * staged loops, per-stage dispatch, and the async-continuation machinery - while Bun rides the\n * single closure. That asymmetry is the realistic-route Node deficit against Fastify: this runner\n * closes it by running validate → derive → before → handler → (after) in one frame and finalizing\n * through the caller's own `finalize` (the Node outcome on the direct lane, `toResponse` on Web),\n * so the same registration feeds both runtimes with no per-lane copy of the lifecycle to drift.\n *\n * Semantics mirror the generic program stage-for-stage for the shapes this lane admits (exactly\n * one derive, one beforeHandle, zero-or-one afterHandle, no onError/around/decorations/contracts/\n * recovery hooks - enforced by `selectRouteLanes`): thrown `Response`/`status(...)` are control\n * flow through `wrapResponse`/`finalize`, anything else logs + 500s via the shared `bareError`\n * lane (identical to `handleLifecycleError` with no `onError` hooks), and a terminal `finalize`\n * throw (e.g. an unstringifiable handler return on the Node lane) is caught exactly as\n * `finishLifecycleContract` catches it. Step functions close over registration state only and take\n * the request state as arguments, so the hot path allocates no per-request closures.\n */\n private buildFusedDeriveBeforeRunner;\n /**\n * Generic fused runner for the body+derive-before(-after) lane: the Node-direct counterpart of\n * `buildFusedBodyDeriveBeforeAfter`. Same contract as `buildFusedDeriveBeforeRunner` above - one\n * frame running parse → validate → derive → before → handler → (after) through the caller's own\n * `finalize` - with the body read ahead of validation, exactly as the generic program orders its\n * body stage before the derive/before stages. `readBodyFramed` keeps the shared bounded-read,\n * content-type, and prototype-poisoning contracts; the 415/400 renders take `wrapResponse`\n * directly, which is what the generic lane's wrap-after-identity amounts to.\n */\n private buildFusedBodyDeriveBeforeAfterRunner;\n private bareError;\n /**\n * Keep the ordinary thrown-error response independent from the caught value. Deliberate Response\n * control flow is handled by `renderBareError`; every other throw gets this fixed public envelope.\n */\n private internalErrorResponse;\n private runWithAround;\n /** Execute the registration-compiled general stage program. */\n private runProgram;\n /** Bind a compiled validation stage to its stable schema and the existing recovery contract. */\n private validateProgramStage;\n /** Preserve the existing bounded body reader and its fail-closed framing/prototype checks. */\n private readProgramBody;\n /** Keep thrown Response/status and redacted 500 semantics in one existing error boundary. */\n private handleProgramError;\n /** Finish a successful program result through response-contract enforcement and finalization. */\n private finishProgramResult;\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 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 the compiled route program 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 /** 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.\n *\n * Bun and the portable router agree on which of two static-and-`:param` paths wins a request, so\n * the table is kept to those paths. Where Bun would otherwise pass a request on to a less specific\n * path, the more specific one carries `fallback`, the portable dispatcher, under that method.\n * `peer` is the platform every request served from the table shares. */\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 * `tls` serves HTTPS directly: `app.listen(443, { tls: { cert, key } })` with PEM text or bytes.\n * Requests then arrive with `https:` URLs. Behind a proxy or a platform that terminates TLS, leave\n * it unset.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n readonly tls?: ListenTlsOptions;\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}",
13845
+ "signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext, HookOutput = never> {\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 /** Each socket path, its declared capabilities, the evidence declarations its handshake captured\n * and the chain it runs; reflection reads it. */\n private readonly wsRoutes;\n /** `wsChanges` when `wsMountsLive` was last worked out; -1 until then. */\n private wsMountsCheckedAt;\n /** Whether an app mounted here takes WebSocket upgrades, as of `wsMountsCheckedAt`. */\n private wsMountsLive;\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 /** True once any `app.ws()` route sets `validateSend: true` - the one case where a broadcast frame\n * is validated (and possibly dropped) per socket, so `app.publish` must stay on the JS registry loop\n * rather than delegate to Bun's native `server.publish`. */\n private wsHasValidatedSend;\n /** Bun's native topic broadcast, bound by `listen()` in native-pubsub mode; `app.publish` uses it\n * instead of the JS registry. `undefined` off Bun, before `listen()`, with a validated-send route,\n * or when a mounted app takes upgrades. */\n private nativePublish;\n private readonly maxBodyBytes;\n private readonly protoPoisoning;\n private readonly formOrigins;\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 private readonly wsUpgradeTimeoutMs;\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 private mountOrder;\n /** Number of composed mounts that must run before the parent route table. Keeps legacy mounts off the hot path. */\n private preRouteMountCount;\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 answer for a request no route matched; `undefined` (the plain 404) until `.use(notFound())`. */\n private notFoundLane;\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 /** Dedicated authentication stages captured by subsequent routes. */\n private readonly authStages;\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 /** True when every request hook is safe to skip on a Bun native route. */\n private bunNativeRequestHooksSafe;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /** True when every response hook only mutates headers and can run after a Bun fused response. */\n private bunNativeResponseHeadersOnly;\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 /** A group's view of the static headers its enclosing scopes declared before it was created. */\n private inheritedStatics;\n /** A group's view of the plugins its enclosing scopes applied before it was created; unset while\n * a plugin applies, so its own dependency `use()` shares the parent's copy. */\n private inheritedPlugins;\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 /** A request the WebSocket handshake check ran the onRequest hooks on and then passed to HTTP →\n * what the hooks returned, so `fetch` routes that instead of running the hooks a second time. */\n private wsHookedPasses;\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 /** Plugins/middleware already applied via `use`, by name - 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 /** Kept so a {@link group} scope is built with exactly this server's settings: fused lanes read\n * several of them at request time, so a group route must never run under different ones. */\n private readonly options;\n /** Static prefix joined onto every route this server registers; non-empty only on a group scope. */\n private routePrefix;\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 * Compose a child fetch app under a literal path prefix.\n *\n * Composed mounts run after the app-global request phase and before the parent's route table. This\n * makes them safe to use in an SSR shell whose `/*` page route would otherwise swallow an API mount.\n * If the child exposes `resolveWebSocketUpgrade`, the same mount also participates in adapter-owned\n * WebSocket upgrades; the serving adapter still upgrades its original socket, while the child sees\n * the mounted request path (stripped when requested).\n *\n * `fallbackOn: 404` is deliberately limited to GET/HEAD/OPTIONS at dispatch time. Those methods are\n * replayable without buffering an untrusted request body; POST/PUT/PATCH and streaming requests\n * never get retried after a child has had a chance to consume them.\n */\n mount(options: MountOptions<EnvOf<Ctx>>): 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx & ContextExtensionOf<ReturnType<H>>, HookOutput | StatusResponseOf<Awaited<ReturnType<H>>>>;\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 /**\n * Register a dedicated authentication stage for subsequent routes.\n *\n * Unlike `derive`, this stage receives a body-blind authentication capsule and is compiled before\n * route validation. Keeping it separate prevents an unrelated derive from accidentally becoming a\n * security gate and lets the route compiler retain a protected fast lane.\n */\n authenticate<Principal>(stage: AuthenticationStage<Principal, EnvOf<Ctx>>): Server<R, Ctx & {\n readonly principal: Principal;\n }, HookOutput>;\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>, HookOutput>;\n /**\n * Run before routing on the raw request. Return a `Response` or a `status()` result to\n * short-circuit, or a replacement `Request` to continue routing with a rewritten method/URL/headers.\n * 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (context: Context & Ctx, next: () => MaybePromise<unknown>) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (result: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (error: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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. In a group, a name the group declares replaces the value its\n * enclosing scopes declared before the group, on the group's routes. 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 /**\n * Apply `all()` or `method()` from `@nifrajs/core/methods`: one handler registered under several\n * methods, or under a method outside the standard seven. The standard methods join the registry.\n *\n * Declared first on purpose. The plugin's handler is typed against this app's context, which\n * TypeScript reads from the first overload it tries.\n */\n use<M extends string, Path extends string, S extends RouteSchema, Output>(plugin: MethodRoutesPlugin<M, Path, S, Output, Ctx>): Server<WithMethodRoutes<R, M, Path, S, Output, HookOutput>, Ctx, HookOutput>;\n /** Enable the opt-in portable response observer methods. */\n use(plugin: ResponseObserverPlugin): this & ResponseObserverMethods;\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, HookOutput>;\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<AddedHookOutput = never>(plugin: IdentityPlugin<AddedHookOutput>): Server<R, Ctx, HookOutput | AddedHookOutput>;\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), however it was configured,\n * so a plugin meant to stack - a second, stricter guard - needs a name of its own per instance.\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<M extends Middleware>(mw: M): Server<R, Ctx, HookOutput | MiddlewareOutputOf<M>>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\n /**\n * Register a **typed SSE route** - an endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. It is a GET route, or a POST route when the schema\n * declares a `body` (a GET carries none): the body validates as on any POST, and the client sends\n * it with `.subscribe(onEvent, { body })` - the shape of a chat stream that posts its prompt. 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`, `maxBufferedBytes`,\n * extra headers). The connection closes when the handler resolves, `stream.close()` runs, or the\n * client disconnects (`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, SseMethodOf<S>, Path, RouteInfoFor<Path, S, Response, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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, HookOutput>;\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, HookOutput>;\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 handshake runs the chain an HTTP `GET` registered here would: the\n * `authenticate()` stages, `derive`s and `beforeHandle`s added before this call, then the optional\n * `handler.upgrade(c)`. Any of them may reject (a `Response`, a `status(...)`, a failed auth stage);\n * `upgrade()` may seed per-connection `ws.data`. To keep a socket public, register it before the\n * guard. 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, Ctx>): string extends Path ? Server<R, Ctx, HookOutput> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx, HookOutput>;\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: string, 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 *\n * A path ending in optional parameters (`/users/:id?`) is one catalog route per concrete pattern,\n * so reflection, OpenAPI, evidence and the typed client all see ordinary routes. */\n registerBatch(routes: readonly {\n readonly method: string;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n /** Join a group scope's prefix BEFORE compilation, so the pattern, the reflected descriptor, the\n * capability guard, the ledger record, and assurance path matching all see the one served path. */\n private prefixed;\n private prepareRoute;\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 `notFound()` plugin. Off the public typed surface. */\n [INSTALL_NOT_FOUND](lane: NotFoundLane): 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 An adapter reports a failure no response hook saw (a hook that threw past `fetch`, a\n * response the runtime refused to write), logged as Bun's `listen()` logs one. */\n [REPORT_ERROR](error: unknown): 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 * @internal The runtime Bun serves this app's WebSocket upgrades with, asked by `listen()` and by a\n * parent that mounts this app: `undefined` while nothing here can take one, `null` when something\n * can but no runtime is at hand. A mounted Nifra app answers through this same seam, so mounting an\n * app without a WebSocket route needs no runtime; a resolver without the seam cannot say, so it\n * counts. `seen` ends a mount cycle (an app mounted under itself to alias a prefix).\n */\n [GET_WS_RUNTIME](seen?: Set<unknown>): WsRuntime | null | undefined;\n /** The `[GET_WS_RUNTIME]` answer for the apps mounted here alone, whatever this app's own routes. */\n private mountedWsRuntime;\n /** Whether an app mounted here takes WebSocket upgrades. Worked out again only after a `ws()` or a\n * `mount()` somewhere, so the upgrade check on a plain request costs one comparison. */\n private mountsTakeUpgrades;\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, and for an `OPTIONS` preflight to a path they serve (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 or mounts is refused\n * (register those on the parent).\n *\n * What this server's `.use()`, made BEFORE the merge, covers on a merged route versus a\n * `group()` route:\n *\n * | installed on this server | group() route | merge()d route |\n * | ------------------------------------------ | ------------- | ------------------------------ |\n * | derive/decorate/beforeHandle/afterHandle, | yes | no - wire it on the merged |\n * | onError/around, authenticate, route-scoped | | server |\n * | assurance | | |\n * | onRequest/onResponse/responseHeaders hooks | yes | yes (app-wide) |\n * | responseContract() | yes | yes, when the route declares a |\n * | | | response and its own server |\n * | | | installed no contract |\n * | effectLedger() | yes | yes, when the route declares |\n * | | | capabilities and has no ledger |\n * | idempotency() | yes | the merged server's own; a |\n * | | | route declaring it without one |\n * | | | is refused at registration |\n *\n * The response contract and the ledger can only add a check or a record, so a merged route is\n * recompiled under them. A runtime installed AFTER the merge covers neither kind of route.\n */\n merge<R2 extends Registry, Ctx2, HookOutput2>(other: Server<R2, Ctx2, HookOutput2>): Server<R & R2, Ctx, HookOutput>;\n /**\n * Declare routes under a static path prefix, with the prefix in the typed client, `routes()`,\n * OpenAPI, capability events, and the effect ledger - the counterpart of Hono's `route()`,\n * Elysia's `group()`, and Fastify's `register({ prefix })`.\n *\n * app\n * .derive(session)\n * .group(\"/admin\", (admin) =>\n * admin.beforeHandle(requireAdmin).get(\"/users\", listUsers).get(\"/users/:id\", getUser),\n * )\n * .get(\"/\", home) // not covered by requireAdmin\n *\n * The builder receives a scope that INHERITS this server's route chain as it stands at the call\n * (`derive`/`decorate`/`authenticate`/`beforeHandle`/`afterHandle`/`onError`/`around`, assurance,\n * capability interceptors, installed runtimes, applied plugins), exactly as a route declared here\n * would. {@link merge} documents how that differs for a merged server. A plugin this server already applied is in effect for the group: the group's `use()` of\n * that same instance does nothing, and its `use()` of another instance under the same name throws a\n * `RouteConfigError` (`PLUGIN_RECONFIGURED`), because that instance could never replace the parent's.\n * A plugin the group applies still shares the parent's copy of a dependency it `use()`s itself.\n * What it adds stays in the group: its chain additions apply only to its own routes, and its\n * request/response hooks (`onRequest`, `onResponse`, `responseHeaders`, `onResponseFinalized`, and\n * middleware bundles that use them) run only for requests whose path is the prefix or below it.\n * Per-route authorization belongs in `authenticate`/`beforeHandle`, which are compiled into each\n * route; request hooks are path prefilters.\n *\n * The prefix is static text - `\"/api\"`, `\"/api/v1\"` - validated when declared: no params,\n * wildcards, empty or dot segments, percent-escapes, or trailing slash. A group's `\"/\"` route\n * serves the prefix itself. Groups nest (`\"/api\"` then `\"/v1\"` serves `/api/v1/...`).\n *\n * Fail closed: the builder must synchronously return the scope it was given; a collision with an\n * existing route throws `RouteConfigError` and adds none of the group's routes; `.ws()`, mounts,\n * MCP `.tool()`s, and `merge()` inside a group are refused (register them on the parent). Once the\n * builder returns, the scope is closed - a leaked reference cannot add routes later.\n */\n group<const P extends string, R2 extends Registry, Ctx2, HookOutput2>(prefix: P, build: (group: Server<EmptyRegistry, Ctx, HookOutput>) => Server<R2, Ctx2, HookOutput2>): Server<R & PrefixRegistry<P, R2>, Ctx, HookOutput>;\n /**\n * Take over another server's routes and hooks - the shared core of {@link merge} and {@link group}.\n * `prefix` selects group semantics: hooks are scoped to requests under the prefix (response hooks\n * included), and the source's global assurance past `inheritedGlobal` (what it copied from this\n * server) is folded into its routes. Without a prefix, merge semantics: request hooks are scoped to\n * the source's routes when it has any, response hooks are appended app-wide.\n */\n private adopt;\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 private firstMountUnder;\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 private runWebSocketRequestHooks;\n private continueWebSocketRequestHooks;\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 trustedPlatform;\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 compiled route program, 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 same error boundary as the compiled route program (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 the compiled route program'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 /** A fused Web lane's render in an async continuation, where a result that cannot be rendered\n * must fail like a handler throw; a synchronous render throw reaches {@link runMatchedLanes}. */\n private respondFused;\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 /**\n * Compile a route's `derive + before` lifecycle to a single closure: the per-request walk through\n * `runSync` → `runHooksSync` is a stack of 3 frames and 2 `Object.assign`s for what is by far the\n * most common middleware shape (auth/trace/id derivation, an auth/policy `beforeHandle`). Folding\n * the same steps into one closure hits the same monomorphic inline-cache site as `buildFusedWeb`,\n * and `Object.assign(ctx, deriveResult)` becomes one extra property write on the context's already\n * hot hidden class. Behavior is byte-identical to the compiled route program: the same thrown-value\n * contract (`Response` is control flow, anything else logs + 500), the same `c.set` semantics, the\n * same `fusedRespond` for the rendered body. The `LifecycleExecutionLane` guarantee\n * (`schema.params === undefined && schema.headers === undefined && derives === 1 &&\n * beforeHandle === 1 && afterHandle === 0 && onError === 0 && !hasResponseContract &&\n * !hasDecorations`) is enforced by `selectRouteLanes`; this lane is selected ONLY when all of those\n * hold. A `query` schema (the route declares `{ query }` alongside the hooks) is validated FIRST,\n * mirroring the compiled route program's stage order; the fused builder runs validate → derive →\n * before → handler in one frame.\n */\n private buildFusedDeriveBefore;\n private buildFusedDeriveBeforeAfter;\n /**\n * Body + lifecycle hooks fused: parse → validate → derive → before → handler → (after) in one\n * closure, the same win `buildFusedBodyRunner` gives for the no-hooks body shape. The shape is\n * `lifecycleHookLane` PLUS a body schema with no other validation conflicts; the lane is selected\n * ONLY when `schema.body !== undefined && schema.query/params/headers === undefined &&\n * schema.onValidationError === undefined && !defaultOnValidationError && !hasIdempotency &&\n * !hasLedger && derives === 1 && beforeHandle === 1 && afterHandle <= 1 && onError === 0 &&\n * !hasResponseContract && !hasDecorations && around === 0`. The same single `querySchema === undefined`\n * trick used in the no-body lane lets the build path stay simple: a query + body route falls back\n * to the generic program (this is rare in practice - validated query + validated body is usually a\n * \"search results\" route with a middleware chain on top, and the generic lane is fine there).\n */\n private buildFusedBodyDeriveBeforeAfter;\n /**\n * Generic (finalize/wrapResponse-parameterized) fused runner for the derive-before(-after) lane:\n * the Node-direct counterpart of `buildFusedDeriveBefore` / `buildFusedDeriveBeforeAfter`.\n *\n * The Web fused builders above return a `Response`, so the Node dispatcher (`webFast === false`)\n * cannot use them and a derive+before route falls back to the generic route program there - two\n * staged loops, per-stage dispatch, and the async-continuation machinery - while Bun rides the\n * single closure. That asymmetry is the realistic-route Node deficit against Fastify: this runner\n * closes it by running validate → derive → before → handler → (after) in one frame and finalizing\n * through the caller's own `finalize` (the Node outcome on the direct lane, `toResponse` on Web),\n * so the same registration feeds both runtimes with no per-lane copy of the lifecycle to drift.\n *\n * Semantics mirror the generic program stage-for-stage for the shapes this lane admits (exactly\n * one derive, one beforeHandle, zero-or-one afterHandle, no onError/around/decorations/contracts/\n * recovery hooks - enforced by `selectRouteLanes`): thrown `Response`/`status(...)` are control\n * flow through `wrapResponse`/`finalize`, anything else logs + 500s via the shared `bareError`\n * lane (identical to `handleLifecycleError` with no `onError` hooks), and a terminal `finalize`\n * throw (e.g. an unstringifiable handler return on the Node lane) is caught exactly as\n * `finishLifecycleContract` catches it. Step functions close over registration state only and take\n * the request state as arguments, so the hot path allocates no per-request closures.\n */\n private buildFusedDeriveBeforeRunner;\n /**\n * Generic fused runner for the body+derive-before(-after) lane: the Node-direct counterpart of\n * `buildFusedBodyDeriveBeforeAfter`. Same contract as `buildFusedDeriveBeforeRunner` above - one\n * frame running parse → validate → derive → before → handler → (after) through the caller's own\n * `finalize` - with the body read ahead of validation, exactly as the generic program orders its\n * body stage before the derive/before stages. `readBodyFramed` keeps the shared bounded-read,\n * content-type, and prototype-poisoning contracts; the 415/400 renders take `wrapResponse`\n * directly, which is what the generic lane's wrap-after-identity amounts to.\n */\n private buildFusedBodyDeriveBeforeAfterRunner;\n private bareError;\n /**\n * Keep the ordinary thrown-error response independent from the caught value. Deliberate Response\n * control flow is handled by `renderBareError`; every other throw gets this fixed public envelope.\n */\n private internalErrorResponse;\n private runWithAround;\n /** Execute the registration-compiled general stage program. */\n private runProgram;\n /** Bind a compiled validation stage to its stable schema and the existing recovery contract. */\n private validateProgramStage;\n /** Preserve the existing bounded body reader and its fail-closed framing/prototype checks. */\n private readProgramBody;\n /** Keep thrown Response/status and redacted 500 semantics in one existing error boundary. */\n private handleProgramError;\n /** Finish a successful program result through response-contract enforcement and finalization. */\n private finishProgramResult;\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 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 the compiled route program 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 /** 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.\n *\n * Bun and the portable router agree on which of two static-and-`:param` paths wins a request, so\n * the table is kept to those paths. Where Bun would otherwise pass a request on to a less specific\n * path, the more specific one carries `fallback`, the portable dispatcher, under that method.\n * `peer` is the platform every request served from the table shares. */\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 * `tls` serves HTTPS directly: `app.listen(443, { tls: { cert, key } })` with PEM text or bytes.\n * Requests then arrive with `https:` URLs. Behind a proxy or a platform that terminates TLS, leave\n * it unset.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n readonly tls?: ListenTlsOptions;\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}",
13798
13846
  "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 */"
13799
13847
  },
13800
13848
  {
13801
13849
  "name": "Server",
13802
13850
  "kind": "class",
13803
13851
  "package": "nifra",
13804
- "signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext, HookOutput = never> {\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 /** Each socket path, its declared capabilities, the evidence declarations its handshake captured\n * and the chain it runs; reflection reads it. */\n private readonly wsRoutes;\n /** `wsChanges` when `wsMountsLive` was last worked out; -1 until then. */\n private wsMountsCheckedAt;\n /** Whether an app mounted here takes WebSocket upgrades, as of `wsMountsCheckedAt`. */\n private wsMountsLive;\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 /** True once any `app.ws()` route sets `validateSend: true` - the one case where a broadcast frame\n * is validated (and possibly dropped) per socket, so `app.publish` must stay on the JS registry loop\n * rather than delegate to Bun's native `server.publish`. */\n private wsHasValidatedSend;\n /** Bun's native topic broadcast, bound by `listen()` in native-pubsub mode; `app.publish` uses it\n * instead of the JS registry. `undefined` off Bun, before `listen()`, with a validated-send route,\n * or when a mounted app takes upgrades. */\n private nativePublish;\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 private readonly wsUpgradeTimeoutMs;\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 private mountOrder;\n /** Number of composed mounts that must run before the parent route table. Keeps legacy mounts off the hot path. */\n private preRouteMountCount;\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 answer for a request no route matched; `undefined` (the plain 404) until `.use(notFound())`. */\n private notFoundLane;\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 /** Dedicated authentication stages captured by subsequent routes. */\n private readonly authStages;\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 /** True when every request hook is safe to skip on a Bun native route. */\n private bunNativeRequestHooksSafe;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /** True when every response hook only mutates headers and can run after a Bun fused response. */\n private bunNativeResponseHeadersOnly;\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 /** A group's view of the static headers its enclosing scopes declared before it was created. */\n private inheritedStatics;\n /** A group's view of the plugins its enclosing scopes applied before it was created; unset while\n * a plugin applies, so its own dependency `use()` shares the parent's copy. */\n private inheritedPlugins;\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 /** A request the WebSocket handshake check ran the onRequest hooks on and then passed to HTTP →\n * what the hooks returned, so `fetch` routes that instead of running the hooks a second time. */\n private wsHookedPasses;\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 /** Plugins/middleware already applied via `use`, by name - 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 /** Kept so a {@link group} scope is built with exactly this server's settings: fused lanes read\n * several of them at request time, so a group route must never run under different ones. */\n private readonly options;\n /** Static prefix joined onto every route this server registers; non-empty only on a group scope. */\n private routePrefix;\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 * Compose a child fetch app under a literal path prefix.\n *\n * Composed mounts run after the app-global request phase and before the parent's route table. This\n * makes them safe to use in an SSR shell whose `/*` page route would otherwise swallow an API mount.\n * If the child exposes `resolveWebSocketUpgrade`, the same mount also participates in adapter-owned\n * WebSocket upgrades; the serving adapter still upgrades its original socket, while the child sees\n * the mounted request path (stripped when requested).\n *\n * `fallbackOn: 404` is deliberately limited to GET/HEAD/OPTIONS at dispatch time. Those methods are\n * replayable without buffering an untrusted request body; POST/PUT/PATCH and streaming requests\n * never get retried after a child has had a chance to consume them.\n */\n mount(options: MountOptions<EnvOf<Ctx>>): 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx & ContextExtensionOf<ReturnType<H>>, HookOutput | StatusResponseOf<Awaited<ReturnType<H>>>>;\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 /**\n * Register a dedicated authentication stage for subsequent routes.\n *\n * Unlike `derive`, this stage receives a body-blind authentication capsule and is compiled before\n * route validation. Keeping it separate prevents an unrelated derive from accidentally becoming a\n * security gate and lets the route compiler retain a protected fast lane.\n */\n authenticate<Principal>(stage: AuthenticationStage<Principal, EnvOf<Ctx>>): Server<R, Ctx & {\n readonly principal: Principal;\n }, HookOutput>;\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>, HookOutput>;\n /**\n * Run before routing on the raw request. Return a `Response` or a `status()` result to\n * short-circuit, or a replacement `Request` to continue routing with a rewritten method/URL/headers.\n * 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (context: Context & Ctx, next: () => MaybePromise<unknown>) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (result: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (error: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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. In a group, a name the group declares replaces the value its\n * enclosing scopes declared before the group, on the group's routes. 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 /**\n * Apply `all()` or `method()` from `@nifrajs/core/methods`: one handler registered under several\n * methods, or under a method outside the standard seven. The standard methods join the registry.\n *\n * Declared first on purpose. The plugin's handler is typed against this app's context, which\n * TypeScript reads from the first overload it tries.\n */\n use<M extends string, Path extends string, S extends RouteSchema, Output>(plugin: MethodRoutesPlugin<M, Path, S, Output, Ctx>): Server<WithMethodRoutes<R, M, Path, S, Output, HookOutput>, Ctx, HookOutput>;\n /** Enable the opt-in portable response observer methods. */\n use(plugin: ResponseObserverPlugin): this & ResponseObserverMethods;\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, HookOutput>;\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<AddedHookOutput = never>(plugin: IdentityPlugin<AddedHookOutput>): Server<R, Ctx, HookOutput | AddedHookOutput>;\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), however it was configured,\n * so a plugin meant to stack - a second, stricter guard - needs a name of its own per instance.\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<M extends Middleware>(mw: M): Server<R, Ctx, HookOutput | MiddlewareOutputOf<M>>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\n /**\n * Register a **typed SSE route** - an endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. It is a GET route, or a POST route when the schema\n * declares a `body` (a GET carries none): the body validates as on any POST, and the client sends\n * it with `.subscribe(onEvent, { body })` - the shape of a chat stream that posts its prompt. 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`, `maxBufferedBytes`,\n * extra headers). The connection closes when the handler resolves, `stream.close()` runs, or the\n * client disconnects (`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, SseMethodOf<S>, Path, RouteInfoFor<Path, S, Response, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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, HookOutput>;\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, HookOutput>;\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 handshake runs the chain an HTTP `GET` registered here would: the\n * `authenticate()` stages, `derive`s and `beforeHandle`s added before this call, then the optional\n * `handler.upgrade(c)`. Any of them may reject (a `Response`, a `status(...)`, a failed auth stage);\n * `upgrade()` may seed per-connection `ws.data`. To keep a socket public, register it before the\n * guard. 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, Ctx>): string extends Path ? Server<R, Ctx, HookOutput> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx, HookOutput>;\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: string, 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 *\n * A path ending in optional parameters (`/users/:id?`) is one catalog route per concrete pattern,\n * so reflection, OpenAPI, evidence and the typed client all see ordinary routes. */\n registerBatch(routes: readonly {\n readonly method: string;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n /** Join a group scope's prefix BEFORE compilation, so the pattern, the reflected descriptor, the\n * capability guard, the ledger record, and assurance path matching all see the one served path. */\n private prefixed;\n private prepareRoute;\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 `notFound()` plugin. Off the public typed surface. */\n [INSTALL_NOT_FOUND](lane: NotFoundLane): 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 An adapter reports a failure no response hook saw (a hook that threw past `fetch`, a\n * response the runtime refused to write), logged as Bun's `listen()` logs one. */\n [REPORT_ERROR](error: unknown): 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 * @internal The runtime Bun serves this app's WebSocket upgrades with, asked by `listen()` and by a\n * parent that mounts this app: `undefined` while nothing here can take one, `null` when something\n * can but no runtime is at hand. A mounted Nifra app answers through this same seam, so mounting an\n * app without a WebSocket route needs no runtime; a resolver without the seam cannot say, so it\n * counts. `seen` ends a mount cycle (an app mounted under itself to alias a prefix).\n */\n [GET_WS_RUNTIME](seen?: Set<unknown>): WsRuntime | null | undefined;\n /** The `[GET_WS_RUNTIME]` answer for the apps mounted here alone, whatever this app's own routes. */\n private mountedWsRuntime;\n /** Whether an app mounted here takes WebSocket upgrades. Worked out again only after a `ws()` or a\n * `mount()` somewhere, so the upgrade check on a plain request costs one comparison. */\n private mountsTakeUpgrades;\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, and for an `OPTIONS` preflight to a path they serve (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 or mounts is refused\n * (register those on the parent).\n */\n merge<R2 extends Registry, Ctx2, HookOutput2>(other: Server<R2, Ctx2, HookOutput2>): Server<R & R2, Ctx, HookOutput>;\n /**\n * Declare routes under a static path prefix, with the prefix in the typed client, `routes()`,\n * OpenAPI, capability events, and the effect ledger - the counterpart of Hono's `route()`,\n * Elysia's `group()`, and Fastify's `register({ prefix })`.\n *\n * app\n * .derive(session)\n * .group(\"/admin\", (admin) =>\n * admin.beforeHandle(requireAdmin).get(\"/users\", listUsers).get(\"/users/:id\", getUser),\n * )\n * .get(\"/\", home) // not covered by requireAdmin\n *\n * The builder receives a scope that INHERITS this server's route chain as it stands at the call\n * (`derive`/`decorate`/`authenticate`/`beforeHandle`/`afterHandle`/`onError`/`around`, assurance,\n * capability interceptors, installed runtimes, applied plugins), exactly as a route declared here\n * would. A plugin this server already applied is in effect for the group: the group's `use()` of\n * that same instance does nothing, and its `use()` of another instance under the same name throws a\n * `RouteConfigError` (`PLUGIN_RECONFIGURED`), because that instance could never replace the parent's.\n * A plugin the group applies still shares the parent's copy of a dependency it `use()`s itself.\n * What it adds stays in the group: its chain additions apply only to its own routes, and its\n * request/response hooks (`onRequest`, `onResponse`, `responseHeaders`, `onResponseFinalized`, and\n * middleware bundles that use them) run only for requests whose path is the prefix or below it.\n * Per-route authorization belongs in `authenticate`/`beforeHandle`, which are compiled into each\n * route; request hooks are path prefilters.\n *\n * The prefix is static text - `\"/api\"`, `\"/api/v1\"` - validated when declared: no params,\n * wildcards, empty or dot segments, percent-escapes, or trailing slash. A group's `\"/\"` route\n * serves the prefix itself. Groups nest (`\"/api\"` then `\"/v1\"` serves `/api/v1/...`).\n *\n * Fail closed: the builder must synchronously return the scope it was given; a collision with an\n * existing route throws `RouteConfigError` and adds none of the group's routes; `.ws()`, mounts,\n * MCP `.tool()`s, and `merge()` inside a group are refused (register them on the parent). Once the\n * builder returns, the scope is closed - a leaked reference cannot add routes later.\n */\n group<const P extends string, R2 extends Registry, Ctx2, HookOutput2>(prefix: P, build: (group: Server<EmptyRegistry, Ctx, HookOutput>) => Server<R2, Ctx2, HookOutput2>): Server<R & PrefixRegistry<P, R2>, Ctx, HookOutput>;\n /**\n * Take over another server's routes and hooks - the shared core of {@link merge} and {@link group}.\n * `prefix` selects group semantics: hooks are scoped to requests under the prefix (response hooks\n * included), and the source's global assurance past `inheritedGlobal` (what it copied from this\n * server) is folded into its routes. Without a prefix, merge semantics: request hooks are scoped to\n * the source's routes when it has any, response hooks are appended app-wide.\n */\n private adopt;\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 private firstMountUnder;\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 private runWebSocketRequestHooks;\n private continueWebSocketRequestHooks;\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 trustedPlatform;\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 compiled route program, 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 same error boundary as the compiled route program (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 the compiled route program'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 /** A fused Web lane's render in an async continuation, where a result that cannot be rendered\n * must fail like a handler throw; a synchronous render throw reaches {@link runMatchedLanes}. */\n private respondFused;\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 /**\n * Compile a route's `derive + before` lifecycle to a single closure: the per-request walk through\n * `runSync` → `runHooksSync` is a stack of 3 frames and 2 `Object.assign`s for what is by far the\n * most common middleware shape (auth/trace/id derivation, an auth/policy `beforeHandle`). Folding\n * the same steps into one closure hits the same monomorphic inline-cache site as `buildFusedWeb`,\n * and `Object.assign(ctx, deriveResult)` becomes one extra property write on the context's already\n * hot hidden class. Behavior is byte-identical to the compiled route program: the same thrown-value\n * contract (`Response` is control flow, anything else logs + 500), the same `c.set` semantics, the\n * same `fusedRespond` for the rendered body. The `LifecycleExecutionLane` guarantee\n * (`schema.params === undefined && schema.headers === undefined && derives === 1 &&\n * beforeHandle === 1 && afterHandle === 0 && onError === 0 && !hasResponseContract &&\n * !hasDecorations`) is enforced by `selectRouteLanes`; this lane is selected ONLY when all of those\n * hold. A `query` schema (the route declares `{ query }` alongside the hooks) is validated FIRST,\n * mirroring the compiled route program's stage order; the fused builder runs validate → derive →\n * before → handler in one frame.\n */\n private buildFusedDeriveBefore;\n private buildFusedDeriveBeforeAfter;\n /**\n * Body + lifecycle hooks fused: parse → validate → derive → before → handler → (after) in one\n * closure, the same win `buildFusedBodyRunner` gives for the no-hooks body shape. The shape is\n * `lifecycleHookLane` PLUS a body schema with no other validation conflicts; the lane is selected\n * ONLY when `schema.body !== undefined && schema.query/params/headers === undefined &&\n * schema.onValidationError === undefined && !defaultOnValidationError && !hasIdempotency &&\n * !hasLedger && derives === 1 && beforeHandle === 1 && afterHandle <= 1 && onError === 0 &&\n * !hasResponseContract && !hasDecorations && around === 0`. The same single `querySchema === undefined`\n * trick used in the no-body lane lets the build path stay simple: a query + body route falls back\n * to the generic program (this is rare in practice - validated query + validated body is usually a\n * \"search results\" route with a middleware chain on top, and the generic lane is fine there).\n */\n private buildFusedBodyDeriveBeforeAfter;\n /**\n * Generic (finalize/wrapResponse-parameterized) fused runner for the derive-before(-after) lane:\n * the Node-direct counterpart of `buildFusedDeriveBefore` / `buildFusedDeriveBeforeAfter`.\n *\n * The Web fused builders above return a `Response`, so the Node dispatcher (`webFast === false`)\n * cannot use them and a derive+before route falls back to the generic route program there - two\n * staged loops, per-stage dispatch, and the async-continuation machinery - while Bun rides the\n * single closure. That asymmetry is the realistic-route Node deficit against Fastify: this runner\n * closes it by running validate → derive → before → handler → (after) in one frame and finalizing\n * through the caller's own `finalize` (the Node outcome on the direct lane, `toResponse` on Web),\n * so the same registration feeds both runtimes with no per-lane copy of the lifecycle to drift.\n *\n * Semantics mirror the generic program stage-for-stage for the shapes this lane admits (exactly\n * one derive, one beforeHandle, zero-or-one afterHandle, no onError/around/decorations/contracts/\n * recovery hooks - enforced by `selectRouteLanes`): thrown `Response`/`status(...)` are control\n * flow through `wrapResponse`/`finalize`, anything else logs + 500s via the shared `bareError`\n * lane (identical to `handleLifecycleError` with no `onError` hooks), and a terminal `finalize`\n * throw (e.g. an unstringifiable handler return on the Node lane) is caught exactly as\n * `finishLifecycleContract` catches it. Step functions close over registration state only and take\n * the request state as arguments, so the hot path allocates no per-request closures.\n */\n private buildFusedDeriveBeforeRunner;\n /**\n * Generic fused runner for the body+derive-before(-after) lane: the Node-direct counterpart of\n * `buildFusedBodyDeriveBeforeAfter`. Same contract as `buildFusedDeriveBeforeRunner` above - one\n * frame running parse → validate → derive → before → handler → (after) through the caller's own\n * `finalize` - with the body read ahead of validation, exactly as the generic program orders its\n * body stage before the derive/before stages. `readBodyFramed` keeps the shared bounded-read,\n * content-type, and prototype-poisoning contracts; the 415/400 renders take `wrapResponse`\n * directly, which is what the generic lane's wrap-after-identity amounts to.\n */\n private buildFusedBodyDeriveBeforeAfterRunner;\n private bareError;\n /**\n * Keep the ordinary thrown-error response independent from the caught value. Deliberate Response\n * control flow is handled by `renderBareError`; every other throw gets this fixed public envelope.\n */\n private internalErrorResponse;\n private runWithAround;\n /** Execute the registration-compiled general stage program. */\n private runProgram;\n /** Bind a compiled validation stage to its stable schema and the existing recovery contract. */\n private validateProgramStage;\n /** Preserve the existing bounded body reader and its fail-closed framing/prototype checks. */\n private readProgramBody;\n /** Keep thrown Response/status and redacted 500 semantics in one existing error boundary. */\n private handleProgramError;\n /** Finish a successful program result through response-contract enforcement and finalization. */\n private finishProgramResult;\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 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 the compiled route program 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 /** 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.\n *\n * Bun and the portable router agree on which of two static-and-`:param` paths wins a request, so\n * the table is kept to those paths. Where Bun would otherwise pass a request on to a less specific\n * path, the more specific one carries `fallback`, the portable dispatcher, under that method.\n * `peer` is the platform every request served from the table shares. */\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 * `tls` serves HTTPS directly: `app.listen(443, { tls: { cert, key } })` with PEM text or bytes.\n * Requests then arrive with `https:` URLs. Behind a proxy or a platform that terminates TLS, leave\n * it unset.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n readonly tls?: ListenTlsOptions;\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}",
13852
+ "signature": "export declare class Server<R extends Registry = EmptyRegistry, Ctx = EmptyContext, HookOutput = never> {\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 /** Each socket path, its declared capabilities, the evidence declarations its handshake captured\n * and the chain it runs; reflection reads it. */\n private readonly wsRoutes;\n /** `wsChanges` when `wsMountsLive` was last worked out; -1 until then. */\n private wsMountsCheckedAt;\n /** Whether an app mounted here takes WebSocket upgrades, as of `wsMountsCheckedAt`. */\n private wsMountsLive;\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 /** True once any `app.ws()` route sets `validateSend: true` - the one case where a broadcast frame\n * is validated (and possibly dropped) per socket, so `app.publish` must stay on the JS registry loop\n * rather than delegate to Bun's native `server.publish`. */\n private wsHasValidatedSend;\n /** Bun's native topic broadcast, bound by `listen()` in native-pubsub mode; `app.publish` uses it\n * instead of the JS registry. `undefined` off Bun, before `listen()`, with a validated-send route,\n * or when a mounted app takes upgrades. */\n private nativePublish;\n private readonly maxBodyBytes;\n private readonly protoPoisoning;\n private readonly formOrigins;\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 private readonly wsUpgradeTimeoutMs;\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 private mountOrder;\n /** Number of composed mounts that must run before the parent route table. Keeps legacy mounts off the hot path. */\n private preRouteMountCount;\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 answer for a request no route matched; `undefined` (the plain 404) until `.use(notFound())`. */\n private notFoundLane;\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 /** Dedicated authentication stages captured by subsequent routes. */\n private readonly authStages;\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 /** True when every request hook is safe to skip on a Bun native route. */\n private bunNativeRequestHooksSafe;\n private readonly onResponseHooks;\n private readonly onNodeResponseHooks;\n /** Registration-time eligibility for the Node response twin lane. */\n private nodeResponseHooksComplete;\n /** True when every response hook only mutates headers and can run after a Bun fused response. */\n private bunNativeResponseHeadersOnly;\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 /** A group's view of the static headers its enclosing scopes declared before it was created. */\n private inheritedStatics;\n /** A group's view of the plugins its enclosing scopes applied before it was created; unset while\n * a plugin applies, so its own dependency `use()` shares the parent's copy. */\n private inheritedPlugins;\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 /** A request the WebSocket handshake check ran the onRequest hooks on and then passed to HTTP →\n * what the hooks returned, so `fetch` routes that instead of running the hooks a second time. */\n private wsHookedPasses;\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 /** Plugins/middleware already applied via `use`, by name - 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 /** Kept so a {@link group} scope is built with exactly this server's settings: fused lanes read\n * several of them at request time, so a group route must never run under different ones. */\n private readonly options;\n /** Static prefix joined onto every route this server registers; non-empty only on a group scope. */\n private routePrefix;\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 * Compose a child fetch app under a literal path prefix.\n *\n * Composed mounts run after the app-global request phase and before the parent's route table. This\n * makes them safe to use in an SSR shell whose `/*` page route would otherwise swallow an API mount.\n * If the child exposes `resolveWebSocketUpgrade`, the same mount also participates in adapter-owned\n * WebSocket upgrades; the serving adapter still upgrades its original socket, while the child sees\n * the mounted request path (stripped when requested).\n *\n * `fallbackOn: 404` is deliberately limited to GET/HEAD/OPTIONS at dispatch time. Those methods are\n * replayable without buffering an untrusted request body; POST/PUT/PATCH and streaming requests\n * never get retried after a child has had a chance to consume them.\n */\n mount(options: MountOptions<EnvOf<Ctx>>): 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx & ContextExtensionOf<ReturnType<H>>, HookOutput | StatusResponseOf<Awaited<ReturnType<H>>>>;\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 /**\n * Register a dedicated authentication stage for subsequent routes.\n *\n * Unlike `derive`, this stage receives a body-blind authentication capsule and is compiled before\n * route validation. Keeping it separate prevents an unrelated derive from accidentally becoming a\n * security gate and lets the route compiler retain a protected fast lane.\n */\n authenticate<Principal>(stage: AuthenticationStage<Principal, EnvOf<Ctx>>): Server<R, Ctx & {\n readonly principal: Principal;\n }, HookOutput>;\n decorate<const K extends string, V>(key: K, value: V): Server<R, Ctx & Record<K, V>, HookOutput>;\n /**\n * Run before routing on the raw request. Return a `Response` or a `status()` result to\n * short-circuit, or a replacement `Request` to continue routing with a rewritten method/URL/headers.\n * 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<H extends (context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (context: Context & Ctx, next: () => MaybePromise<unknown>) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (result: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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<H extends (error: unknown, context: Context & Ctx) => MaybePromise<unknown>>(fn: H): Server<R, Ctx, HookOutput | HookOutputOf<ReturnType<H>>>;\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. In a group, a name the group declares replaces the value its\n * enclosing scopes declared before the group, on the group's routes. 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 /**\n * Apply `all()` or `method()` from `@nifrajs/core/methods`: one handler registered under several\n * methods, or under a method outside the standard seven. The standard methods join the registry.\n *\n * Declared first on purpose. The plugin's handler is typed against this app's context, which\n * TypeScript reads from the first overload it tries.\n */\n use<M extends string, Path extends string, S extends RouteSchema, Output>(plugin: MethodRoutesPlugin<M, Path, S, Output, Ctx>): Server<WithMethodRoutes<R, M, Path, S, Output, HookOutput>, Ctx, HookOutput>;\n /** Enable the opt-in portable response observer methods. */\n use(plugin: ResponseObserverPlugin): this & ResponseObserverMethods;\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, HookOutput>;\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<AddedHookOutput = never>(plugin: IdentityPlugin<AddedHookOutput>): Server<R, Ctx, HookOutput | AddedHookOutput>;\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), however it was configured,\n * so a plugin meant to stack - a second, stricter guard - needs a name of its own per instance.\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<M extends Middleware>(mw: M): Server<R, Ctx, HookOutput | MiddlewareOutputOf<M>>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\n /**\n * Register a **typed SSE route** - an endpoint streaming `text/event-stream` whose event\n * payloads are contracted by `schema.sse`. It is a GET route, or a POST route when the schema\n * declares a `body` (a GET carries none): the body validates as on any POST, and the client sends\n * it with `.subscribe(onEvent, { body })` - the shape of a chat stream that posts its prompt. 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`, `maxBufferedBytes`,\n * extra headers). The connection closes when the handler resolves, `stream.close()` runs, or the\n * client disconnects (`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, SseMethodOf<S>, Path, RouteInfoFor<Path, S, Response, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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>, HookOutput>>, Ctx, HookOutput>;\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, HookOutput>;\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, HookOutput>;\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 handshake runs the chain an HTTP `GET` registered here would: the\n * `authenticate()` stages, `derive`s and `beforeHandle`s added before this call, then the optional\n * `handler.upgrade(c)`. Any of them may reject (a `Response`, a `status(...)`, a failed auth stage);\n * `upgrade()` may seed per-connection `ws.data`. To keep a socket public, register it before the\n * guard. 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, Ctx>): string extends Path ? Server<R, Ctx, HookOutput> : Server<AddRoute<R, \"WS\", Path, WsRouteInfoFor<Path, Schema, Send>>, Ctx, HookOutput>;\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: string, 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 *\n * A path ending in optional parameters (`/users/:id?`) is one catalog route per concrete pattern,\n * so reflection, OpenAPI, evidence and the typed client all see ordinary routes. */\n registerBatch(routes: readonly {\n readonly method: string;\n readonly path: string;\n readonly schema: RouteSchema | undefined;\n readonly handler: (context: never) => unknown;\n }[]): void;\n /** Join a group scope's prefix BEFORE compilation, so the pattern, the reflected descriptor, the\n * capability guard, the ledger record, and assurance path matching all see the one served path. */\n private prefixed;\n private prepareRoute;\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 `notFound()` plugin. Off the public typed surface. */\n [INSTALL_NOT_FOUND](lane: NotFoundLane): 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 An adapter reports a failure no response hook saw (a hook that threw past `fetch`, a\n * response the runtime refused to write), logged as Bun's `listen()` logs one. */\n [REPORT_ERROR](error: unknown): 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 * @internal The runtime Bun serves this app's WebSocket upgrades with, asked by `listen()` and by a\n * parent that mounts this app: `undefined` while nothing here can take one, `null` when something\n * can but no runtime is at hand. A mounted Nifra app answers through this same seam, so mounting an\n * app without a WebSocket route needs no runtime; a resolver without the seam cannot say, so it\n * counts. `seen` ends a mount cycle (an app mounted under itself to alias a prefix).\n */\n [GET_WS_RUNTIME](seen?: Set<unknown>): WsRuntime | null | undefined;\n /** The `[GET_WS_RUNTIME]` answer for the apps mounted here alone, whatever this app's own routes. */\n private mountedWsRuntime;\n /** Whether an app mounted here takes WebSocket upgrades. Worked out again only after a `ws()` or a\n * `mount()` somewhere, so the upgrade check on a plain request costs one comparison. */\n private mountsTakeUpgrades;\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, and for an `OPTIONS` preflight to a path they serve (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 or mounts is refused\n * (register those on the parent).\n *\n * What this server's `.use()`, made BEFORE the merge, covers on a merged route versus a\n * `group()` route:\n *\n * | installed on this server | group() route | merge()d route |\n * | ------------------------------------------ | ------------- | ------------------------------ |\n * | derive/decorate/beforeHandle/afterHandle, | yes | no - wire it on the merged |\n * | onError/around, authenticate, route-scoped | | server |\n * | assurance | | |\n * | onRequest/onResponse/responseHeaders hooks | yes | yes (app-wide) |\n * | responseContract() | yes | yes, when the route declares a |\n * | | | response and its own server |\n * | | | installed no contract |\n * | effectLedger() | yes | yes, when the route declares |\n * | | | capabilities and has no ledger |\n * | idempotency() | yes | the merged server's own; a |\n * | | | route declaring it without one |\n * | | | is refused at registration |\n *\n * The response contract and the ledger can only add a check or a record, so a merged route is\n * recompiled under them. A runtime installed AFTER the merge covers neither kind of route.\n */\n merge<R2 extends Registry, Ctx2, HookOutput2>(other: Server<R2, Ctx2, HookOutput2>): Server<R & R2, Ctx, HookOutput>;\n /**\n * Declare routes under a static path prefix, with the prefix in the typed client, `routes()`,\n * OpenAPI, capability events, and the effect ledger - the counterpart of Hono's `route()`,\n * Elysia's `group()`, and Fastify's `register({ prefix })`.\n *\n * app\n * .derive(session)\n * .group(\"/admin\", (admin) =>\n * admin.beforeHandle(requireAdmin).get(\"/users\", listUsers).get(\"/users/:id\", getUser),\n * )\n * .get(\"/\", home) // not covered by requireAdmin\n *\n * The builder receives a scope that INHERITS this server's route chain as it stands at the call\n * (`derive`/`decorate`/`authenticate`/`beforeHandle`/`afterHandle`/`onError`/`around`, assurance,\n * capability interceptors, installed runtimes, applied plugins), exactly as a route declared here\n * would. {@link merge} documents how that differs for a merged server. A plugin this server already applied is in effect for the group: the group's `use()` of\n * that same instance does nothing, and its `use()` of another instance under the same name throws a\n * `RouteConfigError` (`PLUGIN_RECONFIGURED`), because that instance could never replace the parent's.\n * A plugin the group applies still shares the parent's copy of a dependency it `use()`s itself.\n * What it adds stays in the group: its chain additions apply only to its own routes, and its\n * request/response hooks (`onRequest`, `onResponse`, `responseHeaders`, `onResponseFinalized`, and\n * middleware bundles that use them) run only for requests whose path is the prefix or below it.\n * Per-route authorization belongs in `authenticate`/`beforeHandle`, which are compiled into each\n * route; request hooks are path prefilters.\n *\n * The prefix is static text - `\"/api\"`, `\"/api/v1\"` - validated when declared: no params,\n * wildcards, empty or dot segments, percent-escapes, or trailing slash. A group's `\"/\"` route\n * serves the prefix itself. Groups nest (`\"/api\"` then `\"/v1\"` serves `/api/v1/...`).\n *\n * Fail closed: the builder must synchronously return the scope it was given; a collision with an\n * existing route throws `RouteConfigError` and adds none of the group's routes; `.ws()`, mounts,\n * MCP `.tool()`s, and `merge()` inside a group are refused (register them on the parent). Once the\n * builder returns, the scope is closed - a leaked reference cannot add routes later.\n */\n group<const P extends string, R2 extends Registry, Ctx2, HookOutput2>(prefix: P, build: (group: Server<EmptyRegistry, Ctx, HookOutput>) => Server<R2, Ctx2, HookOutput2>): Server<R & PrefixRegistry<P, R2>, Ctx, HookOutput>;\n /**\n * Take over another server's routes and hooks - the shared core of {@link merge} and {@link group}.\n * `prefix` selects group semantics: hooks are scoped to requests under the prefix (response hooks\n * included), and the source's global assurance past `inheritedGlobal` (what it copied from this\n * server) is folded into its routes. Without a prefix, merge semantics: request hooks are scoped to\n * the source's routes when it has any, response hooks are appended app-wide.\n */\n private adopt;\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 private firstMountUnder;\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 private runWebSocketRequestHooks;\n private continueWebSocketRequestHooks;\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 trustedPlatform;\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 compiled route program, 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 same error boundary as the compiled route program (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 the compiled route program'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 /** A fused Web lane's render in an async continuation, where a result that cannot be rendered\n * must fail like a handler throw; a synchronous render throw reaches {@link runMatchedLanes}. */\n private respondFused;\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 /**\n * Compile a route's `derive + before` lifecycle to a single closure: the per-request walk through\n * `runSync` → `runHooksSync` is a stack of 3 frames and 2 `Object.assign`s for what is by far the\n * most common middleware shape (auth/trace/id derivation, an auth/policy `beforeHandle`). Folding\n * the same steps into one closure hits the same monomorphic inline-cache site as `buildFusedWeb`,\n * and `Object.assign(ctx, deriveResult)` becomes one extra property write on the context's already\n * hot hidden class. Behavior is byte-identical to the compiled route program: the same thrown-value\n * contract (`Response` is control flow, anything else logs + 500), the same `c.set` semantics, the\n * same `fusedRespond` for the rendered body. The `LifecycleExecutionLane` guarantee\n * (`schema.params === undefined && schema.headers === undefined && derives === 1 &&\n * beforeHandle === 1 && afterHandle === 0 && onError === 0 && !hasResponseContract &&\n * !hasDecorations`) is enforced by `selectRouteLanes`; this lane is selected ONLY when all of those\n * hold. A `query` schema (the route declares `{ query }` alongside the hooks) is validated FIRST,\n * mirroring the compiled route program's stage order; the fused builder runs validate → derive →\n * before → handler in one frame.\n */\n private buildFusedDeriveBefore;\n private buildFusedDeriveBeforeAfter;\n /**\n * Body + lifecycle hooks fused: parse → validate → derive → before → handler → (after) in one\n * closure, the same win `buildFusedBodyRunner` gives for the no-hooks body shape. The shape is\n * `lifecycleHookLane` PLUS a body schema with no other validation conflicts; the lane is selected\n * ONLY when `schema.body !== undefined && schema.query/params/headers === undefined &&\n * schema.onValidationError === undefined && !defaultOnValidationError && !hasIdempotency &&\n * !hasLedger && derives === 1 && beforeHandle === 1 && afterHandle <= 1 && onError === 0 &&\n * !hasResponseContract && !hasDecorations && around === 0`. The same single `querySchema === undefined`\n * trick used in the no-body lane lets the build path stay simple: a query + body route falls back\n * to the generic program (this is rare in practice - validated query + validated body is usually a\n * \"search results\" route with a middleware chain on top, and the generic lane is fine there).\n */\n private buildFusedBodyDeriveBeforeAfter;\n /**\n * Generic (finalize/wrapResponse-parameterized) fused runner for the derive-before(-after) lane:\n * the Node-direct counterpart of `buildFusedDeriveBefore` / `buildFusedDeriveBeforeAfter`.\n *\n * The Web fused builders above return a `Response`, so the Node dispatcher (`webFast === false`)\n * cannot use them and a derive+before route falls back to the generic route program there - two\n * staged loops, per-stage dispatch, and the async-continuation machinery - while Bun rides the\n * single closure. That asymmetry is the realistic-route Node deficit against Fastify: this runner\n * closes it by running validate → derive → before → handler → (after) in one frame and finalizing\n * through the caller's own `finalize` (the Node outcome on the direct lane, `toResponse` on Web),\n * so the same registration feeds both runtimes with no per-lane copy of the lifecycle to drift.\n *\n * Semantics mirror the generic program stage-for-stage for the shapes this lane admits (exactly\n * one derive, one beforeHandle, zero-or-one afterHandle, no onError/around/decorations/contracts/\n * recovery hooks - enforced by `selectRouteLanes`): thrown `Response`/`status(...)` are control\n * flow through `wrapResponse`/`finalize`, anything else logs + 500s via the shared `bareError`\n * lane (identical to `handleLifecycleError` with no `onError` hooks), and a terminal `finalize`\n * throw (e.g. an unstringifiable handler return on the Node lane) is caught exactly as\n * `finishLifecycleContract` catches it. Step functions close over registration state only and take\n * the request state as arguments, so the hot path allocates no per-request closures.\n */\n private buildFusedDeriveBeforeRunner;\n /**\n * Generic fused runner for the body+derive-before(-after) lane: the Node-direct counterpart of\n * `buildFusedBodyDeriveBeforeAfter`. Same contract as `buildFusedDeriveBeforeRunner` above - one\n * frame running parse → validate → derive → before → handler → (after) through the caller's own\n * `finalize` - with the body read ahead of validation, exactly as the generic program orders its\n * body stage before the derive/before stages. `readBodyFramed` keeps the shared bounded-read,\n * content-type, and prototype-poisoning contracts; the 415/400 renders take `wrapResponse`\n * directly, which is what the generic lane's wrap-after-identity amounts to.\n */\n private buildFusedBodyDeriveBeforeAfterRunner;\n private bareError;\n /**\n * Keep the ordinary thrown-error response independent from the caught value. Deliberate Response\n * control flow is handled by `renderBareError`; every other throw gets this fixed public envelope.\n */\n private internalErrorResponse;\n private runWithAround;\n /** Execute the registration-compiled general stage program. */\n private runProgram;\n /** Bind a compiled validation stage to its stable schema and the existing recovery contract. */\n private validateProgramStage;\n /** Preserve the existing bounded body reader and its fail-closed framing/prototype checks. */\n private readProgramBody;\n /** Keep thrown Response/status and redacted 500 semantics in one existing error boundary. */\n private handleProgramError;\n /** Finish a successful program result through response-contract enforcement and finalization. */\n private finishProgramResult;\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 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 the compiled route program 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 /** 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.\n *\n * Bun and the portable router agree on which of two static-and-`:param` paths wins a request, so\n * the table is kept to those paths. Where Bun would otherwise pass a request on to a less specific\n * path, the more specific one carries `fallback`, the portable dispatcher, under that method.\n * `peer` is the platform every request served from the table shares. */\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 * `tls` serves HTTPS directly: `app.listen(443, { tls: { cert, key } })` with PEM text or bytes.\n * Requests then arrive with `https:` URLs. Behind a proxy or a platform that terminates TLS, leave\n * it unset.\n */\n listen(port: number, options?: {\n readonly reusePort?: boolean;\n readonly hostname?: string;\n readonly idleTimeoutSec?: number;\n readonly tls?: ListenTlsOptions;\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}",
13805
13853
  "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 */"
13806
13854
  },
13807
13855
  {
@@ -14042,13 +14090,13 @@
14042
14090
  "name": "ServerOptions",
14043
14091
  "kind": "interface",
14044
14092
  "package": "@nifrajs/core",
14045
- "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 /** WebSocket upgrade admission/guard timeout (ms). Default 10_000; set to 0 only for a deliberate unbounded guard. */\n readonly wsUpgradeTimeoutMs?: 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 /**\n * When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false.\n * `{ drainMs }` sets how long in-flight requests get to finish before the stop forces them closed\n * (default 10_000) - keep it under the platform's kill grace period (`docker stop` waits 10 s).\n */\n readonly gracefulSignals?: boolean | {\n readonly drainMs?: number;\n };\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}"
14093
+ "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). Every guarded\n * payload pays one iterative pass over its parsed object nodes; `\"ignore\"` skips it.\n */\n readonly protoPoisoning?: \"reject\" | \"strip\" | \"ignore\";\n /**\n * Other sites whose HTML forms may post to a body-schema route: exact origins, or a function that\n * receives the `Origin`. A urlencoded, multipart or `text/plain` body is one a form on any site can\n * send with the visitor's cookies and no preflight, so one whose `Origin` names another site is\n * refused with `403` before it is read. Same-origin posts and requests without an `Origin`, such\n * as server-to-server calls, pass. JSON is not affected: a browser preflights it, so CORS decides.\n */\n readonly formOrigins?: ReadonlyArray<string> | ((origin: string) => boolean);\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 /**\n * Max inbound WebSocket message size (bytes). A larger message never reaches the handler and the\n * socket closes with `1009`. Default: `maxBodyBytes` (1 MB). Bun and Node stop buffering at the cap,\n * so a huge frame is never held in memory; on Bun a mounted app's smaller cap, and on Deno and\n * Workers every cap, is checked after the runtime has buffered the whole message.\n */\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 /** WebSocket upgrade admission/guard timeout (ms). Default 10_000; set to 0 only for a deliberate unbounded guard. */\n readonly wsUpgradeTimeoutMs?: 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 /**\n * When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false.\n * `{ drainMs }` sets how long in-flight requests get to finish before the stop forces them closed\n * (default 10_000) - keep it under the platform's kill grace period (`docker stop` waits 10 s).\n */\n readonly gracefulSignals?: boolean | {\n readonly drainMs?: number;\n };\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}"
14046
14094
  },
14047
14095
  {
14048
14096
  "name": "ServerOptions",
14049
14097
  "kind": "interface",
14050
14098
  "package": "nifra",
14051
- "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 /** WebSocket upgrade admission/guard timeout (ms). Default 10_000; set to 0 only for a deliberate unbounded guard. */\n readonly wsUpgradeTimeoutMs?: 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 /**\n * When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false.\n * `{ drainMs }` sets how long in-flight requests get to finish before the stop forces them closed\n * (default 10_000) - keep it under the platform's kill grace period (`docker stop` waits 10 s).\n */\n readonly gracefulSignals?: boolean | {\n readonly drainMs?: number;\n };\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}"
14099
+ "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). Every guarded\n * payload pays one iterative pass over its parsed object nodes; `\"ignore\"` skips it.\n */\n readonly protoPoisoning?: \"reject\" | \"strip\" | \"ignore\";\n /**\n * Other sites whose HTML forms may post to a body-schema route: exact origins, or a function that\n * receives the `Origin`. A urlencoded, multipart or `text/plain` body is one a form on any site can\n * send with the visitor's cookies and no preflight, so one whose `Origin` names another site is\n * refused with `403` before it is read. Same-origin posts and requests without an `Origin`, such\n * as server-to-server calls, pass. JSON is not affected: a browser preflights it, so CORS decides.\n */\n readonly formOrigins?: ReadonlyArray<string> | ((origin: string) => boolean);\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 /**\n * Max inbound WebSocket message size (bytes). A larger message never reaches the handler and the\n * socket closes with `1009`. Default: `maxBodyBytes` (1 MB). Bun and Node stop buffering at the cap,\n * so a huge frame is never held in memory; on Bun a mounted app's smaller cap, and on Deno and\n * Workers every cap, is checked after the runtime has buffered the whole message.\n */\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 /** WebSocket upgrade admission/guard timeout (ms). Default 10_000; set to 0 only for a deliberate unbounded guard. */\n readonly wsUpgradeTimeoutMs?: 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 /**\n * When `listen()`ing, install SIGTERM/SIGINT handlers that gracefully `stop()`. Default false.\n * `{ drainMs }` sets how long in-flight requests get to finish before the stop forces them closed\n * (default 10_000) - keep it under the platform's kill grace period (`docker stop` waits 10 s).\n */\n readonly gracefulSignals?: boolean | {\n readonly drainMs?: number;\n };\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}"
14052
14100
  },
14053
14101
  {
14054
14102
  "name": "ServerZoneGuardOptions",
@@ -14146,7 +14194,7 @@
14146
14194
  "name": "SessionOptions",
14147
14195
  "kind": "interface",
14148
14196
  "package": "@nifrajs/auth",
14149
- "signature": "export interface SessionOptions {\n /** Signing secret (≥ 32 bytes), or a rotation list: the **first** secret signs new cookies and\n * any listed secret verifies, so rotating without invalidating live sessions is: prepend the new\n * secret, drop the old one after `maxAge` has elapsed. A bare secret swap (no list) invalidates\n * all existing sessions. */\n readonly secret: string | readonly string[];\n /** Provide a store for **store mode**; omit for **cookie mode** (stateless). */\n readonly store?: SessionStore;\n /** Cookie name. Default `nifra_session`. */\n readonly cookieName?: string;\n /** Session lifetime in **seconds**. Default 7 days. */\n readonly maxAge?: number;\n /** Slide the expiry forward on every commit (default `true`); `false` = fixed absolute expiry. */\n readonly rolling?: boolean;\n /** Extra cookie attributes (the session cookie is always HttpOnly; `Secure`/`SameSite=Lax`/`Path=/`\n * default via `c.set.cookie`). Pass `{ secure: false }` for local http dev. */\n readonly cookie?: SessionCookieOptions;\n /** Clock (ms) - injected for testability; production passes `() => Date.now()` (the default). */\n readonly now?: () => number;\n}"
14197
+ "signature": "export interface SessionOptions {\n /** Signing secret (≥ 32 bytes), or a rotation list: the **first** secret signs new cookies and\n * any listed secret verifies, so rotating without invalidating live sessions is: prepend the new\n * secret, drop the old one after `maxAge` has elapsed. A bare secret swap (no list) invalidates\n * all existing sessions. */\n readonly secret: string | readonly string[];\n /** Provide a store for **store mode**; omit for **cookie mode** (stateless). */\n readonly store?: SessionStore;\n /** Cookie name. Default `nifra_session`. */\n readonly cookieName?: string;\n /** Session lifetime in **seconds**. Default 7 days. */\n readonly maxAge?: number;\n /** Slide the expiry forward on every commit (default `true`); `false` = fixed absolute expiry. */\n readonly rolling?: boolean;\n /** Extra cookie attributes (the session cookie is always HttpOnly; `Secure`/`SameSite=Lax`/`Path=/`\n * default via `c.set.cookie`). Pass `{ secure: false }` for local http dev. */\n readonly cookie?: SessionCookieOptions;\n /** Clock (ms) - injected for testability; production passes `() => Date.now()` (the default). */\n readonly now?: () => number;\n /**\n * Also accept a session cookie signed by `@nifrajs/auth` before 5.0, whose signature does not cover\n * the cookie name, so upgrading from 4.x signs no one out. Off by default: while it is on, any\n * value the app signs with this secret through `@nifrajs/core`'s `signValue` (a signed preference\n * cookie, say) and that parses as a session reads as one. Turn it on for one `maxAge` after the\n * upgrade, then remove it; each such session is re-signed in the current form on its next commit.\n */\n readonly acceptLegacyCookies?: boolean;\n}"
14150
14198
  },
14151
14199
  {
14152
14200
  "name": "SessionRecord",
@@ -14823,7 +14871,7 @@
14823
14871
  "name": "StoredJob",
14824
14872
  "kind": "interface",
14825
14873
  "package": "@nifrajs/jobs",
14826
- "signature": "export interface StoredJob {\n readonly id: string;\n readonly name: string;\n readonly payload: unknown;\n readonly attempt: number;\n readonly maxAttempts: number;\n /**\n * The producer's W3C `traceparent`, as given to {@link JobStore.enqueue}. A store that does not\n * persist it still runs every job; only the link between the producer's and the run's spans is lost.\n */\n readonly traceparent?: string;\n}",
14874
+ "signature": "export interface StoredJob {\n readonly id: string;\n readonly name: string;\n readonly payload: unknown;\n readonly attempt: number;\n readonly maxAttempts: number;\n /**\n * The producer's W3C `traceparent`, as given to {@link JobStore.enqueue}. A store that does not\n * persist it still runs every job; only the link between the producer's and the run's spans is lost.\n */\n readonly traceparent?: string;\n /**\n * This lease's token, new on every `lease`. The queue hands it back to `complete`, `retry`,\n * `deadLetter` and `renew`, so a store can ignore a call from a worker whose lease ran out and\n * was taken by another. A store without tokens leaves it unset.\n */\n readonly lease?: string;\n}",
14827
14875
  "doc": "/** A job as handed back by {@link JobStore.lease}. `attempt` is the count of PRIOR attempts (0 the first time). */"
14828
14876
  },
14829
14877
  {
@@ -15688,14 +15736,14 @@
15688
15736
  "name": "VERSION",
15689
15737
  "kind": "const",
15690
15738
  "package": "@nifrajs/core",
15691
- "signature": "export declare const VERSION: \"5.0.0\";",
15739
+ "signature": "export declare const VERSION: \"5.1.0\";",
15692
15740
  "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 */"
15693
15741
  },
15694
15742
  {
15695
15743
  "name": "VERSION",
15696
15744
  "kind": "const",
15697
15745
  "package": "nifra",
15698
- "signature": "export declare const VERSION: \"5.0.0\";",
15746
+ "signature": "export declare const VERSION: \"5.1.0\";",
15699
15747
  "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 */"
15700
15748
  },
15701
15749
  {
@@ -15922,7 +15970,7 @@
15922
15970
  "name": "WebSocketHubApp",
15923
15971
  "kind": "interface",
15924
15972
  "package": "@nifrajs/workers",
15925
- "signature": "export interface WebSocketHubApp<Env = unknown> {\n resolveWebSocketUpgrade(request: Request, platform?: {\n readonly env: Env;\n readonly waitUntil: (promise: Promise<unknown>) => void;\n }): WebSocketUpgradeOutcome | Promise<WebSocketUpgradeOutcome>;\n}",
15973
+ "signature": "export interface WebSocketHubApp<Env = unknown> {\n resolveWebSocketUpgrade(request: Request, platform?: {\n readonly env: Env;\n readonly waitUntil: (promise: Promise<unknown>) => void;\n }): WebSocketUpgradeOutcome | Promise<WebSocketUpgradeOutcome>;\n /** Answers an upgrade request for a path with no WebSocket route, as `fetch` does on every other\n * runtime. An app without it gets `426`. */\n fetch?(request: Request, platform?: {\n readonly env: Env;\n readonly waitUntil: (promise: Promise<unknown>) => void;\n }): Response | Promise<Response>;\n}",
15926
15974
  "doc": "/** The nifra-app surface the hub needs - every `server()` app satisfies it. */"
15927
15975
  },
15928
15976
  {
@@ -15936,14 +15984,14 @@
15936
15984
  "name": "WebSocketUpgradeOutcome",
15937
15985
  "kind": "type",
15938
15986
  "package": "@nifrajs/core",
15939
- "signature": "export type WebSocketUpgradeOutcome = {\n readonly kind: \"pass\";\n} | {\n readonly kind: \"reject\";\n readonly response: Response;\n} | {\n readonly kind: \"upgrade\";\n readonly handler: WebSocketHandler;\n readonly data: unknown;\n /** The app's pub/sub registry - the adapter wires `ws.subscribe` + close-cleanup to it. */\n readonly pubsub: TopicRegistry;\n /** The installed runtime's {@link attachWebSocket}, carried on the outcome so an adapter can wire\n * a standard socket without a static import of the WS implementation (which would defeat the\n * `.use(websocket())` tree-shaking). `@nifrajs/workers` may import `attachWebSocket` directly instead. */\n readonly attach: WsAttach;\n readonly maxPayloadBytes?: number;\n};",
15987
+ "signature": "export type WebSocketUpgradeOutcome = {\n readonly kind: \"pass\";\n} | {\n readonly kind: \"reject\";\n readonly response: Response;\n} | {\n readonly kind: \"upgrade\";\n readonly handler: WebSocketHandler;\n readonly data: unknown;\n /** The app's pub/sub registry - the adapter wires `ws.subscribe` + close-cleanup to it. */\n readonly pubsub: TopicRegistry;\n /** The installed runtime's {@link attachWebSocket}, carried on the outcome so an adapter can wire\n * a standard socket without a static import of the WS implementation (which would defeat the\n * `.use(websocket())` tree-shaking). `@nifrajs/workers` may import `attachWebSocket` directly instead. */\n readonly attach: WsAttach;\n readonly maxPayloadBytes?: number;\n /** Builds `ws.send` over an adapter's native send, enforcing the route's {@link\n * WebSocketHandler.validateSend}. Set on every outcome a nifra app produces; an adapter that\n * wires its own sockets instead of calling `attach` (Node, Deno) builds `send` with it. */\n readonly sender?: WsSender;\n};",
15940
15988
  "doc": "/**\n * The outcome of `app.resolveWebSocketUpgrade(req)` - for serving adapters:\n * - `pass` - not a WS upgrade for a registered WS route; handle as a normal HTTP request.\n * - `reject` - a WS route matched but `upgrade()` rejected (or the path was malformed); return `response`.\n * - `upgrade` - perform the runtime upgrade, then dispatch the native socket's events to `handler`,\n * seeding `ws.data` with `data`.\n */"
15941
15989
  },
15942
15990
  {
15943
15991
  "name": "WebSocketUpgradeOutcome",
15944
15992
  "kind": "type",
15945
15993
  "package": "nifra",
15946
- "signature": "export type WebSocketUpgradeOutcome = {\n readonly kind: \"pass\";\n} | {\n readonly kind: \"reject\";\n readonly response: Response;\n} | {\n readonly kind: \"upgrade\";\n readonly handler: WebSocketHandler;\n readonly data: unknown;\n /** The app's pub/sub registry - the adapter wires `ws.subscribe` + close-cleanup to it. */\n readonly pubsub: TopicRegistry;\n /** The installed runtime's {@link attachWebSocket}, carried on the outcome so an adapter can wire\n * a standard socket without a static import of the WS implementation (which would defeat the\n * `.use(websocket())` tree-shaking). `@nifrajs/workers` may import `attachWebSocket` directly instead. */\n readonly attach: WsAttach;\n readonly maxPayloadBytes?: number;\n};",
15994
+ "signature": "export type WebSocketUpgradeOutcome = {\n readonly kind: \"pass\";\n} | {\n readonly kind: \"reject\";\n readonly response: Response;\n} | {\n readonly kind: \"upgrade\";\n readonly handler: WebSocketHandler;\n readonly data: unknown;\n /** The app's pub/sub registry - the adapter wires `ws.subscribe` + close-cleanup to it. */\n readonly pubsub: TopicRegistry;\n /** The installed runtime's {@link attachWebSocket}, carried on the outcome so an adapter can wire\n * a standard socket without a static import of the WS implementation (which would defeat the\n * `.use(websocket())` tree-shaking). `@nifrajs/workers` may import `attachWebSocket` directly instead. */\n readonly attach: WsAttach;\n readonly maxPayloadBytes?: number;\n /** Builds `ws.send` over an adapter's native send, enforcing the route's {@link\n * WebSocketHandler.validateSend}. Set on every outcome a nifra app produces; an adapter that\n * wires its own sockets instead of calling `attach` (Node, Deno) builds `send` with it. */\n readonly sender?: WsSender;\n};",
15947
15995
  "doc": "/**\n * The outcome of `app.resolveWebSocketUpgrade(req)` - for serving adapters:\n * - `pass` - not a WS upgrade for a registered WS route; handle as a normal HTTP request.\n * - `reject` - a WS route matched but `upgrade()` rejected (or the path was malformed); return `response`.\n * - `upgrade` - perform the runtime upgrade, then dispatch the native socket's events to `handler`,\n * seeding `ws.data` with `data`.\n */"
15948
15996
  },
15949
15997
  {
@@ -15990,7 +16038,7 @@
15990
16038
  "name": "WireDecodeLimits",
15991
16039
  "kind": "interface",
15992
16040
  "package": "@nifrajs/core",
15993
- "signature": "export interface WireDecodeLimits {\n /** Maximum number of interned nodes. Default 10,000. */\n readonly maxNodes?: number;\n /** Maximum nesting depth across containers and references. Default 256. */\n readonly maxDepth?: number;\n /** Maximum total object/array/map/set entries visited. Default 100,000. */\n readonly maxCollectionEntries?: number;\n /** Maximum UTF-8 string plus decoded binary bytes materialized. Default 16 MiB. */\n readonly maxDecodedBytes?: number;\n}",
16041
+ "signature": "export interface WireDecodeLimits {\n /** Maximum number of interned nodes. Default 10,000. */\n readonly maxNodes?: number;\n /** Maximum nesting depth across containers and references. Default 256. */\n readonly maxDepth?: number;\n /** Maximum total object/array/map/set entries visited. Default 100,000. */\n readonly maxCollectionEntries?: number;\n /** Maximum UTF-8 string plus decoded binary bytes materialized. Default 16 MiB. */\n readonly maxDecodedBytes?: number;\n /**\n * Maximum decimal digits in one `bigint`. Default 4,096 (past 8192-bit integers). Parsing grows\n * faster than the digit count, so one long token would cost seconds of CPU under the byte limit.\n */\n readonly maxBigIntDigits?: number;\n}",
15994
16042
  "doc": "/** Resource limits applied while reconstructing transport-controlled wire data. */"
15995
16043
  },
15996
16044
  {
@@ -16059,7 +16107,7 @@
16059
16107
  "name": "WorkerOptions",
16060
16108
  "kind": "interface",
16061
16109
  "package": "@nifrajs/jobs",
16062
- "signature": "export interface WorkerOptions {\n /** Max jobs in flight at once. Default 1. A slot frees as soon as its job settles, and the next poll fills it. */\n readonly concurrency?: number;\n /** How often to poll the store for due jobs (ms). Default 250. */\n readonly pollIntervalMs?: number;\n /** How long a leased job is hidden before it's considered abandoned and re-leased (ms). Default 30_000. */\n readonly leaseMs?: number;\n /** Called when a poll round fails (the store's `lease` threw); polling continues on the next tick.\n * Default: `console.error`. A throwing handler here is swallowed. */\n readonly onPollError?: (error: unknown) => void;\n}"
16110
+ "signature": "export interface WorkerOptions {\n /** Max jobs in flight at once. Default 1. A slot frees as soon as its job settles, and the next poll fills it. */\n readonly concurrency?: number;\n /** How often to poll the store for due jobs (ms). Default 250. */\n readonly pollIntervalMs?: number;\n /** How long a leased job is hidden before it's considered abandoned and re-leased (ms). Default\n * 30_000. A store with `renew` keeps a running job's lease alive; every job's `timeoutMs` must be\n * below it. */\n readonly leaseMs?: number;\n /** Called when a poll round fails (the store's `lease` threw) or a lease renewal fails; polling\n * continues on the next tick. Default: `console.error`. A throwing handler here is swallowed. */\n readonly onPollError?: (error: unknown) => void;\n}"
16063
16111
  },
16064
16112
  {
16065
16113
  "name": "WorkersCacheLike",
@@ -16121,7 +16169,7 @@
16121
16169
  "name": "WsCallOptions",
16122
16170
  "kind": "interface",
16123
16171
  "package": "@nifrajs/client",
16124
- "signature": "export interface WsCallOptions {\n query?: Record<string, string | number | boolean>;\n /** WebSocket subprotocols. A browser handshake cannot carry custom headers - authenticate via\n * `upgrade()` reading cookies/query/subprotocol, not an Authorization header. */\n protocols?: string | string[];\n /** Abort to close the socket (same effect as calling `close()`). */\n signal?: AbortSignal;\n /** Socket-level failures (connection refused, abnormal close). */\n onError?: (error: unknown) => void;\n}"
16172
+ "signature": "export interface WsCallOptions {\n /** Sent on the handshake URL as an HTTP call sends it: an array repeats its key once per item,\n * and an `undefined` value is left out. */\n query?: Record<string, string | number | boolean | readonly (string | number | boolean)[] | undefined>;\n /** WebSocket subprotocols. A browser handshake cannot carry custom headers - authenticate via\n * `upgrade()` reading cookies/query/subprotocol, not an Authorization header. */\n protocols?: string | string[];\n /** Abort to close the socket (same effect as calling `close()`). */\n signal?: AbortSignal;\n /** Socket-level failures (connection refused, abnormal close). */\n onError?: (error: unknown) => void;\n}"
16125
16173
  },
16126
16174
  {
16127
16175
  "name": "WsHandle",
@@ -16140,7 +16188,7 @@
16140
16188
  "name": "ZoneClassifier",
16141
16189
  "kind": "interface",
16142
16190
  "package": "@nifrajs/web",
16143
- "signature": "export interface ZoneClassifier {\n readonly appRoot: string;\n /** Classify a file by its absolute (or appRoot-relative) path. Results are cached per path. */\n classify(file: string): Classification;\n}"
16191
+ "signature": "export interface ZoneClassifier {\n readonly appRoot: string;\n /**\n * Classify a file by its absolute (or appRoot-relative) path. Results are cached per path.\n *\n * With `specifier`, the import as written that resolved to `file`: when it names a package that\n * gives each export entry its own side (`\"nifra\": { \"environment\": { \".\": \"backend\", \"./react\":\n * \"frontend\" } }`), the entry it names decides, since two entries may share one file. A specifier\n * naming an entry the map leaves out is an error. The resolved file must belong to that entry, as\n * the package's own imports reach it; one only other entries reach is judged by its path.\n */\n classify(file: string, specifier?: string): Classification;\n}"
16144
16192
  },
16145
16193
  {
16146
16194
  "name": "ZoneClassifierOptions",
@@ -16152,7 +16200,7 @@
16152
16200
  "name": "ZoneConfig",
16153
16201
  "kind": "interface",
16154
16202
  "package": "@nifrajs/web",
16155
- "signature": "export interface ZoneConfig {\n /**\n * The side of a package that does not declare one in its own package.json, by name: exact\n * (`\"@shop/db\"`) or a trailing-`*` prefix (`\"@shop/*\"`). The exact name wins over a prefix, the\n * longest prefix over a shorter one, and a package's own declaration over all of them.\n */\n readonly packages?: Readonly<Record<string, PackageEnvironment>>;\n /** App-relative folders holding backend code, beside `backend/` (`\"migrations\"`). */\n readonly backend?: readonly string[];\n /** App-relative folders holding frontend code, beside `frontend/`. */\n readonly frontend?: readonly string[];\n /** App-relative folders holding code both sides import, beside `shared/`. */\n readonly shared?: readonly string[];\n}",
16203
+ "signature": "export interface ZoneConfig {\n /**\n * The side of a package that does not declare one in its own package.json, by name: exact\n * (`\"@shop/db\"`) or a trailing-`*` prefix (`\"@shop/*\"`). The exact name wins over a prefix, the\n * longest prefix over a shorter one, and a package's own declaration over all of them.\n */\n readonly packages?: Readonly<Record<string, PackageEnvironment>>;\n /**\n * App-relative folders or files holding backend code, beside `backend/` (`\"migrations\"`). A path\n * listed inside another one's folder overrides it: the most specific entry wins.\n */\n readonly backend?: readonly string[];\n /** App-relative folders or files holding frontend code, beside `frontend/`. */\n readonly frontend?: readonly string[];\n /** App-relative folders or files holding code both sides import, beside `shared/`. */\n readonly shared?: readonly string[];\n}",
16156
16204
  "doc": "/**\n * App-side zone settings, read from `\"nifra\": { \"zones\": ... }` in the app's package.json so every\n * build, dev server, `nifra check` and the editor plugin see the same ones without running app code.\n */"
16157
16205
  },
16158
16206
  {
@@ -16274,7 +16322,8 @@
16274
16322
  "name": "approvalRequestFromEvent",
16275
16323
  "kind": "function",
16276
16324
  "package": "@nifrajs/coding-agent",
16277
- "signature": "export declare function approvalRequestFromEvent(event: AgentApprovalRequiredEvent): ApprovalRequest;"
16325
+ "signature": "export declare function approvalRequestFromEvent(event: AgentApprovalRequiredEvent, timeoutMs?: ApprovalTimeout): ApprovalRequest;",
16326
+ "doc": "/**\n * Project a backend approval event into a request. Pass the broker's timeout\n * (`ApprovalManager.timeoutMs`) so `expiresAt` matches when it will actually be denied; the default\n * is the broker's default of 5 minutes.\n */"
16278
16327
  },
16279
16328
  {
16280
16329
  "name": "approvalResolvedEvent",
@@ -16956,14 +17005,14 @@
16956
17005
  "name": "checkResponseContract",
16957
17006
  "kind": "function",
16958
17007
  "package": "@nifrajs/core",
16959
- "signature": "export declare function checkResponseContract(schema: StandardSchemaV1, result: unknown, mode: \"warn\" | \"enforce\"): ResponseContractOutcome | Promise<ResponseContractOutcome>;",
17008
+ "signature": "export declare function checkResponseContract(schema: StandardSchemaV1, result: unknown, mode: \"warn\" | \"enforce\", options?: ResponseContractOptions): ResponseContractOutcome | Promise<ResponseContractOutcome>;",
16960
17009
  "doc": "/**\n * Check one result against the route's declared response schema.\n *\n * Returns synchronously when the schema does (the common case), so an app that opts in does not pay a\n * microtask per response for a check that had no work to do.\n */"
16961
17010
  },
16962
17011
  {
16963
17012
  "name": "checkRouteResponseContract",
16964
17013
  "kind": "function",
16965
17014
  "package": "@nifrajs/core",
16966
- "signature": "export declare function checkRouteResponseContract(definition: ResponseContractDefinition, result: unknown, mode: \"warn\" | \"enforce\", jsonReply?: {\n readonly body: unknown;\n}): ResponseContractOutcome | Promise<ResponseContractOutcome>;",
17015
+ "signature": "export declare function checkRouteResponseContract(definition: ResponseContractDefinition, result: unknown, mode: \"warn\" | \"enforce\", jsonReply?: {\n readonly body: unknown;\n}, options?: ResponseContractOptions): ResponseContractOutcome | Promise<ResponseContractOutcome>;",
16967
17016
  "doc": "/**\n * Check a route's success or status-specific error payload. Plain `status()` results retain their\n * status while enforcement replaces only the body with the validator's output. A `c.json(...)`\n * reply is held to the contract through the value it was built from (`jsonReply`). Any other raw\n * `Response` remains an explicit transport escape hatch because inspecting it would consume\n * streams or alter redirects; assurance/static checks must govern that path separately.\n */"
16968
17017
  },
16969
17018
  {
@@ -17560,7 +17609,7 @@
17560
17609
  "kind": "function",
17561
17610
  "package": "@nifrajs/middleware",
17562
17611
  "signature": "export declare function createEventLoopLagSampler(resolutionMs?: number, monitor?: LoopDelayMonitor): () => number;",
17563
- "doc": "/**\n * Event-loop-lag sampler. By default it measures timer drift using only Web/JS runtime primitives, so\n * it works under Node ESM, Bun, Deno, and workers without a hidden CommonJS `require` fallback. An\n * injected histogram remains available for deterministic tests or a runtime-native monitor. Each read\n * returns recent mean lag and resets the sampling window.\n */"
17612
+ "doc": "/**\n * Event-loop-lag sampler. By default it measures timer drift using only Web/JS runtime primitives, so\n * it works under Node ESM, Bun, Deno, and workers without a hidden CommonJS `require` fallback. An\n * injected histogram remains available for deterministic tests or a runtime-native monitor. A read\n * returns the mean lag of the samples taken since the previous read and starts a new window; a read\n * with no new sample since then returns the same value again, so every request that arrives between\n * two samples of a lagging loop sees the lag.\n */"
17564
17613
  },
17565
17614
  {
17566
17615
  "name": "createEventRegistry",
@@ -18038,6 +18087,13 @@
18038
18087
  "signature": "export declare function declaredCapabilities(context: object): readonly string[];",
18039
18088
  "doc": "/**\n * Read the route's token-only declaration for admission plugins. This intentionally exposes neither\n * the request nor runtime evidence; it is the stable public seam for private entitlement policy.\n */"
18040
18089
  },
18090
+ {
18091
+ "name": "declaredSide",
18092
+ "kind": "function",
18093
+ "package": "@nifrajs/web",
18094
+ "signature": "export declare function declaredSide(environment: unknown, specifier: string): PackageEnvironment | undefined;",
18095
+ "doc": "/**\n * The side a package's `\"nifra\": { \"environment\": ... }` value gives the bare import `specifier` of it:\n * the package-wide string, or the side of the entry it names - the map's exact subpath, else its most\n * specific `*` pattern. `undefined` when it gives none, as a map that leaves the entry out does.\n */"
18096
+ },
18041
18097
  {
18042
18098
  "name": "decode",
18043
18099
  "kind": "function",
@@ -18205,7 +18261,7 @@
18205
18261
  "kind": "function",
18206
18262
  "package": "@nifrajs/env",
18207
18263
  "signature": "export declare function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptions): EnvResult<S>;",
18208
- "doc": "/**\n * Validate the environment against a schema and return a **frozen, typed** object - or throw at\n * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails\n * loud and immediately instead of erroring on the first request that touches a bad var. This is the\n * boot-time half of nifra's \"validate at every boundary\" rule, for config.\n *\n * ```ts\n * // env.ts - imported once at startup\n * import { defineEnv, env } from \"@nifrajs/env\"\n * export const ENV = defineEnv({\n * DATABASE_URL: env.url(),\n * PORT: env.port({ default: 3000 }),\n * NODE_ENV: env.enum([\"development\", \"production\", \"test\"], { default: \"development\" }),\n * STRIPE_SECRET: env.string(),\n * DEBUG: env.boolean({ default: false }),\n * })\n * // ENV.PORT: number, ENV.NODE_ENV: \"development\" | \"production\" | \"test\", … all validated.\n * ```\n *\n * Errors name the offending variable and the reason - never its value (it may be a secret); a BYO\n * validator's message that quotes the value gets `<redacted>` in its place. BYO\n * validators (`t`, zod, valibot) work too; only the `env.*` helpers coerce from strings, so a plain\n * `t.number()` would see the raw string - use `env.number()` for coercion.\n */"
18264
+ "doc": "/**\n * Validate the environment against a schema and return a **frozen, typed** object - or throw at\n * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails\n * loud and immediately instead of erroring on the first request that touches a bad var. This is the\n * boot-time half of nifra's \"validate at every boundary\" rule, for config.\n *\n * ```ts\n * // env.ts - imported once at startup\n * import { defineEnv, env } from \"@nifrajs/env\"\n * export const ENV = defineEnv({\n * DATABASE_URL: env.url(),\n * PORT: env.port({ default: 3000 }),\n * NODE_ENV: env.enum([\"development\", \"production\", \"test\"], { default: \"development\" }),\n * STRIPE_SECRET: env.string(),\n * DEBUG: env.boolean({ default: false }),\n * })\n * // ENV.PORT: number, ENV.NODE_ENV: \"development\" | \"production\" | \"test\", … all validated.\n * ```\n *\n * Errors name the offending variable and the reason - never its value (it may be a secret). BYO\n * validators (`t`, zod, valibot) work too, but their messages may quote the value, so a set value\n * they refuse is reported as invalid without their words; an unset one shows their message. Only the\n * `env.*` helpers coerce from strings, so a plain `t.number()` would see the raw string - use\n * `env.number()` for coercion.\n */"
18209
18265
  },
18210
18266
  {
18211
18267
  "name": "defineEventContract",
@@ -18753,7 +18809,7 @@
18753
18809
  "kind": "function",
18754
18810
  "package": "@nifrajs/core",
18755
18811
  "signature": "export declare function evaluateRouteAssurance(source: unknown, policyInput: AssurancePolicy, options?: AssuranceEvaluationOptions): AssuranceReport;",
18756
- "doc": "/** Evaluate reflected route evidence against the first matching policy rule. */"
18812
+ "doc": "/** Evaluate reflected route evidence against the first matching policy rule, plus every matching\n * baseline rule. */"
18757
18813
  },
18758
18814
  {
18759
18815
  "name": "eventDeliveryCertificationProfile",
@@ -19299,7 +19355,7 @@
19299
19355
  "kind": "function",
19300
19356
  "package": "@nifrajs/web",
19301
19357
  "signature": "export declare function htmlFileFor(pattern: string): string;",
19302
- "doc": "/** Map a route path to its output file: `/` → `index.html`, `/a/b` → `a/b/index.html`. */"
19358
+ "doc": "/**\n * Map a route path to its output file: `/` → `index.html`, `/a/b` → `a/b/index.html`. Segments are\n * written decoded (`/caf%C3%A9` → `café/index.html`) because a static host decodes the request path\n * before it looks for a file; a segment with no such file name stays as written.\n */"
19303
19359
  },
19304
19360
  {
19305
19361
  "name": "httpToolAdapter",
@@ -19486,7 +19542,8 @@
19486
19542
  "name": "installForms",
19487
19543
  "kind": "function",
19488
19544
  "package": "@nifrajs/web",
19489
- "signature": "export declare function installForms(router: ClientRouter): () => void;"
19545
+ "signature": "export declare function installForms(router: ClientRouter): () => void;",
19546
+ "doc": "/**\n * Intercept submissions of same-origin `<form method=\"post\">` whose action targets an app route:\n * submit via the router (no full reload - POST the action, then revalidate the active loader). On\n * failure it falls back to a native submit, so the form still works. Returns a teardown function.\n */"
19490
19547
  },
19491
19548
  {
19492
19549
  "name": "installHistory",
@@ -19673,6 +19730,20 @@
19673
19730
  "signature": "export declare function isSafeReviewDiff(value: unknown): value is string;",
19674
19731
  "doc": "/** Validate the only repository selector exposed by the host review RPC. */"
19675
19732
  },
19733
+ {
19734
+ "name": "isSameOriginForm",
19735
+ "kind": "function",
19736
+ "package": "@nifrajs/core",
19737
+ "signature": "export declare function isSameOriginForm(origin: string, secFetchSite: string | null, request: {\n readonly url: string;\n}): boolean;",
19738
+ "doc": "/**\n * {@link isSameOriginRequest} for a browser form submission. Under `Referrer-Policy: no-referrer` a\n * browser sends a same-origin form POST with `Origin: null`; that one passes on its\n * `Sec-Fetch-Site: same-origin`, a header page script cannot set.\n */"
19739
+ },
19740
+ {
19741
+ "name": "isSameOriginForm",
19742
+ "kind": "function",
19743
+ "package": "nifra",
19744
+ "signature": "export declare function isSameOriginForm(origin: string, secFetchSite: string | null, request: {\n readonly url: string;\n}): boolean;",
19745
+ "doc": "/**\n * {@link isSameOriginRequest} for a browser form submission. Under `Referrer-Policy: no-referrer` a\n * browser sends a same-origin form POST with `Origin: null`; that one passes on its\n * `Sec-Fetch-Site: same-origin`, a header page script cannot set.\n */"
19746
+ },
19676
19747
  {
19677
19748
  "name": "isSameOriginPath",
19678
19749
  "kind": "function",
@@ -19691,14 +19762,14 @@
19691
19762
  "name": "isSameOriginRequest",
19692
19763
  "kind": "function",
19693
19764
  "package": "@nifrajs/core",
19694
- "signature": "export declare function isSameOriginRequest(origin: string, request: Request): boolean;",
19765
+ "signature": "export declare function isSameOriginRequest(origin: string, request: {\n readonly url: string;\n}): boolean;",
19695
19766
  "doc": "/**\n * True when `origin` is the request's own origin, as observed from inside a possibly-proxied server.\n *\n * The host must match exactly. The scheme must be equal or STRONGER on the Origin side, never weaker:\n *\n * - `https://app` page → `http://app` request URL: accepted. This is what every TLS-terminating\n * proxy looks like from the origin server - Cloudflare, a tunnel, an ingress. The socket is plain\n * HTTP, so `request.url` says `http:` while the browser correctly reports an `https:` page.\n * - `http://app` page → `https://app` request URL: rejected. Nifra terminated TLS itself here, so a\n * plaintext page on the same host is the downgrade an attacker would need and buys nothing real.\n *\n * Comparing full origins instead is not the stricter option, it is an outage: measured, it rejects\n * every server-function POST behind a terminating proxy, while the cross-origin attacker it aims at\n * was already rejected by the host comparison. Nifra deliberately does not read `X-Forwarded-Proto` -\n * a forwarded header is attacker-controlled unless something upstream is proven to overwrite it - so\n * the scheme in `request.url` is the socket's, not the browser's, and this asymmetry is how the two\n * are reconciled without trusting a header.\n *\n * An unparseable Origin is not same-origin.\n */"
19696
19767
  },
19697
19768
  {
19698
19769
  "name": "isSameOriginRequest",
19699
19770
  "kind": "function",
19700
19771
  "package": "nifra",
19701
- "signature": "export declare function isSameOriginRequest(origin: string, request: Request): boolean;",
19772
+ "signature": "export declare function isSameOriginRequest(origin: string, request: {\n readonly url: string;\n}): boolean;",
19702
19773
  "doc": "/**\n * True when `origin` is the request's own origin, as observed from inside a possibly-proxied server.\n *\n * The host must match exactly. The scheme must be equal or STRONGER on the Origin side, never weaker:\n *\n * - `https://app` page → `http://app` request URL: accepted. This is what every TLS-terminating\n * proxy looks like from the origin server - Cloudflare, a tunnel, an ingress. The socket is plain\n * HTTP, so `request.url` says `http:` while the browser correctly reports an `https:` page.\n * - `http://app` page → `https://app` request URL: rejected. Nifra terminated TLS itself here, so a\n * plaintext page on the same host is the downgrade an attacker would need and buys nothing real.\n *\n * Comparing full origins instead is not the stricter option, it is an outage: measured, it rejects\n * every server-function POST behind a terminating proxy, while the cross-origin attacker it aims at\n * was already rejected by the host comparison. Nifra deliberately does not read `X-Forwarded-Proto` -\n * a forwarded header is attacker-controlled unless something upstream is proven to overwrite it - so\n * the scheme in `request.url` is the socket's, not the browser's, and this asymmetry is how the two\n * are reconciled without trusting a header.\n *\n * An unparseable Origin is not same-origin.\n */"
19703
19774
  },
19704
19775
  {
@@ -19948,7 +20019,7 @@
19948
20019
  "kind": "function",
19949
20020
  "package": "@nifrajs/cron",
19950
20021
  "signature": "export declare function matches(fields: CronFields, date: Date): boolean;",
19951
- "doc": "/**\n * Does `date` (in its LOCAL time - cron is local-time by convention) match the fields, to the\n * minute? Day-of-month and day-of-week follow the standard OR rule: when BOTH are restricted, a\n * match on EITHER is a match; when only one is restricted, only that one must match.\n */"
20022
+ "doc": "/**\n * Does `date` (in its LOCAL time - cron is local-time by convention) match the fields, to the\n * minute? Day-of-month and day-of-week follow the standard OR rule: when BOTH are restricted, a\n * match on EITHER is a match; otherwise both must match (a bare `*` matches every day).\n */"
19952
20023
  },
19953
20024
  {
19954
20025
  "name": "matchesAssuranceSelector",
@@ -20389,7 +20460,7 @@
20389
20460
  "kind": "function",
20390
20461
  "package": "@nifrajs/middleware",
20391
20462
  "signature": "export declare function openapi(options?: OpenApiOptions): IdentityPlugin;",
20392
- "doc": "/**\n * Serve an OpenAPI 3.1 document (a structural subset - see {@link buildOpenApiDocument}) at\n * `options.path` (default `/openapi.json`), generated from the app's registered routes. Generation is\n * **lazy + memoized**: it reads `app.routes()` on the first request, by which point every route is\n * registered - so the plugin's own position in the chain doesn't matter.\n *\n * Pass `ui: true` (or `ui: { path, title, cdn }`) to also serve a Scalar API-reference page (default\n * `/reference`) that renders the spec. The page loads Scalar from a CDN; pin/self-host via `ui.cdn`,\n * and remember to allow that origin if you ship a `script-src` Content-Security-Policy.\n *\n * ```ts\n * app.use(openapi({ info: { title: \"My API\", version: \"1.0.0\" }, ui: true }))\n * ```\n */"
20463
+ "doc": "/**\n * Serve an OpenAPI 3.1 document (a structural subset - see {@link buildOpenApiDocument}) at\n * `options.path` (default `/openapi.json`), generated from the app's registered routes. Generation is\n * **lazy + memoized**: it reads `app.routes()` on the first request, by which point every route is\n * registered - so the plugin's own position in the chain doesn't matter.\n *\n * Pass `ui: true` (or `ui: { path, title, cdn, integrity }`) to also serve a Scalar API-reference page\n * (default `/reference`) that renders the spec. By default the page loads an exact Scalar version from\n * jsDelivr with a Subresource Integrity hash, so a changed file is refused rather than run on your\n * origin. Self-host it via `ui.cdn` (with your copy's `ui.integrity`), and allow the script's origin if\n * you ship a `script-src` Content-Security-Policy.\n *\n * ```ts\n * app.use(openapi({ info: { title: \"My API\", version: \"1.0.0\" }, ui: true }))\n * ```\n */"
20393
20464
  },
20394
20465
  {
20395
20466
  "name": "orchestrationTelemetry",
@@ -20821,7 +20892,7 @@
20821
20892
  "kind": "function",
20822
20893
  "package": "@nifrajs/web",
20823
20894
  "signature": "export declare function parseZoneConfig(value: unknown, source: string): ZoneConfig;",
20824
- "doc": "/**\n * Validate a `zones` setting. `source` names where it came from in the error. Folders are plain\n * app-relative paths (a trailing `/**` is accepted and dropped); any other glob is refused, so a\n * pattern can never match less than its author meant without saying so.\n */"
20895
+ "doc": "/**\n * Validate a `zones` setting. `source` names where it came from in the error. Folders and files are\n * plain app-relative paths (a trailing `/**` is accepted and dropped); any other glob is refused, so\n * a pattern can never match less than its author meant without saying so. One path under two sides\n * is refused; a path nested in another's folder is not, since the most specific one decides.\n */"
20825
20896
  },
20826
20897
  {
20827
20898
  "name": "pathTag",
@@ -21184,8 +21255,8 @@
21184
21255
  "name": "readBodyFramed",
21185
21256
  "kind": "function",
21186
21257
  "package": "@nifrajs/core",
21187
- "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>, bodySchema?: object): Promise<T>;",
21188
- "doc": "/**\n * The shared content-type dispatcher around the JSON and urlencoded lanes. A `bodySchema` branded\n * with {@link SCHEMA_BODY_READER} takes every other media type; JSON and urlencoded bodies keep\n * their lanes whatever the schema carries.\n */"
21258
+ "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>, bodySchema?: object, formOrigins?: FormOrigins): Promise<T>;",
21259
+ "doc": "/**\n * The shared content-type dispatcher around the JSON and urlencoded lanes. A `bodySchema` branded\n * with {@link SCHEMA_BODY_READER} takes every other media type; JSON and urlencoded bodies keep\n * their lanes whatever the schema carries. A form media type whose `Origin` is another site's, and\n * not one of `formOrigins`, is refused with `403` before the body is read.\n */"
21189
21260
  },
21190
21261
  {
21191
21262
  "name": "readBoundedBytes",
@@ -21759,7 +21830,7 @@
21759
21830
  "kind": "function",
21760
21831
  "package": "@nifrajs/mcp",
21761
21832
  "signature": "export declare function respondMcpHttp(request: Request, tools: McpTool[], serverInfo: {\n name: string;\n version: string;\n}, options?: McpHttpOptions): Promise<Response>;",
21762
- "doc": "/**\n * Handle one MCP request over HTTP against the given `tools`/`features`. POST a JSON-RPC body → a JSON-RPC\n * response, or an SSE stream carrying progress notifications and the final response when the client\n * accepts `text/event-stream`; GET → a health page or a cancellable SSE stream; OPTIONS → CORS preflight.\n * Never throws - a bad body becomes a JSON-RPC parse error. Dual-era: a modern (2026-07-28) POST that\n * mirrors its method/name/version into headers is validated against the body before dispatch and gets spec\n * HTTP statuses; legacy requests are served unchanged. The dispatch is the shared, transport-agnostic\n * {@link handleRpc}.\n */"
21833
+ "doc": "/**\n * Handle one MCP request over HTTP against the given `tools`/`features`. POST a JSON-RPC body → a JSON-RPC\n * response, or an SSE stream carrying progress notifications and the final response when the client\n * accepts `text/event-stream`; GET → a health page or a keep-alive SSE stream that closes after five minutes\n * (`405` when `authorizeMessage` is set); OPTIONS → CORS preflight.\n * Never throws - a bad body becomes a JSON-RPC parse error. Dual-era: a modern (2026-07-28) POST that\n * mirrors its method/name/version into headers is validated against the body before dispatch and gets spec\n * HTTP statuses; legacy requests are served unchanged. The dispatch is the shared, transport-agnostic\n * {@link handleRpc}.\n */"
21763
21834
  },
21764
21835
  {
21765
21836
  "name": "responseCache",
@@ -21771,8 +21842,14 @@
21771
21842
  "name": "responseContract",
21772
21843
  "kind": "function",
21773
21844
  "package": "@nifrajs/core",
21774
- "signature": "export declare function responseContract(mode?: ResponseContractMode): IdentityPlugin;",
21775
- "doc": "/**\n * Hold every route's declared `response` schema to what the handler actually returned.\n *\n * app.use(responseContract(\"enforce\"))\n *\n * Install it before the routes it should cover - like `idempotency()`, the decision is made per route\n * at registration, so routes registered earlier are not retroactively covered.\n *\n * The check itself is cheap - with a compiled validator it measures in the ~100ns-per-response\n * range, within benchmark noise of an uncontracted route on any route that carries middleware or a\n * derive. What a contracted route does give up is the bare-route fused lane (the check needs the\n * handler's value before it becomes bytes), which only a route with NO other lifecycle steps was\n * taking anyway. Opt-in because not installing the plugin keeps the lane out of the bundle, not\n * because enforcement is expensive.\n */"
21845
+ "signature": "export declare function responseContract(mode?: ResponseContractMode, options?: ResponseContractOptions): IdentityPlugin;",
21846
+ "doc": "/**\n * Hold every route's declared `response` schema to what the handler actually returned.\n *\n * app.use(responseContract(\"enforce\")) // a closed t.object -> 500 on extras\n * app.use(responseContract(\"enforce\", { extra: \"strip\" })) // extras dropped, declared fields sent\n *\n * Install it before the routes it should cover - like `idempotency()`, the decision is made per route\n * at registration, so routes registered earlier are not retroactively covered. It covers routes on\n * the server it is installed on, its `group()`s, and servers `merge()`d into it afterwards.\n *\n * The check itself is cheap - with a compiled validator it measures in the ~100ns-per-response\n * range, within benchmark noise of an uncontracted route on any route that carries middleware or a\n * derive. What a contracted route does give up is the bare-route fused lane (the check needs the\n * handler's value before it becomes bytes), which only a route with NO other lifecycle steps was\n * taking anyway. Opt-in because not installing the plugin keeps the lane out of the bundle, not\n * because enforcement is expensive.\n */"
21847
+ },
21848
+ {
21849
+ "name": "responseContractGaps",
21850
+ "kind": "function",
21851
+ "package": "@nifrajs/cli",
21852
+ "signature": "export declare function responseContractGaps(routes: readonly AssuredRoute[]): ResponseContractGaps;"
21776
21853
  },
21777
21854
  {
21778
21855
  "name": "responseFromStored",
@@ -21821,7 +21898,7 @@
21821
21898
  "kind": "function",
21822
21899
  "package": "@nifrajs/web",
21823
21900
  "signature": "export declare function revalidateEndpoint(options: RevalidateEndpointOptions): (req: Request, platform?: ISRPlatform) => Promise<Response>;",
21824
- "doc": "/**\n * An **on-demand revalidation** (purge) endpoint - a `fetch` handler that drops cached pages by path\n * or invalidates every entry carrying a tag. `POST` with the secret in the token header and either\n * `?path=/blog/x`, `?tag=products`, a JSON `{ \"path\": \"/blog/x\" }` / `{ \"tag\": \"products\" }` body, or a\n * batch `{ \"paths\": [...], \"tags\": [...] }` of at most 100 paths and 32 tags.\n * The token is checked in **constant time** (wrong/missing → `401`); malformed targets → `400`;\n * non-POST → `405`. A store without tag support returns `501` for tag requests. Mount it on a nifra route, e.g.\n * `app.post(\"/__nifra/revalidate\", (c) => handler(c.req))`.\n */"
21901
+ "doc": "/**\n * An **on-demand revalidation** (purge) endpoint - a `fetch` handler that drops cached pages by path\n * or invalidates every entry carrying a tag. `POST` with the secret in the token header and either\n * `?path=/blog/x`, `?tag=products`, a JSON `{ \"path\": \"/blog/x\" }` / `{ \"tag\": \"products\" }` body, or a\n * batch `{ \"paths\": [...], \"tags\": [...] }` of at most 100 paths and 32 tags.\n * The token is checked in **constant time** (wrong/missing → `401`); malformed targets → `400`;\n * a JSON body over 1 MiB → `413`; non-POST → `405`. A store without tag support returns `501` for tag requests. Mount it on a nifra route, e.g.\n * `app.post(\"/__nifra/revalidate\", (c) => handler(c.req))`.\n */"
21825
21902
  },
21826
21903
  {
21827
21904
  "name": "rewriteSsrImports",