@nifrajs/core 3.1.0 → 3.3.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 (146) hide show
  1. package/README.md +21 -0
  2. package/dist/durable-adapters.d.ts.map +1 -1
  3. package/dist/durable-adapters.js +26 -3
  4. package/dist/durable-adapters.js.map +1 -1
  5. package/dist/durable-approval.d.ts +56 -0
  6. package/dist/durable-approval.d.ts.map +1 -0
  7. package/dist/durable-approval.js +233 -0
  8. package/dist/durable-approval.js.map +1 -0
  9. package/dist/durable-effect.d.ts +42 -0
  10. package/dist/durable-effect.d.ts.map +1 -0
  11. package/dist/durable-effect.js +234 -0
  12. package/dist/durable-effect.js.map +1 -0
  13. package/dist/durable-execution.d.ts +8 -346
  14. package/dist/durable-execution.d.ts.map +1 -1
  15. package/dist/durable-execution.js +7 -1150
  16. package/dist/durable-execution.js.map +1 -1
  17. package/dist/durable-saga.d.ts +94 -0
  18. package/dist/durable-saga.d.ts.map +1 -0
  19. package/dist/durable-saga.js +550 -0
  20. package/dist/durable-saga.js.map +1 -0
  21. package/dist/edge-kit.d.ts +2 -2
  22. package/dist/edge-kit.d.ts.map +1 -1
  23. package/dist/edge-kit.js +2 -2
  24. package/dist/edge-kit.js.map +1 -1
  25. package/dist/index.d.ts +23 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +18 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/internal/durable-approval-protocol.d.ts +1 -1
  30. package/dist/internal/durable-approval-protocol.d.ts.map +1 -1
  31. package/dist/internal/durable-effect-protocol.d.ts +1 -1
  32. package/dist/internal/durable-effect-protocol.d.ts.map +1 -1
  33. package/dist/internal/durable-saga-protocol.d.ts +1 -1
  34. package/dist/internal/durable-saga-protocol.d.ts.map +1 -1
  35. package/dist/internal/durable-shared.d.ts +26 -0
  36. package/dist/internal/durable-shared.d.ts.map +1 -0
  37. package/dist/internal/durable-shared.js +131 -0
  38. package/dist/internal/durable-shared.js.map +1 -0
  39. package/dist/internal/durable-types.d.ts +159 -0
  40. package/dist/internal/durable-types.d.ts.map +1 -0
  41. package/dist/internal/durable-types.js +2 -0
  42. package/dist/internal/durable-types.js.map +1 -0
  43. package/dist/internal/route-compiler.d.ts +61 -0
  44. package/dist/internal/route-compiler.d.ts.map +1 -0
  45. package/dist/internal/route-compiler.js +121 -0
  46. package/dist/internal/route-compiler.js.map +1 -0
  47. package/dist/internal/route-execution.d.ts +6 -4
  48. package/dist/internal/route-execution.d.ts.map +1 -1
  49. package/dist/internal/route-execution.js +2 -17
  50. package/dist/internal/route-execution.js.map +1 -1
  51. package/dist/internal/route-lanes.d.ts +35 -0
  52. package/dist/internal/route-lanes.d.ts.map +1 -0
  53. package/dist/internal/route-lanes.js +150 -0
  54. package/dist/internal/route-lanes.js.map +1 -0
  55. package/dist/internal/route-program.d.ts +67 -0
  56. package/dist/internal/route-program.d.ts.map +1 -0
  57. package/dist/internal/route-program.js +199 -0
  58. package/dist/internal/route-program.js.map +1 -0
  59. package/dist/server/bare-error-lane.d.ts +1 -1
  60. package/dist/server/bare-error-lane.d.ts.map +1 -1
  61. package/dist/server/bare-error-lane.js +3 -3
  62. package/dist/server/bare-error-lane.js.map +1 -1
  63. package/dist/server/body-lane.d.ts +13 -0
  64. package/dist/server/body-lane.d.ts.map +1 -0
  65. package/dist/server/body-lane.js +134 -0
  66. package/dist/server/body-lane.js.map +1 -0
  67. package/dist/server/contract.d.ts +40 -14
  68. package/dist/server/contract.d.ts.map +1 -1
  69. package/dist/server/contract.js +7 -0
  70. package/dist/server/contract.js.map +1 -1
  71. package/dist/server/cookies.d.ts.map +1 -1
  72. package/dist/server/cookies.js +16 -2
  73. package/dist/server/cookies.js.map +1 -1
  74. package/dist/server/plugin.d.ts +2 -2
  75. package/dist/server/plugin.d.ts.map +1 -1
  76. package/dist/server/plugin.js +6 -1
  77. package/dist/server/plugin.js.map +1 -1
  78. package/dist/server/registry.d.ts +40 -12
  79. package/dist/server/registry.d.ts.map +1 -1
  80. package/dist/server/request-context.d.ts +4 -28
  81. package/dist/server/request-context.d.ts.map +1 -1
  82. package/dist/server/request-context.js +10 -185
  83. package/dist/server/request-context.js.map +1 -1
  84. package/dist/server/respond.d.ts.map +1 -1
  85. package/dist/server/respond.js +39 -2
  86. package/dist/server/respond.js.map +1 -1
  87. package/dist/server/runtime-core.d.ts +18 -2
  88. package/dist/server/runtime-core.d.ts.map +1 -1
  89. package/dist/server/runtime-core.js +0 -23
  90. package/dist/server/runtime-core.js.map +1 -1
  91. package/dist/server/server-types.d.ts +3 -0
  92. package/dist/server/server-types.d.ts.map +1 -1
  93. package/dist/server/server.d.ts +113 -84
  94. package/dist/server/server.d.ts.map +1 -1
  95. package/dist/server/server.js +506 -639
  96. package/dist/server/server.js.map +1 -1
  97. package/dist/server/validation.d.ts +5 -0
  98. package/dist/server/validation.d.ts.map +1 -0
  99. package/dist/server/validation.js +13 -0
  100. package/dist/server/validation.js.map +1 -0
  101. package/dist/server/ws-bun.d.ts +11 -3
  102. package/dist/server/ws-bun.d.ts.map +1 -1
  103. package/dist/server/ws-bun.js +42 -12
  104. package/dist/server/ws-bun.js.map +1 -1
  105. package/dist/server/ws-hook.d.ts +3 -2
  106. package/dist/server/ws-hook.d.ts.map +1 -1
  107. package/dist/server.d.ts +2 -2
  108. package/dist/server.d.ts.map +1 -1
  109. package/dist/server.js +1 -1
  110. package/dist/server.js.map +1 -1
  111. package/dist/single-copy.d.ts.map +1 -1
  112. package/dist/single-copy.js +3 -1
  113. package/dist/single-copy.js.map +1 -1
  114. package/package.json +6 -3
  115. package/src/durable-adapters.ts +20 -0
  116. package/src/durable-approval.ts +281 -0
  117. package/src/durable-effect.ts +300 -0
  118. package/src/durable-execution.ts +8 -1627
  119. package/src/durable-saga.ts +744 -0
  120. package/src/edge-kit.ts +2 -2
  121. package/src/index.ts +129 -2
  122. package/src/internal/durable-approval-protocol.ts +1 -1
  123. package/src/internal/durable-effect-protocol.ts +1 -1
  124. package/src/internal/durable-saga-protocol.ts +1 -1
  125. package/src/internal/durable-shared.ts +157 -0
  126. package/src/internal/durable-types.ts +194 -0
  127. package/src/internal/route-compiler.ts +234 -0
  128. package/src/internal/route-execution.ts +34 -84
  129. package/src/internal/route-lanes.ts +221 -0
  130. package/src/internal/route-program.ts +404 -0
  131. package/src/server/bare-error-lane.ts +3 -2
  132. package/src/server/body-lane.ts +203 -0
  133. package/src/server/contract.ts +70 -20
  134. package/src/server/cookies.ts +16 -2
  135. package/src/server/plugin.ts +11 -5
  136. package/src/server/registry.ts +71 -16
  137. package/src/server/request-context.ts +7 -262
  138. package/src/server/respond.ts +45 -2
  139. package/src/server/runtime-core.ts +28 -2
  140. package/src/server/server-types.ts +3 -0
  141. package/src/server/server.ts +1152 -1260
  142. package/src/server/validation.ts +19 -0
  143. package/src/server/ws-bun.ts +44 -11
  144. package/src/server/ws-hook.ts +3 -2
  145. package/src/server.ts +7 -2
  146. package/src/single-copy.ts +3 -1
