@prisma-next/framework-components 0.5.0-dev.8 → 0.5.0-dev.81
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 +53 -4
- package/dist/authoring.d.mts +2 -2
- package/dist/authoring.mjs +2 -122
- package/dist/codec-m_-FAyQn.d.mts +168 -0
- package/dist/codec-m_-FAyQn.d.mts.map +1 -0
- package/dist/codec.d.mts +48 -2
- package/dist/codec.d.mts.map +1 -0
- package/dist/codec.mjs +67 -4
- package/dist/codec.mjs.map +1 -1
- package/dist/components.d.mts +1 -1
- package/dist/components.mjs +2 -3
- package/dist/control.d.mts +420 -74
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +83 -49
- package/dist/control.mjs.map +1 -1
- package/dist/emission-types-BKa4bR9m.d.mts +39 -0
- package/dist/emission-types-BKa4bR9m.d.mts.map +1 -0
- package/dist/emission.d.mts +2 -2
- package/dist/emission.mjs +1 -1
- package/dist/execution.d.mts +5 -5
- package/dist/execution.d.mts.map +1 -1
- package/dist/execution.mjs +4 -6
- package/dist/execution.mjs.map +1 -1
- package/dist/{framework-authoring-D1-JZ37B.d.mts → framework-authoring-DGIQbNPt.d.mts} +43 -12
- package/dist/framework-authoring-DGIQbNPt.d.mts.map +1 -0
- package/dist/framework-authoring-DxXcjyJX.mjs +209 -0
- package/dist/framework-authoring-DxXcjyJX.mjs.map +1 -0
- package/dist/{framework-components-DFZMi2h7.d.mts → framework-components-BGo7HsbL.d.mts} +45 -55
- package/dist/framework-components-BGo7HsbL.d.mts.map +1 -0
- package/dist/{framework-components-C8ZhSwXe.mjs → framework-components-FdqmlGUj.mjs} +3 -3
- package/dist/framework-components-FdqmlGUj.mjs.map +1 -0
- package/dist/psl-ast-Ckn_G-jv.d.mts +159 -0
- package/dist/psl-ast-Ckn_G-jv.d.mts.map +1 -0
- package/dist/psl-ast.d.mts +2 -0
- package/dist/psl-ast.mjs +1 -0
- package/dist/runtime.d.mts +395 -19
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +256 -7
- package/dist/runtime.mjs.map +1 -1
- package/dist/{types-import-spec-C4sc7wbb.d.mts → types-import-spec-BxI5cSQy.d.mts} +2 -2
- package/dist/types-import-spec-BxI5cSQy.d.mts.map +1 -0
- package/package.json +10 -6
- package/src/control/control-capabilities.ts +96 -0
- package/src/{control-descriptors.ts → control/control-descriptors.ts} +7 -7
- package/src/{control-instances.ts → control/control-instances.ts} +52 -6
- package/src/{control-migration-types.ts → control/control-migration-types.ts} +251 -63
- package/src/control/control-operation-preview.ts +23 -0
- package/src/control/control-spaces.ts +82 -0
- package/src/{control-stack.ts → control/control-stack.ts} +77 -94
- package/src/control/emission-types.ts +49 -0
- package/src/control/psl-ast.ts +193 -0
- package/src/{execution-descriptors.ts → execution/execution-descriptors.ts} +7 -7
- package/src/{execution-instances.ts → execution/execution-instances.ts} +1 -1
- package/src/{execution-requirements.ts → execution/execution-requirements.ts} +1 -1
- package/src/execution/query-plan.ts +53 -0
- package/src/execution/race-against-abort.ts +89 -0
- package/src/execution/run-with-middleware.ts +153 -0
- package/src/execution/runtime-core.ts +133 -0
- package/src/execution/runtime-error.ts +94 -0
- package/src/execution/runtime-middleware.ts +235 -0
- package/src/exports/authoring.ts +5 -2
- package/src/exports/codec.ts +27 -2
- package/src/exports/components.ts +2 -2
- package/src/exports/control.ts +41 -13
- package/src/exports/emission.ts +2 -2
- package/src/exports/execution.ts +5 -5
- package/src/exports/psl-ast.ts +1 -0
- package/src/exports/runtime.ts +18 -5
- package/src/shared/codec-descriptor.ts +87 -0
- package/src/shared/codec-types.ts +79 -0
- package/src/shared/codec.ts +80 -0
- package/src/shared/column-spec.ts +83 -0
- package/src/{framework-authoring.ts → shared/framework-authoring.ts} +210 -23
- package/src/{framework-components.ts → shared/framework-components.ts} +22 -48
- package/src/{mutation-default-types.ts → shared/mutation-default-types.ts} +22 -2
- package/dist/authoring.mjs.map +0 -1
- package/dist/codec-types-DQ1Agjom.d.mts +0 -58
- package/dist/codec-types-DQ1Agjom.d.mts.map +0 -1
- package/dist/emission-types-BPAALJbF.d.mts +0 -24
- package/dist/emission-types-BPAALJbF.d.mts.map +0 -1
- package/dist/framework-authoring-D1-JZ37B.d.mts.map +0 -1
- package/dist/framework-components-C8ZhSwXe.mjs.map +0 -1
- package/dist/framework-components-DFZMi2h7.d.mts.map +0 -1
- package/dist/types-import-spec-C4sc7wbb.d.mts.map +0 -1
- package/src/codec-types.ts +0 -64
- package/src/control-capabilities.ts +0 -34
- package/src/emission-types.ts +0 -28
- package/src/runtime-error.ts +0 -55
- package/src/runtime-middleware.ts +0 -83
- /package/src/{control-result-types.ts → control/control-result-types.ts} +0 -0
- /package/src/{control-schema-view.ts → control/control-schema-view.ts} +0 -0
- /package/src/{async-iterable-result.ts → execution/async-iterable-result.ts} +0 -0
- /package/src/{execution-stack.ts → execution/execution-stack.ts} +0 -0
- /package/src/{types-import-spec.ts → shared/types-import-spec.ts} +0 -0
package/dist/runtime.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { o as CodecCallContext } from "./codec-m_-FAyQn.mjs";
|
|
1
2
|
import { PlanMeta } from "@prisma-next/contract/types";
|
|
2
3
|
|
|
3
|
-
//#region src/async-iterable-result.d.ts
|
|
4
|
+
//#region src/execution/async-iterable-result.d.ts
|
|
4
5
|
declare class AsyncIterableResult<Row> implements AsyncIterable<Row>, PromiseLike<Row[]> {
|
|
5
6
|
private readonly generator;
|
|
6
7
|
private consumed;
|
|
@@ -14,13 +15,79 @@ declare class AsyncIterableResult<Row> implements AsyncIterable<Row>, PromiseLik
|
|
|
14
15
|
then<TResult1 = Row[], TResult2 = never>(onfulfilled?: ((value: Row[]) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
|
|
15
16
|
}
|
|
16
17
|
//#endregion
|
|
17
|
-
//#region src/
|
|
18
|
+
//#region src/execution/query-plan.d.ts
|
|
19
|
+
/**
|
|
20
|
+
* Family-agnostic plan marker.
|
|
21
|
+
*
|
|
22
|
+
* Carries only `meta` (the family-agnostic plan metadata) and the optional
|
|
23
|
+
* phantom `_row` parameter that lets type-level utilities recover the row
|
|
24
|
+
* type from a plan value. SQL and Mongo extend this marker with their own
|
|
25
|
+
* concrete shapes (`SqlQueryPlan`, `MongoQueryPlan`).
|
|
26
|
+
*
|
|
27
|
+
* `QueryPlan` is the *pre-lowering* marker — i.e. the surface a builder
|
|
28
|
+
* produces before family-specific lowering turns it into an executable
|
|
29
|
+
* plan (`ExecutionPlan`).
|
|
30
|
+
*/
|
|
31
|
+
interface QueryPlan<Row = unknown> {
|
|
32
|
+
readonly meta: PlanMeta;
|
|
33
|
+
/**
|
|
34
|
+
* Phantom property to carry the Row generic for type-level utilities.
|
|
35
|
+
* Not set at runtime; used only for `ResultType` extraction.
|
|
36
|
+
*/
|
|
37
|
+
readonly _row?: Row;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Family-agnostic execution-plan marker.
|
|
41
|
+
*
|
|
42
|
+
* Extends `QueryPlan` with no additional structural fields — the marker
|
|
43
|
+
* exists to nominally distinguish executable plans from pre-lowering plans
|
|
44
|
+
* in the type system. Family-specific execution plans (`SqlExecutionPlan`,
|
|
45
|
+
* `MongoExecutionPlan`) extend this marker with their concrete shapes
|
|
46
|
+
* (e.g. `sql + params` for SQL, `wireCommand` for Mongo).
|
|
47
|
+
*/
|
|
48
|
+
interface ExecutionPlan<Row = unknown> extends QueryPlan<Row> {}
|
|
49
|
+
/**
|
|
50
|
+
* Extracts the `Row` type from a plan via the phantom `_row` property.
|
|
51
|
+
*
|
|
52
|
+
* Works with any plan that extends `QueryPlan<Row>` — including
|
|
53
|
+
* `ExecutionPlan<Row>`, `SqlQueryPlan<Row>`, `SqlExecutionPlan<Row>`,
|
|
54
|
+
* `MongoQueryPlan<Row>`, and `MongoExecutionPlan<Row>`.
|
|
55
|
+
*
|
|
56
|
+
* The `_row` property must be present in the plan's static type for the
|
|
57
|
+
* conditional to bind `R`; objects whose type lacks `_row` resolve to
|
|
58
|
+
* `never`. Without the `keyof` guard, `extends { _row?: infer R }` would
|
|
59
|
+
* silently match any object and infer `unknown`.
|
|
60
|
+
*
|
|
61
|
+
* Example: `type Row = ResultType<typeof plan>`.
|
|
62
|
+
*/
|
|
63
|
+
type ResultType<P> = '_row' extends keyof P ? P extends {
|
|
64
|
+
readonly _row?: infer R;
|
|
65
|
+
} ? R : never : never;
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/execution/runtime-error.d.ts
|
|
18
68
|
interface RuntimeErrorEnvelope extends Error {
|
|
19
69
|
readonly code: string;
|
|
20
70
|
readonly category: 'PLAN' | 'CONTRACT' | 'LINT' | 'BUDGET' | 'RUNTIME';
|
|
21
71
|
readonly severity: 'error';
|
|
22
72
|
readonly details?: Record<string, unknown>;
|
|
23
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Stable code emitted by the runtime when an in-flight `execute()`
|
|
76
|
+
* is cancelled via the per-query `AbortSignal`. The envelope's
|
|
77
|
+
* `details.phase` distinguishes where the abort was observed:
|
|
78
|
+
*
|
|
79
|
+
* - `'encode'` — abort fired during `encodeParams` (SQL) or
|
|
80
|
+
* `resolveValue` (Mongo).
|
|
81
|
+
* - `'decode'` — abort fired during `decodeRow` / `decodeField`.
|
|
82
|
+
* - `'stream'` — abort fired between rows or before any codec call
|
|
83
|
+
* (already-aborted at entry).
|
|
84
|
+
* - `'beforeExecute'` / `'afterExecute'` / `'onRow'` — abort fired
|
|
85
|
+
* on entry to or during the corresponding middleware phase
|
|
86
|
+
* (cooperative cancellation per the param-transform seam).
|
|
87
|
+
*/
|
|
88
|
+
declare const RUNTIME_ABORTED: "RUNTIME.ABORTED";
|
|
89
|
+
/** Discriminator placed in `details.phase` of a `RUNTIME.ABORTED` envelope. */
|
|
90
|
+
type RuntimeAbortedPhase = 'encode' | 'decode' | 'stream' | 'beforeExecute' | 'afterExecute' | 'onRow';
|
|
24
91
|
/**
|
|
25
92
|
* Type guard for the runtime-error envelope produced by `runtimeError`.
|
|
26
93
|
*
|
|
@@ -29,38 +96,233 @@ interface RuntimeErrorEnvelope extends Error {
|
|
|
29
96
|
*/
|
|
30
97
|
declare function isRuntimeError(error: unknown): error is RuntimeErrorEnvelope;
|
|
31
98
|
declare function runtimeError(code: string, message: string, details?: Record<string, unknown>): RuntimeErrorEnvelope;
|
|
99
|
+
/**
|
|
100
|
+
* Construct a `RUNTIME.ABORTED` envelope. Phase distinguishes where the
|
|
101
|
+
* abort was observed — codec call sites (`encode` / `decode` / `stream`)
|
|
102
|
+
* or middleware seams (`beforeExecute` / `afterExecute` / `onRow`), as
|
|
103
|
+
* enumerated on {@link RuntimeAbortedPhase}. Cause carries
|
|
104
|
+
* `signal.reason` verbatim from the platform — native abort produces a
|
|
105
|
+
* `DOMException`, explicit `controller.abort(reason)` produces whatever
|
|
106
|
+
* the caller passed. No synthesis happens here.
|
|
107
|
+
*/
|
|
108
|
+
declare function runtimeAborted(phase: RuntimeAbortedPhase, cause?: unknown): RuntimeErrorEnvelope;
|
|
32
109
|
//#endregion
|
|
33
|
-
//#region src/
|
|
110
|
+
//#region src/execution/race-against-abort.d.ts
|
|
111
|
+
/**
|
|
112
|
+
* Throw a phase-tagged `RUNTIME.ABORTED` envelope if the supplied
|
|
113
|
+
* context is already aborted at the precheck site. Centralises the
|
|
114
|
+
* `if (ctx.signal?.aborted) throw runtimeAborted(...)` pattern that
|
|
115
|
+
* every codec dispatch site (and the `beforeExecute` middleware phase)
|
|
116
|
+
* repeats. Accepts both the framework `CodecCallContext` and the
|
|
117
|
+
* `RuntimeMiddlewareContext`; both expose `signal?: AbortSignal`.
|
|
118
|
+
*/
|
|
119
|
+
declare function checkAborted(ctx: {
|
|
120
|
+
readonly signal?: AbortSignal;
|
|
121
|
+
}, phase: RuntimeAbortedPhase): void;
|
|
122
|
+
/**
|
|
123
|
+
* Race a per-cell `Promise.all` (or any other in-flight work promise) against
|
|
124
|
+
* the supplied abort signal so the runtime returns `RUNTIME.ABORTED` promptly
|
|
125
|
+
* even when codec bodies ignore the signal. In-flight bodies that ignore the
|
|
126
|
+
* signal are abandoned and run to completion in the background — the
|
|
127
|
+
* cooperative-cancellation contract documented in ADR 204.
|
|
128
|
+
*
|
|
129
|
+
* Call sites still SHOULD pre-check `signal.aborted` and short-circuit with
|
|
130
|
+
* a phase-tagged `RUNTIME.ABORTED` envelope before invoking this helper —
|
|
131
|
+
* that path is the canonical "aborted at entry" surface and avoids
|
|
132
|
+
* scheduling the work promise. As a defensive belt-and-braces, this helper
|
|
133
|
+
* also handles the already-aborted case internally: `AbortSignal` does not
|
|
134
|
+
* replay past abort events to listeners registered after the abort, so we
|
|
135
|
+
* inspect `signal.aborted` synchronously and reject with the sentinel
|
|
136
|
+
* before installing the listener. The rejection is still attributed to the
|
|
137
|
+
* abort path via the sentinel-identity check.
|
|
138
|
+
*
|
|
139
|
+
* Distinguishing the rejection source is load-bearing for AC-ERR4
|
|
140
|
+
* (`RUNTIME.ENCODE_FAILED` / `RUNTIME.DECODE_FAILED` pass through unchanged).
|
|
141
|
+
* The semantically equivalent `abortable(signal)` helper in
|
|
142
|
+
* `@prisma-next/utils` rejects with `signal.reason ?? new DOMException(...)`,
|
|
143
|
+
* which is not stably distinguishable from a codec-thrown error by identity
|
|
144
|
+
* alone (a fresh fallback DOMException is allocated per call). We instead
|
|
145
|
+
* track abort attribution with a unique sentinel: only the `onAbort` listener
|
|
146
|
+
* installed here ever rejects with the sentinel, so an `error === sentinel`
|
|
147
|
+
* identity check after the race is unambiguous.
|
|
148
|
+
*
|
|
149
|
+
* Lives in `framework-components` (rather than the SQL family, where it
|
|
150
|
+
* originated in m2) so every family runtime that needs cooperative
|
|
151
|
+
* cancellation around a codec-dispatch `Promise.all` (SQL encode + decode
|
|
152
|
+
* today, Mongo encode in m3) shares the same attribution logic.
|
|
153
|
+
*/
|
|
154
|
+
declare function raceAgainstAbort<T>(work: Promise<T>, signal: AbortSignal | undefined, phase: RuntimeAbortedPhase): Promise<T>;
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/execution/runtime-middleware.d.ts
|
|
34
157
|
interface RuntimeLog {
|
|
35
158
|
info(event: unknown): void;
|
|
36
159
|
warn(event: unknown): void;
|
|
37
160
|
error(event: unknown): void;
|
|
38
161
|
debug?(event: unknown): void;
|
|
39
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Per-execute context threaded through every middleware phase
|
|
165
|
+
* (`beforeExecute`, `onRow`, `afterExecute`). Allocated once per
|
|
166
|
+
* `runtime.execute()` call and shared by reference across all
|
|
167
|
+
* middleware in the chain.
|
|
168
|
+
*
|
|
169
|
+
* - `signal` carries the per-query `AbortSignal` -- the same
|
|
170
|
+
* reference that `runtime.execute(plan, { signal })` was invoked
|
|
171
|
+
* with, and the same reference threaded into the per-call
|
|
172
|
+
* `CodecCallContext` (ADR 207). Middleware that wraps a
|
|
173
|
+
* network-backed SDK forwards `ctx.signal` into that SDK to
|
|
174
|
+
* propagate caller cancellation; pure-CPU middleware ignores it.
|
|
175
|
+
*
|
|
176
|
+
* Symmetric plumbing across all middleware phases (rather than only
|
|
177
|
+
* `beforeExecute`) is a deliberate choice: a middleware that wraps a
|
|
178
|
+
* downstream observability hook or post-processor in `afterExecute` /
|
|
179
|
+
* `onRow` needs the same cancellation reach as its `beforeExecute`
|
|
180
|
+
* counterpart.
|
|
181
|
+
*/
|
|
40
182
|
interface RuntimeMiddlewareContext {
|
|
41
183
|
readonly contract: unknown;
|
|
42
184
|
readonly mode: 'strict' | 'permissive';
|
|
43
185
|
readonly now: () => number;
|
|
44
186
|
readonly log: RuntimeLog;
|
|
187
|
+
/**
|
|
188
|
+
* Returns a stable string identifying the (storage, statement, params)
|
|
189
|
+
* tuple of an execution. Two semantically equivalent executions return
|
|
190
|
+
* the same string. Used by middleware that need per-execution identity
|
|
191
|
+
* (caching, request coalescing).
|
|
192
|
+
*
|
|
193
|
+
* The family runtime owns the implementation:
|
|
194
|
+
* - SQL: `meta.storageHash` + `exec.sql` + `canonicalStringify(exec.params)`
|
|
195
|
+
* - Mongo: `meta.storageHash` + `canonicalStringify({ ...exec.command })`
|
|
196
|
+
*
|
|
197
|
+
* The method is `async` because the underlying digest helper
|
|
198
|
+
* (`hashContent`) uses the WebCrypto API, whose `crypto.subtle.digest`
|
|
199
|
+
* primitive is asynchronous by design.
|
|
200
|
+
*
|
|
201
|
+
* The returned string is intended to be consumed directly as a `Map` key
|
|
202
|
+
* — it is not (and should not be) further hashed by callers.
|
|
203
|
+
*/
|
|
204
|
+
contentHash(exec: ExecutionPlan): Promise<string>;
|
|
205
|
+
/**
|
|
206
|
+
* Per-execute cancellation signal threaded through every middleware
|
|
207
|
+
* phase. Middleware that wraps async work or downstream cancellable
|
|
208
|
+
* primitives should observe this and abort early when the consumer
|
|
209
|
+
* cancels.
|
|
210
|
+
*/
|
|
211
|
+
readonly signal?: AbortSignal;
|
|
45
212
|
}
|
|
46
213
|
interface AfterExecuteResult {
|
|
47
214
|
readonly rowCount: number;
|
|
48
215
|
readonly latencyMs: number;
|
|
49
216
|
readonly completed: boolean;
|
|
217
|
+
/**
|
|
218
|
+
* Indicates where the rows observed during this execution came from.
|
|
219
|
+
*
|
|
220
|
+
* - `'driver'` — the default. Rows came from the underlying driver via
|
|
221
|
+
* `runDriver` / `runWithMiddleware`'s normal path.
|
|
222
|
+
* - `'middleware'` — a `RuntimeMiddleware.intercept` hook short-circuited
|
|
223
|
+
* execution and supplied the rows directly. The driver was not invoked.
|
|
224
|
+
*
|
|
225
|
+
* Observers (telemetry, lints, budgets) that need to distinguish between
|
|
226
|
+
* driver-served and middleware-served executions read this field.
|
|
227
|
+
* Observers that don't care can ignore it.
|
|
228
|
+
*/
|
|
229
|
+
readonly source: 'driver' | 'middleware';
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Result of a successful `RuntimeMiddleware.intercept` hook.
|
|
233
|
+
*
|
|
234
|
+
* Carries the rows that the middleware wishes to return in place of
|
|
235
|
+
* invoking the driver. The runtime iterates `rows` in order and yields
|
|
236
|
+
* each row to the consumer; `beforeExecute`, `runDriver`, and `onRow` are
|
|
237
|
+
* all skipped on the hit path. `afterExecute` still fires with
|
|
238
|
+
* `source: 'middleware'`.
|
|
239
|
+
*
|
|
240
|
+
* `rows` accepts both `Iterable` (arrays, sync generators) and
|
|
241
|
+
* `AsyncIterable` (async generators). `for await` natively handles both
|
|
242
|
+
* via `Symbol.asyncIterator` / `Symbol.iterator` fallback, so the
|
|
243
|
+
* orchestrator does not need to branch on the variant. Cached arrays in
|
|
244
|
+
* the cache middleware are the common case; streaming variants support
|
|
245
|
+
* future use cases like mock layers replaying recordings.
|
|
246
|
+
*
|
|
247
|
+
* Row shape is `Record<string, unknown>` — the same untyped shape
|
|
248
|
+
* `onRow` receives. The SQL runtime decodes intercepted rows through its
|
|
249
|
+
* normal codec pass, so interceptors cache and return raw (undecoded)
|
|
250
|
+
* rows.
|
|
251
|
+
*/
|
|
252
|
+
interface InterceptResult {
|
|
253
|
+
readonly rows: AsyncIterable<Record<string, unknown>> | Iterable<Record<string, unknown>>;
|
|
50
254
|
}
|
|
51
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Marker interface for family-specific param-ref mutators threaded into
|
|
257
|
+
* `beforeExecute` as the third argument. The framework treats the mutator
|
|
258
|
+
* opaquely — it allocates and forwards the family's mutator instance so
|
|
259
|
+
* `runWithMiddleware` can stay family-agnostic. SQL extends this with
|
|
260
|
+
* `SqlParamRefMutator` (over `ParamRef`); Mongo extends with
|
|
261
|
+
* `MongoParamRefMutator` (over `MongoParamRef`).
|
|
262
|
+
*
|
|
263
|
+
* Extension authors target the family-specific mutator type, not this
|
|
264
|
+
* marker.
|
|
265
|
+
*/
|
|
266
|
+
declare const PARAM_REF_MUTATOR_BRAND: unique symbol;
|
|
267
|
+
type ParamRefMutator = {
|
|
268
|
+
readonly [PARAM_REF_MUTATOR_BRAND]?: never;
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* Family-agnostic middleware SPI parameterized over the plan marker.
|
|
272
|
+
*
|
|
273
|
+
* `TPlan` defaults to the framework `QueryPlan` marker so a generic
|
|
274
|
+
* middleware (e.g. cross-family telemetry) can be authored without
|
|
275
|
+
* naming a family. Family-specific middleware (`SqlMiddleware`,
|
|
276
|
+
* `MongoMiddleware`) narrow `TPlan` to their concrete plan type.
|
|
277
|
+
*
|
|
278
|
+
* `TMutator` is the family-specific {@link ParamRefMutator} the runtime
|
|
279
|
+
* threads into `beforeExecute(plan, ctx, params)` as a third argument.
|
|
280
|
+
* Existing `(plan)` / `(plan, ctx)` middleware bodies continue to compile
|
|
281
|
+
* — TypeScript permits assigning a function with fewer parameters to a
|
|
282
|
+
* function-typed slot that declares more. The third arg is additive.
|
|
283
|
+
*/
|
|
284
|
+
interface RuntimeMiddleware<TPlan extends QueryPlan = QueryPlan, TMutator extends ParamRefMutator = ParamRefMutator> {
|
|
52
285
|
readonly name: string;
|
|
53
286
|
readonly familyId?: string;
|
|
54
287
|
readonly targetId?: string;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Optional short-circuit hook. Runs inside `runWithMiddleware`, after
|
|
290
|
+
* the orchestrator receives the lowered plan and before any
|
|
291
|
+
* `beforeExecute` hook fires. Middleware run in registration order; the
|
|
292
|
+
* first to return a non-`undefined` `InterceptResult` wins, and
|
|
293
|
+
* subsequent middleware's `intercept` does not fire.
|
|
294
|
+
*
|
|
295
|
+
* On a hit, `beforeExecute`, `runDriver`, and `onRow` are all skipped.
|
|
296
|
+
* `afterExecute` still fires with `source: 'middleware'`.
|
|
297
|
+
*
|
|
298
|
+
* Returning `undefined` (or omitting the hook entirely) signals
|
|
299
|
+
* passthrough — execution proceeds through the normal driver path.
|
|
300
|
+
*
|
|
301
|
+
* Errors thrown inside `intercept` are rethrown by `runWithMiddleware`
|
|
302
|
+
* as the original `Error` — no envelope is guaranteed at this layer.
|
|
303
|
+
* Before rethrowing, `afterExecute` fires with `completed: false` and
|
|
304
|
+
* `source: 'middleware'`. Errors thrown by `afterExecute` during the
|
|
305
|
+
* error path remain swallowed (existing semantics, unchanged).
|
|
306
|
+
*
|
|
307
|
+
* Used by middleware that need to short-circuit execution and supply
|
|
308
|
+
* rows directly: caching, mocks, rate limiting, circuit breaking.
|
|
309
|
+
*/
|
|
310
|
+
intercept?(plan: TPlan, ctx: RuntimeMiddlewareContext): Promise<InterceptResult | undefined>;
|
|
311
|
+
beforeExecute?(plan: TPlan, ctx: RuntimeMiddlewareContext, params?: TMutator): void | Promise<void>;
|
|
312
|
+
onRow?(row: Record<string, unknown>, plan: TPlan, ctx: RuntimeMiddlewareContext): Promise<void>;
|
|
313
|
+
afterExecute?(plan: TPlan, result: AfterExecuteResult, ctx: RuntimeMiddlewareContext): Promise<void>;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Optional per-`execute` options accepted by every family runtime.
|
|
317
|
+
*
|
|
318
|
+
* `signal` is the per-query cancellation signal. The runtime threads the
|
|
319
|
+
* signal through to every codec call for the query and uses it to short-
|
|
320
|
+
* circuit the row stream with `RUNTIME.ABORTED` when the caller aborts.
|
|
321
|
+
* Omitting the option (or passing `undefined`) preserves today's behavior
|
|
322
|
+
* bit-for-bit.
|
|
323
|
+
*/
|
|
324
|
+
interface RuntimeExecuteOptions {
|
|
325
|
+
readonly signal?: AbortSignal;
|
|
64
326
|
}
|
|
65
327
|
/**
|
|
66
328
|
* Cross-family SPI for any runtime that can execute plans and be shut down.
|
|
@@ -68,17 +330,131 @@ interface RuntimeMiddleware {
|
|
|
68
330
|
* Mongo structurally (due to its phantom Row parameter using a unique symbol).
|
|
69
331
|
*
|
|
70
332
|
* The `_row` intersection on `execute` connects the `Row` type parameter to the
|
|
71
|
-
* plan, mirroring how `
|
|
333
|
+
* plan, mirroring how `QueryPlan<Row>` carries a phantom `_row?: Row`.
|
|
72
334
|
*/
|
|
73
|
-
interface RuntimeExecutor<TPlan extends {
|
|
74
|
-
readonly meta: PlanMeta;
|
|
75
|
-
}> {
|
|
335
|
+
interface RuntimeExecutor<TPlan extends QueryPlan> {
|
|
76
336
|
execute<Row>(plan: TPlan & {
|
|
77
337
|
readonly _row?: Row;
|
|
78
|
-
}): AsyncIterableResult<Row>;
|
|
338
|
+
}, options?: RuntimeExecuteOptions): AsyncIterableResult<Row>;
|
|
79
339
|
close(): Promise<void>;
|
|
80
340
|
}
|
|
81
341
|
declare function checkMiddlewareCompatibility(middleware: RuntimeMiddleware, runtimeFamilyId: string, runtimeTargetId: string): void;
|
|
82
342
|
//#endregion
|
|
83
|
-
|
|
343
|
+
//#region src/execution/run-with-middleware.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* Drives a single execution of `runDriver()` through the middleware lifecycle.
|
|
346
|
+
*
|
|
347
|
+
* Lifecycle, in order:
|
|
348
|
+
* 1. For each middleware in registration order: `intercept(exec, ctx)`. The
|
|
349
|
+
* first non-`undefined` result wins; subsequent middleware's `intercept`
|
|
350
|
+
* does not fire. On a hit, the runtime emits a `middleware.intercept`
|
|
351
|
+
* debug event naming the winning middleware, switches the row source to
|
|
352
|
+
* the intercepted rows, and proceeds with `source: 'middleware'`. On
|
|
353
|
+
* all-passthrough (every `intercept` returns `undefined` or is omitted),
|
|
354
|
+
* `source: 'driver'` is used and the row source is `runDriver()`.
|
|
355
|
+
* 2. If `source === 'driver'`: for each middleware in registration order,
|
|
356
|
+
* `beforeExecute(exec, ctx)`. Skipped on the intercepted hit path —
|
|
357
|
+
* `beforeExecute` semantically means "about to hit the driver".
|
|
358
|
+
* 3. Iterate the row source. On the driver path, for each row, for each
|
|
359
|
+
* middleware in registration order: `onRow(row, exec, ctx)`; then yield
|
|
360
|
+
* the row. On the intercepted hit path, `onRow` is skipped — intercepted
|
|
361
|
+
* rows did not originate from a driver row stream — but rows are still
|
|
362
|
+
* yielded to the consumer in order.
|
|
363
|
+
* 4. On successful completion: for each middleware in registration order:
|
|
364
|
+
* `afterExecute(exec, { rowCount, latencyMs, completed: true, source },
|
|
365
|
+
* ctx)`.
|
|
366
|
+
* 5. On any error thrown during steps 1–3: for each middleware in
|
|
367
|
+
* registration order: `afterExecute(exec, { rowCount, latencyMs,
|
|
368
|
+
* completed: false, source }, ctx)`. Errors thrown by `afterExecute`
|
|
369
|
+
* during the error path are swallowed so they do not mask the original
|
|
370
|
+
* error. The original error is then rethrown.
|
|
371
|
+
*
|
|
372
|
+
* The `source` field on `AfterExecuteResult` lets observers (telemetry,
|
|
373
|
+
* lints, budgets) distinguish driver-served from middleware-served
|
|
374
|
+
* executions without needing their own out-of-band signal.
|
|
375
|
+
*
|
|
376
|
+
* This helper is the single canonical implementation of the middleware
|
|
377
|
+
* orchestration loop; family runtimes should not reimplement it.
|
|
378
|
+
*/
|
|
379
|
+
declare function runWithMiddleware<TExec extends ExecutionPlan, Row, TMutator extends ParamRefMutator = ParamRefMutator>(exec: TExec, middleware: ReadonlyArray<RuntimeMiddleware<TExec, TMutator>>, ctx: RuntimeMiddlewareContext, runDriver: () => AsyncIterable<Row>, paramsMutator?: TMutator): AsyncIterableResult<Row>;
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/execution/runtime-core.d.ts
|
|
382
|
+
/**
|
|
383
|
+
* Constructor options shared by every concrete `RuntimeCore` subclass.
|
|
384
|
+
*
|
|
385
|
+
* Family runtimes typically build the middleware list and the
|
|
386
|
+
* `RuntimeMiddlewareContext` themselves (running compatibility checks,
|
|
387
|
+
* narrowing the context's `contract` field, etc.) before calling `super`.
|
|
388
|
+
*/
|
|
389
|
+
interface RuntimeCoreOptions<TMiddleware extends RuntimeMiddleware<ExecutionPlan>> {
|
|
390
|
+
readonly middleware: ReadonlyArray<TMiddleware>;
|
|
391
|
+
readonly ctx: RuntimeMiddlewareContext;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Family-agnostic abstract runtime base.
|
|
395
|
+
*
|
|
396
|
+
* Defines the entire `execute(plan)` template in one place:
|
|
397
|
+
*
|
|
398
|
+
* 1. `runBeforeCompile(plan)` — concrete; defaults to identity. SQL overrides
|
|
399
|
+
* this to run its `beforeCompile` middleware-hook chain.
|
|
400
|
+
* 2. `lower(plan)` — abstract. Each family produces its `*ExecutionPlan`
|
|
401
|
+
* (SQL via `lowerSqlPlan`, Mongo via `adapter.lower`).
|
|
402
|
+
* 3. `runWithMiddleware(exec, this.middleware, this.ctx,
|
|
403
|
+
* () => runDriver(exec))` — concrete; lifts the middleware lifecycle
|
|
404
|
+
* out of the family runtimes into the canonical helper.
|
|
405
|
+
*
|
|
406
|
+
* Concrete subclasses must implement `lower`, `runDriver`, and `close`.
|
|
407
|
+
*
|
|
408
|
+
* The class is generic over:
|
|
409
|
+
* - `TPlan` — the family's pre-lowering plan type.
|
|
410
|
+
* - `TExec` — the family's post-lowering (executable) plan type.
|
|
411
|
+
* - `TMiddleware` — the family's middleware type. Constrained to
|
|
412
|
+
* `RuntimeMiddleware<TExec>` because `runWithMiddleware` invokes the
|
|
413
|
+
* `beforeExecute` / `onRow` / `afterExecute` hooks with the lowered
|
|
414
|
+
* `TExec`. (The spec/plan wording "RuntimeMiddleware<TPlan>" is
|
|
415
|
+
* tightened to `<TExec>` here so the helper call typechecks; the
|
|
416
|
+
* intent is unchanged — middleware sees the post-lowering plan.)
|
|
417
|
+
*/
|
|
418
|
+
declare abstract class RuntimeCore<TPlan extends QueryPlan, TExec extends ExecutionPlan, TMiddleware extends RuntimeMiddleware<TExec>> implements RuntimeExecutor<TPlan> {
|
|
419
|
+
protected readonly middleware: ReadonlyArray<TMiddleware>;
|
|
420
|
+
protected readonly ctx: RuntimeMiddlewareContext;
|
|
421
|
+
constructor(options: RuntimeCoreOptions<TMiddleware>);
|
|
422
|
+
/**
|
|
423
|
+
* Pre-lowering hook for plan rewriting. Defaults to identity. Subclasses
|
|
424
|
+
* may override to run a `beforeCompile` middleware chain (SQL does this
|
|
425
|
+
* to support typed AST rewrites — see `before-compile-chain.ts`).
|
|
426
|
+
*/
|
|
427
|
+
protected runBeforeCompile(plan: TPlan): TPlan | Promise<TPlan>;
|
|
428
|
+
/**
|
|
429
|
+
* Lower a pre-lowering `TPlan` into the family's executable `TExec`.
|
|
430
|
+
* Family-specific: SQL produces `{ sql, params, ast?, ... }`; Mongo
|
|
431
|
+
* produces `{ command, ... }`.
|
|
432
|
+
*
|
|
433
|
+
* `ctx` carries per-query cancellation (and any future fields on
|
|
434
|
+
* `CodecCallContext`); concrete subclasses forward it to the
|
|
435
|
+
* encode-side codec dispatch site (e.g. SQL's `encodeParams` in m2,
|
|
436
|
+
* Mongo's `resolveValue` in m3). The runtime allocates one ctx per
|
|
437
|
+
* `execute()` call and threads the same reference everywhere; the
|
|
438
|
+
* `signal` field inside may be `undefined`, but the ctx object itself
|
|
439
|
+
* is always present.
|
|
440
|
+
*/
|
|
441
|
+
protected abstract lower(plan: TPlan, ctx: CodecCallContext): TExec | Promise<TExec>;
|
|
442
|
+
/**
|
|
443
|
+
* Drive the underlying transport for a lowered `TExec`. Yields raw rows
|
|
444
|
+
* directly from the driver as `Record<string, unknown>`; codec decoding
|
|
445
|
+
* (if any) is the subclass's responsibility, applied by wrapping
|
|
446
|
+
* `execute()` rather than living inside this hook.
|
|
447
|
+
*
|
|
448
|
+
* The `Row` type parameter on `execute()` is satisfied by the caller via
|
|
449
|
+
* the plan's phantom `_row`; the runtime treats rows as opaque records
|
|
450
|
+
* here and trusts the caller's row typing.
|
|
451
|
+
*/
|
|
452
|
+
protected abstract runDriver(exec: TExec): AsyncIterable<Record<string, unknown>>;
|
|
453
|
+
abstract close(): Promise<void>;
|
|
454
|
+
execute<Row>(plan: TPlan & {
|
|
455
|
+
readonly _row?: Row;
|
|
456
|
+
}, options?: RuntimeExecuteOptions): AsyncIterableResult<Row>;
|
|
457
|
+
}
|
|
458
|
+
//#endregion
|
|
459
|
+
export { type AfterExecuteResult, AsyncIterableResult, type ExecutionPlan, type InterceptResult, type ParamRefMutator, type QueryPlan, RUNTIME_ABORTED, type ResultType, type RuntimeAbortedPhase, RuntimeCore, type RuntimeCoreOptions, type RuntimeErrorEnvelope, type RuntimeExecuteOptions, type RuntimeExecutor, type RuntimeLog, type RuntimeMiddleware, type RuntimeMiddlewareContext, checkAborted, checkMiddlewareCompatibility, isRuntimeError, raceAgainstAbort, runWithMiddleware, runtimeAborted, runtimeError };
|
|
84
460
|
//# sourceMappingURL=runtime.d.mts.map
|
package/dist/runtime.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/async-iterable-result.ts","../src/runtime-error.ts","../src/runtime-middleware.ts"
|
|
1
|
+
{"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/execution/async-iterable-result.ts","../src/execution/query-plan.ts","../src/execution/runtime-error.ts","../src/execution/race-against-abort.ts","../src/execution/runtime-middleware.ts","../src/execution/run-with-middleware.ts","../src/execution/runtime-core.ts"],"mappings":"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"}
|