@nifrajs/core 2.13.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/assurance.d.ts +16 -8
- package/dist/assurance.d.ts.map +1 -1
- package/dist/assurance.js +33 -0
- package/dist/assurance.js.map +1 -1
- package/dist/binary.d.ts +32 -0
- package/dist/binary.d.ts.map +1 -1
- package/dist/binary.js +17 -0
- package/dist/binary.js.map +1 -1
- package/dist/durable-adapters.d.ts.map +1 -1
- package/dist/durable-adapters.js +21 -50
- package/dist/durable-adapters.js.map +1 -1
- package/dist/durable-execution.d.ts.map +1 -1
- package/dist/durable-execution.js +49 -69
- package/dist/durable-execution.js.map +1 -1
- package/dist/edge-kit.d.ts +27 -0
- package/dist/edge-kit.d.ts.map +1 -0
- package/dist/edge-kit.js +24 -0
- package/dist/edge-kit.js.map +1 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/durable-approval-protocol.d.ts +13 -0
- package/dist/internal/durable-approval-protocol.d.ts.map +1 -0
- package/dist/internal/durable-approval-protocol.js +66 -0
- package/dist/internal/durable-approval-protocol.js.map +1 -0
- package/dist/internal/durable-effect-protocol.d.ts +14 -0
- package/dist/internal/durable-effect-protocol.d.ts.map +1 -0
- package/dist/internal/durable-effect-protocol.js +16 -0
- package/dist/internal/durable-effect-protocol.js.map +1 -0
- package/dist/internal/durable-saga-protocol.d.ts +8 -0
- package/dist/internal/durable-saga-protocol.d.ts.map +1 -0
- package/dist/internal/durable-saga-protocol.js +21 -0
- package/dist/internal/durable-saga-protocol.js.map +1 -0
- package/dist/internal/route-catalog.d.ts +3 -0
- package/dist/internal/route-catalog.d.ts.map +1 -1
- package/dist/internal/route-catalog.js +5 -0
- package/dist/internal/route-catalog.js.map +1 -1
- package/dist/internal/route-execution.d.ts +11 -5
- package/dist/internal/route-execution.d.ts.map +1 -1
- package/dist/internal/route-execution.js +2 -1
- package/dist/internal/route-execution.js.map +1 -1
- package/dist/response-observer.d.ts +25 -0
- package/dist/response-observer.d.ts.map +1 -0
- package/dist/response-observer.js +40 -0
- package/dist/response-observer.js.map +1 -0
- package/dist/security/baseline.d.ts +68 -0
- package/dist/security/baseline.d.ts.map +1 -0
- package/dist/security/baseline.js +118 -0
- package/dist/security/baseline.js.map +1 -0
- package/dist/server/bare-error-lane.d.ts +26 -0
- package/dist/server/bare-error-lane.d.ts.map +1 -0
- package/dist/server/bare-error-lane.js +60 -0
- package/dist/server/bare-error-lane.js.map +1 -0
- package/dist/server/body.d.ts +7 -0
- package/dist/server/body.d.ts.map +1 -1
- package/dist/server/body.js +7 -0
- package/dist/server/body.js.map +1 -1
- package/dist/server/bridge-markers.d.ts +25 -0
- package/dist/server/bridge-markers.d.ts.map +1 -0
- package/dist/server/bridge-markers.js +25 -0
- package/dist/server/bridge-markers.js.map +1 -0
- package/dist/server/context.d.ts +6 -1
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/header-case.d.ts.map +1 -1
- package/dist/server/header-case.js +2 -1
- package/dist/server/header-case.js.map +1 -1
- package/dist/server/http.d.ts +36 -3
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +49 -3
- package/dist/server/http.js.map +1 -1
- package/dist/server/install.d.ts +6 -8
- package/dist/server/install.d.ts.map +1 -1
- package/dist/server/install.js +7 -0
- package/dist/server/install.js.map +1 -1
- package/dist/server/node-outcome-hook.d.ts +2 -1
- package/dist/server/node-outcome-hook.d.ts.map +1 -1
- package/dist/server/node-outcome-hook.js.map +1 -1
- package/dist/server/node-outcome.d.ts +17 -2
- package/dist/server/node-outcome.d.ts.map +1 -1
- package/dist/server/node-outcome.js +37 -3
- package/dist/server/node-outcome.js.map +1 -1
- package/dist/server/plugin.d.ts +1 -1
- package/dist/server/plugin.d.ts.map +1 -1
- package/dist/server/query.d.ts +7 -1
- package/dist/server/query.d.ts.map +1 -1
- package/dist/server/query.js +8 -3
- package/dist/server/query.js.map +1 -1
- package/dist/server/registry.d.ts +11 -2
- package/dist/server/registry.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +17 -4
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +82 -45
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/respond.d.ts.map +1 -1
- package/dist/server/respond.js +19 -2
- package/dist/server/respond.js.map +1 -1
- package/dist/server/response-contract-lane.d.ts.map +1 -1
- package/dist/server/response-contract-lane.js +5 -2
- package/dist/server/response-contract-lane.js.map +1 -1
- package/dist/server/response-observer-runtime.d.ts +20 -0
- package/dist/server/response-observer-runtime.d.ts.map +1 -0
- package/dist/server/response-observer-runtime.js +95 -0
- package/dist/server/response-observer-runtime.js.map +1 -0
- package/dist/server/runtime-core.d.ts +60 -0
- package/dist/server/runtime-core.d.ts.map +1 -1
- package/dist/server/runtime-core.js +65 -1
- package/dist/server/runtime-core.js.map +1 -1
- package/dist/server/server-types.d.ts +18 -1
- package/dist/server/server-types.d.ts.map +1 -1
- package/dist/server/server.d.ts +89 -48
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +397 -276
- package/dist/server/server.js.map +1 -1
- package/dist/server/websocket.d.ts +20 -4
- package/dist/server/websocket.d.ts.map +1 -1
- package/dist/server/websocket.js +81 -11
- package/dist/server/websocket.js.map +1 -1
- package/dist/server/ws-bun.d.ts +1 -1
- package/dist/server/ws-bun.d.ts.map +1 -1
- package/dist/server/ws-bun.js +12 -8
- package/dist/server/ws-bun.js.map +1 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -1
- package/dist/server.js.map +1 -1
- package/dist/single-copy-register.d.ts +2 -0
- package/dist/single-copy-register.d.ts.map +1 -0
- package/dist/single-copy-register.js +24 -0
- package/dist/single-copy-register.js.map +1 -0
- package/dist/single-copy.d.ts +156 -0
- package/dist/single-copy.d.ts.map +1 -0
- package/dist/single-copy.js +470 -0
- package/dist/single-copy.js.map +1 -0
- package/package.json +24 -2
- package/src/assurance.ts +58 -1
- package/src/binary.ts +35 -0
- package/src/durable-adapters.ts +26 -51
- package/src/durable-execution.ts +46 -88
- package/src/edge-kit.ts +27 -0
- package/src/errors.ts +1 -0
- package/src/index.ts +1 -1
- package/src/internal/durable-approval-protocol.ts +92 -0
- package/src/internal/durable-effect-protocol.ts +37 -0
- package/src/internal/durable-saga-protocol.ts +55 -0
- package/src/internal/route-catalog.ts +6 -0
- package/src/internal/route-execution.ts +23 -16
- package/src/response-observer.ts +64 -0
- package/src/security/baseline.ts +172 -0
- package/src/server/bare-error-lane.ts +76 -0
- package/src/server/body.ts +8 -0
- package/src/server/bridge-markers.ts +24 -0
- package/src/server/context.ts +6 -1
- package/src/server/header-case.ts +3 -1
- package/src/server/http.ts +53 -3
- package/src/server/install.ts +14 -0
- package/src/server/node-outcome-hook.ts +2 -1
- package/src/server/node-outcome.ts +44 -3
- package/src/server/plugin.ts +1 -1
- package/src/server/query.ts +10 -4
- package/src/server/registry.ts +19 -4
- package/src/server/request-context.ts +106 -51
- package/src/server/respond.ts +26 -1
- package/src/server/response-contract-lane.ts +6 -2
- package/src/server/response-observer-runtime.ts +135 -0
- package/src/server/runtime-core.ts +98 -1
- package/src/server/server-types.ts +18 -1
- package/src/server/server.ts +607 -376
- package/src/server/websocket.ts +127 -17
- package/src/server/ws-bun.ts +26 -7
- package/src/server.ts +2 -1
- package/src/single-copy-register.ts +24 -0
- package/src/single-copy.ts +524 -0
package/src/server/websocket.ts
CHANGED
|
@@ -164,10 +164,18 @@ export interface WebSocketHandler<
|
|
|
164
164
|
/**
|
|
165
165
|
* The **outbound** frame contract (server → client), a Standard Schema. Purely type-level: it types
|
|
166
166
|
* the frames the typed client's `.ws()` handle receives, and documents what this route pushes. The
|
|
167
|
-
* server does NOT runtime-validate its own sends - the inbound `messageSchema` guards the
|
|
168
|
-
* boundary; outbound honesty is the handler author's code
|
|
167
|
+
* server does NOT runtime-validate its own sends by default - the inbound `messageSchema` guards the
|
|
168
|
+
* trust boundary; outbound honesty is the handler author's code. Set {@link validateSend} to opt into
|
|
169
|
+
* a synchronous runtime check of JSON text/UTF-8 binary frames.
|
|
169
170
|
*/
|
|
170
171
|
sendSchema?: Send
|
|
172
|
+
/**
|
|
173
|
+
* Opt-in runtime enforcement for {@link sendSchema}. Invalid JSON, schema failures, and async
|
|
174
|
+
* validators are dropped before the native socket's `send()` runs and reported to `error()` when it
|
|
175
|
+
* exists. This is a development/contract check for the server's own output, not an inbound security
|
|
176
|
+
* boundary. It is off by default and requires `sendSchema` at registration.
|
|
177
|
+
*/
|
|
178
|
+
validateSend?: boolean
|
|
171
179
|
/** Decode versioned transport frames before inbound schema validation. Omit for legacy JSON. */
|
|
172
180
|
transport?: {
|
|
173
181
|
readonly registry: TransportCodecRegistry
|
|
@@ -246,24 +254,19 @@ function toBinary(raw: unknown): Uint8Array {
|
|
|
246
254
|
* `open` event (Deno). Lifecycle callbacks are error-isolated - a throw (or async rejection) routes to
|
|
247
255
|
* `error()` and never tears the process down; binary frames are normalized to `Uint8Array`.
|
|
248
256
|
*/
|
|
249
|
-
export function attachWebSocket
|
|
257
|
+
export function attachWebSocket<
|
|
258
|
+
Data = unknown,
|
|
259
|
+
Env = unknown,
|
|
260
|
+
Schema extends StandardSchemaV1 | undefined = undefined,
|
|
261
|
+
Send extends StandardSchemaV1 | undefined = undefined,
|
|
262
|
+
>(
|
|
250
263
|
socket: StandardWebSocket,
|
|
251
|
-
handler: WebSocketHandler,
|
|
264
|
+
handler: WebSocketHandler<Data, Env, Schema, Send>,
|
|
252
265
|
data: unknown,
|
|
253
266
|
options: { openNow: boolean; pubsub: TopicRegistry; maxPayloadBytes?: number },
|
|
254
|
-
): NifraWebSocket {
|
|
267
|
+
): NifraWebSocket<Data> {
|
|
255
268
|
const { pubsub } = options
|
|
256
|
-
|
|
257
|
-
send: (payload) => socket.send(payload),
|
|
258
|
-
close: (code, reason) => socket.close(code, reason),
|
|
259
|
-
get readyState() {
|
|
260
|
-
return socket.readyState
|
|
261
|
-
},
|
|
262
|
-
subscribe: (topic) => pubsub.subscribe(topic, ws),
|
|
263
|
-
unsubscribe: (topic) => pubsub.unsubscribe(topic, ws),
|
|
264
|
-
data,
|
|
265
|
-
raw: socket,
|
|
266
|
-
}
|
|
269
|
+
let ws!: NifraWebSocket<Data>
|
|
267
270
|
const reportError = (error: unknown): void => {
|
|
268
271
|
if (handler.error === undefined) return
|
|
269
272
|
try {
|
|
@@ -273,6 +276,24 @@ export function attachWebSocket(
|
|
|
273
276
|
/* the error handler itself failed - last resort, swallow */
|
|
274
277
|
}
|
|
275
278
|
}
|
|
279
|
+
const send = createWebSocketSender(
|
|
280
|
+
(payload) => socket.send(payload),
|
|
281
|
+
handler.sendSchema,
|
|
282
|
+
handler.validateSend,
|
|
283
|
+
handler.transport,
|
|
284
|
+
reportError,
|
|
285
|
+
)
|
|
286
|
+
ws = {
|
|
287
|
+
send,
|
|
288
|
+
close: (code, reason) => socket.close(code, reason),
|
|
289
|
+
get readyState() {
|
|
290
|
+
return socket.readyState
|
|
291
|
+
},
|
|
292
|
+
subscribe: (topic) => pubsub.subscribe(topic, ws),
|
|
293
|
+
unsubscribe: (topic) => pubsub.unsubscribe(topic, ws),
|
|
294
|
+
data: data as Data,
|
|
295
|
+
raw: socket,
|
|
296
|
+
}
|
|
276
297
|
const safe = (call: () => MaybePromise<void>): void => {
|
|
277
298
|
try {
|
|
278
299
|
const r = call()
|
|
@@ -300,7 +321,13 @@ export function attachWebSocket(
|
|
|
300
321
|
return
|
|
301
322
|
}
|
|
302
323
|
}
|
|
303
|
-
safe(() =>
|
|
324
|
+
safe(() =>
|
|
325
|
+
(
|
|
326
|
+
handler.message as
|
|
327
|
+
| ((socket: NifraWebSocket<Data>, value: WebSocketData) => MaybePromise<void>)
|
|
328
|
+
| undefined
|
|
329
|
+
)?.(ws, payload),
|
|
330
|
+
)
|
|
304
331
|
})
|
|
305
332
|
socket.addEventListener(
|
|
306
333
|
"close",
|
|
@@ -321,6 +348,89 @@ export function attachWebSocket(
|
|
|
321
348
|
const WS_MESSAGE_DECODER = new TextDecoder()
|
|
322
349
|
const WS_PAYLOAD_ENCODER = new TextEncoder()
|
|
323
350
|
|
|
351
|
+
type WebSocketSendPayload = string | ArrayBufferView | ArrayBuffer
|
|
352
|
+
|
|
353
|
+
const OUTBOUND_VALIDATION_ERROR = "outbound WebSocket frame failed sendSchema validation"
|
|
354
|
+
|
|
355
|
+
function outboundValueOf(
|
|
356
|
+
payload: WebSocketSendPayload,
|
|
357
|
+
transport: WebSocketHandler["transport"],
|
|
358
|
+
): unknown {
|
|
359
|
+
const text =
|
|
360
|
+
typeof payload === "string"
|
|
361
|
+
? payload
|
|
362
|
+
: WS_MESSAGE_DECODER.decode(
|
|
363
|
+
payload instanceof ArrayBuffer
|
|
364
|
+
? new Uint8Array(payload)
|
|
365
|
+
: new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength),
|
|
366
|
+
)
|
|
367
|
+
return transport === undefined
|
|
368
|
+
? JSON.parse(text)
|
|
369
|
+
: decodeTransportFrame(text, transport.registry, {
|
|
370
|
+
...(transport.maxBytes === undefined ? {} : { maxBytes: transport.maxBytes }),
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Build the socket's send function once. The disabled path returns the native sender directly, so
|
|
376
|
+
* the default type-only contract adds no per-frame branch or schema work. Runtime validation is
|
|
377
|
+
* deliberately synchronous: a socket `send()` cannot await an async Standard Schema without changing
|
|
378
|
+
* the portable API, so an async result fails closed and is never sent.
|
|
379
|
+
*/
|
|
380
|
+
export function createWebSocketSender(
|
|
381
|
+
send: (payload: WebSocketSendPayload) => void,
|
|
382
|
+
schema: StandardSchemaV1 | undefined,
|
|
383
|
+
enabled: boolean | undefined,
|
|
384
|
+
transport: WebSocketHandler["transport"],
|
|
385
|
+
onError: (error: unknown) => void,
|
|
386
|
+
): (payload: WebSocketSendPayload) => void {
|
|
387
|
+
if (enabled !== true || schema === undefined) return send
|
|
388
|
+
let reporting = false
|
|
389
|
+
const reportFailure = (error: unknown): void => {
|
|
390
|
+
// An error handler may try to send a diagnostic. Do not recurse forever when that diagnostic also
|
|
391
|
+
// violates the same outbound contract. EVERY failure path reports through here - a path that calls
|
|
392
|
+
// `onError` directly reopens that recursion for the one rejection shape it happens to cover.
|
|
393
|
+
if (reporting) return
|
|
394
|
+
reporting = true
|
|
395
|
+
try {
|
|
396
|
+
onError(error)
|
|
397
|
+
} finally {
|
|
398
|
+
reporting = false
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return (payload) => {
|
|
402
|
+
let value: unknown
|
|
403
|
+
try {
|
|
404
|
+
value = outboundValueOf(payload, transport)
|
|
405
|
+
} catch {
|
|
406
|
+
reportFailure(new Error(OUTBOUND_VALIDATION_ERROR))
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
let outcome: ValidationOutcome<unknown> | Promise<ValidationOutcome<unknown>>
|
|
411
|
+
try {
|
|
412
|
+
outcome = validateStandard(schema, value) as
|
|
413
|
+
| ValidationOutcome<unknown>
|
|
414
|
+
| Promise<ValidationOutcome<unknown>>
|
|
415
|
+
} catch {
|
|
416
|
+
reportFailure(new Error(OUTBOUND_VALIDATION_ERROR))
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
if (outcome instanceof Promise) {
|
|
420
|
+
// Do not await or send later: the portable `send()` contract is synchronous. Attach a rejection
|
|
421
|
+
// handler so a validator that rejects cannot become an unhandled process-level rejection.
|
|
422
|
+
outcome.catch(() => {})
|
|
423
|
+
reportFailure(new Error(`${OUTBOUND_VALIDATION_ERROR}; validator must be synchronous`))
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
if (!outcome.ok) {
|
|
427
|
+
reportFailure(new Error(OUTBOUND_VALIDATION_ERROR))
|
|
428
|
+
return
|
|
429
|
+
}
|
|
430
|
+
send(payload)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
324
434
|
/**
|
|
325
435
|
* If the handler declares a `messageSchema`, return a copy whose `message` validates each frame -
|
|
326
436
|
* parse as JSON, run the Standard Schema, then call the user's `message` with the typed value, or
|
package/src/server/ws-bun.ts
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* (erased). No `Bun.*` calls here - the runtime seam stays in `server.ts` (see runtime-boundary.test).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import {
|
|
9
|
+
createWebSocketSender,
|
|
10
|
+
type NifraWebSocket,
|
|
11
|
+
type TopicRegistry,
|
|
12
|
+
type WebSocketData,
|
|
13
|
+
type WebSocketHandler,
|
|
14
|
+
} from "./websocket.ts"
|
|
9
15
|
import type { BunWsHandlers } from "./ws-hook.ts"
|
|
10
16
|
|
|
11
17
|
/** Per-connection state Bun's `websocket` callbacks read via `ws.data`: the matched handler, the
|
|
@@ -33,11 +39,24 @@ function toBinaryData(message: ArrayBuffer | Uint8Array): Uint8Array {
|
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
/** Wrap a Bun `ServerWebSocket` as the portable {@link NifraWebSocket} handed to WS callbacks. */
|
|
36
|
-
function wrapBunSocket(
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
function wrapBunSocket(
|
|
43
|
+
raw: BunSocket,
|
|
44
|
+
topics: TopicRegistry,
|
|
45
|
+
handler: WebSocketHandler,
|
|
46
|
+
): NifraWebSocket {
|
|
47
|
+
let ws!: NifraWebSocket
|
|
48
|
+
const reportError = (error: unknown): void => reportWsError(error, ws, handler)
|
|
49
|
+
const send = createWebSocketSender(
|
|
50
|
+
(data) => {
|
|
39
51
|
raw.send(data)
|
|
40
52
|
},
|
|
53
|
+
handler.sendSchema,
|
|
54
|
+
handler.validateSend,
|
|
55
|
+
handler.transport,
|
|
56
|
+
reportError,
|
|
57
|
+
)
|
|
58
|
+
ws = {
|
|
59
|
+
send,
|
|
41
60
|
close: (code, reason) => raw.close(code, reason),
|
|
42
61
|
get readyState() {
|
|
43
62
|
return raw.readyState
|
|
@@ -86,19 +105,19 @@ export function createBunWsHandlers(topics: TopicRegistry): BunWsHandlers {
|
|
|
86
105
|
return {
|
|
87
106
|
open: (raw) => {
|
|
88
107
|
const ws = raw as BunSocket
|
|
89
|
-
const nifra = wrapBunSocket(ws, topics)
|
|
108
|
+
const nifra = wrapBunSocket(ws, topics, ws.data.handler)
|
|
90
109
|
ws.data.nifra = nifra
|
|
91
110
|
dispatchWsCallback(() => ws.data.handler.open?.(nifra), nifra, ws.data.handler)
|
|
92
111
|
},
|
|
93
112
|
message: (raw, message) => {
|
|
94
113
|
const ws = raw as BunSocket
|
|
95
|
-
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics)
|
|
114
|
+
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics, ws.data.handler)
|
|
96
115
|
const data: WebSocketData = typeof message === "string" ? message : toBinaryData(message)
|
|
97
116
|
dispatchWsCallback(() => ws.data.handler.message?.(nifra, data), nifra, ws.data.handler)
|
|
98
117
|
},
|
|
99
118
|
close: (raw, code, reason) => {
|
|
100
119
|
const ws = raw as BunSocket
|
|
101
|
-
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics)
|
|
120
|
+
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics, ws.data.handler)
|
|
102
121
|
topics.unsubscribeAll(nifra) // drop topic subscriptions so the registry never holds a dead socket
|
|
103
122
|
dispatchWsCallback(() => ws.data.handler.close?.(nifra, code, reason), nifra, ws.data.handler)
|
|
104
123
|
},
|
package/src/server.ts
CHANGED
|
@@ -45,7 +45,7 @@ export {
|
|
|
45
45
|
type ScheduledHandler,
|
|
46
46
|
toFetchHandler,
|
|
47
47
|
} from "./server/edge.ts"
|
|
48
|
-
export { pathnameOf, type UrlParts, urlPartsOf } from "./server/http.ts"
|
|
48
|
+
export { isSameOriginPath, pathnameOf, type UrlParts, urlPartsOf } from "./server/http.ts"
|
|
49
49
|
export {
|
|
50
50
|
commonSecretPatterns,
|
|
51
51
|
jsonLogger,
|
|
@@ -71,6 +71,7 @@ export {
|
|
|
71
71
|
type VercelHandler,
|
|
72
72
|
} from "./server/platform-adapters.ts"
|
|
73
73
|
export type { Registry, RouteInfo } from "./server/registry.ts"
|
|
74
|
+
export { type PlainRender, type ResponseResult, status } from "./server/runtime-core.ts"
|
|
74
75
|
export {
|
|
75
76
|
type AdmissionController,
|
|
76
77
|
type AdmissionDecision,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect entry (`@nifrajs/core/single-copy/register`): install the single-copy resolver into the
|
|
3
|
+
* Bun runtime.
|
|
4
|
+
*
|
|
5
|
+
* Preload it - never import it from application code:
|
|
6
|
+
*
|
|
7
|
+
* ```toml
|
|
8
|
+
* # bunfig.toml
|
|
9
|
+
* preload = ["@nifrajs/core/single-copy/register"]
|
|
10
|
+
* [test]
|
|
11
|
+
* preload = ["@nifrajs/core/single-copy/register"]
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* A resolver only affects imports that have not resolved yet, and a module's own imports resolve
|
|
15
|
+
* before its body runs. Registering from inside application code would therefore miss exactly the
|
|
16
|
+
* imports it exists to redirect. `preload` runs before the entry point, which is the only moment that
|
|
17
|
+
* covers the whole graph.
|
|
18
|
+
*
|
|
19
|
+
* `nifra check` reads this specifier out of `bunfig.toml` as the proof that the runtime arm is armed,
|
|
20
|
+
* so the string above is a contract rather than a suggestion.
|
|
21
|
+
*/
|
|
22
|
+
import { registerSingleCopy } from "./single-copy"
|
|
23
|
+
|
|
24
|
+
registerSingleCopy()
|