@@ -122,6 +122,8 @@ function staticJsonResponse(
122
122
  contentType,
123
123
  )
124
124
  }
125
+ // lgtm [js/stack-trace-exposure] `body` is already serialized; ordinary thrown errors are replaced
126
+ // with the fixed internal-error envelope before reaching this response boundary.
125
127
  return new Response(body, init)
126
128
  }
127
129
 
@@ -160,6 +162,7 @@ function withStaticHeaderInit(
160
162
  // portable constructor path there and select the Deno-specific shape only for Web responses that
161
163
  // carry a plain record. The first request lazily probes Deno's native JSON content-type so this
162
164
  // preserves the runtime's Response.json contract instead of baking in Bun's charset suffix.
165
+ const IS_BUN = typeof (globalThis as { Bun?: unknown }).Bun !== "undefined"
163
166
  const IS_DENO = typeof (globalThis as { Deno?: unknown }).Deno !== "undefined"
164
167
  let denoJsonContentType: string | undefined
165
168
 
@@ -176,6 +179,8 @@ function denoResponseWithJsonBody(
176
179
  headers: Record<string, string>,
177
180
  defaultContentType = responseJsonContentType(),
178
181
  ): Response {
182
+ // lgtm [js/stack-trace-exposure] this body is serialized data; ordinary thrown errors are replaced
183
+ // with the fixed internal-error envelope before reaching this response boundary.
179
184
  const response = new Response(body, { status })
180
185
  let hasContentType = false
181
186
  for (const [name, value] of Object.entries(headers)) {
@@ -188,6 +193,24 @@ function denoResponseWithJsonBody(
188
193
  return response
189
194
  }
190
195
 
196
+ /**
197
+ * Render a JSON value with caller-owned headers on the runtimes where mutating the response is
198
+ * cheaper than asking the Response constructor to ingest a record. Node deliberately stays on the
199
+ * record path: its undici implementation is a little faster there, and its production HTTP adapter
200
+ * normally uses the direct node outcome anyway. The two operations are equivalent at the Web
201
+ * boundary: Response.json supplies the same default content type, then the caller's headers override
202
+ * it exactly as `withJsonContentType` did.
203
+ */
204
+ function jsonResponseWithOwnHeaders(
205
+ result: object,
206
+ status: number,
207
+ headers: Record<string, string>,
208
+ ): Response {
209
+ const response = status === 200 ? Response.json(result) : Response.json(result, { status })
210
+ for (const name of Object.keys(headers)) response.headers.set(name, headers[name]!)
211
+ return stamped(response)
212
+ }
213
+
191
214
  // The framework-buffered-body marker shared with the Node adapter: a Response carrying it exposes
192
215
  // its already-serialized bytes without draining. On the Web serving paths it exists ONLY when a
193
216
  // registered body/raw hook needs it, so hook-less apps pay nothing.
@@ -438,6 +461,24 @@ export function toResponse(
438
461
  if (status === 204 || status === 205 || status === 304) {
439
462
  return stamped(new Response(null, headers === undefined ? { status } : { status, headers }))
440
463
  }
464
+ // Bun and Deno both make a JSON response first and then accept a few header mutations more cheaply
465
+ // than ingesting the same plain record in the constructor. This is the common dynamic-header
466
+ // shape (`c.set.headers`) after all cookies/static-header/tagging cases have been excluded. Keep the
467
+ // Node record path unchanged: its Web constructor wins by a small margin, and the native Node
468
+ // adapter's normal route finalizer does not build this Response in the first place.
469
+ if (
470
+ own !== undefined &&
471
+ !(own instanceof Headers) &&
472
+ statics === undefined &&
473
+ (set._cookies === undefined || set._cookies.length === 0) &&
474
+ (IS_BUN || IS_DENO) &&
475
+ !tagResponseBody &&
476
+ result !== undefined &&
477
+ typeof result === "object" &&
478
+ result !== null
479
+ ) {
480
+ return jsonResponseWithOwnHeaders(result, status, own)
481
+ }
441
482
  if (own === undefined && result !== undefined) {
442
483
  // Fast respond (profiled ~50 ns/req faster on every plain-JSON return): `JSON.stringify` + a
443
484
  // prebuilt init beats `Response.json`'s internal init handling. Output is byte-identical -
@@ -451,7 +492,8 @@ export function toResponse(
451
492
  : { status, headers: jsonCtHeaders }
452
493
  return tagged(
453
494
  statics === undefined
454
- ? new Response(body, init)
495
+ ? // lgtm [js/stack-trace-exposure] the serialized body is not a caught error stack.
496
+ new Response(body, init)
455
497
  : staticJsonResponse(body, status, statics, JSON_CONTENT_TYPE, init),
456
498
  body,
457
499
  tagResponseBody,
@@ -471,7 +513,8 @@ export function toResponse(
471
513
  headers as Record<string, string>,
472
514
  JSON_CT_HEADERS.get("content-type") ?? "application/json;charset=utf-8",
473
515
  )
474
- : new Response(body, { status, headers: withJsonContentType(headers) })
516
+ : // lgtm [js/stack-trace-exposure] the serialized body is not a caught error stack.
517
+ new Response(body, { status, headers: withJsonContentType(headers) })
475
518
  return tagged(
476
519
  response,
477
520
  body,
@@ -64,6 +64,22 @@ export interface ResponseResult {
64
64
  readonly plain?: PlainRender
65
65
  }
66
66
 
67
+ /**
68
+ * Type-only metadata carried by {@link status}. The symbol is declared, not created, so this brand
69
+ * adds no runtime property and no per-response allocation. It lets the registry distinguish a typed
70
+ * early response from an ordinary handler value while preserving the existing ResponseResult marker.
71
+ */
72
+ export declare const STATUS_RESPONSE_TYPE: unique symbol
73
+
74
+ /** A status-bearing response whose code and body remain visible to TypeScript. */
75
+ export interface StatusResponse<Code extends number = number, Body = unknown>
76
+ extends ResponseResult {
77
+ readonly [STATUS_RESPONSE_TYPE]: {
78
+ readonly code: Code
79
+ readonly body: Body
80
+ }
81
+ }
82
+
67
83
  export function isResponseResult(value: unknown): value is ResponseResult {
68
84
  return (
69
85
  typeof value === "object" &&
@@ -114,11 +130,21 @@ export function plainRenderHeaders(
114
130
  * The body is serialized by the lane that renders it, exactly like a handler's plain return, so the
115
131
  * response carries a `content-length` rather than falling to chunked, and queued cookies still apply.
116
132
  */
133
+ export function status<const Code extends number>(
134
+ code: Code,
135
+ body?: undefined,
136
+ init?: { readonly headers?: Readonly<Record<string, string>> },
137
+ ): StatusResponse<Code, undefined>
138
+ export function status<const Code extends number, const Body>(
139
+ code: Code,
140
+ body: Body,
141
+ init?: { readonly headers?: Readonly<Record<string, string>> },
142
+ ): StatusResponse<Code, Body>
117
143
  export function status(
118
144
  code: number,
119
145
  body?: unknown,
120
146
  init?: { readonly headers?: Readonly<Record<string, string>> },
121
- ): ResponseResult {
147
+ ): StatusResponse<number, unknown> {
122
148
  // The range `Response` accepts, enforced HERE so the plain lane cannot outrun it. A plain render
123
149
  // is written straight to the socket by the Node adapter, where `writeHead` takes 100-999 - so a
124
150
  // status this rejects would otherwise ship on Node and throw on every Web runtime, from the same
@@ -141,7 +167,7 @@ export function status(
141
167
  headers["content-type"] ??= "application/json;charset=utf-8"
142
168
  return new Response(JSON.stringify(body), { status: code, headers })
143
169
  },
144
- }
170
+ } as StatusResponse<number, unknown>
145
171
  }
146
172
 
147
173
  /** The concrete `Request` for a source - itself when a real `Request` was passed (the Web path), or the
@@ -256,6 +256,9 @@ export interface RunningServer {
256
256
  readonly hostname: string
257
257
  readonly pendingRequests: number
258
258
  stop(closeActiveConnections?: boolean): void
259
+ /** Bun's native topic broadcast, present on the Bun `Server` handle. `app.publish` delegates to it
260
+ * in native-pubsub mode; absent on other runtimes' running-server views. */
261
+ publish?(topic: string, data: string | ArrayBufferView | ArrayBuffer): number
259
262
  }
260
263
 
261
264
  /**