@nifrajs/core 1.12.0 → 2.0.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 (167) hide show
  1. package/README.md +10 -1
  2. package/dist/assurance.d.ts +11 -2
  3. package/dist/assurance.d.ts.map +1 -1
  4. package/dist/assurance.js +20 -0
  5. package/dist/assurance.js.map +1 -1
  6. package/dist/effect-ledger.d.ts +9 -0
  7. package/dist/effect-ledger.d.ts.map +1 -0
  8. package/dist/effect-ledger.js +8 -0
  9. package/dist/effect-ledger.js.map +1 -0
  10. package/dist/idempotency-plugin.d.ts +8 -0
  11. package/dist/idempotency-plugin.d.ts.map +1 -0
  12. package/dist/idempotency-plugin.js +8 -0
  13. package/dist/idempotency-plugin.js.map +1 -0
  14. package/dist/index.d.ts +6 -34
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -30
  17. package/dist/index.js.map +1 -1
  18. package/dist/mcp.d.ts +7 -0
  19. package/dist/mcp.d.ts.map +1 -0
  20. package/dist/mcp.js +56 -0
  21. package/dist/mcp.js.map +1 -0
  22. package/dist/node-direct.d.ts +5 -0
  23. package/dist/node-direct.d.ts.map +1 -0
  24. package/dist/node-direct.js +27 -0
  25. package/dist/node-direct.js.map +1 -0
  26. package/dist/reflection.d.ts +5 -0
  27. package/dist/reflection.d.ts.map +1 -1
  28. package/dist/reflection.js +2 -0
  29. package/dist/reflection.js.map +1 -1
  30. package/dist/router/pattern.d.ts +42 -0
  31. package/dist/router/pattern.d.ts.map +1 -0
  32. package/dist/router/pattern.js +127 -0
  33. package/dist/router/pattern.js.map +1 -0
  34. package/dist/router/router.d.ts +2 -1
  35. package/dist/router/router.d.ts.map +1 -1
  36. package/dist/router/router.js +11 -48
  37. package/dist/router/router.js.map +1 -1
  38. package/dist/server/client-ip.d.ts +35 -0
  39. package/dist/server/client-ip.d.ts.map +1 -0
  40. package/dist/server/client-ip.js +42 -0
  41. package/dist/server/client-ip.js.map +1 -0
  42. package/dist/server/context.d.ts +47 -2
  43. package/dist/server/context.d.ts.map +1 -1
  44. package/dist/server/contract.d.ts +37 -10
  45. package/dist/server/contract.d.ts.map +1 -1
  46. package/dist/server/contract.js +33 -8
  47. package/dist/server/contract.js.map +1 -1
  48. package/dist/server/http.d.ts +14 -0
  49. package/dist/server/http.d.ts.map +1 -0
  50. package/dist/server/http.js +45 -0
  51. package/dist/server/http.js.map +1 -0
  52. package/dist/server/idempotency-lane.d.ts +44 -0
  53. package/dist/server/idempotency-lane.d.ts.map +1 -0
  54. package/dist/server/idempotency-lane.js +181 -0
  55. package/dist/server/idempotency-lane.js.map +1 -0
  56. package/dist/server/install.d.ts +21 -0
  57. package/dist/server/install.d.ts.map +1 -0
  58. package/dist/server/install.js +21 -0
  59. package/dist/server/install.js.map +1 -0
  60. package/dist/server/ledger-lane.d.ts +53 -0
  61. package/dist/server/ledger-lane.d.ts.map +1 -0
  62. package/dist/server/ledger-lane.js +82 -0
  63. package/dist/server/ledger-lane.js.map +1 -0
  64. package/dist/server/mcp-hook.d.ts +28 -0
  65. package/dist/server/mcp-hook.d.ts.map +1 -0
  66. package/dist/server/mcp-hook.js +2 -0
  67. package/dist/server/mcp-hook.js.map +1 -0
  68. package/dist/server/node-outcome-hook.d.ts +9 -0
  69. package/dist/server/node-outcome-hook.d.ts.map +1 -0
  70. package/dist/server/node-outcome-hook.js +2 -0
  71. package/dist/server/node-outcome-hook.js.map +1 -0
  72. package/dist/server/node-outcome.d.ts +37 -0
  73. package/dist/server/node-outcome.d.ts.map +1 -0
  74. package/dist/server/node-outcome.js +75 -0
  75. package/dist/server/node-outcome.js.map +1 -0
  76. package/dist/server/plugin.d.ts +78 -0
  77. package/dist/server/plugin.d.ts.map +1 -0
  78. package/dist/server/plugin.js +57 -0
  79. package/dist/server/plugin.js.map +1 -0
  80. package/dist/server/query.d.ts +18 -0
  81. package/dist/server/query.d.ts.map +1 -0
  82. package/dist/server/query.js +102 -0
  83. package/dist/server/query.js.map +1 -0
  84. package/dist/server/registry.d.ts +31 -6
  85. package/dist/server/registry.d.ts.map +1 -1
  86. package/dist/server/request-context.d.ts +51 -0
  87. package/dist/server/request-context.d.ts.map +1 -0
  88. package/dist/server/request-context.js +184 -0
  89. package/dist/server/request-context.js.map +1 -0
  90. package/dist/server/respond.d.ts +17 -0
  91. package/dist/server/respond.d.ts.map +1 -0
  92. package/dist/server/respond.js +81 -0
  93. package/dist/server/respond.js.map +1 -0
  94. package/dist/server/runtime-core.d.ts +36 -0
  95. package/dist/server/runtime-core.d.ts.map +1 -0
  96. package/dist/server/runtime-core.js +51 -0
  97. package/dist/server/runtime-core.js.map +1 -0
  98. package/dist/server/server-types.d.ts +203 -0
  99. package/dist/server/server-types.d.ts.map +1 -0
  100. package/dist/server/server-types.js +2 -0
  101. package/dist/server/server-types.js.map +1 -0
  102. package/dist/server/server.d.ts +135 -358
  103. package/dist/server/server.d.ts.map +1 -1
  104. package/dist/server/server.js +476 -1065
  105. package/dist/server/server.js.map +1 -1
  106. package/dist/server/sse-hook.d.ts +10 -0
  107. package/dist/server/sse-hook.d.ts.map +1 -0
  108. package/dist/server/sse-hook.js +2 -0
  109. package/dist/server/sse-hook.js.map +1 -0
  110. package/dist/server/sse.d.ts +7 -23
  111. package/dist/server/sse.d.ts.map +1 -1
  112. package/dist/server/sse.js +18 -0
  113. package/dist/server/sse.js.map +1 -1
  114. package/dist/server/websocket.d.ts +17 -1
  115. package/dist/server/websocket.d.ts.map +1 -1
  116. package/dist/server/websocket.js.map +1 -1
  117. package/dist/server/ws-hook.d.ts +8 -11
  118. package/dist/server/ws-hook.d.ts.map +1 -1
  119. package/dist/server/ws-hook.js +7 -14
  120. package/dist/server/ws-hook.js.map +1 -1
  121. package/dist/server.d.ts +21 -0
  122. package/dist/server.d.ts.map +1 -0
  123. package/dist/server.js +16 -0
  124. package/dist/server.js.map +1 -0
  125. package/dist/ws.d.ts +16 -7
  126. package/dist/ws.d.ts.map +1 -1
  127. package/dist/ws.js +25 -10
  128. package/dist/ws.js.map +1 -1
  129. package/package.json +82 -6
  130. package/src/assurance.ts +36 -1
  131. package/src/effect-ledger.ts +9 -0
  132. package/src/idempotency-plugin.ts +7 -0
  133. package/src/index.ts +6 -132
  134. package/src/mcp.ts +65 -0
  135. package/src/node-direct.ts +37 -0
  136. package/src/reflection.ts +7 -0
  137. package/src/router/pattern.ts +176 -0
  138. package/src/router/router.ts +11 -69
  139. package/src/server/client-ip.ts +60 -0
  140. package/src/server/context.ts +50 -2
  141. package/src/server/contract.ts +68 -25
  142. package/src/server/http.ts +58 -0
  143. package/src/server/idempotency-lane.ts +287 -0
  144. package/src/server/install.ts +28 -0
  145. package/src/server/ledger-lane.ts +125 -0
  146. package/src/server/mcp-hook.ts +41 -0
  147. package/src/server/node-outcome-hook.ts +9 -0
  148. package/src/server/node-outcome.ts +112 -0
  149. package/src/server/plugin.ts +92 -0
  150. package/src/server/query.ts +119 -0
  151. package/src/server/registry.ts +36 -6
  152. package/src/server/request-context.ts +271 -0
  153. package/src/server/respond.ts +93 -0
  154. package/src/server/runtime-core.ts +74 -0
  155. package/src/server/server-types.ts +204 -0
  156. package/src/server/server.ts +863 -1657
  157. package/src/server/sse-hook.ts +14 -0
  158. package/src/server/sse.ts +26 -0
  159. package/src/server/websocket.ts +20 -0
  160. package/src/server/ws-hook.ts +8 -19
  161. package/src/server.ts +92 -0
  162. package/src/ws.ts +33 -10
  163. package/dist/invariants.d.ts +0 -70
  164. package/dist/invariants.d.ts.map +0 -1
  165. package/dist/invariants.js +0 -487
  166. package/dist/invariants.js.map +0 -1
  167. package/src/invariants.ts +0 -604
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-lane.js","sourceRoot":"","sources":["../../src/server/ledger-lane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAoCpD;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAA4B;IACpE,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACvC,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAA;IAC7D,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAA;IAC5D,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,UAAU,CAAC,yDAAyD,CAAC,CAAA;IACjF,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAA;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IAEzB,OAAO;QACL,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI;YAChC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAA;YAC/C,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAA;QACzF,CAAC;QACD,MAAM,CAAC,QAAQ;YACb,OAAO,mBAAmB,CAAC;gBACzB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,KAAK,EAAE,QAAQ,CAAC,KAAK;aACtB,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,CAAC,OAAO,EAAE,MAAM;YACpB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACrC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW;YAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;YAClC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC7C,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,6FAA6F;gBAC7F,+FAA+F;gBAC/F,WAAW,CAAC;oBACV,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,IAAI,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;iBAChD,CAAC,CAAA;YACJ,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;KACF,CAAA;AACH,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,MAAM,OAAO,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAA;IAClD,MAAM,KAAK,GAAG,CAAsB,GAAM,EAAK,EAAE;QAC/C,CAAC;QAAC,GAA0C,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAA;QAC5E,OAAO,GAAG,CAAA;IACZ,CAAC,CAAA;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,qBAAqB,EAAE,CAAmB,CAAA;AACtF,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { StandardSchemaV1 } from "../schema/standard.js";
2
+ import type { Context, RouteSchema } from "./context.js";
3
+ import type { McpPromptDescriptor, McpResourceDescriptor, PromptArgument, RouteDescriptor, ToolAnnotations } from "./server-types.js";
4
+ export interface McpToolConfig {
5
+ readonly description: string;
6
+ readonly input: StandardSchemaV1;
7
+ readonly output?: StandardSchemaV1;
8
+ readonly annotations?: ToolAnnotations;
9
+ }
10
+ export interface McpToolPlan {
11
+ readonly path: string;
12
+ readonly schema: RouteSchema;
13
+ readonly run: (context: Context) => unknown;
14
+ readonly descriptor: NonNullable<RouteDescriptor["tool"]>;
15
+ }
16
+ export interface McpRuntime {
17
+ tool(name: string, config: McpToolConfig, handler: (input: unknown, context: Context) => unknown): McpToolPlan;
18
+ resource(uri: string, config: {
19
+ readonly name: string;
20
+ readonly description?: string;
21
+ readonly mimeType?: string;
22
+ }, read: McpResourceDescriptor["read"]): McpResourceDescriptor;
23
+ prompt(name: string, config: {
24
+ readonly description: string;
25
+ readonly arguments?: readonly PromptArgument[];
26
+ }, handler: McpPromptDescriptor["handler"]): McpPromptDescriptor;
27
+ }
28
+ //# sourceMappingURL=mcp-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-hook.d.ts","sourceRoot":"","sources":["../../src/server/mcp-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,KAAK,EACV,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,eAAe,EAChB,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;CACvC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;IAC3C,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,GACrD,WAAW,CAAA;IACd,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAC5F,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC,GAClC,qBAAqB,CAAA;IACxB,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;KAAE,EACxF,OAAO,EAAE,mBAAmB,CAAC,SAAS,CAAC,GACtC,mBAAmB,CAAA;CACvB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-hook.js","sourceRoot":"","sources":["../../src/server/mcp-hook.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ /** Lazy Node-direct renderer seam. The base server retains the typed method but not its renderer. */
2
+ import type { NodeServeOutcome } from "./node-outcome.js";
3
+ import type { CtxSet } from "./server.js";
4
+ export interface NodeOutcomeRuntime {
5
+ toOutcome(result: unknown, set: CtxSet): NodeServeOutcome;
6
+ fromResponse(response: Response): NodeServeOutcome;
7
+ timeout(): NodeServeOutcome;
8
+ }
9
+ //# sourceMappingURL=node-outcome-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-outcome-hook.d.ts","sourceRoot":"","sources":["../../src/server/node-outcome-hook.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAA;IACzD,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,CAAA;IAClD,OAAO,IAAI,gBAAgB,CAAA;CAC5B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=node-outcome-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-outcome-hook.js","sourceRoot":"","sources":["../../src/server/node-outcome-hook.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { type HandlerResult } from "./runtime-core.js";
2
+ import type { CtxSet } from "./server.js";
3
+ /**
4
+ * What {@link Server.resolveNode} returns: either a plain-data render the `@nifrajs/node` adapter writes
5
+ * to the socket directly (`kind: "json"` - status + headers + cookies + a pre-stringified body, **no**
6
+ * undici `Response` built or drained), a marked buffered response body (`kind: "body"` - e.g.
7
+ * @nifrajs/web's non-deferred SSR HTML), or a `Response` (`kind: "response"`) for everything else
8
+ * (redirects, 404/405/errors, unmarked or streaming bodies). Internal to the nifra<->node bridge.
9
+ */
10
+ export type NodeServeOutcome = {
11
+ readonly kind: "response";
12
+ readonly response: Response;
13
+ } | {
14
+ readonly kind: "json";
15
+ readonly status: number;
16
+ /** `c.set.headers` backing, or `undefined` when the handler never set a header. */
17
+ readonly headers: Readonly<Record<string, string>> | undefined;
18
+ /** Queued `Set-Cookie` lines, or `undefined`; the adapter emits one header line each. */
19
+ readonly cookies: readonly string[] | undefined;
20
+ /** The JSON body already stringified, or `null` for an empty (204) response. */
21
+ readonly body: string | null;
22
+ } | {
23
+ readonly kind: "body";
24
+ readonly status: number;
25
+ readonly headers: Readonly<Record<string, string | readonly string[]>> | undefined;
26
+ readonly body: string | Uint8Array;
27
+ };
28
+ /**
29
+ * `finalize` for the node-direct path - mirror of `toResponse` that skips the `Response` build:
30
+ * a plain value becomes pre-stringified JSON primitives (the adapter `JSON.stringify`s once, here, not
31
+ * via `Response.json` + a body drain); a handler-returned `Response` is wrapped as-is, with queued
32
+ * cookies appended exactly as `toResponse` does (so the set-cookie-then-`redirect()` pattern still
33
+ * works on Node).
34
+ */
35
+ export declare function toNodeOutcome(result: HandlerResult, set: CtxSet): NodeServeOutcome;
36
+ export declare function nodeOutcomeFromResponse(response: Response): NodeServeOutcome;
37
+ //# sourceMappingURL=node-outcome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-outcome.d.ts","sourceRoot":"","sources":["../../src/server/node-outcome.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,aAAa,EAAoB,MAAM,mBAAmB,CAAA;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC1D;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IAC9D,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IAC/C,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;CACnC,CAAA;AAEL;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAwBlF;AAID,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,CAK5E"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Node-direct outcome shaping: the `@nifrajs/node` bridge's render form and the `Response` -> outcome
3
+ * conversion. Mirrors `respond.ts` but skips the undici `Response` build where the adapter can write a
4
+ * plain-data render straight to the socket. Imports only runtime-core + respond + the spine types.
5
+ */
6
+ import { appendCookiesToResponse } from "./respond.js";
7
+ import { isResponseResult } from "./runtime-core.js";
8
+ /**
9
+ * `finalize` for the node-direct path - mirror of `toResponse` that skips the `Response` build:
10
+ * a plain value becomes pre-stringified JSON primitives (the adapter `JSON.stringify`s once, here, not
11
+ * via `Response.json` + a body drain); a handler-returned `Response` is wrapped as-is, with queued
12
+ * cookies appended exactly as `toResponse` does (so the set-cookie-then-`redirect()` pattern still
13
+ * works on Node).
14
+ */
15
+ export function toNodeOutcome(result, set) {
16
+ if (isResponseResult(result)) {
17
+ const body = result.toNodeBody?.();
18
+ if (body !== undefined) {
19
+ return {
20
+ kind: "body",
21
+ status: body.status,
22
+ headers: appendCookiesToNodeHeaders(body.headers, set._cookies),
23
+ body: body.body,
24
+ };
25
+ }
26
+ return nodeOutcomeFromResponse(appendCookiesToResponse(result.toResponse(), set));
27
+ }
28
+ if (result instanceof Response) {
29
+ return nodeOutcomeFromResponse(appendCookiesToResponse(result, set));
30
+ }
31
+ const status = set.status ?? (result === undefined ? 204 : 200);
32
+ return {
33
+ kind: "json",
34
+ status,
35
+ headers: set._headers,
36
+ cookies: set._cookies,
37
+ body: result === undefined ? null : JSON.stringify(result),
38
+ };
39
+ }
40
+ const NODE_RESPONSE_BODY = Symbol.for("nifra.response.body");
41
+ export function nodeOutcomeFromResponse(response) {
42
+ const body = nodeResponseBody(response);
43
+ return body === undefined
44
+ ? { kind: "response", response }
45
+ : { kind: "body", status: response.status, headers: responseHeadersForNode(response), body };
46
+ }
47
+ function nodeResponseBody(response) {
48
+ if (response.bodyUsed)
49
+ return undefined;
50
+ const body = response[NODE_RESPONSE_BODY];
51
+ return typeof body === "string" || body instanceof Uint8Array ? body : undefined;
52
+ }
53
+ function responseHeadersForNode(response) {
54
+ let headers;
55
+ response.headers.forEach((value, key) => {
56
+ headers ??= {};
57
+ headers[key] = value;
58
+ });
59
+ const setCookies = response.headers.getSetCookie?.();
60
+ if (setCookies !== undefined && setCookies.length > 0) {
61
+ headers ??= {};
62
+ headers["set-cookie"] = setCookies;
63
+ }
64
+ return headers;
65
+ }
66
+ function appendCookiesToNodeHeaders(headers, cookies) {
67
+ if (cookies === undefined || cookies.length === 0)
68
+ return headers;
69
+ const out = headers === undefined ? {} : { ...headers };
70
+ const existing = out["set-cookie"];
71
+ const setCookies = existing === undefined ? [] : typeof existing === "string" ? [existing] : [...existing];
72
+ out["set-cookie"] = [...setCookies, ...cookies];
73
+ return out;
74
+ }
75
+ //# sourceMappingURL=node-outcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-outcome.js","sourceRoot":"","sources":["../../src/server/node-outcome.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Plugin definers and their types. A plugin is a function that augments an app (calling
3
+ * `use`/`derive`/`decorate` and/or registering routes) and returns it; these helpers attach a name
4
+ * for idempotent dedupe and pin the type-threading so `.use()` preserves the caller's typed server.
5
+ */
6
+ import type { AnyServer } from "./server.js";
7
+ /**
8
+ * A nifra **plugin**: a function that augments an app - calling `use`/`derive`/`decorate` and/or
9
+ * registering routes - and returns it. Because `derive`/`decorate` are type-threaded, an **inline**
10
+ * `app.use((a) => a.derive(...).decorate(...))` carries the added context to handlers defined after
11
+ * it (the `use` overload is generic over the concrete `this`). Wrap with {@link definePlugin} to
12
+ * attach a name for idempotent dedupe (applying the same named plugin twice - e.g. transitively - is
13
+ * a no-op).
14
+ */
15
+ export type NifraPlugin<In extends AnyServer = AnyServer, Out extends AnyServer = In> = ((app: In) => Out) & {
16
+ readonly pluginName?: string;
17
+ };
18
+ /**
19
+ * A named type-identity plugin built with {@link defineIdentityPlugin}. It returns the same concrete
20
+ * server type it receives, preserving the caller's typed registry and context across `.use()` while
21
+ * still allowing the plugin to register runtime hooks or handlers.
22
+ */
23
+ export type IdentityPlugin = (<S extends AnyServer>(app: S) => S) & {
24
+ readonly pluginName?: string;
25
+ };
26
+ /**
27
+ * Name + ergonomics for a plugin that **adds typed context** (`derive`/`decorate`). `app.use(myPlugin)`
28
+ * applies it once; a second `use` of the same name is skipped (idempotent), so plugins can depend on each
29
+ * other without double-registering hooks.
30
+ *
31
+ * ```ts
32
+ * export const requestId = definePlugin("requestId", (app) => app.derive(() => ({ requestId: uuid() })))
33
+ * app.use(requestId) // downstream handlers see c.requestId
34
+ * ```
35
+ *
36
+ * FOOTGUN: only use this for a plugin that adds context. For a plugin that **mounts routes/hooks but adds
37
+ * NO context** (an auth router, an audit logger), use {@link defineRouterPlugin} ({@link defineIdentityPlugin}).
38
+ * `definePlugin((app) => app.get(...))` infers `app: Server<any, any>`, so `.use()` returns `Server<any, any>`
39
+ * and your whole typed client silently collapses to `any` - no type error, no runtime error.
40
+ */
41
+ export declare function definePlugin<In extends AnyServer, Out extends AnyServer>(name: string, apply: (app: In) => Out): NifraPlugin<In, Out>;
42
+ /**
43
+ * Define a type-**identity** plugin: it registers routes/hooks as a side effect but returns the app with
44
+ * its `Registry` + `Context` UNCHANGED. Use this (not {@link definePlugin}) for any plugin that doesn't
45
+ * add context types - e.g. one mounting an auth handler. It threads the caller's *concrete* server type
46
+ * through `use`, so routes declared after `app.use(plugin)` keep their types.
47
+ *
48
+ * Why a dedicated helper: `definePlugin((app) => app)` infers `app: Server<any, any>`, so `use` returns
49
+ * `Server<any, any>` and the whole typed client collapses to `any`. The explicit generic return type here
50
+ * (which a plain `Object.assign` can't preserve) is what keeps `use` returning the precise server type.
51
+ *
52
+ * ```ts
53
+ * export const audit = defineIdentityPlugin("audit", (app) => app.onResponse(logResponse))
54
+ * const api = server().get("/a", h).use(audit).get("/b", h) // /a AND /b stay typed
55
+ * ```
56
+ */
57
+ export declare function defineIdentityPlugin(name: string, apply: <S extends AnyServer>(app: S) => S): IdentityPlugin;
58
+ /**
59
+ * Alias of {@link defineIdentityPlugin} with a name that says what it's FOR: a plugin that **mounts
60
+ * routes/hooks but adds no context type** (an auth router, an audit logger). Use this - not
61
+ * {@link definePlugin} - for any such plugin, or the typed client silently collapses to `any`. The
62
+ * "identity" in {@link defineIdentityPlugin} refers to the type-identity it preserves; `defineRouterPlugin`
63
+ * is the same thing under a clearer name.
64
+ *
65
+ * Mount routes as a **side effect**, then return the app unchanged (registering via `.get`/`.post` would
66
+ * change the type away from the identity `S`; the mounted routes run but aren't in the caller's typed
67
+ * registry - that's the trade that keeps everything else typed):
68
+ *
69
+ * ```ts
70
+ * export const scim = defineRouterPlugin("scim", (app) => {
71
+ * app.get("/scim/v2/Users", listUsers) // side effect: mounted at runtime
72
+ * return app // return S unchanged → routes added after .use(scim) stay typed
73
+ * })
74
+ * const api = server().get("/a", h).use(scim).get("/b", h) // /a AND /b stay typed
75
+ * ```
76
+ */
77
+ export declare const defineRouterPlugin: typeof defineIdentityPlugin;
78
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/server/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CAAC,EAAE,SAAS,SAAS,GAAG,SAAS,EAAE,GAAG,SAAS,SAAS,GAAG,EAAE,IAAI,CAAC,CACvF,GAAG,EAAE,EAAE,KACJ,GAAG,CAAC,GAAG;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG;IAClE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,SAAS,EACtE,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,GAAG,GACtB,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,CAEtB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GACxC,cAAc,CAEhB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,EAAE,OAAO,oBAA2C,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Name + ergonomics for a plugin that **adds typed context** (`derive`/`decorate`). `app.use(myPlugin)`
3
+ * applies it once; a second `use` of the same name is skipped (idempotent), so plugins can depend on each
4
+ * other without double-registering hooks.
5
+ *
6
+ * ```ts
7
+ * export const requestId = definePlugin("requestId", (app) => app.derive(() => ({ requestId: uuid() })))
8
+ * app.use(requestId) // downstream handlers see c.requestId
9
+ * ```
10
+ *
11
+ * FOOTGUN: only use this for a plugin that adds context. For a plugin that **mounts routes/hooks but adds
12
+ * NO context** (an auth router, an audit logger), use {@link defineRouterPlugin} ({@link defineIdentityPlugin}).
13
+ * `definePlugin((app) => app.get(...))` infers `app: Server<any, any>`, so `.use()` returns `Server<any, any>`
14
+ * and your whole typed client silently collapses to `any` - no type error, no runtime error.
15
+ */
16
+ export function definePlugin(name, apply) {
17
+ return Object.assign(apply, { pluginName: name });
18
+ }
19
+ /**
20
+ * Define a type-**identity** plugin: it registers routes/hooks as a side effect but returns the app with
21
+ * its `Registry` + `Context` UNCHANGED. Use this (not {@link definePlugin}) for any plugin that doesn't
22
+ * add context types - e.g. one mounting an auth handler. It threads the caller's *concrete* server type
23
+ * through `use`, so routes declared after `app.use(plugin)` keep their types.
24
+ *
25
+ * Why a dedicated helper: `definePlugin((app) => app)` infers `app: Server<any, any>`, so `use` returns
26
+ * `Server<any, any>` and the whole typed client collapses to `any`. The explicit generic return type here
27
+ * (which a plain `Object.assign` can't preserve) is what keeps `use` returning the precise server type.
28
+ *
29
+ * ```ts
30
+ * export const audit = defineIdentityPlugin("audit", (app) => app.onResponse(logResponse))
31
+ * const api = server().get("/a", h).use(audit).get("/b", h) // /a AND /b stay typed
32
+ * ```
33
+ */
34
+ export function defineIdentityPlugin(name, apply) {
35
+ return Object.assign(apply, { pluginName: name });
36
+ }
37
+ /**
38
+ * Alias of {@link defineIdentityPlugin} with a name that says what it's FOR: a plugin that **mounts
39
+ * routes/hooks but adds no context type** (an auth router, an audit logger). Use this - not
40
+ * {@link definePlugin} - for any such plugin, or the typed client silently collapses to `any`. The
41
+ * "identity" in {@link defineIdentityPlugin} refers to the type-identity it preserves; `defineRouterPlugin`
42
+ * is the same thing under a clearer name.
43
+ *
44
+ * Mount routes as a **side effect**, then return the app unchanged (registering via `.get`/`.post` would
45
+ * change the type away from the identity `S`; the mounted routes run but aren't in the caller's typed
46
+ * registry - that's the trade that keeps everything else typed):
47
+ *
48
+ * ```ts
49
+ * export const scim = defineRouterPlugin("scim", (app) => {
50
+ * app.get("/scim/v2/Users", listUsers) // side effect: mounted at runtime
51
+ * return app // return S unchanged → routes added after .use(scim) stay typed
52
+ * })
53
+ * const api = server().get("/a", h).use(scim).get("/b", h) // /a AND /b stay typed
54
+ * ```
55
+ */
56
+ export const defineRouterPlugin = defineIdentityPlugin;
57
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/server/plugin.ts"],"names":[],"mappings":"AA4BA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,KAAuB;IAEvB,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAyB,CAAA;AAC3E,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,KAAyC;IAEzC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAmB,CAAA;AACrE,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAgC,oBAAoB,CAAA"}
@@ -0,0 +1,18 @@
1
+ import type { RequestSource } from "./server.js";
2
+ export declare function searchOf(url: string): string;
3
+ /** A query value: a single occurrence is a string; a repeated key promotes to a string[] so an
4
+ * array query schema (`t.array(t.string())`) can validate `?tag=a&tag=b` - last-wins silently
5
+ * dropped values before (audit 2026-06). Single-occurrence keys stay plain strings, so existing
6
+ * `t.string()` schemas are untouched; a repeated key against a string schema now FAILS validation
7
+ * (an explicit 400 beats silently picking one). */
8
+ export type QueryValue = string | string[];
9
+ export declare function queryObjectOf(search: string): Record<string, QueryValue>;
10
+ /** `application/x-www-form-urlencoded`, with or without a charset suffix. */
11
+ export declare function isUrlEncodedForm(contentType: string): boolean;
12
+ /**
13
+ * Read an HTML-form body (urlencoded) into the plain object a body schema validates - same byte
14
+ * cap as the JSON path (a lying/absent Content-Length can't force an oversized buffer), same
15
+ * repeated-key -> `string[]` promotion as query parsing, same `__proto__` guard.
16
+ */
17
+ export declare function readBoundedForm(req: RequestSource, maxBytes: number): Promise<Record<string, QueryValue> | Response>;
18
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/server/query.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;mDAImD;AACnD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;AAqC1C,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAyBxE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAK7D;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,CAchD"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Query-string and urlencoded-form parsing. Pure request-shaping helpers with no server internals:
3
+ * the fast scanner for `c.query`, the repeated-key -> `string[]` promotion shared by query + form,
4
+ * and the byte-capped HTML-form reader. Split out of the server kernel so the file stays one domain.
5
+ */
6
+ import { readBoundedBytes } from "./body.js";
7
+ import { jsonError, urlPartsOf } from "./http.js";
8
+ // The query string ("?a=1", or "" when absent) - for lazily building `c.query` only when read.
9
+ // The fragment (after the first `#`) bounds the search: a `?` that appears only inside the fragment
10
+ // is NOT a query (matches WHATWG). Fragments never reach the server in `req.url`, so this is purely
11
+ // for provable equivalence with `new URL(req.url).search`.
12
+ export function searchOf(url) {
13
+ return urlPartsOf(url).search;
14
+ }
15
+ /** Accumulate into a NULL-PROTOTYPE record (every call site below creates one): with no inherited
16
+ * `constructor`/`toString`/`__proto__` accessors, a hostile key is just an own data key - the
17
+ * promotion logic can't collide with `Object.prototype` members, and `__proto__` needs no special
18
+ * case (direct assignment on a null-proto object creates an own property). */
19
+ function setQueryValue(out, key, value) {
20
+ const existing = out[key];
21
+ if (existing === undefined) {
22
+ out[key] = value;
23
+ }
24
+ else if (typeof existing === "string") {
25
+ out[key] = [existing, value];
26
+ }
27
+ else {
28
+ existing.push(value);
29
+ }
30
+ }
31
+ function queryObjectFallback(search) {
32
+ // Manual iteration instead of Object.fromEntries: repeated keys must promote to arrays
33
+ // (fromEntries is last-wins), and __proto__ needs the same own-property guard.
34
+ const out = Object.create(null);
35
+ for (const [key, value] of new URLSearchParams(search)) {
36
+ setQueryValue(out, key, value);
37
+ }
38
+ return out;
39
+ }
40
+ /**
41
+ * Build the plain object passed to query schemas. Plain ASCII-ish queries avoid
42
+ * `URLSearchParams` + iterator allocations; encoded queries fall back to the Web API so `+`,
43
+ * percent-decoding, malformed escapes, and empty-key behavior stay exact. Repeated keys promote
44
+ * to `string[]` on BOTH paths (see {@link setQueryValue}).
45
+ */
46
+ // Shared empty result for no-query requests: frozen + null-prototype (same shape contract as the
47
+ // populated path), allocated once instead of per request.
48
+ const EMPTY_QUERY = Object.freeze(Object.create(null));
49
+ export function queryObjectOf(search) {
50
+ const start = search.charCodeAt(0) === 63 /* ? */ ? 1 : 0;
51
+ if (start >= search.length)
52
+ return EMPTY_QUERY;
53
+ for (let i = start; i < search.length; i++) {
54
+ const c = search.charCodeAt(i);
55
+ if (c === 37 /* % */ || c === 43 /* + */)
56
+ return queryObjectFallback(search);
57
+ }
58
+ const out = Object.create(null);
59
+ let pos = start;
60
+ while (pos <= search.length) {
61
+ const amp = search.indexOf("&", pos);
62
+ const end = amp === -1 ? search.length : amp;
63
+ if (end > pos) {
64
+ const eq = search.indexOf("=", pos);
65
+ const split = eq !== -1 && eq < end ? eq : end;
66
+ const key = search.slice(pos, split);
67
+ const value = split === end ? "" : search.slice(split + 1, end);
68
+ setQueryValue(out, key, value);
69
+ }
70
+ if (amp === -1)
71
+ break;
72
+ pos = amp + 1;
73
+ }
74
+ return out;
75
+ }
76
+ /** `application/x-www-form-urlencoded`, with or without a charset suffix. */
77
+ export function isUrlEncodedForm(contentType) {
78
+ return (contentType === "application/x-www-form-urlencoded" ||
79
+ contentType.startsWith("application/x-www-form-urlencoded;"));
80
+ }
81
+ const FORM_DECODER = new TextDecoder();
82
+ /**
83
+ * Read an HTML-form body (urlencoded) into the plain object a body schema validates - same byte
84
+ * cap as the JSON path (a lying/absent Content-Length can't force an oversized buffer), same
85
+ * repeated-key -> `string[]` promotion as query parsing, same `__proto__` guard.
86
+ */
87
+ export async function readBoundedForm(req, maxBytes) {
88
+ const read = await readBoundedBytes(req, maxBytes);
89
+ if (!read.ok) {
90
+ return read.status === 413
91
+ ? jsonError(413, "payload_too_large")
92
+ : jsonError(400, "invalid_content_length");
93
+ }
94
+ const out = Object.create(null);
95
+ // URLSearchParams owns the format's quirks (`+` as space, percent-decoding, empty keys);
96
+ // it never throws on junk input, so no try/catch is needed here.
97
+ for (const [key, value] of new URLSearchParams(FORM_DECODER.decode(read.bytes))) {
98
+ setQueryValue(out, key, value);
99
+ }
100
+ return out;
101
+ }
102
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/server/query.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { InferOutput, StandardSchemaV1 } from "../schema/standard.js";
1
+ import type { InferInput, InferOutput, StandardSchemaV1 } from "../schema/standard.js";
2
2
  import type { Params, RouteSchema } from "./context.js";
