@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.
- package/README.md +21 -0
- package/dist/durable-adapters.d.ts.map +1 -1
- package/dist/durable-adapters.js +26 -3
- package/dist/durable-adapters.js.map +1 -1
- package/dist/durable-approval.d.ts +56 -0
- package/dist/durable-approval.d.ts.map +1 -0
- package/dist/durable-approval.js +233 -0
- package/dist/durable-approval.js.map +1 -0
- package/dist/durable-effect.d.ts +42 -0
- package/dist/durable-effect.d.ts.map +1 -0
- package/dist/durable-effect.js +234 -0
- package/dist/durable-effect.js.map +1 -0
- package/dist/durable-execution.d.ts +8 -346
- package/dist/durable-execution.d.ts.map +1 -1
- package/dist/durable-execution.js +7 -1150
- package/dist/durable-execution.js.map +1 -1
- package/dist/durable-saga.d.ts +94 -0
- package/dist/durable-saga.d.ts.map +1 -0
- package/dist/durable-saga.js +550 -0
- package/dist/durable-saga.js.map +1 -0
- package/dist/edge-kit.d.ts +2 -2
- package/dist/edge-kit.d.ts.map +1 -1
- package/dist/edge-kit.js +2 -2
- package/dist/edge-kit.js.map +1 -1
- package/dist/index.d.ts +23 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/durable-approval-protocol.d.ts +1 -1
- package/dist/internal/durable-approval-protocol.d.ts.map +1 -1
- package/dist/internal/durable-effect-protocol.d.ts +1 -1
- package/dist/internal/durable-effect-protocol.d.ts.map +1 -1
- package/dist/internal/durable-saga-protocol.d.ts +1 -1
- package/dist/internal/durable-saga-protocol.d.ts.map +1 -1
- package/dist/internal/durable-shared.d.ts +26 -0
- package/dist/internal/durable-shared.d.ts.map +1 -0
- package/dist/internal/durable-shared.js +131 -0
- package/dist/internal/durable-shared.js.map +1 -0
- package/dist/internal/durable-types.d.ts +159 -0
- package/dist/internal/durable-types.d.ts.map +1 -0
- package/dist/internal/durable-types.js +2 -0
- package/dist/internal/durable-types.js.map +1 -0
- package/dist/internal/route-compiler.d.ts +61 -0
- package/dist/internal/route-compiler.d.ts.map +1 -0
- package/dist/internal/route-compiler.js +121 -0
- package/dist/internal/route-compiler.js.map +1 -0
- package/dist/internal/route-execution.d.ts +6 -4
- package/dist/internal/route-execution.d.ts.map +1 -1
- package/dist/internal/route-execution.js +2 -17
- package/dist/internal/route-execution.js.map +1 -1
- package/dist/internal/route-lanes.d.ts +35 -0
- package/dist/internal/route-lanes.d.ts.map +1 -0
- package/dist/internal/route-lanes.js +150 -0
- package/dist/internal/route-lanes.js.map +1 -0
- package/dist/internal/route-program.d.ts +67 -0
- package/dist/internal/route-program.d.ts.map +1 -0
- package/dist/internal/route-program.js +199 -0
- package/dist/internal/route-program.js.map +1 -0
- package/dist/server/bare-error-lane.d.ts +1 -1
- package/dist/server/bare-error-lane.d.ts.map +1 -1
- package/dist/server/bare-error-lane.js +3 -3
- package/dist/server/bare-error-lane.js.map +1 -1
- package/dist/server/body-lane.d.ts +13 -0
- package/dist/server/body-lane.d.ts.map +1 -0
- package/dist/server/body-lane.js +134 -0
- package/dist/server/body-lane.js.map +1 -0
- package/dist/server/contract.d.ts +40 -14
- package/dist/server/contract.d.ts.map +1 -1
- package/dist/server/contract.js +7 -0
- package/dist/server/contract.js.map +1 -1
- package/dist/server/cookies.d.ts.map +1 -1
- package/dist/server/cookies.js +16 -2
- package/dist/server/cookies.js.map +1 -1
- package/dist/server/plugin.d.ts +2 -2
- package/dist/server/plugin.d.ts.map +1 -1
- package/dist/server/plugin.js +6 -1
- package/dist/server/plugin.js.map +1 -1
- package/dist/server/registry.d.ts +40 -12
- package/dist/server/registry.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +4 -28
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +10 -185
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/respond.d.ts.map +1 -1
- package/dist/server/respond.js +39 -2
- package/dist/server/respond.js.map +1 -1
- package/dist/server/runtime-core.d.ts +18 -2
- package/dist/server/runtime-core.d.ts.map +1 -1
- package/dist/server/runtime-core.js +0 -23
- package/dist/server/runtime-core.js.map +1 -1
- package/dist/server/server-types.d.ts +3 -0
- package/dist/server/server-types.d.ts.map +1 -1
- package/dist/server/server.d.ts +113 -84
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +506 -639
- package/dist/server/server.js.map +1 -1
- package/dist/server/validation.d.ts +5 -0
- package/dist/server/validation.d.ts.map +1 -0
- package/dist/server/validation.js +13 -0
- package/dist/server/validation.js.map +1 -0
- package/dist/server/ws-bun.d.ts +11 -3
- package/dist/server/ws-bun.d.ts.map +1 -1
- package/dist/server/ws-bun.js +42 -12
- package/dist/server/ws-bun.js.map +1 -1
- package/dist/server/ws-hook.d.ts +3 -2
- package/dist/server/ws-hook.d.ts.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/single-copy.d.ts.map +1 -1
- package/dist/single-copy.js +3 -1
- package/dist/single-copy.js.map +1 -1
- package/package.json +6 -3
- package/src/durable-adapters.ts +20 -0
- package/src/durable-approval.ts +281 -0
- package/src/durable-effect.ts +300 -0
- package/src/durable-execution.ts +8 -1627
- package/src/durable-saga.ts +744 -0
- package/src/edge-kit.ts +2 -2
- package/src/index.ts +129 -2
- package/src/internal/durable-approval-protocol.ts +1 -1
- package/src/internal/durable-effect-protocol.ts +1 -1
- package/src/internal/durable-saga-protocol.ts +1 -1
- package/src/internal/durable-shared.ts +157 -0
- package/src/internal/durable-types.ts +194 -0
- package/src/internal/route-compiler.ts +234 -0
- package/src/internal/route-execution.ts +34 -84
- package/src/internal/route-lanes.ts +221 -0
- package/src/internal/route-program.ts +404 -0
- package/src/server/bare-error-lane.ts +3 -2
- package/src/server/body-lane.ts +203 -0
- package/src/server/contract.ts +70 -20
- package/src/server/cookies.ts +16 -2
- package/src/server/plugin.ts +11 -5
- package/src/server/registry.ts +71 -16
- package/src/server/request-context.ts +7 -262
- package/src/server/respond.ts +45 -2
- package/src/server/runtime-core.ts +28 -2
- package/src/server/server-types.ts +3 -0
- package/src/server/server.ts +1152 -1260
- package/src/server/validation.ts +19 -0
- package/src/server/ws-bun.ts +44 -11
- package/src/server/ws-hook.ts +3 -2
- package/src/server.ts +7 -2
- package/src/single-copy.ts +3 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StandardIssue } from "../schema/standard.ts"
|
|
2
|
+
import { type ResponseResult, status } from "./runtime-core.ts"
|
|
3
|
+
|
|
4
|
+
function validationIssues(issues: ReadonlyArray<StandardIssue>): {
|
|
5
|
+
ok: false
|
|
6
|
+
error: string
|
|
7
|
+
issues: unknown[]
|
|
8
|
+
} {
|
|
9
|
+
const serialized = issues.map((issue) => {
|
|
10
|
+
const path = issue.path?.map((seg) => String(typeof seg === "object" ? seg.key : seg))
|
|
11
|
+
return path !== undefined ? { message: issue.message, path } : { message: issue.message }
|
|
12
|
+
})
|
|
13
|
+
return { ok: false, error: "validation", issues: serialized }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The shared 422 response result used by every body-validation lane. */
|
|
17
|
+
export function plainValidationError(issues: ReadonlyArray<StandardIssue>): ResponseResult {
|
|
18
|
+
return status(422, validationIssues(issues))
|
|
19
|
+
}
|
package/src/server/ws-bun.ts
CHANGED
|
@@ -28,6 +28,10 @@ export interface BunSocket {
|
|
|
28
28
|
send(data: string | ArrayBufferView | ArrayBuffer, compress?: boolean): number
|
|
29
29
|
close(code?: number, reason?: string): void
|
|
30
30
|
readonly readyState: number
|
|
31
|
+
// Bun's native (uWebSockets) topic pub/sub - used only in native-pubsub mode (no per-socket
|
|
32
|
+
// outbound validation), where `app.publish` routes through the Bun server's `publish`.
|
|
33
|
+
subscribe(topic: string): void
|
|
34
|
+
unsubscribe(topic: string): void
|
|
31
35
|
// readonly: we never reassign `ws.data` wholesale, only mutate its fields (`.nifra`, `.data`).
|
|
32
36
|
readonly data: BunWsData
|
|
33
37
|
}
|
|
@@ -38,11 +42,19 @@ function toBinaryData(message: ArrayBuffer | Uint8Array): Uint8Array {
|
|
|
38
42
|
return message instanceof Uint8Array ? message : new Uint8Array(message)
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Wrap a Bun `ServerWebSocket` as the portable {@link NifraWebSocket} handed to WS callbacks.
|
|
47
|
+
*
|
|
48
|
+
* `nativePubsub` selects the topic backend: in native mode `subscribe`/`unsubscribe` go straight to
|
|
49
|
+
* Bun's own (uWebSockets) pub/sub so a broadcast via the Bun server's `publish` reaches this socket
|
|
50
|
+
* with no per-connection JS loop; otherwise they use the runtime-neutral {@link TopicRegistry}. Native
|
|
51
|
+
* mode is used only when no route validates outbound frames, so raw and validated sends are identical.
|
|
52
|
+
*/
|
|
42
53
|
function wrapBunSocket(
|
|
43
54
|
raw: BunSocket,
|
|
44
55
|
topics: TopicRegistry,
|
|
45
56
|
handler: WebSocketHandler,
|
|
57
|
+
nativePubsub: boolean,
|
|
46
58
|
): NifraWebSocket {
|
|
47
59
|
let ws!: NifraWebSocket
|
|
48
60
|
const reportError = (error: unknown): void => reportWsError(error, ws, handler)
|
|
@@ -61,8 +73,12 @@ function wrapBunSocket(
|
|
|
61
73
|
get readyState() {
|
|
62
74
|
return raw.readyState
|
|
63
75
|
},
|
|
64
|
-
subscribe:
|
|
65
|
-
|
|
76
|
+
subscribe: nativePubsub
|
|
77
|
+
? (topic) => raw.subscribe(topic)
|
|
78
|
+
: (topic) => topics.subscribe(topic, ws),
|
|
79
|
+
unsubscribe: nativePubsub
|
|
80
|
+
? (topic) => raw.unsubscribe(topic)
|
|
81
|
+
: (topic) => topics.unsubscribe(topic, ws),
|
|
66
82
|
get data() {
|
|
67
83
|
return raw.data.data
|
|
68
84
|
},
|
|
@@ -99,26 +115,43 @@ function dispatchWsCallback(
|
|
|
99
115
|
}
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
/**
|
|
103
|
-
* `
|
|
104
|
-
|
|
118
|
+
/**
|
|
119
|
+
* The shared Bun `websocket` dispatcher config for one app - each connection's `ws.data.handler` is
|
|
120
|
+
* the matched route's handler, set by `server.upgrade`.
|
|
121
|
+
*
|
|
122
|
+
* `nativePubsub` (set by `listen()` when the app has no validated-send route) makes subscriptions use
|
|
123
|
+
* Bun's own pub/sub; there the registry holds nothing and Bun auto-drops native subscriptions on
|
|
124
|
+
* close, so the `unsubscribeAll` sweep is skipped.
|
|
125
|
+
*/
|
|
126
|
+
export function createBunWsHandlers(topics: TopicRegistry, nativePubsub = false): BunWsHandlers {
|
|
105
127
|
return {
|
|
106
128
|
open: (raw) => {
|
|
107
129
|
const ws = raw as BunSocket
|
|
108
|
-
const nifra = wrapBunSocket(ws, topics, ws.data.handler)
|
|
130
|
+
const nifra = wrapBunSocket(ws, topics, ws.data.handler, nativePubsub)
|
|
109
131
|
ws.data.nifra = nifra
|
|
110
132
|
dispatchWsCallback(() => ws.data.handler.open?.(nifra), nifra, ws.data.handler)
|
|
111
133
|
},
|
|
112
134
|
message: (raw, message) => {
|
|
113
135
|
const ws = raw as BunSocket
|
|
114
|
-
const
|
|
136
|
+
const handler = ws.data.handler
|
|
137
|
+
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics, handler, nativePubsub)
|
|
115
138
|
const data: WebSocketData = typeof message === "string" ? message : toBinaryData(message)
|
|
116
|
-
|
|
139
|
+
// Hottest WS path - dispatch inline rather than through `dispatchWsCallback` so no per-frame
|
|
140
|
+
// closure is allocated. Same contract: a sync throw or async rejection routes to `handler.error`.
|
|
141
|
+
try {
|
|
142
|
+
const result = handler.message?.(nifra, data)
|
|
143
|
+
if (result instanceof Promise)
|
|
144
|
+
result.catch((e: unknown) => reportWsError(e, nifra, handler))
|
|
145
|
+
} catch (error) {
|
|
146
|
+
reportWsError(error, nifra, handler)
|
|
147
|
+
}
|
|
117
148
|
},
|
|
118
149
|
close: (raw, code, reason) => {
|
|
119
150
|
const ws = raw as BunSocket
|
|
120
|
-
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics, ws.data.handler)
|
|
121
|
-
|
|
151
|
+
const nifra = ws.data.nifra ?? wrapBunSocket(ws, topics, ws.data.handler, nativePubsub)
|
|
152
|
+
// Registry mode: drop topic subscriptions so it never holds a dead socket. Native mode: Bun
|
|
153
|
+
// unsubscribes the socket from every topic on close, so there is nothing to sweep here.
|
|
154
|
+
if (!nativePubsub) topics.unsubscribeAll(nifra)
|
|
122
155
|
dispatchWsCallback(() => ws.data.handler.close?.(nifra, code, reason), nifra, ws.data.handler)
|
|
123
156
|
},
|
|
124
157
|
}
|
package/src/server/ws-hook.ts
CHANGED
|
@@ -30,8 +30,9 @@ export interface WsRuntime {
|
|
|
30
30
|
wrapHandler(handler: WebSocketHandler): WebSocketHandler
|
|
31
31
|
/** One in-process pub/sub registry per app (backs `ws.subscribe` + `app.publish`). */
|
|
32
32
|
createTopics(): TopicRegistry
|
|
33
|
-
/** The Bun `websocket` config for `listen()` when the app has WS routes.
|
|
34
|
-
|
|
33
|
+
/** The Bun `websocket` config for `listen()` when the app has WS routes. `nativePubsub` routes
|
|
34
|
+
* `ws.subscribe` through Bun's own pub/sub (set when no route validates outbound frames). */
|
|
35
|
+
bunHandlers(topics: TopicRegistry, nativePubsub?: boolean): BunWsHandlers
|
|
35
36
|
/** `attachWebSocket` - wires a standard server socket (Workers `WebSocketPair`) to a handler. */
|
|
36
37
|
attach(
|
|
37
38
|
socket: StandardWebSocket,
|
package/src/server.ts
CHANGED
|
@@ -70,8 +70,13 @@ export {
|
|
|
70
70
|
toVercelHandler,
|
|
71
71
|
type VercelHandler,
|
|
72
72
|
} from "./server/platform-adapters.ts"
|
|
73
|
-
export type { Registry, RouteInfo } from "./server/registry.ts"
|
|
74
|
-
export {
|
|
73
|
+
export type { Registry, ResponseMapFor, RouteInfo, RouteInfoFor } from "./server/registry.ts"
|
|
74
|
+
export {
|
|
75
|
+
type PlainRender,
|
|
76
|
+
type ResponseResult,
|
|
77
|
+
type StatusResponse,
|
|
78
|
+
status,
|
|
79
|
+
} from "./server/runtime-core.ts"
|
|
75
80
|
export {
|
|
76
81
|
type AdmissionController,
|
|
77
82
|
type AdmissionDecision,
|
package/src/single-copy.ts
CHANGED
|
@@ -472,7 +472,9 @@ export function singleCopyPlugin(options: SingleCopyOptions = {}): SingleCopyPlu
|
|
|
472
472
|
const scopes = declared
|
|
473
473
|
.filter((entry) => entry.endsWith("/*"))
|
|
474
474
|
.map((entry) => `${escapeRegExp(entry.slice(0, -1))}[^/]+`)
|
|
475
|
-
|
|
475
|
+
// Subpaths pin too, for exact names and scope patterns alike: `@nifrajs/core/server` must
|
|
476
|
+
// resolve to the same copy as `@nifrajs/core`, or a deep import quietly splits the package.
|
|
477
|
+
const alternatives = [...exact, ...scopes].map((name) => `${name}(?:/.*)?`)
|
|
476
478
|
if (alternatives.length > 0) {
|
|
477
479
|
const filter = new RegExp(`^(?:${alternatives.join("|")})$`)
|
|
478
480
|
build.onResolve({ filter }, (args) => {
|