@jarenjs/db 0.49.2 → 0.66.1
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/ARCHITECTURE.md +420 -71
- package/README.md +711 -79
- package/docs/HOSTS.md +269 -0
- package/docs/JOBS-FORMAT.md +309 -45
- package/docs/LIVE-FORMAT.md +156 -19
- package/docs/MIGRATION-FORMAT.md +247 -40
- package/docs/MODEL-FORMAT.md +968 -86
- package/package.json +21 -8
- package/schemas/jaren-migration.draft-07.schema.json +73 -0
- package/schemas/jaren-migration.schema.json +73 -0
- package/schemas/jaren-model.draft-07.schema.json +224 -162
- package/schemas/jaren-model.schema.json +224 -162
- package/src/algebra.js +227 -9
- package/src/backup.js +161 -0
- package/src/cancellation.js +48 -0
- package/src/capture.js +255 -44
- package/src/cli.js +337 -50
- package/src/cursor.js +411 -0
- package/src/dag-job.js +154 -21
- package/src/ddl.js +125 -11
- package/src/dialect.js +267 -112
- package/src/dialects/expression-read.js +158 -0
- package/src/dialects/postgres.js +618 -0
- package/src/dialects/rtree-ddl.js +129 -0
- package/src/dialects/sqlite.js +245 -12
- package/src/document-files.js +311 -0
- package/src/document-steps.js +422 -0
- package/src/documents.js +335 -0
- package/src/driver.js +503 -69
- package/src/drivers/bun.js +37 -1
- package/src/drivers/indexeddb-snapshot.js +149 -0
- package/src/drivers/node-pool.js +11 -0
- package/src/drivers/node-worker-endpoint.js +105 -0
- package/src/drivers/node-worker.js +204 -0
- package/src/drivers/node.js +41 -7
- package/src/drivers/postgres.js +331 -0
- package/src/drivers/wasm-oo1.js +97 -0
- package/src/drivers/wasm-session.js +67 -0
- package/src/drivers/wasm.js +18 -83
- package/src/drivers/worker-pool.js +183 -0
- package/src/drivers/worker-protocol.js +79 -0
- package/src/drivers/worker-queue.js +60 -0
- package/src/emit-model.js +14 -0
- package/src/emit.js +349 -51
- package/src/entity.js +102 -59
- package/src/errors.js +430 -2
- package/src/expression.js +284 -0
- package/src/graph.js +64 -8
- package/src/index.js +48 -19
- package/src/introspect.js +583 -0
- package/src/jobs.js +870 -99
- package/src/json-bytes.js +58 -0
- package/src/live-time.js +12 -3
- package/src/live.js +11 -1
- package/src/maintenance.js +175 -0
- package/src/migrate.js +606 -333
- package/src/model.js +241 -8
- package/src/plan.js +1238 -160
- package/src/pragmas.js +314 -0
- package/src/profile.js +151 -3
- package/src/query.js +1748 -312
- package/src/residual.js +17 -0
- package/src/series.js +12 -4
- package/src/store.js +1672 -276
- package/src/tracker.js +367 -68
- package/src/udf.js +88 -7
- package/types/index.d.ts +1246 -32
- package/types/node-pool.d.ts +28 -0
- package/types/node-worker.d.ts +54 -0
- package/types/node.d.ts +72 -3
- package/types/postgres.d.ts +46 -0
- package/types/typed.d.ts +81 -3
- package/types/wasm.d.ts +21 -0
- package/dist/types/algebra.d.ts +0 -230
- package/dist/types/app.d.ts +0 -49
- package/dist/types/capture.d.ts +0 -85
- package/dist/types/cli.d.ts +0 -2
- package/dist/types/dag-job.d.ts +0 -40
- package/dist/types/ddl.d.ts +0 -229
- package/dist/types/derive.d.ts +0 -250
- package/dist/types/dialect.d.ts +0 -154
- package/dist/types/dialects/sqlite.d.ts +0 -9
- package/dist/types/driver.d.ts +0 -110
- package/dist/types/drivers/bun.d.ts +0 -47
- package/dist/types/drivers/node.d.ts +0 -37
- package/dist/types/drivers/wasm.d.ts +0 -65
- package/dist/types/emit-model.d.ts +0 -44
- package/dist/types/emit.d.ts +0 -75
- package/dist/types/entity.d.ts +0 -23
- package/dist/types/errors.d.ts +0 -170
- package/dist/types/graph.d.ts +0 -28
- package/dist/types/index.d.ts +0 -37
- package/dist/types/jobs.d.ts +0 -140
- package/dist/types/knn.d.ts +0 -69
- package/dist/types/live-time.d.ts +0 -141
- package/dist/types/live.d.ts +0 -64
- package/dist/types/migrate.d.ts +0 -170
- package/dist/types/model.d.ts +0 -36
- package/dist/types/patch-sql.d.ts +0 -37
- package/dist/types/plan.d.ts +0 -142
- package/dist/types/profile.d.ts +0 -80
- package/dist/types/query.d.ts +0 -112
- package/dist/types/residual.d.ts +0 -64
- package/dist/types/series.d.ts +0 -227
- package/dist/types/store.d.ts +0 -60
- package/dist/types/tracker.d.ts +0 -43
- package/dist/types/typed.d.ts +0 -15
- package/dist/types/types.d.ts +0 -26
- package/dist/types/udf.d.ts +0 -75
- package/dist/types/window.d.ts +0 -52
package/types/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
* `@jarenjs/db/typed`.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import type { Runtime } from '@jarenjs/core/runtime';
|
|
20
|
+
|
|
19
21
|
// ————— errors —————
|
|
20
22
|
|
|
21
23
|
export declare const DB_CODES: Readonly<Record<string, string>>;
|
|
@@ -25,8 +27,37 @@ export declare class DbCompileError extends Error {
|
|
|
25
27
|
readonly code: string;
|
|
26
28
|
readonly reason: string;
|
|
27
29
|
readonly docPath?: string;
|
|
30
|
+
/** Present on a `JD0002` raised by a driver failure at open: the
|
|
31
|
+
* classifier's class and verdict (MODEL-FORMAT §7). */
|
|
32
|
+
readonly class?: DriverErrorClass;
|
|
33
|
+
readonly retryable?: boolean;
|
|
28
34
|
}
|
|
29
35
|
|
|
36
|
+
/** The stable classes `classifyDriverError` assigns (MODEL-FORMAT §7). */
|
|
37
|
+
export type DriverErrorClass = 'busy' | 'full' | 'readonly' | 'io' | 'corrupt' | 'cantopen'
|
|
38
|
+
| 'constraint' | 'duplicate' | 'overflow' | 'error';
|
|
39
|
+
|
|
40
|
+
/** Classify a SQLite driver failure: the class, the runtime code it is
|
|
41
|
+
* raised under (`null` for `overflow`, which the query path answers by
|
|
42
|
+
* re-running in the engine), whether a retry can succeed, and the
|
|
43
|
+
* sentence the wrapped error leads with. */
|
|
44
|
+
export declare function classifyDriverError(error: unknown,
|
|
45
|
+
unique?: { table: string; column: string }):
|
|
46
|
+
{ class: DriverErrorClass; code: string | null; retryable: boolean; reason: string };
|
|
47
|
+
/** Wrap a driver failure as the coded runtime error its class calls
|
|
48
|
+
* for, `class`/`retryable`/`cause` attached; anything that is not a
|
|
49
|
+
* driver's own error is returned as it is. */
|
|
50
|
+
export declare function wrapDriverError(error: unknown, details?: {
|
|
51
|
+
docPath?: string; collection?: string; key?: string | number;
|
|
52
|
+
unique?: { table: string; column: string }; duplicateReason?: string;
|
|
53
|
+
code?: string; reason?: string;
|
|
54
|
+
/** Wrap even a failure that is not a driver's under `code`, with
|
|
55
|
+
* `class: 'error'` — for a lifecycle that promises a coded failure. */
|
|
56
|
+
always?: boolean }): Error;
|
|
57
|
+
/** Whether an error is a SQLite driver's own (a numeric result code, or
|
|
58
|
+
* node:sqlite's error shape). */
|
|
59
|
+
export declare function isDriverError(error: unknown): boolean;
|
|
60
|
+
|
|
30
61
|
export declare class DbRuntimeError extends Error {
|
|
31
62
|
constructor(code: string, reason: string, options?: {
|
|
32
63
|
docPath?: string;
|
|
@@ -41,6 +72,10 @@ export declare class DbRuntimeError extends Error {
|
|
|
41
72
|
readonly collection?: string;
|
|
42
73
|
readonly key?: unknown;
|
|
43
74
|
readonly errors?: unknown[];
|
|
75
|
+
/** Present on an error the driver-failure classifier wrapped
|
|
76
|
+
* (MODEL-FORMAT §7): the stable class and whether a retry can succeed. */
|
|
77
|
+
readonly class?: DriverErrorClass;
|
|
78
|
+
readonly retryable?: boolean;
|
|
44
79
|
}
|
|
45
80
|
|
|
46
81
|
// ————— shared shapes —————
|
|
@@ -73,8 +108,67 @@ export type ValueOrPromise<T> = T | Promise<T>;
|
|
|
73
108
|
*/
|
|
74
109
|
export interface QueryCursor<T = unknown> {
|
|
75
110
|
next(): Promise<IteratorResult<T, undefined>>;
|
|
111
|
+
/** Release the statement, exactly once, at the row boundary the
|
|
112
|
+
* cursor is on; idempotent, and what `for await`'s break, throw and
|
|
113
|
+
* exhaustion all reach. */
|
|
76
114
|
return(): Promise<IteratorResult<T, undefined>>;
|
|
77
115
|
[Symbol.asyncIterator](): QueryCursor<T>;
|
|
116
|
+
/** What this cursor will do for the externals it was given: pull one
|
|
117
|
+
* database row per `next()`, or fill a buffer on the first pull. */
|
|
118
|
+
readonly streaming: 'row' | 'buffered';
|
|
119
|
+
/** What forces the buffer, `null` when the cursor streams. */
|
|
120
|
+
readonly barrier: CursorBarrier | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Why a cursor buffers: `construct` is the stable identifier (a
|
|
124
|
+
* planner construct such as `$orderby` or `$let`, or `external`,
|
|
125
|
+
* `window`, `pushdown`), `reason` the sentence for a person. */
|
|
126
|
+
export interface CursorBarrier {
|
|
127
|
+
readonly construct: string;
|
|
128
|
+
readonly reason: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The safe execution profile (MODEL-FORMAT §8): five independent bounds
|
|
133
|
+
* — engine limits, a row bound, reference containment, mandatory
|
|
134
|
+
* predicates, a member allow-list — plus the graph bounds. Every member
|
|
135
|
+
* is optional over the `'safe'` defaults. A budget the engine can count is ENFORCED; one it
|
|
136
|
+
* cannot count on SQLite (visited rows, elapsed statement time) is
|
|
137
|
+
* refused at preflight on plan shape (`refuseFullScan`) or reported as
|
|
138
|
+
* unavailable (`explain().budget`), never approximated.
|
|
139
|
+
*/
|
|
140
|
+
export interface ProfileSpec {
|
|
141
|
+
limits?: { sequenceItems?: number; resultItems?: number; steps?: number; depth?: number };
|
|
142
|
+
/** Rows a fetch may return, materialise or feed a residual, per call
|
|
143
|
+
* (`JD2007` when crossed). */
|
|
144
|
+
maxRows?: number;
|
|
145
|
+
externals?: readonly string[];
|
|
146
|
+
functions?: readonly string[];
|
|
147
|
+
collations?: readonly string[];
|
|
148
|
+
/** The names a document may read — collections AND entity roots;
|
|
149
|
+
* `null` allows all of the store's. */
|
|
150
|
+
collections?: readonly string[] | null;
|
|
151
|
+
/** A predicate conjoined into every plan over the named collection or
|
|
152
|
+
* entity, at its root, after translation. */
|
|
153
|
+
predicates?: Readonly<Record<string, unknown>>;
|
|
154
|
+
/** Refuse a plan whose shape is a full-table scan — including the
|
|
155
|
+
* whole-root fetch an entity residual needs (`JD0011`). */
|
|
156
|
+
refuseFullScan?: boolean;
|
|
157
|
+
/** A cap on any include's per-root rows, on the include depth, and on
|
|
158
|
+
* one item's serialised bytes (`JD2076`); `null` for none. */
|
|
159
|
+
maxIncludedRows?: number | null;
|
|
160
|
+
maxDepth?: number | null;
|
|
161
|
+
maxBytes?: number | null;
|
|
162
|
+
/** Per ROOT (a collection or an entity), the members a document may
|
|
163
|
+
* READ, as the model's own singular index-path spelling (`'$.name'`,
|
|
164
|
+
* `'$.address.city'`). Allowing a member allows everything under it
|
|
165
|
+
* and none of its siblings. A root the list does not name is
|
|
166
|
+
* unrestricted; a root the MODEL does not declare is `JD0011` before
|
|
167
|
+
* any statement. Reading a root item whole — the bare binding, an
|
|
168
|
+
* alias of it, a wildcard with no singular prefix — is refused rather
|
|
169
|
+
* than narrowed, and so is a graph `load()` of a policed entity, which
|
|
170
|
+
* answers whole documents by definition. */
|
|
171
|
+
members?: Readonly<Record<string, readonly string[]>>;
|
|
78
172
|
}
|
|
79
173
|
|
|
80
174
|
export interface ExecuteOptions {
|
|
@@ -82,11 +176,55 @@ export interface ExecuteOptions {
|
|
|
82
176
|
strict?: boolean;
|
|
83
177
|
/** `false` forces the set residual — the oracle's harness switch. */
|
|
84
178
|
pushdown?: boolean;
|
|
179
|
+
/** The safety profile for THIS call, replacing the store's (normalized
|
|
180
|
+
* over the `'safe'` defaults, MODEL-FORMAT §8); applies to collection,
|
|
181
|
+
* entity, graph, include and store-root execution alike. */
|
|
182
|
+
profile?: 'safe' | ProfileSpec;
|
|
183
|
+
/** Cancellation: a call already aborted runs no statement (`JD2072`);
|
|
184
|
+
* a cursor or page is released at its next row boundary. */
|
|
185
|
+
signal?: AbortSignal;
|
|
186
|
+
/** An epoch-millisecond deadline, checked before a statement runs and
|
|
187
|
+
* at every row boundary of a cursor or page (`JD2075`). NOT a
|
|
188
|
+
* statement timeout: the shipped SQLite drivers expose no interrupt
|
|
189
|
+
* (`capabilities.statementTimeout` is `false`), so a single statement
|
|
190
|
+
* runs to its end — `explain().budget.time` says so. */
|
|
191
|
+
deadline?: number;
|
|
192
|
+
/** On a cursor: a plan that would buffer — a set residual, a
|
|
193
|
+
* k-nearest cut, a native group, a chain's window, an external the
|
|
194
|
+
* database cannot bind — is the refusal `JD0037` naming the barrier,
|
|
195
|
+
* raised before any statement runs; the plan is declined, never run
|
|
196
|
+
* with its memory behaviour quietly changed. On `execute()` it is a
|
|
197
|
+
* `TypeError`: a whole answer has no stream to hold to. */
|
|
198
|
+
strictStreaming?: boolean;
|
|
85
199
|
}
|
|
86
200
|
|
|
87
|
-
|
|
201
|
+
/** What a cursor takes: `execute`'s options, `signal` honoured at every
|
|
202
|
+
* row boundary — an aborted cursor releases its statement and every
|
|
203
|
+
* later pull is `JD2072`. */
|
|
204
|
+
export interface CursorOptions extends ExecuteOptions {}
|
|
205
|
+
|
|
206
|
+
/** An entity cursor's options. `tracking: true` registers every yielded
|
|
207
|
+
* entity document with the unit of work — a snapshot per row, so the
|
|
208
|
+
* tracker grows with the result and is bounded by nothing but it; off
|
|
209
|
+
* by default for exactly that reason. The document must then return a
|
|
210
|
+
* bare entity binding (`JD0034` for a projection, a count or a window). */
|
|
211
|
+
export interface EntityCursorOptions extends CursorOptions {
|
|
212
|
+
tracking?: boolean;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** An include's clauses: the root's without `after` — a keyset cursor
|
|
216
|
+
* paginates the root alone; an include windows with `skip`/`take`. */
|
|
217
|
+
export interface LoadInclude extends Omit<LoadSpec, 'after'> {
|
|
88
218
|
/** Project the related-row COUNT instead of the rows. */
|
|
89
219
|
count?: boolean;
|
|
220
|
+
/** The per-root bounds (MODEL-FORMAT §10.4): rows of this relation
|
|
221
|
+
* per parent (default `INCLUDE_ROWS_DEFAULT`, or the include's own
|
|
222
|
+
* `take`), and serialised bytes per parent (default
|
|
223
|
+
* `INCLUDE_BYTES_DEFAULT`). Crossing one is the refusal `JD2073`,
|
|
224
|
+
* never a truncated graph. `Infinity` (`null` in JSON) is the
|
|
225
|
+
* unbounded case, spelled. */
|
|
226
|
+
maxRows?: number | null;
|
|
227
|
+
maxBytes?: number | null;
|
|
90
228
|
}
|
|
91
229
|
|
|
92
230
|
export interface LoadSpec {
|
|
@@ -95,16 +233,103 @@ export interface LoadSpec {
|
|
|
95
233
|
orderBy?: unknown;
|
|
96
234
|
take?: number;
|
|
97
235
|
skip?: number;
|
|
98
|
-
/** The keyset cursor
|
|
99
|
-
|
|
236
|
+
/** The keyset cursor (MODEL-FORMAT §10.5): the structural continuation
|
|
237
|
+
* a page emitted, over the declared ordering with the primary key
|
|
238
|
+
* appended; or, the single-column form, one value of a unique
|
|
239
|
+
* ordering column. */
|
|
240
|
+
after?: string | number | LoadContinuation;
|
|
100
241
|
maxDepth?: number;
|
|
101
242
|
include?: Readonly<Record<string, boolean | LoadInclude>>;
|
|
102
243
|
}
|
|
103
244
|
|
|
245
|
+
/** One term of a keyset ordering's identity: the mapped column, its
|
|
246
|
+
* direction, and where its nulls sort. */
|
|
247
|
+
export interface OrderIdentity {
|
|
248
|
+
readonly column: string;
|
|
249
|
+
readonly desc: boolean;
|
|
250
|
+
readonly nullsFirst: boolean;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** One term of the order a statement actually executes under. `source`
|
|
254
|
+
* is closed: a mapped `column`, a `document` path the dialect extracts,
|
|
255
|
+
* the `group` key of a bucketed plan, or the row `identity` an emitter
|
|
256
|
+
* appends so a sequence answers in insertion order. Only a `column`
|
|
257
|
+
* term carries a column name, only a `document` term a path; the
|
|
258
|
+
* identity term carries neither, and its `nullsFirst` is `null` because
|
|
259
|
+
* a row identity is never absent. `tieBreaker` marks a term the plan
|
|
260
|
+
* appended rather than one the caller declared. */
|
|
261
|
+
export interface EffectiveOrderTerm {
|
|
262
|
+
readonly source: 'column' | 'document' | 'group' | 'identity';
|
|
263
|
+
readonly binding: string | null;
|
|
264
|
+
readonly column: string | null;
|
|
265
|
+
readonly path: readonly (string | number)[] | null;
|
|
266
|
+
readonly desc: boolean;
|
|
267
|
+
readonly nullsFirst: boolean | null;
|
|
268
|
+
readonly tieBreaker: boolean;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* The continuation a page emits (MODEL-FORMAT §10.5): unsigned,
|
|
273
|
+
* structural, opaque — the ordering's identity, so it cannot be
|
|
274
|
+
* replayed against another ordering (`JD0035`); the last row's declared
|
|
275
|
+
* order-key values as the document carries them; and the row's primary
|
|
276
|
+
* key, the tie-breaker the plan appends. Signing, tenant scoping, expiry
|
|
277
|
+
* and wire encoding are the HOST's: the store has no principal and no
|
|
278
|
+
* key, and a continuation handed to an untrusted client unsigned is the
|
|
279
|
+
* host's mistake, not a store guarantee.
|
|
280
|
+
*/
|
|
281
|
+
export interface LoadContinuation {
|
|
282
|
+
readonly order: readonly OrderIdentity[];
|
|
283
|
+
readonly keys: readonly unknown[];
|
|
284
|
+
readonly key: EntityKeyArg;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** A page's options: `limit` roots at most (default `PAGE_LIMIT_DEFAULT`),
|
|
288
|
+
* `maxBytes` serialised bytes at most (`Infinity`/absent for no byte
|
|
289
|
+
* bound), the continuation to resume from, and `consistency` —
|
|
290
|
+
* `'snapshot'` is refused (`JD0036`) over an ordering whose keys a
|
|
291
|
+
* write may change; `'live'` (the default) reports the truth in
|
|
292
|
+
* `snapshot`. */
|
|
293
|
+
export interface PageOptions<C = LoadContinuation> extends EntityCursorOptions {
|
|
294
|
+
limit?: number;
|
|
295
|
+
after?: C;
|
|
296
|
+
maxBytes?: number | null;
|
|
297
|
+
consistency?: 'live' | 'snapshot';
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** One page: never more than `limit` items or `maxBytes` bytes; the
|
|
301
|
+
* continuation of the last delivered item (or the one resumed from, when
|
|
302
|
+
* nothing fit); `hasMore` by one peek past the page; `snapshot` true
|
|
303
|
+
* only over an immutable ordering — otherwise LIVE pagination, where a
|
|
304
|
+
* row whose order key changes can move across the cursor. */
|
|
305
|
+
export interface Page<T, C = LoadContinuation> {
|
|
306
|
+
readonly items: T[];
|
|
307
|
+
readonly continuation: C | null;
|
|
308
|
+
readonly hasMore: boolean;
|
|
309
|
+
readonly snapshot: boolean;
|
|
310
|
+
}
|
|
311
|
+
|
|
104
312
|
export interface LoadExplanation {
|
|
105
313
|
sql: string;
|
|
106
314
|
pagination: 'keyset' | 'offset' | 'none';
|
|
107
315
|
includes: ReadonlyArray<{ path: string; kind: string; count: boolean }>;
|
|
316
|
+
/** The per-root bounds every row-projecting include runs under;
|
|
317
|
+
* `null` is the unbounded case a caller spelled. */
|
|
318
|
+
bounds: ReadonlyArray<{ path: string; maxRows: number | null; maxBytes: number | null }>;
|
|
319
|
+
/** The effective deterministic order the statement executes under, in
|
|
320
|
+
* every load mode: the declared terms, then the tie-breaker the clause
|
|
321
|
+
* appends — the primary key in keyset mode, the row identity
|
|
322
|
+
* otherwise. */
|
|
323
|
+
order: readonly EffectiveOrderTerm[];
|
|
324
|
+
/** The keyset ordering's IDENTITY: the value a continuation carries and
|
|
325
|
+
* is checked against (`JD0035`); `null` for a load outside keyset
|
|
326
|
+
* mode, which has no continuation to emit. Whether a page over it is a
|
|
327
|
+
* snapshot is `snapshot`. */
|
|
328
|
+
identity: readonly OrderIdentity[] | null;
|
|
329
|
+
snapshot: boolean | null;
|
|
330
|
+
/** A graph load pulls one root row per statement row, always. */
|
|
331
|
+
streaming: 'row';
|
|
332
|
+
barrier: null;
|
|
108
333
|
}
|
|
109
334
|
|
|
110
335
|
/** What `saveChanges()` returns: data, not a boolean (§11.6). */
|
|
@@ -128,17 +353,165 @@ export interface StoreStats {
|
|
|
128
353
|
tracked: number;
|
|
129
354
|
pendingInserts: number;
|
|
130
355
|
pendingDeletes: number;
|
|
356
|
+
/** Pending `link`/`unlink` records: one per entity, own key and member (§11.7). */
|
|
357
|
+
pendingMemberships: number;
|
|
131
358
|
} | null;
|
|
132
359
|
liveQueries: number;
|
|
133
360
|
}
|
|
134
361
|
|
|
362
|
+
/**
|
|
363
|
+
* The connection pragmas in effect, read back from the connection after
|
|
364
|
+
* the open sequence applied them — never the requested values. `null`
|
|
365
|
+
* where the driver's binding declares the pragma absent or the engine
|
|
366
|
+
* answers nothing (a `:memory:` database's `mmapSize`).
|
|
367
|
+
*/
|
|
368
|
+
export interface StorePragmas {
|
|
369
|
+
readonly busyTimeout: number | null;
|
|
370
|
+
readonly journalMode: 'delete' | 'truncate' | 'persist' | 'memory' | 'wal' | 'off' | null;
|
|
371
|
+
readonly synchronous: 'off' | 'normal' | 'full' | 'extra' | null;
|
|
372
|
+
readonly walAutocheckpoint: number | null;
|
|
373
|
+
readonly journalSizeLimit: number | null;
|
|
374
|
+
readonly cacheSize: number | null;
|
|
375
|
+
readonly mmapSize: number | null;
|
|
376
|
+
readonly tempStore: 'default' | 'file' | 'memory' | null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export interface MaintenanceCapabilities {
|
|
380
|
+
readonly checkpoint: boolean;
|
|
381
|
+
readonly integrityCheck: boolean;
|
|
382
|
+
readonly foreignKeyCheck: boolean;
|
|
383
|
+
readonly optimize: boolean;
|
|
384
|
+
/** The online backup (`backupTo`): the Node binding's; `false`
|
|
385
|
+
* elsewhere, where the call is refused `JD2077`. */
|
|
386
|
+
readonly backup: boolean;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** The platform's progress report, verbatim: the last event may still
|
|
390
|
+
* carry a remainder — completion is the resolved call. */
|
|
391
|
+
export interface BackupProgress {
|
|
392
|
+
readonly totalPages: number;
|
|
393
|
+
readonly remainingPages: number;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export interface BackupOptions {
|
|
397
|
+
/** Pages copied per step (the platform's `rate`); progress and the
|
|
398
|
+
* cancellation check happen between steps. */
|
|
399
|
+
rate?: number;
|
|
400
|
+
onProgress?: (progress: BackupProgress) => void;
|
|
401
|
+
/** Cancels between pages: `JD2079`, the temporary file removed, the
|
|
402
|
+
* target untouched. */
|
|
403
|
+
signal?: AbortSignal;
|
|
404
|
+
/** An epoch-millisecond deadline on the store's clock, honoured before
|
|
405
|
+
* the copy and between its pages (`JD2075`, same cleanup). */
|
|
406
|
+
deadline?: number;
|
|
407
|
+
/** The checkpoint that fixes the snapshot boundary (default
|
|
408
|
+
* `'passive'`; `false` skips it; a read-only store skips it by
|
|
409
|
+
* default and refuses an explicit one `JD2077`). */
|
|
410
|
+
checkpoint?: 'passive' | 'full' | 'restart' | 'truncate' | false;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export interface BackupResult {
|
|
414
|
+
readonly path: string;
|
|
415
|
+
/** The page total the platform answered. */
|
|
416
|
+
readonly pages: number;
|
|
417
|
+
readonly checkpoint: CheckpointResult | null;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Cancellation of a maintenance operation: checked once, before the
|
|
421
|
+
* one statement it issues (`JD2081` / `JD2075`, on the store's clock). */
|
|
422
|
+
export interface MaintenanceCallOptions {
|
|
423
|
+
signal?: AbortSignal;
|
|
424
|
+
/** An epoch-millisecond deadline on the runtime record's clock. */
|
|
425
|
+
deadline?: number;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export interface CheckpointOptions extends MaintenanceCallOptions {
|
|
429
|
+
/** `PRAGMA wal_checkpoint` mode (default `'passive'`). */
|
|
430
|
+
mode?: 'passive' | 'full' | 'restart' | 'truncate';
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** The engine's own checkpoint row: `-1` frames on a database that is
|
|
434
|
+
* not in WAL mode. A second passive checkpoint reports the same counts
|
|
435
|
+
* as the first; a second `truncate` reports zeros. */
|
|
436
|
+
export interface CheckpointResult {
|
|
437
|
+
readonly busy: boolean;
|
|
438
|
+
readonly logFrames: number;
|
|
439
|
+
readonly checkpointedFrames: number;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export interface IntegrityCheckOptions extends MaintenanceCallOptions {
|
|
443
|
+
/** At most this many problem rows (`PRAGMA integrity_check(N)`). */
|
|
444
|
+
limit?: number;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** `ok` for the engine's single `ok` row; otherwise its problem rows
|
|
448
|
+
* verbatim. Corruption is the result, never a throw. */
|
|
449
|
+
export interface IntegrityCheckResult {
|
|
450
|
+
readonly ok: boolean;
|
|
451
|
+
readonly problems: readonly string[];
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export interface ForeignKeyViolation {
|
|
455
|
+
readonly table: string;
|
|
456
|
+
readonly rowId: number | null;
|
|
457
|
+
readonly parent: string;
|
|
458
|
+
readonly fkid: number;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export interface ForeignKeyCheckResult {
|
|
462
|
+
readonly ok: boolean;
|
|
463
|
+
readonly violations: readonly ForeignKeyViolation[];
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** `PRAGMA optimize` reports nothing; the honest result is that it ran. */
|
|
467
|
+
export interface OptimizeResult {
|
|
468
|
+
readonly ran: true;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** The granularity at which each lifecycle honours `signal`/`deadline`:
|
|
472
|
+
* the boundaries the driver actually has. `midStatement` is a filled
|
|
473
|
+
* slot — `false` on every shipped SQLite binding, which exposes no
|
|
474
|
+
* interrupt. */
|
|
475
|
+
export interface CancellationCapabilities {
|
|
476
|
+
readonly query: 'row';
|
|
477
|
+
readonly queue: true;
|
|
478
|
+
readonly migration: 'step';
|
|
479
|
+
readonly maintenance: 'statement';
|
|
480
|
+
readonly backup: 'page';
|
|
481
|
+
readonly midStatement: boolean;
|
|
482
|
+
}
|
|
483
|
+
|
|
135
484
|
export interface StoreCapabilities {
|
|
136
485
|
readonly version: string;
|
|
137
486
|
readonly readOnly: boolean;
|
|
138
487
|
readonly validated: boolean;
|
|
139
488
|
readonly profiled: boolean;
|
|
489
|
+
/** The read-back connection configuration (MODEL-FORMAT §4). */
|
|
490
|
+
readonly pragmas: StorePragmas;
|
|
491
|
+
/** `pragmas.busyTimeout` under its long-published name. */
|
|
140
492
|
readonly busyTimeoutMs: number | null;
|
|
493
|
+
/** `pragmas.journalMode` under its long-published name. */
|
|
141
494
|
readonly journalMode: string | null;
|
|
495
|
+
/** The configuration pragmas the driver's binding declares it can
|
|
496
|
+
* apply, by option name; a request outside them is `JD0007`. */
|
|
497
|
+
readonly configurablePragmas: readonly string[];
|
|
498
|
+
/** Per-operation availability of the maintenance surface: `false`
|
|
499
|
+
* where the driver's binding does not declare an operation and, for
|
|
500
|
+
* the two that write, on a read-only store; a call is refused
|
|
501
|
+
* `JD2077` exactly where this says `false`. */
|
|
502
|
+
readonly maintenance: MaintenanceCapabilities;
|
|
503
|
+
/** Where a cancellation takes effect, per lifecycle (MODEL-FORMAT §4). */
|
|
504
|
+
readonly cancellation: CancellationCapabilities;
|
|
505
|
+
/** Whether the binding's statements carry a lazy row iterator; when
|
|
506
|
+
* `false` every cursor reports `streaming: 'buffered'` with a
|
|
507
|
+
* `{ construct: 'driver' }` barrier. Probed at open. */
|
|
508
|
+
readonly lazyIteration: boolean;
|
|
509
|
+
readonly sessions: boolean;
|
|
510
|
+
readonly sessionReason: string | null;
|
|
511
|
+
readonly worker: boolean;
|
|
512
|
+
readonly pooling: boolean;
|
|
513
|
+
readonly poolReaders: number;
|
|
514
|
+
readonly poolWriters: number;
|
|
142
515
|
readonly capture: 'session' | 'journal' | 'none';
|
|
143
516
|
readonly captureLog: boolean;
|
|
144
517
|
readonly live: boolean;
|
|
@@ -167,7 +540,7 @@ export interface Collection<T = unknown> {
|
|
|
167
540
|
* a synchronous driver stays synchronous. */
|
|
168
541
|
execute<R = unknown>(document: unknown, options?: ExecuteOptions): ValueOrPromise<SequenceResult<R>>;
|
|
169
542
|
/** The same document as an item cursor — one item per pull. */
|
|
170
|
-
query<R = unknown>(document: unknown, options?:
|
|
543
|
+
query<R = unknown>(document: unknown, options?: CursorOptions): QueryCursor<R>;
|
|
171
544
|
explain(document: unknown, options?: ExecuteOptions): Promise<unknown>;
|
|
172
545
|
/** Register a live query (LIVE-FORMAT §7); requires capture. */
|
|
173
546
|
live(document: unknown, options?: LiveOptions): Promise<LiveQuery>;
|
|
@@ -186,17 +559,56 @@ export interface SyncCollection<T = unknown> {
|
|
|
186
559
|
|
|
187
560
|
// ————— entities (phase B) —————
|
|
188
561
|
|
|
562
|
+
/** One row of an entity's relation table (MODEL-FORMAT §10.1): the
|
|
563
|
+
* declared relation as plain data a query producer can lower a hop
|
|
564
|
+
* from — never a document dialect. For a foreign-key relation `via`
|
|
565
|
+
* names the key property, `fkEntity` the entity holding it, `fkTargets`
|
|
566
|
+
* the entity it references and `targetKey` the key property it
|
|
567
|
+
* references there (the column a hop's equality compares `via` with);
|
|
568
|
+
* `kind` says which side holds the key (`oneToOne`: the declaring
|
|
569
|
+
* entity; `oneToMany`: the target). A many-to-many carries its
|
|
570
|
+
* `joinTable` and the target's `targetKey`. */
|
|
571
|
+
export interface RelationEntry {
|
|
572
|
+
readonly to: string;
|
|
573
|
+
readonly kind: 'oneToOne' | 'oneToMany' | 'manyToMany';
|
|
574
|
+
readonly via?: string;
|
|
575
|
+
readonly fkEntity?: string;
|
|
576
|
+
readonly fkTargets?: string;
|
|
577
|
+
readonly joinTable?: string;
|
|
578
|
+
readonly targetKey: string;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** An entity's relation table: one entry per declared relation member. */
|
|
582
|
+
export type RelationTable = Readonly<Record<string, RelationEntry>>;
|
|
583
|
+
|
|
584
|
+
/** The identity every entity set of one store shares — two sets with one
|
|
585
|
+
* `scope` may be joined in one document — carrying the relation tables
|
|
586
|
+
* of every root, keyed by entity name, so a hop can chain into another
|
|
587
|
+
* root of the same scope. */
|
|
588
|
+
export interface EntityScope {
|
|
589
|
+
readonly relations: Readonly<Record<string, RelationTable>>;
|
|
590
|
+
}
|
|
591
|
+
|
|
189
592
|
export interface UntrackedReads<T = unknown> {
|
|
190
593
|
get(key: EntityKeyArg): Promise<T | undefined>;
|
|
191
594
|
load(spec?: LoadSpec): Promise<T[]>;
|
|
192
595
|
}
|
|
193
596
|
|
|
194
597
|
export interface EntitySet<T = unknown, I = unknown> {
|
|
598
|
+
/** The provider phantom: a chain over this set infers its item type. */
|
|
599
|
+
readonly __item?: T;
|
|
195
600
|
create(doc: I): Promise<Readonly<T>>;
|
|
196
601
|
get(key: EntityKeyArg): Promise<Readonly<T> | undefined>;
|
|
197
602
|
update(key: EntityKeyArg, changes: Partial<T>): Promise<Readonly<T>>;
|
|
198
603
|
delete(key: EntityKeyArg): Promise<boolean>;
|
|
199
604
|
load(spec?: LoadSpec): Promise<ReadonlyArray<Readonly<T>>>;
|
|
605
|
+
/** The graph cursor: one root graph per pull, its includes attached
|
|
606
|
+
* and bounded (§10.4), from the same one statement `load` runs;
|
|
607
|
+
* `return()` releases it. Untracked unless `tracking: true`. */
|
|
608
|
+
loadCursor(spec?: LoadSpec, options?: EntityCursorOptions): QueryCursor<Readonly<T>>;
|
|
609
|
+
/** One bounded page over the composite keyset (§10.5). A `take` or
|
|
610
|
+
* `skip` in the spec is refused: the page windows by its limit. */
|
|
611
|
+
page(spec?: LoadSpec, options?: PageOptions): Promise<Page<Readonly<T>>>;
|
|
200
612
|
explainLoad(spec?: LoadSpec): LoadExplanation;
|
|
201
613
|
/** Track a pending insert (local, synchronous — no round trip). */
|
|
202
614
|
add(doc: I): Readonly<T>;
|
|
@@ -206,7 +618,33 @@ export interface EntitySet<T = unknown, I = unknown> {
|
|
|
206
618
|
remove(key: EntityKeyArg | T): void;
|
|
207
619
|
/** Drop tracking without scheduling anything — conflict recovery. */
|
|
208
620
|
discard(key: EntityKeyArg | T): void;
|
|
621
|
+
/** Attach / detach one many-to-many membership through the unit of
|
|
622
|
+
* work (§11.7): local bookkeeping, written by `saveChanges()` as join
|
|
623
|
+
* rows against the join table as it stands then — idempotent. `own`
|
|
624
|
+
* and `target` are each a key or a document carrying the key. */
|
|
625
|
+
link(own: EntityKeyArg | T, member: string, target: EntityKeyArg | object): void;
|
|
626
|
+
unlink(own: EntityKeyArg | T, member: string, target: EntityKeyArg | object): void;
|
|
209
627
|
asNoTracking(): UntrackedReads<T>;
|
|
628
|
+
/** The provider contract over this entity's root (MODEL-FORMAT §10.1):
|
|
629
|
+
* the document is over the multi-entity root and arrives whole; the
|
|
630
|
+
* answer is the engine's result shape, value-or-promise (D2). */
|
|
631
|
+
execute<R = unknown>(document: unknown, options?: ExecuteOptions): ValueOrPromise<SequenceResult<R>>;
|
|
632
|
+
/** The same document as an item cursor: one row per pull from an open
|
|
633
|
+
* statement, released on `return()`; a set residual materialises the
|
|
634
|
+
* fetched root first and says so (`streaming: 'buffered'`). A chain's
|
|
635
|
+
* `for await` over this set is this cursor. Untracked unless
|
|
636
|
+
* `tracking: true`. */
|
|
637
|
+
cursor<R = T>(document: unknown, options?: EntityCursorOptions): QueryCursor<R>;
|
|
638
|
+
explain(document: unknown, options?: ExecuteOptions): Promise<unknown>;
|
|
639
|
+
/** The root expression this set's rows are bound through (`$.<Name>[*]`). */
|
|
640
|
+
readonly root: string;
|
|
641
|
+
/** The identity every entity set of one store shares: two sets with one
|
|
642
|
+
* `scope` may be joined in one document; it carries every root's
|
|
643
|
+
* relation table. */
|
|
644
|
+
readonly scope: EntityScope;
|
|
645
|
+
/** This entity's relation table (MODEL-FORMAT §10.1) — what a query
|
|
646
|
+
* producer lowers a relation hop from. */
|
|
647
|
+
readonly relations: RelationTable;
|
|
210
648
|
}
|
|
211
649
|
|
|
212
650
|
export interface SyncUntrackedReads<T = unknown> {
|
|
@@ -215,17 +653,39 @@ export interface SyncUntrackedReads<T = unknown> {
|
|
|
215
653
|
}
|
|
216
654
|
|
|
217
655
|
export interface SyncEntitySet<T = unknown, I = unknown> {
|
|
656
|
+
/** The provider phantom: a chain over this set infers its item type. */
|
|
657
|
+
readonly __item?: T;
|
|
218
658
|
create(doc: I): Readonly<T>;
|
|
219
659
|
get(key: EntityKeyArg): Readonly<T> | undefined;
|
|
220
660
|
update(key: EntityKeyArg, changes: Partial<T>): Readonly<T>;
|
|
221
661
|
delete(key: EntityKeyArg): boolean;
|
|
222
662
|
load(spec?: LoadSpec): ReadonlyArray<Readonly<T>>;
|
|
663
|
+
loadCursor(spec?: LoadSpec, options?: EntityCursorOptions): SyncQueryCursor<Readonly<T>>;
|
|
664
|
+
page(spec?: LoadSpec, options?: PageOptions): Page<Readonly<T>>;
|
|
665
|
+
cursor<R = T>(document: unknown, options?: EntityCursorOptions): SyncQueryCursor<R>;
|
|
223
666
|
explainLoad(spec?: LoadSpec): LoadExplanation;
|
|
224
667
|
add(doc: I): Readonly<T>;
|
|
225
668
|
put(next: T): Readonly<T>;
|
|
226
669
|
remove(key: EntityKeyArg | T): void;
|
|
227
670
|
discard(key: EntityKeyArg | T): void;
|
|
671
|
+
link(own: EntityKeyArg | T, member: string, target: EntityKeyArg | object): void;
|
|
672
|
+
unlink(own: EntityKeyArg | T, member: string, target: EntityKeyArg | object): void;
|
|
228
673
|
asNoTracking(): SyncUntrackedReads<T>;
|
|
674
|
+
/** The provider contract over this entity's root, answering values. */
|
|
675
|
+
execute<R = unknown>(document: unknown, options?: ExecuteOptions): SequenceResult<R>;
|
|
676
|
+
explain(document: unknown, options?: ExecuteOptions): unknown;
|
|
677
|
+
readonly root: string;
|
|
678
|
+
readonly scope: EntityScope;
|
|
679
|
+
readonly relations: RelationTable;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/** A lazy synchronous cursor; return, disposal, errors and close release its source. */
|
|
683
|
+
export interface SyncQueryCursor<T = unknown> extends IterableIterator<T> {
|
|
684
|
+
readonly streaming: 'row' | 'buffered';
|
|
685
|
+
readonly barrier: CursorBarrier | null;
|
|
686
|
+
return(): IteratorResult<T, undefined>;
|
|
687
|
+
[Symbol.iterator](): SyncQueryCursor<T>;
|
|
688
|
+
[Symbol.dispose](): void;
|
|
229
689
|
}
|
|
230
690
|
|
|
231
691
|
// ————— the store —————
|
|
@@ -235,8 +695,16 @@ export interface SyncStore {
|
|
|
235
695
|
* the consumer's words; the handle's writes take it and reads answer it. */
|
|
236
696
|
collection<T = unknown>(name: string): SyncCollection<T>;
|
|
237
697
|
entity(name: string): SyncEntitySet;
|
|
238
|
-
transaction<R>(fn: (store:
|
|
698
|
+
transaction<R>(fn: (store: TransactionStore) => R): R;
|
|
239
699
|
execute?<R = unknown>(document: unknown, options?: ExecuteOptions): SequenceResult<R>;
|
|
700
|
+
explain?(document: unknown, options?: ExecuteOptions): unknown;
|
|
701
|
+
/** The entity roots this store-level provider serves (present with
|
|
702
|
+
* entities): it has no single root of its own, so a chain over it is
|
|
703
|
+
* refused by name — chain over `entity(name)` instead. */
|
|
704
|
+
readonly roots?: readonly string[];
|
|
705
|
+
/** The relation tables of every entity, keyed by entity name (present
|
|
706
|
+
* with entities; MODEL-FORMAT §10.1). */
|
|
707
|
+
readonly relations?: Readonly<Record<string, RelationTable>>;
|
|
240
708
|
saveChanges?(): SaveReport;
|
|
241
709
|
}
|
|
242
710
|
|
|
@@ -253,15 +721,65 @@ export interface Store {
|
|
|
253
721
|
* in the engine's result shape. */
|
|
254
722
|
execute?<R = unknown>(document: unknown, options?: ExecuteOptions): ValueOrPromise<SequenceResult<R>>;
|
|
255
723
|
explain?(document: unknown, options?: ExecuteOptions): Promise<unknown>;
|
|
724
|
+
/** The entity roots this store-level provider serves (present with
|
|
725
|
+
* entities): it has no single root of its own, so a chain over it is
|
|
726
|
+
* refused by name — chain over `entity(name)` instead. */
|
|
727
|
+
readonly roots?: readonly string[];
|
|
728
|
+
/** The relation tables of every entity, keyed by entity name (present
|
|
729
|
+
* with entities; MODEL-FORMAT §10.1). */
|
|
730
|
+
readonly relations?: Readonly<Record<string, RelationTable>>;
|
|
256
731
|
/** The unit of work (§11); present only with entities. */
|
|
257
732
|
saveChanges?(): Promise<SaveReport>;
|
|
258
|
-
|
|
733
|
+
/**
|
|
734
|
+
* A top-level transaction. The callback receives a
|
|
735
|
+
* {@link TransactionStore} whose handles are INSIDE it; this store's
|
|
736
|
+
* own handles are an unrelated caller and wait for the commit.
|
|
737
|
+
*
|
|
738
|
+
* `signal` abandons the call while it is still QUEUED — the callback
|
|
739
|
+
* then never runs and no statement is issued (`JD2064`). A transaction
|
|
740
|
+
* that has already taken the connection runs to its own end.
|
|
741
|
+
*
|
|
742
|
+
* `unitOfWork: 'own'` gives the callback a tracker of its own, so two
|
|
743
|
+
* concurrent handlers hold two records for one entity key and neither
|
|
744
|
+
* sees the other's pending state; `'shared'` (the default) writes
|
|
745
|
+
* through the store's, which is what lets a caller `add()` a document
|
|
746
|
+
* outside the transaction and save it inside. Both behave identically
|
|
747
|
+
* with and without capture.
|
|
748
|
+
*/
|
|
749
|
+
transaction<R>(fn: (store: TransactionStore) => R | Promise<R>,
|
|
750
|
+
options?: TransactionScopeOptions): Promise<Awaited<R>>;
|
|
259
751
|
/** Register a change observer; requires capture. Returns unsubscribe. */
|
|
260
752
|
observe(fn: (record: ChangeRecord) => void): () => void;
|
|
261
|
-
/** Read the persisted log forward (JD2051 without
|
|
753
|
+
/** Read the persisted log forward from `after` (`JD2051` without
|
|
754
|
+
* `capture.log`) — EVERY surviving record in one array, UNBOUNDED, with
|
|
755
|
+
* no watermark: a reconnecting consumer whose cursor fell below the
|
|
756
|
+
* retention floor receives the surviving suffix and cannot tell it
|
|
757
|
+
* from the whole. Unsafe for a reconnecting consumer; `changes.page()`
|
|
758
|
+
* is the supported path (LIVE-FORMAT §5). */
|
|
262
759
|
changesSince?(after: number): Promise<ChangeRecord[]>;
|
|
760
|
+
/** The bounded change reader: the log's watermarks and pages that
|
|
761
|
+
* never exceed their bounds and report a retention gap explicitly;
|
|
762
|
+
* present exactly when the log is enabled. */
|
|
763
|
+
readonly changes?: ChangesReader;
|
|
263
764
|
/** PRAGMA data_version — the coarse cross-connection signal. */
|
|
264
765
|
dataVersion(): Promise<number>;
|
|
766
|
+
/** `PRAGMA wal_checkpoint(<mode>)` under the store gate (MODEL-FORMAT
|
|
767
|
+
* §4). Refused `JD2077` on a read-only store or a binding that does
|
|
768
|
+
* not declare it; a driver failure is `JD2078`. */
|
|
769
|
+
checkpoint(options?: CheckpointOptions): Promise<CheckpointResult>;
|
|
770
|
+
/** `PRAGMA integrity_check` under the store gate; corruption is the
|
|
771
|
+
* RESULT (`ok: false`), never a throw. */
|
|
772
|
+
integrityCheck(options?: IntegrityCheckOptions): Promise<IntegrityCheckResult>;
|
|
773
|
+
/** `PRAGMA foreign_key_check` under the store gate. */
|
|
774
|
+
foreignKeyCheck(options?: MaintenanceCallOptions): Promise<ForeignKeyCheckResult>;
|
|
775
|
+
/** `PRAGMA optimize` under the store gate; refused `JD2077` on a
|
|
776
|
+
* read-only store. */
|
|
777
|
+
optimize(options?: MaintenanceCallOptions): Promise<OptimizeResult>;
|
|
778
|
+
/** An online backup published whole or not at all (MODEL-FORMAT §4):
|
|
779
|
+
* copied to a temporary sibling, renamed onto `targetPath` only at
|
|
780
|
+
* verified completion; a cancelled (`JD2079`) or failed (`JD2078`)
|
|
781
|
+
* copy leaves neither file. Writers proceed during the copy. */
|
|
782
|
+
backupTo(targetPath: string, options?: BackupOptions): Promise<BackupResult>;
|
|
265
783
|
/** Register a live query over an entity-root document (re-run
|
|
266
784
|
* strategy in this version); present only with entities. */
|
|
267
785
|
live?(document: unknown, options?: LiveOptions): Promise<LiveQuery>;
|
|
@@ -269,12 +787,148 @@ export interface Store {
|
|
|
269
787
|
* `graceMs` to wind up; the connection closes whether or not they
|
|
270
788
|
* did, and a handler still in flight is reported as JD2062. */
|
|
271
789
|
close(options?: { graceMs?: number }): Promise<void>;
|
|
272
|
-
/** The queue surface; present when opened with `jobs` (JOBS-FORMAT).
|
|
273
|
-
|
|
790
|
+
/** The queue surface; present when opened with `jobs` (JOBS-FORMAT).
|
|
791
|
+
* Root calls here take the store gate — an unrelated enqueue, claim,
|
|
792
|
+
* checkpoint or settlement never joins an open application
|
|
793
|
+
* transaction's fate. The transactional-outbox spelling is the
|
|
794
|
+
* `tx.jobs` a transaction callback receives, which runs as the exact
|
|
795
|
+
* scope and co-commits with the domain transaction. */
|
|
796
|
+
readonly jobs?: JobsApi & JobsAdminApi;
|
|
274
797
|
/** Present exactly when the driver is synchronous — never stubs. */
|
|
275
798
|
readonly sync?: SyncStore;
|
|
276
799
|
}
|
|
277
800
|
|
|
801
|
+
/** The options a top-level transaction takes. An unknown `unitOfWork`
|
|
802
|
+
* value is a compile error here and runtime API misuse there. */
|
|
803
|
+
export interface TransactionScopeOptions {
|
|
804
|
+
/** Abandons the call while it is still QUEUED (`JD2064`); a
|
|
805
|
+
* transaction that has taken the connection runs to its own end. */
|
|
806
|
+
signal?: AbortSignal;
|
|
807
|
+
/** `'own'` gives the callback an independent tracker; `'shared'`
|
|
808
|
+
* (the default) writes through the store's. */
|
|
809
|
+
unitOfWork?: 'own' | 'shared';
|
|
810
|
+
/** `'immediate'` takes the write lock up front (`BEGIN IMMEDIATE`), so
|
|
811
|
+
* a body that reads before it writes never meets the read→write
|
|
812
|
+
* upgrade `SQLITE_BUSY` the busy handler cannot retry — what a claim
|
|
813
|
+
* needs under concurrent writers; `'deferred'` (the default) is the
|
|
814
|
+
* savepoint as always. A nested `tx.transaction()` is a savepoint
|
|
815
|
+
* whichever mode the root chose; the synchronous twin has no mode. */
|
|
816
|
+
mode?: 'deferred' | 'immediate';
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* The named-savepoint group a live transaction view carries
|
|
821
|
+
* (MODEL-FORMAT §5.2): checkpoint-and-continue without a sentinel
|
|
822
|
+
* exception. The label is a map key and diagnostic for that exact
|
|
823
|
+
* transaction — never SQL; the driver generates the identifier. A
|
|
824
|
+
* blank, duplicate or unknown label is `JD2071`; a stale or
|
|
825
|
+
* cross-scope view is `JD2070` first. `rollbackTo` keeps the target
|
|
826
|
+
* active (repeated rollback is defined) and invalidates every later
|
|
827
|
+
* checkpoint; `release` removes the target and every later checkpoint,
|
|
828
|
+
* keeping their rows — the engine's own semantics, exactly.
|
|
829
|
+
*/
|
|
830
|
+
export interface SavepointController {
|
|
831
|
+
create(label: string): Promise<void>;
|
|
832
|
+
rollbackTo(label: string): Promise<void>;
|
|
833
|
+
release(label: string): Promise<void>;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/** The synchronous twin of {@link SavepointController}, answering
|
|
837
|
+
* values (present under `tx.sync` on a synchronous driver). */
|
|
838
|
+
export interface SyncSavepointController {
|
|
839
|
+
create(label: string): void;
|
|
840
|
+
rollbackTo(label: string): void;
|
|
841
|
+
release(label: string): void;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/** The synchronous surface a transaction view carries: the store's,
|
|
845
|
+
* plus the transaction-only savepoint group. */
|
|
846
|
+
export interface TransactionSyncStore extends SyncStore {
|
|
847
|
+
readonly savepoints: SyncSavepointController;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* The store a transaction callback receives: the same surface, with
|
|
852
|
+
* every handle bound to THIS transaction's exact scope.
|
|
853
|
+
*
|
|
854
|
+
* `tx.collection(...)`, `tx.entity(...)`, `tx.sync`, `tx.jobs` and
|
|
855
|
+
* `tx.saveChanges()` run as the transaction's owner, and
|
|
856
|
+
* `tx.transaction(...)` nests through its savepoint. The outer store's
|
|
857
|
+
* handles are, by construction, an unrelated caller: they wait for the
|
|
858
|
+
* commit, and one awaited from inside the callback is a self-wait that
|
|
859
|
+
* `JD0012` names rather than a hang.
|
|
860
|
+
*
|
|
861
|
+
* The view lives exactly as long as its own scope: any stateful member
|
|
862
|
+
* used after the transaction settled, or while an async inner savepoint
|
|
863
|
+
* is current, refuses `JD2070` before touching tracker state or the
|
|
864
|
+
* database. There is deliberately no `close` — a transaction view does
|
|
865
|
+
* not own the store lifetime; the root store remains the only owner of
|
|
866
|
+
* the connection.
|
|
867
|
+
*/
|
|
868
|
+
export interface TransactionStore extends Omit<Store,
|
|
869
|
+
'close' | 'transaction' | 'sync' | 'checkpoint' | 'integrityCheck' | 'foreignKeyCheck' | 'optimize' | 'backupTo'
|
|
870
|
+
| 'jobs'> {
|
|
871
|
+
/** The transactional outbox (JOBS-FORMAT §3): no administration here —
|
|
872
|
+
* an admin operation is a root call. */
|
|
873
|
+
readonly jobs?: JobsApi;
|
|
874
|
+
transaction<R>(fn: (store: TransactionStore) => R | Promise<R>): Promise<Awaited<R>>;
|
|
875
|
+
/** Named partial rollback over the transaction's one savepoint stack
|
|
876
|
+
* (MODEL-FORMAT §5.2). Root stores, clients, workers and checkpoint
|
|
877
|
+
* stores expose none of it. */
|
|
878
|
+
readonly savepoints: SavepointController;
|
|
879
|
+
/** Present exactly when the driver is synchronous, as on the store. */
|
|
880
|
+
readonly sync?: TransactionSyncStore;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/** The log's two watermarks (LIVE-FORMAT §5): the earliest surviving
|
|
884
|
+
* sequence (`null` when nothing survives) and the highest sequence the
|
|
885
|
+
* FILE ever allocated — durable across an emptied log, a reopen and a
|
|
886
|
+
* second store over the same file, never a process counter. */
|
|
887
|
+
export interface ChangeBounds {
|
|
888
|
+
readonly earliestAvailable: number | null;
|
|
889
|
+
readonly highWatermark: number;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/** A change page's options: `after` is the last sequence seen and is
|
|
893
|
+
* required — there is no legitimate "give me everything" for a change
|
|
894
|
+
* log; `limit` records at most (default `PAGE_LIMIT_DEFAULT`),
|
|
895
|
+
* `maxBytes` serialised patch bytes at most (none unless given),
|
|
896
|
+
* `signal` honoured at a record boundary (`JD2072`). */
|
|
897
|
+
export interface ChangePageOptions {
|
|
898
|
+
after: number;
|
|
899
|
+
limit?: number;
|
|
900
|
+
maxBytes?: number | null;
|
|
901
|
+
signal?: AbortSignal;
|
|
902
|
+
/** An epoch-millisecond deadline, read against the store's clock at every record boundary (`JD2075`). */
|
|
903
|
+
deadline?: number;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* One page of the log. `resetRequired: true` means the record after
|
|
908
|
+
* `after` no longer survives: `items` is EMPTY and `next` absent — a
|
|
909
|
+
* total refusal, never a partial suffix — and the consumer re-seeds
|
|
910
|
+
* from a snapshot and resumes at `highWatermark`. Otherwise `next` is
|
|
911
|
+
* the sequence to continue from (`after` itself when nothing was
|
|
912
|
+
* delivered), `hasMore` says whether records remain above it, and the
|
|
913
|
+
* watermarks are the log's as read after the page.
|
|
914
|
+
*/
|
|
915
|
+
export interface ChangePage {
|
|
916
|
+
readonly items: ChangeRecord[];
|
|
917
|
+
readonly next?: number;
|
|
918
|
+
readonly earliestAvailable: number | null;
|
|
919
|
+
readonly highWatermark: number;
|
|
920
|
+
readonly hasMore: boolean;
|
|
921
|
+
readonly resetRequired: boolean;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/** The bounded change reader (LIVE-FORMAT §5). A record larger than
|
|
925
|
+
* `maxBytes` is `JD2074` without advancing `next` — the same rule, the
|
|
926
|
+
* same implementation, as an entity page. */
|
|
927
|
+
export interface ChangesReader {
|
|
928
|
+
bounds(): Promise<ChangeBounds>;
|
|
929
|
+
page(options: ChangePageOptions): Promise<ChangePage>;
|
|
930
|
+
}
|
|
931
|
+
|
|
278
932
|
/** One committed transaction's change record (LIVE-FORMAT §§1–5). */
|
|
279
933
|
export interface ChangeRecord {
|
|
280
934
|
/** Monotonic; continues across reopens when the log is enabled. */
|
|
@@ -393,6 +1047,14 @@ export interface LiveBounds {
|
|
|
393
1047
|
export interface OpenStoreOptions {
|
|
394
1048
|
driver: Driver;
|
|
395
1049
|
path?: string;
|
|
1050
|
+
/**
|
|
1051
|
+
* What a store-level call does while another caller's transaction owns
|
|
1052
|
+
* the connection. `'wait'` (the default) queues behind it under
|
|
1053
|
+
* `queueTimeout` and then refuses `JD0012`; `'strict'` refuses at once,
|
|
1054
|
+
* for a host that would rather see the contention than pay for it.
|
|
1055
|
+
* Either way the call never joins the transaction.
|
|
1056
|
+
*/
|
|
1057
|
+
transactions?: 'wait' | 'strict';
|
|
396
1058
|
/** Change capture (LIVE-FORMAT): off unless requested. */
|
|
397
1059
|
capture?: boolean | CaptureOptions;
|
|
398
1060
|
/** Live-query bounds (LIVE-FORMAT §12). */
|
|
@@ -408,11 +1070,50 @@ export interface OpenStoreOptions {
|
|
|
408
1070
|
* where one was injected; without it the document is refused rather
|
|
409
1071
|
* than answered in UTC. No time-zone database is bundled. */
|
|
410
1072
|
zoneProvider?: unknown;
|
|
1073
|
+
/** The host's runtime record (`@jarenjs/core/runtime`): the clock the
|
|
1074
|
+
* capture log and the job queue stamp, the identifier a `uuid`
|
|
1075
|
+
* identity and a `default: 'uuid'` allocate, the job queue's backoff
|
|
1076
|
+
* jitter and the zone provider — each read only where the explicit
|
|
1077
|
+
* option (`zoneProvider`, `jobs.now`, `jobs.random`) is absent, and
|
|
1078
|
+
* handed on to the job engine. */
|
|
1079
|
+
runtime?: Partial<Runtime>;
|
|
1080
|
+
/** How long work waits for an open transaction to settle before
|
|
1081
|
+
* `JD0012` (MODEL-FORMAT §5.1); reaches every driver. */
|
|
1082
|
+
queueTimeout?: number;
|
|
1083
|
+
/**
|
|
1084
|
+
* The connection pragmas — a closed, validated set (MODEL-FORMAT §4).
|
|
1085
|
+
* An option naming any other pragma is `JD0006`; a pragma the driver
|
|
1086
|
+
* or the store kind cannot apply is `JD0007`; every value is read back
|
|
1087
|
+
* after the open sequence and reported on `capabilities.pragmas`, and
|
|
1088
|
+
* one the engine did not take is `JD0008`.
|
|
1089
|
+
*/
|
|
1090
|
+
/** `PRAGMA busy_timeout`, in milliseconds (default 5000). */
|
|
411
1091
|
busyTimeout?: number;
|
|
412
|
-
|
|
1092
|
+
/** `PRAGMA journal_mode` (default `'wal'` on a writable file; a
|
|
1093
|
+
* read-only store keeps the file's mode and refuses an explicit one). */
|
|
1094
|
+
journalMode?: 'delete' | 'truncate' | 'persist' | 'memory' | 'wal' | 'off';
|
|
1095
|
+
/** `PRAGMA synchronous`. */
|
|
1096
|
+
synchronous?: 'off' | 'normal' | 'full' | 'extra';
|
|
1097
|
+
/** `PRAGMA wal_autocheckpoint`, in pages; `0` disables. */
|
|
1098
|
+
walAutocheckpoint?: number;
|
|
1099
|
+
/** `PRAGMA journal_size_limit`, in bytes; `-1` for none. */
|
|
1100
|
+
journalSizeLimit?: number;
|
|
1101
|
+
/** `PRAGMA cache_size`: pages, or negative KiB. */
|
|
1102
|
+
cacheSize?: number;
|
|
1103
|
+
/** `PRAGMA mmap_size`, in bytes. */
|
|
1104
|
+
mmapSize?: number;
|
|
1105
|
+
/** `PRAGMA temp_store`. */
|
|
1106
|
+
tempStore?: 'default' | 'file' | 'memory';
|
|
413
1107
|
statementCacheBound?: number;
|
|
414
|
-
profile
|
|
1108
|
+
/** The store-level safety profile (MODEL-FORMAT §8). */
|
|
1109
|
+
profile?: 'safe' | ProfileSpec;
|
|
415
1110
|
readOnly?: boolean;
|
|
1111
|
+
/** A `createJsltRegistry()` registry (Ring 2/3): the operators a
|
|
1112
|
+
* query may use, and the pushable subset. */
|
|
1113
|
+
operators?: unknown;
|
|
1114
|
+
/** Raw registry-free operators; never pushed. */
|
|
1115
|
+
functions?: Record<string, unknown>;
|
|
1116
|
+
extensions?: Record<string, unknown>;
|
|
416
1117
|
}
|
|
417
1118
|
|
|
418
1119
|
export declare function openStore(model: unknown, options: OpenStoreOptions): Promise<Store>;
|
|
@@ -433,17 +1134,55 @@ export interface Dialect {
|
|
|
433
1134
|
export interface Driver {
|
|
434
1135
|
readonly name: string;
|
|
435
1136
|
readonly dialect: Dialect;
|
|
436
|
-
|
|
1137
|
+
/** Open a connection (value-or-promise) at `path` (`':memory:'` for
|
|
1138
|
+
* none) with the driver's own options. */
|
|
1139
|
+
open(path: string, options?: unknown): unknown;
|
|
437
1140
|
}
|
|
438
1141
|
|
|
439
1142
|
export declare const sqliteDialect: Dialect;
|
|
440
1143
|
export declare function createDialect(spec: unknown): Dialect;
|
|
1144
|
+
/** The closed set of dialect capabilities, each with the answer a
|
|
1145
|
+
* spelling spec that says nothing gets. `createDialect` refuses a name
|
|
1146
|
+
* outside it, so a misspelling cannot read as a quiet `false`. */
|
|
1147
|
+
export declare const DIALECT_CAPABILITIES: Readonly<Record<string, boolean>>;
|
|
1148
|
+
/** The R*Tree mapping's DDL group for one spelling spec — the virtual
|
|
1149
|
+
* table and the three row triggers that keep it in sync. Composed into
|
|
1150
|
+
* a dialect whose `capabilities.virtualTables` is true. */
|
|
1151
|
+
export declare function rtreeDdl(spec: unknown): Record<string, Function>;
|
|
441
1152
|
export declare const SQLITE_FLOOR: string;
|
|
1153
|
+
/** Assemble the connection contract around a raw binding whose
|
|
1154
|
+
* capabilities a probe has already answered. */
|
|
1155
|
+
export declare function finishConnection(
|
|
1156
|
+
raw: unknown, dialect: Dialect, synchronous: boolean,
|
|
1157
|
+
capabilities: Readonly<Record<string, unknown>>, queueTimeout: number,
|
|
1158
|
+
): unknown;
|
|
1159
|
+
/** The default probe: SQLite's version report, its compile options and
|
|
1160
|
+
* what the binding declares. */
|
|
1161
|
+
export declare function sqliteProbe(
|
|
1162
|
+
raw: unknown, dialect: Dialect, declared: unknown,
|
|
1163
|
+
): unknown;
|
|
1164
|
+
/** The capability answers every connection carries, each defaulted to
|
|
1165
|
+
* the conservative one — what a probe for another engine fills in. */
|
|
1166
|
+
export declare function baseCapabilities(): Record<string, unknown>;
|
|
1167
|
+
/** The option names of the closed configurable-pragma set, in the
|
|
1168
|
+
* order the open sequence applies them (MODEL-FORMAT §4). */
|
|
1169
|
+
export declare const PRAGMA_NAMES: readonly string[];
|
|
1170
|
+
/** The `PRAGMA wal_checkpoint` modes, closed. */
|
|
1171
|
+
export declare const CHECKPOINT_MODES: readonly string[];
|
|
1172
|
+
/** The maintenance operations, in the order `capabilities.maintenance`
|
|
1173
|
+
* lists them. */
|
|
1174
|
+
export declare const MAINTENANCE_OPERATIONS: readonly string[];
|
|
442
1175
|
|
|
443
1176
|
// ————— entities: models, mapping, generated types —————
|
|
444
1177
|
|
|
445
1178
|
export declare function normalizeEntities(model: unknown): Map<string, unknown>;
|
|
446
1179
|
export declare function explainMapping(model: unknown): unknown;
|
|
1180
|
+
/** The relation tables of normalized entities, keyed by entity name
|
|
1181
|
+
* then by relation member (MODEL-FORMAT §10.1) — what every entity set
|
|
1182
|
+
* exposes as `relations` and every scope carries for all its roots. */
|
|
1183
|
+
export declare function relationTables(
|
|
1184
|
+
entities: Map<string, unknown>,
|
|
1185
|
+
): Readonly<Record<string, RelationTable>>;
|
|
447
1186
|
|
|
448
1187
|
/**
|
|
449
1188
|
* Build the EMIT-FORMAT model document for a model's entities.
|
|
@@ -466,6 +1205,8 @@ export declare function translateOperations(
|
|
|
466
1205
|
export declare function keyToken(parts: readonly unknown[]): string;
|
|
467
1206
|
export declare function createCaptureEngine(options: unknown): unknown;
|
|
468
1207
|
export declare const CHANGES_TABLE: string;
|
|
1208
|
+
/** The change log's durable state table: the highest sequence the file ever allocated (LIVE-FORMAT §5). */
|
|
1209
|
+
export declare const CHANGES_STATE_TABLE: string;
|
|
469
1210
|
export declare const DEFAULT_RETENTION: number;
|
|
470
1211
|
/** Deep-freeze a JSON value in place and return it (idempotent). */
|
|
471
1212
|
export declare function deepFreeze<T>(value: T): T;
|
|
@@ -474,6 +1215,58 @@ export declare const BATCH_ROW_BOUND: number;
|
|
|
474
1215
|
|
|
475
1216
|
// ————— migrations —————
|
|
476
1217
|
|
|
1218
|
+
/** Where a migration runs: the driver, the file (`':memory:'` when
|
|
1219
|
+
* absent) and the busy timeout the run opens with. */
|
|
1220
|
+
export interface MigrationTarget {
|
|
1221
|
+
driver: Driver;
|
|
1222
|
+
path?: string;
|
|
1223
|
+
/** `PRAGMA busy_timeout` for the run's connection, ms (default 5000). */
|
|
1224
|
+
busyTimeout?: number;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/** One progress event: the migration and collection a data step is
|
|
1228
|
+
* walking, and the running count of the rows it has transformed,
|
|
1229
|
+
* derived or asserted so far (one of the three counters per event). */
|
|
1230
|
+
export interface MigrationProgress {
|
|
1231
|
+
readonly migration: string;
|
|
1232
|
+
readonly collection: string;
|
|
1233
|
+
readonly transformed?: number;
|
|
1234
|
+
readonly derived?: number;
|
|
1235
|
+
readonly asserted?: number;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/** One row of an introspection's loss report: what the physical shape
|
|
1239
|
+
* does not carry, by a stable code, once, sorted. */
|
|
1240
|
+
export interface IntrospectReportRow {
|
|
1241
|
+
readonly code: string;
|
|
1242
|
+
/** The physical object it is about (`users`, `users.gx_age`). */
|
|
1243
|
+
readonly object: string;
|
|
1244
|
+
readonly detail: string;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/** Every code the loss report uses, with what it means. */
|
|
1248
|
+
export declare const INTROSPECT_CODES: Readonly<Record<string, string>>;
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* Database → model, read-only. Answers the `jaren-model` document this
|
|
1252
|
+
* database's shape says it is, beside a report of everything the shape
|
|
1253
|
+
* cannot carry. `strict` refuses instead of returning a partial model.
|
|
1254
|
+
*/
|
|
1255
|
+
export declare function introspectModel(connection: unknown, options?: {
|
|
1256
|
+
strict?: boolean;
|
|
1257
|
+
/** Narrow the read to a named set of tables. */
|
|
1258
|
+
tables?: readonly string[];
|
|
1259
|
+
/** The document pointer a text key column cannot record, per table. */
|
|
1260
|
+
keys?: Record<string, string>;
|
|
1261
|
+
}): unknown;
|
|
1262
|
+
|
|
1263
|
+
/** The neutral IR one read produces: tables with their columns,
|
|
1264
|
+
* generated expressions, indexes and foreign keys, plus the views a
|
|
1265
|
+
* model cannot declare. */
|
|
1266
|
+
export declare function readSchema(connection: unknown, options?: {
|
|
1267
|
+
tables?: readonly string[];
|
|
1268
|
+
}): unknown;
|
|
1269
|
+
|
|
477
1270
|
export interface MigrateOptions {
|
|
478
1271
|
baseline: unknown;
|
|
479
1272
|
model?: unknown;
|
|
@@ -481,14 +1274,64 @@ export interface MigrateOptions {
|
|
|
481
1274
|
dryRun?: boolean;
|
|
482
1275
|
batchSize?: number;
|
|
483
1276
|
shadow?: boolean;
|
|
1277
|
+
/** Where the shadow replay runs (default `':memory:'`). */
|
|
1278
|
+
shadowPath?: string;
|
|
1279
|
+
/** The host's declared index-expression functions, by name — the same
|
|
1280
|
+
* declarations `openStore` is given, resolved into the planned DDL. */
|
|
1281
|
+
expressions?: Record<string, ExpressionFunction>;
|
|
1282
|
+
/** The driver the shadow replay opens through (default the target's).
|
|
1283
|
+
* A file engine's shadow is another file; a SERVER engine's is another
|
|
1284
|
+
* schema, and only the host can name one — the baseline shape the
|
|
1285
|
+
* replay creates would otherwise collide with the real store's. */
|
|
1286
|
+
shadowDriver?: unknown;
|
|
1287
|
+
/** Called once per batch a data step walks (transform, derive, or a
|
|
1288
|
+
* per-document assertion). */
|
|
1289
|
+
onProgress?: (progress: MigrationProgress) => void;
|
|
484
1290
|
/** Re-register declared deterministic functions on every connection
|
|
485
1291
|
* the migration opens (real, shadow, reference) — §10. */
|
|
486
1292
|
registerFunctions?: (connection: unknown) => unknown;
|
|
1293
|
+
/** The host's runtime record: the clock every applied migration is
|
|
1294
|
+
* stamped with and the deadline is read against; the platform's own
|
|
1295
|
+
* when absent. */
|
|
1296
|
+
runtime?: Partial<Runtime>;
|
|
1297
|
+
/** Cancels between migrations, steps and batches (`JD2080`); the
|
|
1298
|
+
* migration in flight rolls back whole. */
|
|
1299
|
+
signal?: AbortSignal;
|
|
1300
|
+
/** An epoch-millisecond deadline on `runtime`'s clock (`JD2075`). */
|
|
1301
|
+
deadline?: number;
|
|
1302
|
+
/** What a MATERIALIZING assertion may hold. A per-document predicate
|
|
1303
|
+
* and a single associative aggregate over the root are answered in
|
|
1304
|
+
* batches and are never bounded by this; anything else must hold the
|
|
1305
|
+
* collection at once and crosses these bounds before the excess is
|
|
1306
|
+
* held (`JD2007` rows, `JD2076` bytes). Defaults to
|
|
1307
|
+
* {@link ASSERTION_BOUNDS_DEFAULT}; `null` on either member removes
|
|
1308
|
+
* that bound, deliberately. */
|
|
1309
|
+
assertionBounds?: { maxRows?: number | null; maxBytes?: number | null };
|
|
487
1310
|
}
|
|
488
1311
|
|
|
1312
|
+
/** The finite defaults a materializing assertion runs under when the
|
|
1313
|
+
* caller declares none: 100,000 rows and 64 MiB. */
|
|
1314
|
+
export declare const ASSERTION_BOUNDS_DEFAULT: {
|
|
1315
|
+
readonly maxRows: number;
|
|
1316
|
+
readonly maxBytes: number;
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
/** How a host must run an assertion, and why. `perDocument` walks in
|
|
1320
|
+
* batches; `fold` is one associative aggregate whose batch answers
|
|
1321
|
+
* combine; `materialize` needs every document at once and is bounded. */
|
|
1322
|
+
export declare function classifyAssertion(query: unknown): {
|
|
1323
|
+
strategy: 'perDocument' | 'fold' | 'materialize';
|
|
1324
|
+
shape: string | null;
|
|
1325
|
+
reason: string;
|
|
1326
|
+
};
|
|
1327
|
+
|
|
489
1328
|
export declare function migrate(
|
|
490
|
-
target:
|
|
1329
|
+
target: MigrationTarget, migrations: readonly unknown[], options: MigrateOptions,
|
|
491
1330
|
): Promise<unknown>;
|
|
1331
|
+
/** Whether an assertion step is a per-document predicate (a FLWOR over
|
|
1332
|
+
* `$[*]` whose body reads only its binding), which the runner evaluates
|
|
1333
|
+
* per batch; anything else reads the collection whole. */
|
|
1334
|
+
export declare function isPerDocumentAssertion(query: unknown): boolean;
|
|
492
1335
|
export declare function planMigration(from: unknown, to: unknown, options?: unknown): unknown;
|
|
493
1336
|
/** The whole-model diff — collections AND entities (MIGRATION-FORMAT §9). */
|
|
494
1337
|
export declare function planModelMigration(from: unknown, to: unknown, options?: unknown): unknown;
|
|
@@ -499,11 +1342,15 @@ export interface MigrationStatusReport {
|
|
|
499
1342
|
drift: string | null;
|
|
500
1343
|
upToDate: boolean;
|
|
501
1344
|
}
|
|
1345
|
+
/** Report a database's migration state without touching it: the
|
|
1346
|
+
* history table is probed, never created. `model` enables the drift
|
|
1347
|
+
* comparison once the chain is fully applied. */
|
|
502
1348
|
export declare function migrationStatus(
|
|
503
|
-
target:
|
|
1349
|
+
target: MigrationTarget,
|
|
504
1350
|
migrations: readonly unknown[],
|
|
505
|
-
options
|
|
506
|
-
registerFunctions?: (connection: unknown) => unknown
|
|
1351
|
+
options?: { model?: unknown;
|
|
1352
|
+
registerFunctions?: (connection: unknown) => unknown;
|
|
1353
|
+
signal?: AbortSignal; deadline?: number; runtime?: Partial<Runtime> },
|
|
507
1354
|
): Promise<MigrationStatusReport>;
|
|
508
1355
|
/** Create a model's whole physical shape on a connection. */
|
|
509
1356
|
export declare function createModelShape(connection: unknown, model: unknown): unknown;
|
|
@@ -521,18 +1368,125 @@ export declare function migrationChecksum(migration: unknown): string;
|
|
|
521
1368
|
export declare const MIGRATION_VERSION: string;
|
|
522
1369
|
export declare const HISTORY_TABLE: string;
|
|
523
1370
|
|
|
1371
|
+
/** The counters a storeless run reports for one collection. */
|
|
1372
|
+
export interface DocumentMigrationCounts {
|
|
1373
|
+
readonly read: number;
|
|
1374
|
+
readonly transformed: number;
|
|
1375
|
+
readonly asserted: number;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
/** What a storeless run did, per collection: `materialized` held the
|
|
1379
|
+
* documents and ran the steps as a Store does; `streamed` carried each
|
|
1380
|
+
* batch through every step in one pass. */
|
|
1381
|
+
export type DocumentMigrationStrategy = 'materialized' | 'streamed';
|
|
1382
|
+
|
|
1383
|
+
export interface DocumentMigrationReport {
|
|
1384
|
+
/** The migration ids this run applied, in order. */
|
|
1385
|
+
readonly applied: string[];
|
|
1386
|
+
/** Always empty: a storeless run has no history to skip against. */
|
|
1387
|
+
readonly skipped: string[];
|
|
1388
|
+
/** The last migration's target shape hash, or null for no migrations. */
|
|
1389
|
+
readonly shape: string | null;
|
|
1390
|
+
readonly counts: Record<string, DocumentMigrationCounts>;
|
|
1391
|
+
readonly strategy: Record<string, DocumentMigrationStrategy>;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
export interface DocumentMigrationOptions {
|
|
1395
|
+
/** What a MATERIALIZING assertion may hold; the same bounds, and the
|
|
1396
|
+
* same refusals, a Store applies. Defaults to
|
|
1397
|
+
* {@link ASSERTION_BOUNDS_DEFAULT}. */
|
|
1398
|
+
assertionBounds?: { maxRows?: number | null; maxBytes?: number | null };
|
|
1399
|
+
/** Documents per assertion batch and per progress event (default 500). */
|
|
1400
|
+
batchSize?: number;
|
|
1401
|
+
onProgress?: (progress: MigrationProgress) => void;
|
|
1402
|
+
/** The key members of a collection's documents, which a transform may
|
|
1403
|
+
* keep but never move; a Store reads these from its model. */
|
|
1404
|
+
keys?: Record<string, readonly string[]>;
|
|
1405
|
+
/** The JSLT compiler a `jslt` step is compiled with (the suite's own
|
|
1406
|
+
* when absent). */
|
|
1407
|
+
compileJslt?: (stylesheet: unknown) => (document: unknown) => unknown;
|
|
1408
|
+
/** The query compiler a `query` step is compiled with. */
|
|
1409
|
+
compileQuery?: (query: unknown) => unknown;
|
|
1410
|
+
runtime?: Partial<Runtime>;
|
|
1411
|
+
/** Cancels between steps and batches (`JD2080`). */
|
|
1412
|
+
signal?: AbortSignal;
|
|
1413
|
+
/** An epoch-millisecond deadline on `runtime`'s clock (`JD2075`). */
|
|
1414
|
+
deadline?: number;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/** Apply a migration's document steps to documents held in memory. The
|
|
1418
|
+
* source is rewindable, so the steps run exactly as a Store runs them —
|
|
1419
|
+
* every step over the whole collection, in step order — which is what
|
|
1420
|
+
* makes the answer, and the refusal, identical to the Store's. A step
|
|
1421
|
+
* that needs tables (`ddl`, `sql`, `rebuild`, `derive`) is refused
|
|
1422
|
+
* (`JD0023`) before the first document is read. */
|
|
1423
|
+
export declare function migrateDocuments(
|
|
1424
|
+
collections: Record<string, readonly unknown[]>,
|
|
1425
|
+
migrations: readonly unknown[],
|
|
1426
|
+
options?: DocumentMigrationOptions,
|
|
1427
|
+
): Promise<{ documents: Record<string, unknown[]>; report: DocumentMigrationReport }>;
|
|
1428
|
+
|
|
1429
|
+
/** Apply a migration's document steps to a source that can be walked
|
|
1430
|
+
* only once, writing each document out as it finishes: the input is
|
|
1431
|
+
* consumed exactly once and nothing beyond one batch is held. A
|
|
1432
|
+
* cross-document assertion, which needs every document at once, is
|
|
1433
|
+
* refused by name rather than silently buffering the collection. */
|
|
1434
|
+
export declare function streamDocuments(
|
|
1435
|
+
sources: Record<string, Iterable<unknown> | AsyncIterable<unknown>>,
|
|
1436
|
+
migrations: readonly unknown[],
|
|
1437
|
+
options: DocumentMigrationOptions & {
|
|
1438
|
+
write: (collection: string, document: unknown) => unknown;
|
|
1439
|
+
},
|
|
1440
|
+
): Promise<DocumentMigrationReport>;
|
|
1441
|
+
|
|
1442
|
+
/** The step kinds that act on documents, and so run on any host. */
|
|
1443
|
+
export declare const DOCUMENT_STEP_KINDS: ReadonlySet<string>;
|
|
1444
|
+
/** The step kinds that need a physical database and are refused without one. */
|
|
1445
|
+
export declare const PHYSICAL_STEP_KINDS: ReadonlySet<string>;
|
|
1446
|
+
/** Compile one document step into the operation every host runs. */
|
|
1447
|
+
export declare function compileDocumentStep(
|
|
1448
|
+
step: unknown, index: number, context: {
|
|
1449
|
+
migrationId: string;
|
|
1450
|
+
compileJslt: (stylesheet: unknown) => (document: unknown) => unknown;
|
|
1451
|
+
compileQuery: (query: unknown) => unknown;
|
|
1452
|
+
keys?: readonly string[];
|
|
1453
|
+
},
|
|
1454
|
+
): unknown;
|
|
1455
|
+
/** Structural validation of one migration document (`JD0023`/`JD0021`). */
|
|
1456
|
+
export declare function checkMigrationDocument(migration: unknown): void;
|
|
1457
|
+
/** The refusal a failing step raises, spelled the one way every host spells it. */
|
|
1458
|
+
export declare function stepFailure(
|
|
1459
|
+
migrationId: string, index: number, kind: string, reason: string, cause?: Error,
|
|
1460
|
+
): DbCompileError;
|
|
1461
|
+
|
|
524
1462
|
// ————— the machinery exports —————
|
|
525
1463
|
// The planner/emitter/residual/profile internals are public for tools
|
|
526
1464
|
// and tests; their documents have their own formats, so their types
|
|
527
1465
|
// are deliberately WIDE (unknown), never wrong.
|
|
528
1466
|
|
|
529
1467
|
export declare function planCollection(name: string, collection: unknown, dialect: Dialect): unknown;
|
|
530
|
-
export declare function compileIndexPath(
|
|
1468
|
+
export declare function compileIndexPath(expression: string, docPath: string): unknown;
|
|
1469
|
+
export declare function normalizeDeclaredSql(sql: string): string;
|
|
1470
|
+
export declare function comparableDeclaredSql(sql: string): string;
|
|
1471
|
+
/** The comparison kind a declared schema type implies — what a column
|
|
1472
|
+
* over that member holds, and how its expression must read it. */
|
|
1473
|
+
export declare function columnKindFor(
|
|
1474
|
+
schemaType: string | undefined,
|
|
1475
|
+
): 'text' | 'number' | 'boolean' | undefined;
|
|
531
1476
|
export declare function schemaTypeAt(schema: unknown, segments: unknown): unknown;
|
|
532
1477
|
export declare const KEY_COLUMN: string;
|
|
533
1478
|
export declare const DOC_COLUMN: string;
|
|
534
1479
|
export declare function planQuery(document: unknown, shape: unknown, options?: unknown): unknown;
|
|
535
1480
|
export declare function assertDecidedKind(node: unknown): void;
|
|
1481
|
+
/** The planner's reason vocabulary: every cause a plan can name for work
|
|
1482
|
+
* it left in the engine, under a stable identifier. Most entries are the
|
|
1483
|
+
* whole sentence; the four that quote the caller's own values carry the
|
|
1484
|
+
* stable opening they begin with. */
|
|
1485
|
+
export declare const PLANNER_REASONS: Readonly<Record<string,
|
|
1486
|
+
{ readonly text: string } | { readonly prefix: string }>>;
|
|
1487
|
+
/** The vocabulary identifier of one reason sentence, or `null` when no
|
|
1488
|
+
* entry claims it. */
|
|
1489
|
+
export declare function reasonId(reason: string): string | null;
|
|
536
1490
|
export declare function entityShape(entity: unknown, entityMapping: unknown): unknown;
|
|
537
1491
|
export declare function entityPathRef(node: unknown, slot: number, shape: unknown): unknown;
|
|
538
1492
|
export declare function planEntityPredicate(node: unknown, slot: number, shape: unknown): unknown;
|
|
@@ -545,12 +1499,80 @@ export declare function parseGraphRow(node: unknown, row: unknown, docField?: st
|
|
|
545
1499
|
export declare function selectPlan(collection: string): unknown;
|
|
546
1500
|
export declare function conjoin(plan: unknown, predicate: unknown): unknown;
|
|
547
1501
|
export declare function assertNoSqlText(plan: unknown): void;
|
|
1502
|
+
/** Whether an order term reads its value from a mapped column rather
|
|
1503
|
+
* than the document. */
|
|
1504
|
+
export declare function ordersByColumn(ref: unknown): boolean;
|
|
1505
|
+
/** The effective order a set of declared terms executes under: the terms,
|
|
1506
|
+
* then the tie-breaker the emitter appends — the primary key when
|
|
1507
|
+
* `keyColumns` is given (keyset mode), one row identity per binding
|
|
1508
|
+
* otherwise. */
|
|
1509
|
+
export declare function effectiveOrder(
|
|
1510
|
+
terms: unknown, options?: { bindings?: (string | null)[]; keyColumns?: readonly string[] },
|
|
1511
|
+
): EffectiveOrderTerm[];
|
|
1512
|
+
/** The effective order of one plan, in the same normalized form its
|
|
1513
|
+
* emitter renders; `null` for a statement that orders nothing. */
|
|
1514
|
+
export declare function planOrder(plan: unknown): EffectiveOrderTerm[] | null;
|
|
548
1515
|
export declare const PLAN_VERSION: number;
|
|
549
1516
|
export declare function typeOfPath(shape: unknown, segments: unknown): unknown;
|
|
550
1517
|
export declare function isNumericType(type: unknown): boolean;
|
|
551
1518
|
export declare function compileSetResidual(document: unknown, limits?: unknown): unknown;
|
|
552
1519
|
export declare function compileRowResidual(rowReturn: unknown, limits?: unknown): unknown;
|
|
1520
|
+
export declare function compilePackedResidual(document: unknown, limits?: unknown): unknown;
|
|
1521
|
+
/** The one cursor mechanism every engine builds on: a row source pulled
|
|
1522
|
+
* one row per `next()` and released exactly once, or a materialised
|
|
1523
|
+
* source that says so. */
|
|
1524
|
+
export declare function createCursor<T = unknown>(spec: {
|
|
1525
|
+
streaming: 'row' | 'buffered';
|
|
1526
|
+
barrier?: CursorBarrier | null;
|
|
1527
|
+
signal?: AbortSignal;
|
|
1528
|
+
materialize?: () => unknown;
|
|
1529
|
+
open?: () => unknown;
|
|
1530
|
+
items?: (row: unknown) => T[];
|
|
1531
|
+
}): QueryCursor<T>;
|
|
553
1532
|
export declare function sequenceResult(items: unknown[]): unknown;
|
|
1533
|
+
// ————— model-declared index expressions —————
|
|
1534
|
+
|
|
1535
|
+
/** The three node kinds, closed: `member`, `value`, `call`. */
|
|
1536
|
+
export declare const EXPRESSION_KINDS: readonly string[];
|
|
1537
|
+
/** How deep a declared expression may nest. */
|
|
1538
|
+
export declare const EXPRESSION_DEPTH: number;
|
|
1539
|
+
/** One host declaration for a function a model's index expression may
|
|
1540
|
+
* name. An engine that registers functions needs `apply`; one that
|
|
1541
|
+
* cannot needs the `sql` name of an IMMUTABLE function it already has. */
|
|
1542
|
+
export interface ExpressionFunction {
|
|
1543
|
+
arity: number;
|
|
1544
|
+
/** Required, and never inferred: an index over a function that may
|
|
1545
|
+
* answer differently for one row is an index that lies. */
|
|
1546
|
+
deterministic: true;
|
|
1547
|
+
apply?: (...args: any[]) => unknown;
|
|
1548
|
+
sql?: string;
|
|
1549
|
+
}
|
|
1550
|
+
/** Resolve one expression against the host's declarations, refusing an
|
|
1551
|
+
* unknown, wrong-arity or non-deterministic function with `JD0004`. */
|
|
1552
|
+
export declare function normalizeExpression(
|
|
1553
|
+
node: unknown, docPath: string, declarations: Record<string, ExpressionFunction>,
|
|
1554
|
+
depth?: number,
|
|
1555
|
+
): unknown;
|
|
1556
|
+
/** The identity two declarations of one expression share. */
|
|
1557
|
+
export declare function canonicalExpression(node: unknown): string;
|
|
1558
|
+
/** Every member path an expression reads, in order. */
|
|
1559
|
+
export declare function expressionMembers(node: unknown, out?: string[]): string[];
|
|
1560
|
+
/** Every function an expression calls, sorted. */
|
|
1561
|
+
export declare function expressionFunctions(node: unknown, out?: Set<string>): string[];
|
|
1562
|
+
/** The SQL an expression compiles to on one dialect. */
|
|
1563
|
+
export declare function expressionSql(
|
|
1564
|
+
node: unknown, dialect: Dialect, context: unknown,
|
|
1565
|
+
): string;
|
|
1566
|
+
/** A short, stable column stem for one expression. */
|
|
1567
|
+
export declare function expressionStem(node: unknown): string;
|
|
1568
|
+
/** The SQL name a declared function is registered under. */
|
|
1569
|
+
export declare function registeredName(name: string): string;
|
|
1570
|
+
/** Register every function a set of expressions calls, on one connection. */
|
|
1571
|
+
export declare function registerExpressionFunctions(
|
|
1572
|
+
connection: unknown, names: readonly string[],
|
|
1573
|
+
declarations: Record<string, ExpressionFunction>,
|
|
1574
|
+
): unknown;
|
|
1575
|
+
|
|
554
1576
|
export declare function deterministicFragment(fragment: unknown): unknown;
|
|
555
1577
|
export declare function registerFragment(connection: unknown, registered: Set<string>, fragment: unknown): void;
|
|
556
1578
|
export declare function createQueryEngine(context: unknown): unknown;
|
|
@@ -558,6 +1580,9 @@ export declare function createQueryState(bound?: number): unknown;
|
|
|
558
1580
|
export declare function createEntityQueryEngine(context: unknown): unknown;
|
|
559
1581
|
export declare function createLoadEngine(context: unknown, entityName: string): unknown;
|
|
560
1582
|
export declare const INCLUDE_DEPTH_DEFAULT: number;
|
|
1583
|
+
export declare const INCLUDE_ROWS_DEFAULT: number;
|
|
1584
|
+
export declare const INCLUDE_BYTES_DEFAULT: number;
|
|
1585
|
+
export declare const PAGE_LIMIT_DEFAULT: number;
|
|
561
1586
|
export declare function normalizeProfile(profile: unknown): unknown;
|
|
562
1587
|
export declare const SAFE_PROFILE: unknown;
|
|
563
1588
|
export declare function translateProfilePredicate(predicate: unknown, shape: unknown): unknown;
|
|
@@ -575,7 +1600,7 @@ export declare function openConnection(raw: unknown, options: unknown): unknown;
|
|
|
575
1600
|
export declare function wrapStatement(statement: unknown): unknown;
|
|
576
1601
|
export declare function lazyOpen(spec: unknown, reason: string, use: unknown, args?: unknown): unknown;
|
|
577
1602
|
export declare function classifyLiveQuery(
|
|
578
|
-
document: unknown, queryShape: unknown, keyed: boolean): unknown;
|
|
1603
|
+
document: unknown, queryShape: unknown, keyed: boolean, eventTime?: unknown): unknown;
|
|
579
1604
|
export declare function createLiveRegistry(
|
|
580
1605
|
bounds: { maxQueries: number; maxMaintained: number }): unknown;
|
|
581
1606
|
export declare function diffRows(oldRows: readonly unknown[], newRows: readonly unknown[]):
|
|
@@ -586,52 +1611,172 @@ export declare function createSortedWindow(
|
|
|
586
1611
|
export declare function compareCodepoint(a: string, b: string): number;
|
|
587
1612
|
export declare function collectEntityRoots(
|
|
588
1613
|
document: unknown, entities: ReadonlyMap<string, unknown>): Set<string>;
|
|
1614
|
+
/** The root expression an entity's rows are bound through (`$.<Name>[*]`) —
|
|
1615
|
+
* what an entity set exposes as `root` and what `collectEntityRoots` reads. */
|
|
1616
|
+
export declare function entityRoot(name: string): string;
|
|
1617
|
+
|
|
1618
|
+
// ————— the derived-index and k-nearest machinery —————
|
|
1619
|
+
// Constants carry their real shapes; the functions take and answer the
|
|
1620
|
+
// planner's own records, which have no published type — WIDE, never
|
|
1621
|
+
// wrong (the line at the top of this file).
|
|
1622
|
+
|
|
1623
|
+
export declare const DERIVE_KINDS: ReadonlySet<string>;
|
|
1624
|
+
export declare const DERIVE_MAPPING: Readonly<Record<string, string | null>>;
|
|
1625
|
+
export declare const PHYSICAL_KINDS: ReadonlySet<string>;
|
|
1626
|
+
export declare const BBOX_COMPONENTS: readonly ['w', 's', 'e', 'n'];
|
|
1627
|
+
export declare const BBOX_INDEX_ORDER: readonly ['w', 'e', 's', 'n'];
|
|
1628
|
+
export declare const PRECISION_MIN: number;
|
|
1629
|
+
export declare const PRECISION_MAX: number;
|
|
1630
|
+
export declare const DIMS_MIN: number;
|
|
1631
|
+
export declare const DIMS_MAX: number;
|
|
1632
|
+
export declare function derivedMappingFor(kind: string, driverMapping: unknown): unknown;
|
|
1633
|
+
export declare function deriveGeohash(value: unknown, precision: number): unknown;
|
|
1634
|
+
export declare function deriveBboxEdge(value: unknown, component: 'w' | 's' | 'e' | 'n'): unknown;
|
|
1635
|
+
export declare function deriveVector(member: unknown, dims: number): unknown;
|
|
1636
|
+
export declare function storedMemberForm(member: unknown): unknown;
|
|
1637
|
+
export declare function derivedValue(column: unknown, member: unknown): unknown;
|
|
1638
|
+
export declare function memberAt(doc: unknown, segments: unknown): unknown;
|
|
1639
|
+
export declare function registerDeriveFunctions(connection: unknown): unknown;
|
|
1640
|
+
export declare function probeVector(value: unknown, dims: number): unknown;
|
|
1641
|
+
export declare function columnScore(bytes: unknown, dims: number, probe: unknown): unknown;
|
|
1642
|
+
export declare const KNN_MARGIN: number;
|
|
1643
|
+
export declare const IDENTITY_CHUNK: number;
|
|
1644
|
+
export declare function cutCandidates(rows: unknown[], m: number, margin: number): unknown;
|
|
1645
|
+
export declare function identityBatches(identities: unknown[]): unknown;
|
|
589
1646
|
|
|
590
1647
|
// ————— the job queue (JOBS-FORMAT) —————
|
|
591
1648
|
|
|
1649
|
+
/** A job's state: `cancelled` is terminal like `done` and `dead` and
|
|
1650
|
+
* is set only by `cancel()` (JOBS-FORMAT §10). */
|
|
1651
|
+
export type JobState = 'pending' | 'leased' | 'done' | 'failed' | 'dead' | 'cancelled';
|
|
1652
|
+
|
|
592
1653
|
export interface JobRecord {
|
|
593
1654
|
readonly id: string;
|
|
594
1655
|
readonly kind: string;
|
|
595
1656
|
readonly payload: unknown;
|
|
596
|
-
readonly state:
|
|
1657
|
+
readonly state: JobState;
|
|
597
1658
|
readonly runAt: number;
|
|
598
1659
|
readonly attempts: number;
|
|
599
1660
|
readonly maxAttempts: number;
|
|
600
1661
|
readonly leaseUntil: number | null;
|
|
601
1662
|
readonly leaseOwner: string | null;
|
|
1663
|
+
/** How many times this job has been claimed. It identifies the
|
|
1664
|
+
* ATTEMPT, which the owner cannot: one worker reuses one owner. */
|
|
1665
|
+
readonly leaseGeneration: number;
|
|
602
1666
|
readonly lastError: string | null;
|
|
603
1667
|
readonly result: unknown;
|
|
604
1668
|
readonly createdAt: number;
|
|
605
1669
|
readonly updatedAt: number;
|
|
606
1670
|
}
|
|
607
1671
|
|
|
1672
|
+
/**
|
|
1673
|
+
* The capability one claim mints: the right to settle THIS attempt of
|
|
1674
|
+
* this job, for as long as the lease is valid.
|
|
1675
|
+
*
|
|
1676
|
+
* It is a token rather than an owner, because an owner is reused by
|
|
1677
|
+
* every attempt one worker makes and so cannot say which attempt is
|
|
1678
|
+
* speaking. It is immutable: `renew` answers a NEW lease and retires
|
|
1679
|
+
* this one, so a reference kept across a renewal can never quietly
|
|
1680
|
+
* become valid again.
|
|
1681
|
+
*
|
|
1682
|
+
* Only `claim` and `renew` hand one out. `get` does not — a record
|
|
1683
|
+
* anyone can read must not carry the capability to settle it.
|
|
1684
|
+
*/
|
|
1685
|
+
export interface JobLease {
|
|
1686
|
+
readonly jobId: string;
|
|
1687
|
+
readonly token: string;
|
|
1688
|
+
readonly generation: number;
|
|
1689
|
+
readonly attempt: number;
|
|
1690
|
+
/** Diagnostics only: never a guard. */
|
|
1691
|
+
readonly owner: string | null;
|
|
1692
|
+
readonly expiresAt: number;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
/** What `claim` answers: the record, and the lease to settle it with. */
|
|
1696
|
+
export interface ClaimedJob extends JobRecord {
|
|
1697
|
+
readonly lease: JobLease;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
608
1700
|
export interface JobCounts {
|
|
609
1701
|
pending: number;
|
|
610
1702
|
leased: number;
|
|
611
1703
|
done: number;
|
|
612
1704
|
failed: number;
|
|
613
1705
|
dead: number;
|
|
1706
|
+
cancelled: number;
|
|
614
1707
|
/** Pending/failed totals per kind — how a handler-less kind REPORTS. */
|
|
615
1708
|
pendingKinds: Record<string, number>;
|
|
616
1709
|
}
|
|
617
1710
|
|
|
1711
|
+
/** What became of one attempt. A LOST settlement is its own outcome:
|
|
1712
|
+
* counting it as a completion is what let a corpse report success over
|
|
1713
|
+
* work another attempt was still doing, and counting it as a failure
|
|
1714
|
+
* would burn a retry the job never spent. */
|
|
1715
|
+
export interface JobOutcome {
|
|
1716
|
+
/** `cancelled`: the attempt was taken from this worker by `cancel()`
|
|
1717
|
+
* with its lease — neither a completion, a failure nor a loss. */
|
|
1718
|
+
readonly outcome: 'completed' | 'failed' | 'lost' | 'cancelled';
|
|
1719
|
+
/** Where the loss was noticed: settling the result, or settling the
|
|
1720
|
+
* failure that came before it. Absent on the other two outcomes. */
|
|
1721
|
+
readonly phase?: 'completion' | 'failure';
|
|
1722
|
+
readonly jobId: string;
|
|
1723
|
+
readonly kind: string;
|
|
1724
|
+
readonly attempt: number;
|
|
1725
|
+
readonly generation: number;
|
|
1726
|
+
/** The refusal code a lost settlement carries (`JD2065`/`JD2066`/
|
|
1727
|
+
* `JD2067`); `null` when the lease was lost some other way. */
|
|
1728
|
+
readonly code?: string | null;
|
|
1729
|
+
readonly reason?: string;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
618
1732
|
export interface JobWorker {
|
|
619
1733
|
start(): JobWorker;
|
|
620
|
-
/**
|
|
621
|
-
|
|
1734
|
+
/** Stop claiming, signal in-flight handlers, and wait up to `graceMs`
|
|
1735
|
+
* (JOBS-FORMAT §6): the record says whether every loop drained. */
|
|
1736
|
+
stop(options?: { graceMs?: number }): Promise<{ drained: boolean; inFlight: number }>;
|
|
622
1737
|
stats(): { claims: number; completions: number; failures: number;
|
|
623
|
-
polls: number; wakes: number
|
|
1738
|
+
polls: number; wakes: number; claimErrors: number; inFlight: number;
|
|
1739
|
+
/** Leases replaced while a handler was still running. */
|
|
1740
|
+
renewals: number;
|
|
1741
|
+
/** Attempts whose lease was lost mid-flight — never a completion,
|
|
1742
|
+
* never a failure. */
|
|
1743
|
+
lostSettlements: number;
|
|
1744
|
+
/** Attempts cancelled through `cancel()` while their handler ran. */
|
|
1745
|
+
cancellations: number };
|
|
1746
|
+
/** The leases this worker holds right now: one per in-flight attempt,
|
|
1747
|
+
* each the newest that attempt has been given. */
|
|
1748
|
+
leases(): readonly JobLease[];
|
|
624
1749
|
}
|
|
625
1750
|
|
|
626
1751
|
export interface JobWorkerOptions {
|
|
627
|
-
|
|
628
|
-
|
|
1752
|
+
/**
|
|
1753
|
+
* `checkpoints` is bound to THIS attempt and follows its current
|
|
1754
|
+
* lease, so a renewal does not strand it. `signal` aborts for either
|
|
1755
|
+
* reason a handler must wind up for: the worker is stopping, or the
|
|
1756
|
+
* job is no longer this attempt's to finish — in which case the
|
|
1757
|
+
* signal's `reason` is the coded refusal that says which.
|
|
1758
|
+
*/
|
|
1759
|
+
handlers: Record<string, (payload: unknown, context: {
|
|
1760
|
+
job: ClaimedJob;
|
|
1761
|
+
checkpoints: { load(runId: string): unknown;
|
|
1762
|
+
save(runId: string, nodeId: string, value: unknown): unknown;
|
|
1763
|
+
complete(runId: string, result: unknown): unknown };
|
|
1764
|
+
signal: AbortSignal }) => unknown>;
|
|
1765
|
+
/** A positive integer; the loops claiming concurrently. */
|
|
629
1766
|
concurrency?: number;
|
|
630
1767
|
pollInterval?: number;
|
|
631
1768
|
leaseMs?: number;
|
|
632
1769
|
owner?: string;
|
|
1770
|
+
/** Renew each attempt's lease while its handler runs (the default).
|
|
1771
|
+
* `false` for a handler that must not outlive its lease. */
|
|
1772
|
+
renew?: boolean;
|
|
1773
|
+
/** Called once per settled attempt, including the lost ones. An
|
|
1774
|
+
* observer that throws never affects the loop. */
|
|
1775
|
+
onOutcome?: (event: JobOutcome) => void;
|
|
633
1776
|
backoffBase?: number;
|
|
634
1777
|
backoffCap?: number;
|
|
1778
|
+
/** How long `stop()` waits for in-flight handlers by default. */
|
|
1779
|
+
stopGraceMs?: number;
|
|
635
1780
|
}
|
|
636
1781
|
|
|
637
1782
|
export interface JobsApi {
|
|
@@ -639,13 +1784,30 @@ export interface JobsApi {
|
|
|
639
1784
|
options?: { id?: string; runAt?: number; maxAttempts?: number }): Promise<string>;
|
|
640
1785
|
get(id: string): Promise<JobRecord | undefined>;
|
|
641
1786
|
counts(): Promise<JobCounts>;
|
|
642
|
-
/** The low-level guarded claim the worker itself uses (§3).
|
|
1787
|
+
/** The low-level guarded claim the worker itself uses (§3). It mints
|
|
1788
|
+
* the fence: a fresh token and the next generation. */
|
|
643
1789
|
claim(options: { kinds: string[]; owner: string; leaseMs?: number }):
|
|
644
|
-
Promise<
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
1790
|
+
Promise<ClaimedJob | undefined>;
|
|
1791
|
+
/**
|
|
1792
|
+
* Replace a lease with a later one (§3). A handler that runs longer
|
|
1793
|
+
* than its lease renews rather than hoping; the lease it is given
|
|
1794
|
+
* back supersedes the one it passed in, which then settles nothing.
|
|
1795
|
+
*
|
|
1796
|
+
* Refuses `JD2065` (the job is not leased — unknown, or already
|
|
1797
|
+
* settled), `JD2066` (the lease was superseded) or `JD2067` (it
|
|
1798
|
+
* expired), never a silent `false`.
|
|
1799
|
+
*/
|
|
1800
|
+
renew(lease: JobLease, options?: { leaseMs?: number }): Promise<JobLease>;
|
|
1801
|
+
/** Settle the attempt this lease holds. `true`, or one of the three
|
|
1802
|
+
* coded refusals above — a caller that cannot tell "already done"
|
|
1803
|
+
* from "you are stale" guesses, and guesses wrong. */
|
|
1804
|
+
complete(lease: JobLease, result?: unknown): Promise<boolean>;
|
|
1805
|
+
fail(lease: JobLease, error: unknown): Promise<boolean>;
|
|
1806
|
+
/** The per-attempt flow checkpoint store binding (§7). Rows are
|
|
1807
|
+
* stamped with the attempt's generation: `load` reads what was
|
|
1808
|
+
* written up to it, and a settlement prunes no further, so a stale
|
|
1809
|
+
* attempt cannot erase a live one's work. */
|
|
1810
|
+
checkpointsFor(job: ClaimedJob): {
|
|
649
1811
|
load(runId: string): unknown;
|
|
650
1812
|
save(runId: string, nodeId: string, value: unknown): unknown;
|
|
651
1813
|
complete(runId: string, result: unknown): unknown;
|
|
@@ -653,12 +1815,52 @@ export interface JobsApi {
|
|
|
653
1815
|
createWorker(options: JobWorkerOptions): JobWorker;
|
|
654
1816
|
}
|
|
655
1817
|
|
|
1818
|
+
export interface JobPageOptions {
|
|
1819
|
+
/** A closed state; every job when absent. */
|
|
1820
|
+
state?: JobState;
|
|
1821
|
+
kind?: string;
|
|
1822
|
+
/** The id to continue past (keyset by id). */
|
|
1823
|
+
after?: string;
|
|
1824
|
+
/** At most this many items (default 100). */
|
|
1825
|
+
limit?: number;
|
|
1826
|
+
/** Row-boundary cancellation, as every cursor (`JD2072` / `JD2075`). */
|
|
1827
|
+
signal?: AbortSignal;
|
|
1828
|
+
deadline?: number;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
/**
|
|
1832
|
+
* Job administration (JOBS-FORMAT §10) — root-only mechanism, never a
|
|
1833
|
+
* schedule: WHEN to sweep or cancel is the host's call.
|
|
1834
|
+
*/
|
|
1835
|
+
export interface JobsAdminApi {
|
|
1836
|
+
/** A keyset cursor over the queue by id, admitted per pull under the
|
|
1837
|
+
* store gate; each item is the record `get` answers. */
|
|
1838
|
+
page(options?: JobPageOptions): QueryCursor<JobRecord>;
|
|
1839
|
+
/** Cancel a queued job by its identity, or a claimed one through its
|
|
1840
|
+
* CURRENT lease (the fence's rule): the row settles as `cancelled`,
|
|
1841
|
+
* a local attempt's handler signal aborts, and the call resolves once
|
|
1842
|
+
* that attempt wound up. `true` when this call cancelled it, `false`
|
|
1843
|
+
* when it already was; `JD2065`/`JD2066`/`JD2067`/`JD2068` as a
|
|
1844
|
+
* settling call refuses. */
|
|
1845
|
+
cancel(id: string, options?: { lease?: JobLease; signal?: AbortSignal; deadline?: number }): Promise<boolean>;
|
|
1846
|
+
/** Return a failed, dead, cancelled or lease-expired job to the queue
|
|
1847
|
+
* with its attempt history intact; `false` when it already was
|
|
1848
|
+
* pending; a live lease refuses `JD2068`, unknown or done `JD2065`. */
|
|
1849
|
+
requeue(id: string, options?: { signal?: AbortSignal; deadline?: number }): Promise<boolean>;
|
|
1850
|
+
/** Delete settled jobs (done, dead, cancelled) last changed before
|
|
1851
|
+
* `settledBefore`, oldest first, at most `limit`, with their
|
|
1852
|
+
* checkpoints; a second identical sweep answers `{ removed: 0 }`. */
|
|
1853
|
+
sweep(options: { settledBefore: number; limit?: number; signal?: AbortSignal; deadline?: number }):
|
|
1854
|
+
Promise<{ removed: number }>;
|
|
1855
|
+
}
|
|
1856
|
+
|
|
656
1857
|
export interface JobsOptions {
|
|
657
1858
|
maxAttempts?: number;
|
|
658
1859
|
leaseMs?: number;
|
|
659
1860
|
pollInterval?: number;
|
|
660
1861
|
backoffBase?: number;
|
|
661
1862
|
backoffCap?: number;
|
|
1863
|
+
stopGraceMs?: number;
|
|
662
1864
|
/** Injectable clock and randomness — every test injects both. */
|
|
663
1865
|
now?: () => number;
|
|
664
1866
|
random?: () => number;
|
|
@@ -672,15 +1874,27 @@ export declare function createDagJobRunner(store: Store, options: {
|
|
|
672
1874
|
pollInterval?: number;
|
|
673
1875
|
leaseMs?: number;
|
|
674
1876
|
owner?: string;
|
|
1877
|
+
renew?: boolean;
|
|
1878
|
+
onOutcome?: (event: JobOutcome) => void;
|
|
675
1879
|
backoffBase?: number;
|
|
676
1880
|
backoffCap?: number;
|
|
1881
|
+
stopGraceMs?: number;
|
|
677
1882
|
}): JobWorker;
|
|
678
1883
|
|
|
1884
|
+
/** The checkpoint row a run's identity lives in — the workflow revision
|
|
1885
|
+
* and a hash of the input a resume must agree with (`JD2069` when it
|
|
1886
|
+
* does not). Pruned with the run it belongs to. */
|
|
1887
|
+
export declare const RUN_IDENTITY_NODE: string;
|
|
1888
|
+
|
|
679
1889
|
export declare function createJobEngine(options: {
|
|
680
1890
|
connection: unknown; now?: () => number; random?: () => number;
|
|
681
|
-
defaults?: JobsOptions }): unknown;
|
|
1891
|
+
defaults?: JobsOptions; runtime?: Partial<Runtime> }): unknown;
|
|
682
1892
|
export declare const JOBS_TABLE: string;
|
|
683
1893
|
export declare const JOB_CHECKPOINTS_TABLE: string;
|
|
684
1894
|
export declare const JOB_DEFAULTS: Readonly<{
|
|
685
1895
|
maxAttempts: number; leaseMs: number; pollInterval: number;
|
|
686
|
-
backoffBase: number; backoffCap: number }>;
|
|
1896
|
+
backoffBase: number; backoffCap: number; stopGraceMs: number }>;
|
|
1897
|
+
/** A total diagnostic string for any value, including ones that fight back. */
|
|
1898
|
+
export declare function describeValue(value: unknown): string;
|
|
1899
|
+
/** A job result as the queue stores it: JSON text, or the reason it could not be. */
|
|
1900
|
+
export declare function serializeResult(value: unknown): unknown;
|