3
3
  /**
4
4
  * One route's input/output shape as the **client** will consume it. `query`/`body`
@@ -11,12 +11,17 @@ export interface RouteInfo {
11
11
  readonly query: unknown;
12
12
  readonly body: unknown;
13
13
  readonly output: unknown;
14
- /** Union of the route's declared error-response body types (from `schema.errors`); `unknown` when the
15
- * route declares none. Surfaced by the typed client as the failure `errorData`. */
14
+ /** The route's declared error bodies as a status-keyed record (from `schema.errors`, e.g.
15
+ * `{ 404: NotFound }`); `unknown` when the route declares none. The typed client turns this into
16
+ * a status-discriminated failure union. */
16
17
  readonly errors?: unknown;
17
18
  /** The SSE event payload type (from `schema.sse`, declared via `app.sse()`); `never` for ordinary
18
19
  * routes. The typed client keys `.subscribe()` availability and its event type off this. */
19
20
  readonly sse?: unknown;
21
+ /** The WebSocket message contract (from `app.ws()`'s `messageSchema`/`sendSchema`): `in` is what the
22
+ * client may send, `out` what the server pushes. Present only on WS entries (method key `"WS"`);
23
+ * the typed client keys `.ws()` availability and its frame types off this. */
24
+ readonly ws?: unknown;
20
25
  }
21
26
  /** The accumulated, type-level map of every route on a Server: path → method → RouteInfo. */
22
27
  export type Registry = Record<string, Record<string, RouteInfo>>;
@@ -33,13 +38,14 @@ type RegistryQuery<S extends RouteSchema> = S extends {
33
38
  type RegistryOutput<S extends RouteSchema, Output> = S extends {
34
39
  response: infer R extends StandardSchemaV1;
35
40
  } ? InferOutput<R> : Output;
36
- /** The union of a route's declared error-response body types (`schema.errors` → `{status: schema}`), so the
37
- * typed client can surface the failure body. `unknown` when the route declares no `errors`. */
41
+ /** A route's declared error-response body types as a STATUS-KEYED record (`schema.errors` →
42
+ * `{ 404: NotFound, 409: Conflict }`), so the typed client can discriminate the failure body by
43
+ * `status`, not just surface a union. `unknown` when the route declares no `errors`. */
38
44
  type RegistryErrors<S extends RouteSchema> = S extends {
39
45
  errors: infer E extends Record<number, StandardSchemaV1>;
40
46
  } ? {
41
47
  [K in keyof E]: E[K] extends StandardSchemaV1 ? InferOutput<E[K]> : never;
42
- }[keyof E] : unknown;
48
+ } : unknown;
43
49
  /** The SSE event payload type from a route's `sse` schema; `never` for ordinary routes. */
44
50
  type RegistrySse<S extends RouteSchema> = S extends {
45
51
  sse: infer E extends StandardSchemaV1;
@@ -55,6 +61,25 @@ export type RouteInfoFor<Path extends string, S extends RouteSchema, Output> = {
55
61
  };
56
62
  /** The client-visible output of a handler: its awaited return, minus raw `Response`. */
57
63
  export type OutputOf<H extends (...args: never[]) => unknown> = Exclude<Awaited<ReturnType<H>>, Response>;
64
+ /**
65
+ * The registry entry for a WebSocket route (stored under the pseudo-method key `"WS"`, so WS routes
66
+ * ride the same path → method map as HTTP routes - no extra Server generic). `in` is the client →
67
+ * server frame type: the `messageSchema`'s INPUT side, since that is what goes on the wire before
68
+ * validation transforms it. `out` is the server → client frame type from `sendSchema` (a type-level
69
+ * contract; the server's own sends are not runtime-validated). Either is `unknown` when undeclared.
70
+ */
71
+ export type WsRouteInfoFor<Path extends string, In extends StandardSchemaV1 | undefined, Out extends StandardSchemaV1 | undefined> = {
72
+ readonly params: Params<Path>;
73
+ readonly query: never;
74
+ readonly body: never;
75
+ readonly output: never;
76
+ readonly errors: unknown;
77
+ readonly sse: never;
78
+ readonly ws: {
79
+ readonly in: In extends StandardSchemaV1 ? InferInput<In> : unknown;
80
+ readonly out: Out extends StandardSchemaV1 ? InferOutput<Out> : unknown;
81
+ };
82
+ };
58
83
  /**
59
84
  * Merge a new route into the registry, combining methods that share a path.
60
85
  *
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/server/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/server/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The runtime request context (`c`): the `RawContext` implementation the handler receives, its lazy
3
+ * `c.set` response-controls backing, and the bounded body readers behind `c.boundedBody`/`c.boundedJson`.
4
+ * Type-imports the kernel's spine (never its values) and pulls its primitives from `runtime-core`, so it
5
+ * sits below the server module in the graph.
6
+ */
7
+ import type { RequestBudget } from "../budget.js";
8
+ import type { Platform } from "./context.js";
9
+ import { CONTEXT_SEARCH, CONTEXT_SET } from "./runtime-core.js";
10
+ import type { CtxSet, RawContext, RequestSource } from "./server.js";
11
+ export declare class RequestContext implements RawContext {
12
+ params: Record<string, string>;
13
+ body: unknown;
14
+ private searchValue;
15
+ private signalValue;
16
+ private budgetValue;
17
+ private platformValue;
18
+ private setValue;
19
+ private queryValue;
20
+ private queryReady;
21
+ private cookiesValue;
22
+ private readonly source;
23
+ private readonly maxBodyBytes;
24
+ constructor(source: RequestSource, params: Record<string, string>, maxBodyBytes: number);
25
+ constructor(source: RequestSource, params: Record<string, string>, search: string | undefined, signal: AbortSignal, budget: RequestBudget, platform: Platform | undefined, maxBodyBytes: number);
26
+ static native(source: RequestSource, params: Record<string, string>, maxBodyBytes: number): RequestContext;
27
+ [CONTEXT_SET](): CtxSet | undefined;
28
+ get [CONTEXT_SEARCH](): string;
29
+ get set(): CtxSet;
30
+ get signal(): AbortSignal;
31
+ get budget(): RequestBudget;
32
+ get env(): unknown;
33
+ get clientIp(): string | undefined;
34
+ get waitUntil(): (promise: Promise<unknown>) => void;
35
+ get req(): Request;
36
+ get request(): Request;
37
+ json(body: unknown, init?: ResponseInit | number): Response;
38
+ text(body: string, init?: ResponseInit | number): Response;
39
+ get query(): unknown;
40
+ set query(v: unknown);
41
+ get cookies(): Readonly<Record<string, string>>;
42
+ boundedBody(maxBytes?: number): Promise<Uint8Array>;
43
+ boundedJson<T = unknown>(maxBytes?: number): Promise<T>;
44
+ }
45
+ /**
46
+ * Read a JSON body with the same byte cap used by schema validation and `c.boundedJson`.
47
+ * Non-chunked, framed requests with an in-cap `Content-Length` use the runtime-native `req.json()`;
48
+ * chunked or length-less requests fall back to the streaming byte-cap guard.
49
+ */
50
+ export declare function readBoundedJsonSource(req: RequestSource, maxBytes: number): Promise<unknown | Response>;
51
+ //# sourceMappingURL=request-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAI5C,OAAO,EACL,cAAc,EACd,WAAW,EAOZ,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AA2CpE,qBAAa,cAAe,YAAW,UAAU;IAKvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,IAAI,EAAE,OAAO,CAAA;IACrB,QAAgB,WAAW,CAAoB;IAC/C,QAAgB,WAAW,CAAyB;IACpD,QAAgB,WAAW,CAA2B;IACtD,QAAgB,aAAa,CAAsB;IAEnD,QAAgB,QAAQ,CAAoB;IAC5C,QAAgB,UAAU,CAAS;IACnC,QAAgB,UAAU,CAAS;IACnC,QAAgB,YAAY,CAA8C;IAC1E,iBAAyB,MAAM,CAAe;IAC9C,iBAAyB,YAAY,CAAQ;gBAEjC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,MAAM;gBAErF,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM;IAwBtB,MAAM,CAAC,MAAM,CACX,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,EAAE,MAAM,GACnB,cAAc;IAIjB,CAAC,WAAW,CAAC,IAAI,MAAM,GAAG,SAAS;IAInC,IAAI,CAAC,cAAc,CAAC,IAAI,MAAM,CAG7B;IAED,IAAI,GAAG,IAAI,MAAM,CAGhB;IAED,IAAI,MAAM,IAAI,WAAW,CAExB;IAED,IAAI,MAAM,IAAI,aAAa,CAE1B;IAED,IAAI,GAAG,IAAI,OAAO,CAEjB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAIjC;IAED,IAAI,SAAS,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAEnD;IAED,IAAI,GAAG,IAAI,OAAO,CAEjB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ;IAI3D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ;IAO1D,IAAI,KAAK,IAAI,OAAO,CAMnB;IAED,IAAI,KAAK,CAAC,CAAC,EAAE,OAAO,EAGnB;IAED,IAAI,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAG9C;IAED,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAInD,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAGxD;AA4BD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,GAAG,QAAQ,CAAC,CA8B7B"}