@jarenjs/db 0.56.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +412 -56
- package/README.md +600 -57
- package/docs/HOSTS.md +269 -0
- package/docs/JOBS-FORMAT.md +293 -45
- package/docs/LIVE-FORMAT.md +169 -20
- package/docs/MIGRATION-FORMAT.md +142 -17
- package/docs/MODEL-FORMAT.md +752 -64
- package/docs/REPLICATION-FORMAT.md +208 -0
- package/package.json +21 -7
- package/schemas/jaren-model.draft-07.schema.json +224 -162
- package/schemas/jaren-model.schema.json +224 -162
- package/schemas/jaren-replication-snapshot.draft-07.schema.json +83 -0
- package/schemas/jaren-replication-snapshot.schema.json +83 -0
- package/schemas/jaren-replication.draft-07.schema.json +82 -0
- package/schemas/jaren-replication.schema.json +82 -0
- package/src/algebra.js +227 -9
- package/src/backup.js +161 -0
- package/src/cancellation.js +48 -0
- package/src/capture.js +230 -47
- package/src/cli.js +165 -59
- package/src/cursor.js +417 -0
- package/src/dag-job.js +154 -21
- package/src/ddl.js +102 -8
- package/src/dialect.js +268 -113
- 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 +244 -11
- package/src/document-files.js +311 -0
- package/src/document-steps.js +422 -0
- package/src/documents.js +335 -0
- package/src/driver.js +448 -61
- 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 +17 -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.js +339 -48
- package/src/entity.js +20 -22
- package/src/errors.js +430 -19
- package/src/expression.js +284 -0
- package/src/graph.js +64 -8
- package/src/index.js +48 -17
- package/src/introspect.js +583 -0
- package/src/jobs.js +843 -107
- package/src/json-bytes.js +58 -0
- package/src/live-join.js +250 -0
- package/src/live-nested.js +120 -0
- package/src/live.js +18 -4
- package/src/logical-rows.js +90 -0
- package/src/maintenance.js +175 -0
- package/src/migrate.js +248 -181
- package/src/model.js +68 -0
- package/src/plan.js +1119 -138
- package/src/pragmas.js +314 -0
- package/src/profile.js +151 -3
- package/src/query.js +1634 -323
- package/src/replication-format.js +115 -0
- package/src/replication.js +332 -0
- package/src/residual.js +17 -0
- package/src/series.js +12 -4
- package/src/store.js +1567 -273
- package/src/tracker.js +203 -29
- package/src/udf.js +88 -7
- package/types/index.d.ts +1158 -27
- package/types/node-pool.d.ts +28 -0
- package/types/node-worker.d.ts +54 -0
- package/types/node.d.ts +69 -2
- package/types/postgres.d.ts +46 -0
- package/types/typed.d.ts +27 -4
- package/types/wasm.d.ts +14 -0
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,6 +176,40 @@ 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;
|
|
199
|
+
}
|
|
200
|
+
|
|
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;
|
|
85
213
|
}
|
|
86
214
|
|
|
87
215
|
/** An include's clauses: the root's without `after` — a keyset cursor
|
|
@@ -89,6 +217,14 @@ export interface ExecuteOptions {
|
|
|
89
217
|
export interface LoadInclude extends Omit<LoadSpec, 'after'> {
|
|
90
218
|
/** Project the related-row COUNT instead of the rows. */
|
|
91
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;
|
|
92
228
|
}
|
|
93
229
|
|
|
94
230
|
export interface LoadSpec {
|
|
@@ -97,16 +233,103 @@ export interface LoadSpec {
|
|
|
97
233
|
orderBy?: unknown;
|
|
98
234
|
take?: number;
|
|
99
235
|
skip?: number;
|
|
100
|
-
/** The keyset cursor
|
|
101
|
-
|
|
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;
|
|
102
241
|
maxDepth?: number;
|
|
103
242
|
include?: Readonly<Record<string, boolean | LoadInclude>>;
|
|
104
243
|
}
|
|
105
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
|
+
|
|
106
312
|
export interface LoadExplanation {
|
|
107
313
|
sql: string;
|
|
108
314
|
pagination: 'keyset' | 'offset' | 'none';
|
|
109
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;
|
|
110
333
|
}
|
|
111
334
|
|
|
112
335
|
/** What `saveChanges()` returns: data, not a boolean (§11.6). */
|
|
@@ -136,13 +359,159 @@ export interface StoreStats {
|
|
|
136
359
|
liveQueries: number;
|
|
137
360
|
}
|
|
138
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
|
+
|
|
139
484
|
export interface StoreCapabilities {
|
|
140
485
|
readonly version: string;
|
|
141
486
|
readonly readOnly: boolean;
|
|
142
487
|
readonly validated: boolean;
|
|
143
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. */
|
|
144
492
|
readonly busyTimeoutMs: number | null;
|
|
493
|
+
/** `pragmas.journalMode` under its long-published name. */
|
|
145
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;
|
|
146
515
|
readonly capture: 'session' | 'journal' | 'none';
|
|
147
516
|
readonly captureLog: boolean;
|
|
148
517
|
readonly live: boolean;
|
|
@@ -171,7 +540,7 @@ export interface Collection<T = unknown> {
|
|
|
171
540
|
* a synchronous driver stays synchronous. */
|
|
172
541
|
execute<R = unknown>(document: unknown, options?: ExecuteOptions): ValueOrPromise<SequenceResult<R>>;
|
|
173
542
|
/** The same document as an item cursor — one item per pull. */
|
|
174
|
-
query<R = unknown>(document: unknown, options?:
|
|
543
|
+
query<R = unknown>(document: unknown, options?: CursorOptions): QueryCursor<R>;
|
|
175
544
|
explain(document: unknown, options?: ExecuteOptions): Promise<unknown>;
|
|
176
545
|
/** Register a live query (LIVE-FORMAT §7); requires capture. */
|
|
177
546
|
live(document: unknown, options?: LiveOptions): Promise<LiveQuery>;
|
|
@@ -233,6 +602,13 @@ export interface EntitySet<T = unknown, I = unknown> {
|
|
|
233
602
|
update(key: EntityKeyArg, changes: Partial<T>): Promise<Readonly<T>>;
|
|
234
603
|
delete(key: EntityKeyArg): Promise<boolean>;
|
|
235
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>>>;
|
|
236
612
|
explainLoad(spec?: LoadSpec): LoadExplanation;
|
|
237
613
|
/** Track a pending insert (local, synchronous — no round trip). */
|
|
238
614
|
add(doc: I): Readonly<T>;
|
|
@@ -253,6 +629,12 @@ export interface EntitySet<T = unknown, I = unknown> {
|
|
|
253
629
|
* the document is over the multi-entity root and arrives whole; the
|
|
254
630
|
* answer is the engine's result shape, value-or-promise (D2). */
|
|
255
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>;
|
|
256
638
|
explain(document: unknown, options?: ExecuteOptions): Promise<unknown>;
|
|
257
639
|
/** The root expression this set's rows are bound through (`$.<Name>[*]`). */
|
|
258
640
|
readonly root: string;
|
|
@@ -278,6 +660,9 @@ export interface SyncEntitySet<T = unknown, I = unknown> {
|
|
|
278
660
|
update(key: EntityKeyArg, changes: Partial<T>): Readonly<T>;
|
|
279
661
|
delete(key: EntityKeyArg): boolean;
|
|
280
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>;
|
|
281
666
|
explainLoad(spec?: LoadSpec): LoadExplanation;
|
|
282
667
|
add(doc: I): Readonly<T>;
|
|
283
668
|
put(next: T): Readonly<T>;
|
|
@@ -294,6 +679,15 @@ export interface SyncEntitySet<T = unknown, I = unknown> {
|
|
|
294
679
|
readonly relations: RelationTable;
|
|
295
680
|
}
|
|
296
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;
|
|
689
|
+
}
|
|
690
|
+
|
|
297
691
|
// ————— the store —————
|
|
298
692
|
|
|
299
693
|
export interface SyncStore {
|
|
@@ -301,7 +695,7 @@ export interface SyncStore {
|
|
|
301
695
|
* the consumer's words; the handle's writes take it and reads answer it. */
|
|
302
696
|
collection<T = unknown>(name: string): SyncCollection<T>;
|
|
303
697
|
entity(name: string): SyncEntitySet;
|
|
304
|
-
transaction<R>(fn: (store:
|
|
698
|
+
transaction<R>(fn: (store: TransactionStore) => R): R;
|
|
305
699
|
execute?<R = unknown>(document: unknown, options?: ExecuteOptions): SequenceResult<R>;
|
|
306
700
|
explain?(document: unknown, options?: ExecuteOptions): unknown;
|
|
307
701
|
/** The entity roots this store-level provider serves (present with
|
|
@@ -315,6 +709,7 @@ export interface SyncStore {
|
|
|
315
709
|
}
|
|
316
710
|
|
|
317
711
|
export interface Store {
|
|
712
|
+
readonly replication?: Replication;
|
|
318
713
|
readonly capabilities: StoreCapabilities;
|
|
319
714
|
readonly dialect: Dialect;
|
|
320
715
|
stats(): StoreStats;
|
|
@@ -336,13 +731,56 @@ export interface Store {
|
|
|
336
731
|
readonly relations?: Readonly<Record<string, RelationTable>>;
|
|
337
732
|
/** The unit of work (§11); present only with entities. */
|
|
338
733
|
saveChanges?(): Promise<SaveReport>;
|
|
339
|
-
|
|
734
|
+
/**
|
|
735
|
+
* A top-level transaction. The callback receives a
|
|
736
|
+
* {@link TransactionStore} whose handles are INSIDE it; this store's
|
|
737
|
+
* own handles are an unrelated caller and wait for the commit.
|
|
738
|
+
*
|
|
739
|
+
* `signal` abandons the call while it is still QUEUED — the callback
|
|
740
|
+
* then never runs and no statement is issued (`JD2064`). A transaction
|
|
741
|
+
* that has already taken the connection runs to its own end.
|
|
742
|
+
*
|
|
743
|
+
* `unitOfWork: 'own'` gives the callback a tracker of its own, so two
|
|
744
|
+
* concurrent handlers hold two records for one entity key and neither
|
|
745
|
+
* sees the other's pending state; `'shared'` (the default) writes
|
|
746
|
+
* through the store's, which is what lets a caller `add()` a document
|
|
747
|
+
* outside the transaction and save it inside. Both behave identically
|
|
748
|
+
* with and without capture.
|
|
749
|
+
*/
|
|
750
|
+
transaction<R>(fn: (store: TransactionStore) => R | Promise<R>,
|
|
751
|
+
options?: TransactionScopeOptions): Promise<Awaited<R>>;
|
|
340
752
|
/** Register a change observer; requires capture. Returns unsubscribe. */
|
|
341
753
|
observe(fn: (record: ChangeRecord) => void): () => void;
|
|
342
|
-
/** Read the persisted log forward (JD2051 without
|
|
754
|
+
/** Read the persisted log forward from `after` (`JD2051` without
|
|
755
|
+
* `capture.log`) — EVERY surviving record in one array, UNBOUNDED, with
|
|
756
|
+
* no watermark: a reconnecting consumer whose cursor fell below the
|
|
757
|
+
* retention floor receives the surviving suffix and cannot tell it
|
|
758
|
+
* from the whole. Unsafe for a reconnecting consumer; `changes.page()`
|
|
759
|
+
* is the supported path (LIVE-FORMAT §5). */
|
|
343
760
|
changesSince?(after: number): Promise<ChangeRecord[]>;
|
|
761
|
+
/** The bounded change reader: the log's watermarks and pages that
|
|
762
|
+
* never exceed their bounds and report a retention gap explicitly;
|
|
763
|
+
* present exactly when the log is enabled. */
|
|
764
|
+
readonly changes?: ChangesReader;
|
|
344
765
|
/** PRAGMA data_version — the coarse cross-connection signal. */
|
|
345
766
|
dataVersion(): Promise<number>;
|
|
767
|
+
/** `PRAGMA wal_checkpoint(<mode>)` under the store gate (MODEL-FORMAT
|
|
768
|
+
* §4). Refused `JD2077` on a read-only store or a binding that does
|
|
769
|
+
* not declare it; a driver failure is `JD2078`. */
|
|
770
|
+
checkpoint(options?: CheckpointOptions): Promise<CheckpointResult>;
|
|
771
|
+
/** `PRAGMA integrity_check` under the store gate; corruption is the
|
|
772
|
+
* RESULT (`ok: false`), never a throw. */
|
|
773
|
+
integrityCheck(options?: IntegrityCheckOptions): Promise<IntegrityCheckResult>;
|
|
774
|
+
/** `PRAGMA foreign_key_check` under the store gate. */
|
|
775
|
+
foreignKeyCheck(options?: MaintenanceCallOptions): Promise<ForeignKeyCheckResult>;
|
|
776
|
+
/** `PRAGMA optimize` under the store gate; refused `JD2077` on a
|
|
777
|
+
* read-only store. */
|
|
778
|
+
optimize(options?: MaintenanceCallOptions): Promise<OptimizeResult>;
|
|
779
|
+
/** An online backup published whole or not at all (MODEL-FORMAT §4):
|
|
780
|
+
* copied to a temporary sibling, renamed onto `targetPath` only at
|
|
781
|
+
* verified completion; a cancelled (`JD2079`) or failed (`JD2078`)
|
|
782
|
+
* copy leaves neither file. Writers proceed during the copy. */
|
|
783
|
+
backupTo(targetPath: string, options?: BackupOptions): Promise<BackupResult>;
|
|
346
784
|
/** Register a live query over an entity-root document (re-run
|
|
347
785
|
* strategy in this version); present only with entities. */
|
|
348
786
|
live?(document: unknown, options?: LiveOptions): Promise<LiveQuery>;
|
|
@@ -350,12 +788,148 @@ export interface Store {
|
|
|
350
788
|
* `graceMs` to wind up; the connection closes whether or not they
|
|
351
789
|
* did, and a handler still in flight is reported as JD2062. */
|
|
352
790
|
close(options?: { graceMs?: number }): Promise<void>;
|
|
353
|
-
/** The queue surface; present when opened with `jobs` (JOBS-FORMAT).
|
|
354
|
-
|
|
791
|
+
/** The queue surface; present when opened with `jobs` (JOBS-FORMAT).
|
|
792
|
+
* Root calls here take the store gate — an unrelated enqueue, claim,
|
|
793
|
+
* checkpoint or settlement never joins an open application
|
|
794
|
+
* transaction's fate. The transactional-outbox spelling is the
|
|
795
|
+
* `tx.jobs` a transaction callback receives, which runs as the exact
|
|
796
|
+
* scope and co-commits with the domain transaction. */
|
|
797
|
+
readonly jobs?: JobsApi & JobsAdminApi;
|
|
355
798
|
/** Present exactly when the driver is synchronous — never stubs. */
|
|
356
799
|
readonly sync?: SyncStore;
|
|
357
800
|
}
|
|
358
801
|
|
|
802
|
+
/** The options a top-level transaction takes. An unknown `unitOfWork`
|
|
803
|
+
* value is a compile error here and runtime API misuse there. */
|
|
804
|
+
export interface TransactionScopeOptions {
|
|
805
|
+
/** Abandons the call while it is still QUEUED (`JD2064`); a
|
|
806
|
+
* transaction that has taken the connection runs to its own end. */
|
|
807
|
+
signal?: AbortSignal;
|
|
808
|
+
/** `'own'` gives the callback an independent tracker; `'shared'`
|
|
809
|
+
* (the default) writes through the store's. */
|
|
810
|
+
unitOfWork?: 'own' | 'shared';
|
|
811
|
+
/** `'immediate'` takes the write lock up front (`BEGIN IMMEDIATE`), so
|
|
812
|
+
* a body that reads before it writes never meets the read→write
|
|
813
|
+
* upgrade `SQLITE_BUSY` the busy handler cannot retry — what a claim
|
|
814
|
+
* needs under concurrent writers; `'deferred'` (the default) is the
|
|
815
|
+
* savepoint as always. A nested `tx.transaction()` is a savepoint
|
|
816
|
+
* whichever mode the root chose; the synchronous twin has no mode. */
|
|
817
|
+
mode?: 'deferred' | 'immediate';
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* The named-savepoint group a live transaction view carries
|
|
822
|
+
* (MODEL-FORMAT §5.2): checkpoint-and-continue without a sentinel
|
|
823
|
+
* exception. The label is a map key and diagnostic for that exact
|
|
824
|
+
* transaction — never SQL; the driver generates the identifier. A
|
|
825
|
+
* blank, duplicate or unknown label is `JD2071`; a stale or
|
|
826
|
+
* cross-scope view is `JD2070` first. `rollbackTo` keeps the target
|
|
827
|
+
* active (repeated rollback is defined) and invalidates every later
|
|
828
|
+
* checkpoint; `release` removes the target and every later checkpoint,
|
|
829
|
+
* keeping their rows — the engine's own semantics, exactly.
|
|
830
|
+
*/
|
|
831
|
+
export interface SavepointController {
|
|
832
|
+
create(label: string): Promise<void>;
|
|
833
|
+
rollbackTo(label: string): Promise<void>;
|
|
834
|
+
release(label: string): Promise<void>;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/** The synchronous twin of {@link SavepointController}, answering
|
|
838
|
+
* values (present under `tx.sync` on a synchronous driver). */
|
|
839
|
+
export interface SyncSavepointController {
|
|
840
|
+
create(label: string): void;
|
|
841
|
+
rollbackTo(label: string): void;
|
|
842
|
+
release(label: string): void;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** The synchronous surface a transaction view carries: the store's,
|
|
846
|
+
* plus the transaction-only savepoint group. */
|
|
847
|
+
export interface TransactionSyncStore extends SyncStore {
|
|
848
|
+
readonly savepoints: SyncSavepointController;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* The store a transaction callback receives: the same surface, with
|
|
853
|
+
* every handle bound to THIS transaction's exact scope.
|
|
854
|
+
*
|
|
855
|
+
* `tx.collection(...)`, `tx.entity(...)`, `tx.sync`, `tx.jobs` and
|
|
856
|
+
* `tx.saveChanges()` run as the transaction's owner, and
|
|
857
|
+
* `tx.transaction(...)` nests through its savepoint. The outer store's
|
|
858
|
+
* handles are, by construction, an unrelated caller: they wait for the
|
|
859
|
+
* commit, and one awaited from inside the callback is a self-wait that
|
|
860
|
+
* `JD0012` names rather than a hang.
|
|
861
|
+
*
|
|
862
|
+
* The view lives exactly as long as its own scope: any stateful member
|
|
863
|
+
* used after the transaction settled, or while an async inner savepoint
|
|
864
|
+
* is current, refuses `JD2070` before touching tracker state or the
|
|
865
|
+
* database. There is deliberately no `close` — a transaction view does
|
|
866
|
+
* not own the store lifetime; the root store remains the only owner of
|
|
867
|
+
* the connection.
|
|
868
|
+
*/
|
|
869
|
+
export interface TransactionStore extends Omit<Store,
|
|
870
|
+
'close' | 'transaction' | 'sync' | 'checkpoint' | 'integrityCheck' | 'foreignKeyCheck' | 'optimize' | 'backupTo'
|
|
871
|
+
| 'jobs' | 'replication'> {
|
|
872
|
+
/** The transactional outbox (JOBS-FORMAT §3): no administration here —
|
|
873
|
+
* an admin operation is a root call. */
|
|
874
|
+
readonly jobs?: JobsApi;
|
|
875
|
+
transaction<R>(fn: (store: TransactionStore) => R | Promise<R>): Promise<Awaited<R>>;
|
|
876
|
+
/** Named partial rollback over the transaction's one savepoint stack
|
|
877
|
+
* (MODEL-FORMAT §5.2). Root stores, clients, workers and checkpoint
|
|
878
|
+
* stores expose none of it. */
|
|
879
|
+
readonly savepoints: SavepointController;
|
|
880
|
+
/** Present exactly when the driver is synchronous, as on the store. */
|
|
881
|
+
readonly sync?: TransactionSyncStore;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/** The log's two watermarks (LIVE-FORMAT §5): the earliest surviving
|
|
885
|
+
* sequence (`null` when nothing survives) and the highest sequence the
|
|
886
|
+
* FILE ever allocated — durable across an emptied log, a reopen and a
|
|
887
|
+
* second store over the same file, never a process counter. */
|
|
888
|
+
export interface ChangeBounds {
|
|
889
|
+
readonly earliestAvailable: number | null;
|
|
890
|
+
readonly highWatermark: number;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/** A change page's options: `after` is the last sequence seen and is
|
|
894
|
+
* required — there is no legitimate "give me everything" for a change
|
|
895
|
+
* log; `limit` records at most (default `PAGE_LIMIT_DEFAULT`),
|
|
896
|
+
* `maxBytes` serialised patch bytes at most (none unless given),
|
|
897
|
+
* `signal` honoured at a record boundary (`JD2072`). */
|
|
898
|
+
export interface ChangePageOptions {
|
|
899
|
+
after: number;
|
|
900
|
+
limit?: number;
|
|
901
|
+
maxBytes?: number | null;
|
|
902
|
+
signal?: AbortSignal;
|
|
903
|
+
/** An epoch-millisecond deadline, read against the store's clock at every record boundary (`JD2075`). */
|
|
904
|
+
deadline?: number;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* One page of the log. `resetRequired: true` means the record after
|
|
909
|
+
* `after` no longer survives: `items` is EMPTY and `next` absent — a
|
|
910
|
+
* total refusal, never a partial suffix — and the consumer re-seeds
|
|
911
|
+
* from a snapshot and resumes at `highWatermark`. Otherwise `next` is
|
|
912
|
+
* the sequence to continue from (`after` itself when nothing was
|
|
913
|
+
* delivered), `hasMore` says whether records remain above it, and the
|
|
914
|
+
* watermarks are the log's as read after the page.
|
|
915
|
+
*/
|
|
916
|
+
export interface ChangePage {
|
|
917
|
+
readonly items: ChangeRecord[];
|
|
918
|
+
readonly next?: number;
|
|
919
|
+
readonly earliestAvailable: number | null;
|
|
920
|
+
readonly highWatermark: number;
|
|
921
|
+
readonly hasMore: boolean;
|
|
922
|
+
readonly resetRequired: boolean;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/** The bounded change reader (LIVE-FORMAT §5). A record larger than
|
|
926
|
+
* `maxBytes` is `JD2074` without advancing `next` — the same rule, the
|
|
927
|
+
* same implementation, as an entity page. */
|
|
928
|
+
export interface ChangesReader {
|
|
929
|
+
bounds(): Promise<ChangeBounds>;
|
|
930
|
+
page(options: ChangePageOptions): Promise<ChangePage>;
|
|
931
|
+
}
|
|
932
|
+
|
|
359
933
|
/** One committed transaction's change record (LIVE-FORMAT §§1–5). */
|
|
360
934
|
export interface ChangeRecord {
|
|
361
935
|
/** Monotonic; continues across reopens when the log is enabled. */
|
|
@@ -405,7 +979,7 @@ export interface LiveEventTime {
|
|
|
405
979
|
|
|
406
980
|
export interface LiveMode {
|
|
407
981
|
readonly strategy: 'rows' | 'window' | 'accumulator' | 'group'
|
|
408
|
-
| 'bucket' | 'rolling' | 'rerun';
|
|
982
|
+
| 'bucket' | 'rolling' | 'join' | 'graph' | 'nested-group' | 'rerun';
|
|
409
983
|
readonly mode: 'incremental' | 'rerun';
|
|
410
984
|
/** Present exactly when the strategy is 'rerun': the named reason. */
|
|
411
985
|
readonly reason?: string;
|
|
@@ -431,6 +1005,9 @@ export interface LiveEvent {
|
|
|
431
1005
|
}
|
|
432
1006
|
|
|
433
1007
|
export interface LiveStats {
|
|
1008
|
+
dependencyReads?: number;
|
|
1009
|
+
refreshedRoots?: number;
|
|
1010
|
+
refreshedGroups?: number;
|
|
434
1011
|
records: number;
|
|
435
1012
|
matched: number;
|
|
436
1013
|
emissions: number;
|
|
@@ -464,6 +1041,8 @@ export interface LiveQuery {
|
|
|
464
1041
|
}
|
|
465
1042
|
|
|
466
1043
|
export interface LiveBounds {
|
|
1044
|
+
/** Serialized input/output cache credit for join, graph and nested-group strategies. */
|
|
1045
|
+
maxBytes?: number;
|
|
467
1046
|
/** Registrations beyond it are JD0052 (default 64). */
|
|
468
1047
|
maxQueries?: number;
|
|
469
1048
|
/** Per-query ceiling on maintained entries — rows, window entries
|
|
@@ -472,8 +1051,17 @@ export interface LiveBounds {
|
|
|
472
1051
|
}
|
|
473
1052
|
|
|
474
1053
|
export interface OpenStoreOptions {
|
|
1054
|
+
replication?: ReplicationOptions;
|
|
475
1055
|
driver: Driver;
|
|
476
1056
|
path?: string;
|
|
1057
|
+
/**
|
|
1058
|
+
* What a store-level call does while another caller's transaction owns
|
|
1059
|
+
* the connection. `'wait'` (the default) queues behind it under
|
|
1060
|
+
* `queueTimeout` and then refuses `JD0012`; `'strict'` refuses at once,
|
|
1061
|
+
* for a host that would rather see the contention than pay for it.
|
|
1062
|
+
* Either way the call never joins the transaction.
|
|
1063
|
+
*/
|
|
1064
|
+
transactions?: 'wait' | 'strict';
|
|
477
1065
|
/** Change capture (LIVE-FORMAT): off unless requested. */
|
|
478
1066
|
capture?: boolean | CaptureOptions;
|
|
479
1067
|
/** Live-query bounds (LIVE-FORMAT §12). */
|
|
@@ -489,13 +1077,43 @@ export interface OpenStoreOptions {
|
|
|
489
1077
|
* where one was injected; without it the document is refused rather
|
|
490
1078
|
* than answered in UTC. No time-zone database is bundled. */
|
|
491
1079
|
zoneProvider?: unknown;
|
|
492
|
-
|
|
1080
|
+
/** The host's runtime record (`@jarenjs/core/runtime`): the clock the
|
|
1081
|
+
* capture log and the job queue stamp, the identifier a `uuid`
|
|
1082
|
+
* identity and a `default: 'uuid'` allocate, the job queue's backoff
|
|
1083
|
+
* jitter and the zone provider — each read only where the explicit
|
|
1084
|
+
* option (`zoneProvider`, `jobs.now`, `jobs.random`) is absent, and
|
|
1085
|
+
* handed on to the job engine. */
|
|
1086
|
+
runtime?: Partial<Runtime>;
|
|
493
1087
|
/** How long work waits for an open transaction to settle before
|
|
494
1088
|
* `JD0012` (MODEL-FORMAT §5.1); reaches every driver. */
|
|
495
1089
|
queueTimeout?: number;
|
|
496
|
-
|
|
1090
|
+
/**
|
|
1091
|
+
* The connection pragmas — a closed, validated set (MODEL-FORMAT §4).
|
|
1092
|
+
* An option naming any other pragma is `JD0006`; a pragma the driver
|
|
1093
|
+
* or the store kind cannot apply is `JD0007`; every value is read back
|
|
1094
|
+
* after the open sequence and reported on `capabilities.pragmas`, and
|
|
1095
|
+
* one the engine did not take is `JD0008`.
|
|
1096
|
+
*/
|
|
1097
|
+
/** `PRAGMA busy_timeout`, in milliseconds (default 5000). */
|
|
1098
|
+
busyTimeout?: number;
|
|
1099
|
+
/** `PRAGMA journal_mode` (default `'wal'` on a writable file; a
|
|
1100
|
+
* read-only store keeps the file's mode and refuses an explicit one). */
|
|
1101
|
+
journalMode?: 'delete' | 'truncate' | 'persist' | 'memory' | 'wal' | 'off';
|
|
1102
|
+
/** `PRAGMA synchronous`. */
|
|
1103
|
+
synchronous?: 'off' | 'normal' | 'full' | 'extra';
|
|
1104
|
+
/** `PRAGMA wal_autocheckpoint`, in pages; `0` disables. */
|
|
1105
|
+
walAutocheckpoint?: number;
|
|
1106
|
+
/** `PRAGMA journal_size_limit`, in bytes; `-1` for none. */
|
|
1107
|
+
journalSizeLimit?: number;
|
|
1108
|
+
/** `PRAGMA cache_size`: pages, or negative KiB. */
|
|
1109
|
+
cacheSize?: number;
|
|
1110
|
+
/** `PRAGMA mmap_size`, in bytes. */
|
|
1111
|
+
mmapSize?: number;
|
|
1112
|
+
/** `PRAGMA temp_store`. */
|
|
1113
|
+
tempStore?: 'default' | 'file' | 'memory';
|
|
497
1114
|
statementCacheBound?: number;
|
|
498
|
-
profile
|
|
1115
|
+
/** The store-level safety profile (MODEL-FORMAT §8). */
|
|
1116
|
+
profile?: 'safe' | ProfileSpec;
|
|
499
1117
|
readOnly?: boolean;
|
|
500
1118
|
/** A `createJsltRegistry()` registry (Ring 2/3): the operators a
|
|
501
1119
|
* query may use, and the pushable subset. */
|
|
@@ -530,7 +1148,37 @@ export interface Driver {
|
|
|
530
1148
|
|
|
531
1149
|
export declare const sqliteDialect: Dialect;
|
|
532
1150
|
export declare function createDialect(spec: unknown): Dialect;
|
|
1151
|
+
/** The closed set of dialect capabilities, each with the answer a
|
|
1152
|
+
* spelling spec that says nothing gets. `createDialect` refuses a name
|
|
1153
|
+
* outside it, so a misspelling cannot read as a quiet `false`. */
|
|
1154
|
+
export declare const DIALECT_CAPABILITIES: Readonly<Record<string, boolean>>;
|
|
1155
|
+
/** The R*Tree mapping's DDL group for one spelling spec — the virtual
|
|
1156
|
+
* table and the three row triggers that keep it in sync. Composed into
|
|
1157
|
+
* a dialect whose `capabilities.virtualTables` is true. */
|
|
1158
|
+
export declare function rtreeDdl(spec: unknown): Record<string, Function>;
|
|
533
1159
|
export declare const SQLITE_FLOOR: string;
|
|
1160
|
+
/** Assemble the connection contract around a raw binding whose
|
|
1161
|
+
* capabilities a probe has already answered. */
|
|
1162
|
+
export declare function finishConnection(
|
|
1163
|
+
raw: unknown, dialect: Dialect, synchronous: boolean,
|
|
1164
|
+
capabilities: Readonly<Record<string, unknown>>, queueTimeout: number,
|
|
1165
|
+
): unknown;
|
|
1166
|
+
/** The default probe: SQLite's version report, its compile options and
|
|
1167
|
+
* what the binding declares. */
|
|
1168
|
+
export declare function sqliteProbe(
|
|
1169
|
+
raw: unknown, dialect: Dialect, declared: unknown,
|
|
1170
|
+
): unknown;
|
|
1171
|
+
/** The capability answers every connection carries, each defaulted to
|
|
1172
|
+
* the conservative one — what a probe for another engine fills in. */
|
|
1173
|
+
export declare function baseCapabilities(): Record<string, unknown>;
|
|
1174
|
+
/** The option names of the closed configurable-pragma set, in the
|
|
1175
|
+
* order the open sequence applies them (MODEL-FORMAT §4). */
|
|
1176
|
+
export declare const PRAGMA_NAMES: readonly string[];
|
|
1177
|
+
/** The `PRAGMA wal_checkpoint` modes, closed. */
|
|
1178
|
+
export declare const CHECKPOINT_MODES: readonly string[];
|
|
1179
|
+
/** The maintenance operations, in the order `capabilities.maintenance`
|
|
1180
|
+
* lists them. */
|
|
1181
|
+
export declare const MAINTENANCE_OPERATIONS: readonly string[];
|
|
534
1182
|
|
|
535
1183
|
// ————— entities: models, mapping, generated types —————
|
|
536
1184
|
|
|
@@ -564,6 +1212,8 @@ export declare function translateOperations(
|
|
|
564
1212
|
export declare function keyToken(parts: readonly unknown[]): string;
|
|
565
1213
|
export declare function createCaptureEngine(options: unknown): unknown;
|
|
566
1214
|
export declare const CHANGES_TABLE: string;
|
|
1215
|
+
/** The change log's durable state table: the highest sequence the file ever allocated (LIVE-FORMAT §5). */
|
|
1216
|
+
export declare const CHANGES_STATE_TABLE: string;
|
|
567
1217
|
export declare const DEFAULT_RETENTION: number;
|
|
568
1218
|
/** Deep-freeze a JSON value in place and return it (idempotent). */
|
|
569
1219
|
export declare function deepFreeze<T>(value: T): T;
|
|
@@ -572,6 +1222,58 @@ export declare const BATCH_ROW_BOUND: number;
|
|
|
572
1222
|
|
|
573
1223
|
// ————— migrations —————
|
|
574
1224
|
|
|
1225
|
+
/** Where a migration runs: the driver, the file (`':memory:'` when
|
|
1226
|
+
* absent) and the busy timeout the run opens with. */
|
|
1227
|
+
export interface MigrationTarget {
|
|
1228
|
+
driver: Driver;
|
|
1229
|
+
path?: string;
|
|
1230
|
+
/** `PRAGMA busy_timeout` for the run's connection, ms (default 5000). */
|
|
1231
|
+
busyTimeout?: number;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/** One progress event: the migration and collection a data step is
|
|
1235
|
+
* walking, and the running count of the rows it has transformed,
|
|
1236
|
+
* derived or asserted so far (one of the three counters per event). */
|
|
1237
|
+
export interface MigrationProgress {
|
|
1238
|
+
readonly migration: string;
|
|
1239
|
+
readonly collection: string;
|
|
1240
|
+
readonly transformed?: number;
|
|
1241
|
+
readonly derived?: number;
|
|
1242
|
+
readonly asserted?: number;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/** One row of an introspection's loss report: what the physical shape
|
|
1246
|
+
* does not carry, by a stable code, once, sorted. */
|
|
1247
|
+
export interface IntrospectReportRow {
|
|
1248
|
+
readonly code: string;
|
|
1249
|
+
/** The physical object it is about (`users`, `users.gx_age`). */
|
|
1250
|
+
readonly object: string;
|
|
1251
|
+
readonly detail: string;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/** Every code the loss report uses, with what it means. */
|
|
1255
|
+
export declare const INTROSPECT_CODES: Readonly<Record<string, string>>;
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* Database → model, read-only. Answers the `jaren-model` document this
|
|
1259
|
+
* database's shape says it is, beside a report of everything the shape
|
|
1260
|
+
* cannot carry. `strict` refuses instead of returning a partial model.
|
|
1261
|
+
*/
|
|
1262
|
+
export declare function introspectModel(connection: unknown, options?: {
|
|
1263
|
+
strict?: boolean;
|
|
1264
|
+
/** Narrow the read to a named set of tables. */
|
|
1265
|
+
tables?: readonly string[];
|
|
1266
|
+
/** The document pointer a text key column cannot record, per table. */
|
|
1267
|
+
keys?: Record<string, string>;
|
|
1268
|
+
}): unknown;
|
|
1269
|
+
|
|
1270
|
+
/** The neutral IR one read produces: tables with their columns,
|
|
1271
|
+
* generated expressions, indexes and foreign keys, plus the views a
|
|
1272
|
+
* model cannot declare. */
|
|
1273
|
+
export declare function readSchema(connection: unknown, options?: {
|
|
1274
|
+
tables?: readonly string[];
|
|
1275
|
+
}): unknown;
|
|
1276
|
+
|
|
575
1277
|
export interface MigrateOptions {
|
|
576
1278
|
baseline: unknown;
|
|
577
1279
|
model?: unknown;
|
|
@@ -579,14 +1281,64 @@ export interface MigrateOptions {
|
|
|
579
1281
|
dryRun?: boolean;
|
|
580
1282
|
batchSize?: number;
|
|
581
1283
|
shadow?: boolean;
|
|
1284
|
+
/** Where the shadow replay runs (default `':memory:'`). */
|
|
1285
|
+
shadowPath?: string;
|
|
1286
|
+
/** The host's declared index-expression functions, by name — the same
|
|
1287
|
+
* declarations `openStore` is given, resolved into the planned DDL. */
|
|
1288
|
+
expressions?: Record<string, ExpressionFunction>;
|
|
1289
|
+
/** The driver the shadow replay opens through (default the target's).
|
|
1290
|
+
* A file engine's shadow is another file; a SERVER engine's is another
|
|
1291
|
+
* schema, and only the host can name one — the baseline shape the
|
|
1292
|
+
* replay creates would otherwise collide with the real store's. */
|
|
1293
|
+
shadowDriver?: unknown;
|
|
1294
|
+
/** Called once per batch a data step walks (transform, derive, or a
|
|
1295
|
+
* per-document assertion). */
|
|
1296
|
+
onProgress?: (progress: MigrationProgress) => void;
|
|
582
1297
|
/** Re-register declared deterministic functions on every connection
|
|
583
1298
|
* the migration opens (real, shadow, reference) — §10. */
|
|
584
1299
|
registerFunctions?: (connection: unknown) => unknown;
|
|
1300
|
+
/** The host's runtime record: the clock every applied migration is
|
|
1301
|
+
* stamped with and the deadline is read against; the platform's own
|
|
1302
|
+
* when absent. */
|
|
1303
|
+
runtime?: Partial<Runtime>;
|
|
1304
|
+
/** Cancels between migrations, steps and batches (`JD2080`); the
|
|
1305
|
+
* migration in flight rolls back whole. */
|
|
1306
|
+
signal?: AbortSignal;
|
|
1307
|
+
/** An epoch-millisecond deadline on `runtime`'s clock (`JD2075`). */
|
|
1308
|
+
deadline?: number;
|
|
1309
|
+
/** What a MATERIALIZING assertion may hold. A per-document predicate
|
|
1310
|
+
* and a single associative aggregate over the root are answered in
|
|
1311
|
+
* batches and are never bounded by this; anything else must hold the
|
|
1312
|
+
* collection at once and crosses these bounds before the excess is
|
|
1313
|
+
* held (`JD2007` rows, `JD2076` bytes). Defaults to
|
|
1314
|
+
* {@link ASSERTION_BOUNDS_DEFAULT}; `null` on either member removes
|
|
1315
|
+
* that bound, deliberately. */
|
|
1316
|
+
assertionBounds?: { maxRows?: number | null; maxBytes?: number | null };
|
|
585
1317
|
}
|
|
586
1318
|
|
|
1319
|
+
/** The finite defaults a materializing assertion runs under when the
|
|
1320
|
+
* caller declares none: 100,000 rows and 64 MiB. */
|
|
1321
|
+
export declare const ASSERTION_BOUNDS_DEFAULT: {
|
|
1322
|
+
readonly maxRows: number;
|
|
1323
|
+
readonly maxBytes: number;
|
|
1324
|
+
};
|
|
1325
|
+
|
|
1326
|
+
/** How a host must run an assertion, and why. `perDocument` walks in
|
|
1327
|
+
* batches; `fold` is one associative aggregate whose batch answers
|
|
1328
|
+
* combine; `materialize` needs every document at once and is bounded. */
|
|
1329
|
+
export declare function classifyAssertion(query: unknown): {
|
|
1330
|
+
strategy: 'perDocument' | 'fold' | 'materialize';
|
|
1331
|
+
shape: string | null;
|
|
1332
|
+
reason: string;
|
|
1333
|
+
};
|
|
1334
|
+
|
|
587
1335
|
export declare function migrate(
|
|
588
|
-
target:
|
|
1336
|
+
target: MigrationTarget, migrations: readonly unknown[], options: MigrateOptions,
|
|
589
1337
|
): Promise<unknown>;
|
|
1338
|
+
/** Whether an assertion step is a per-document predicate (a FLWOR over
|
|
1339
|
+
* `$[*]` whose body reads only its binding), which the runner evaluates
|
|
1340
|
+
* per batch; anything else reads the collection whole. */
|
|
1341
|
+
export declare function isPerDocumentAssertion(query: unknown): boolean;
|
|
590
1342
|
export declare function planMigration(from: unknown, to: unknown, options?: unknown): unknown;
|
|
591
1343
|
/** The whole-model diff — collections AND entities (MIGRATION-FORMAT §9). */
|
|
592
1344
|
export declare function planModelMigration(from: unknown, to: unknown, options?: unknown): unknown;
|
|
@@ -597,11 +1349,15 @@ export interface MigrationStatusReport {
|
|
|
597
1349
|
drift: string | null;
|
|
598
1350
|
upToDate: boolean;
|
|
599
1351
|
}
|
|
1352
|
+
/** Report a database's migration state without touching it: the
|
|
1353
|
+
* history table is probed, never created. `model` enables the drift
|
|
1354
|
+
* comparison once the chain is fully applied. */
|
|
600
1355
|
export declare function migrationStatus(
|
|
601
|
-
target:
|
|
1356
|
+
target: MigrationTarget,
|
|
602
1357
|
migrations: readonly unknown[],
|
|
603
|
-
options
|
|
604
|
-
registerFunctions?: (connection: unknown) => unknown
|
|
1358
|
+
options?: { model?: unknown;
|
|
1359
|
+
registerFunctions?: (connection: unknown) => unknown;
|
|
1360
|
+
signal?: AbortSignal; deadline?: number; runtime?: Partial<Runtime> },
|
|
605
1361
|
): Promise<MigrationStatusReport>;
|
|
606
1362
|
/** Create a model's whole physical shape on a connection. */
|
|
607
1363
|
export declare function createModelShape(connection: unknown, model: unknown): unknown;
|
|
@@ -619,6 +1375,97 @@ export declare function migrationChecksum(migration: unknown): string;
|
|
|
619
1375
|
export declare const MIGRATION_VERSION: string;
|
|
620
1376
|
export declare const HISTORY_TABLE: string;
|
|
621
1377
|
|
|
1378
|
+
/** The counters a storeless run reports for one collection. */
|
|
1379
|
+
export interface DocumentMigrationCounts {
|
|
1380
|
+
readonly read: number;
|
|
1381
|
+
readonly transformed: number;
|
|
1382
|
+
readonly asserted: number;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/** What a storeless run did, per collection: `materialized` held the
|
|
1386
|
+
* documents and ran the steps as a Store does; `streamed` carried each
|
|
1387
|
+
* batch through every step in one pass. */
|
|
1388
|
+
export type DocumentMigrationStrategy = 'materialized' | 'streamed';
|
|
1389
|
+
|
|
1390
|
+
export interface DocumentMigrationReport {
|
|
1391
|
+
/** The migration ids this run applied, in order. */
|
|
1392
|
+
readonly applied: string[];
|
|
1393
|
+
/** Always empty: a storeless run has no history to skip against. */
|
|
1394
|
+
readonly skipped: string[];
|
|
1395
|
+
/** The last migration's target shape hash, or null for no migrations. */
|
|
1396
|
+
readonly shape: string | null;
|
|
1397
|
+
readonly counts: Record<string, DocumentMigrationCounts>;
|
|
1398
|
+
readonly strategy: Record<string, DocumentMigrationStrategy>;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
export interface DocumentMigrationOptions {
|
|
1402
|
+
/** What a MATERIALIZING assertion may hold; the same bounds, and the
|
|
1403
|
+
* same refusals, a Store applies. Defaults to
|
|
1404
|
+
* {@link ASSERTION_BOUNDS_DEFAULT}. */
|
|
1405
|
+
assertionBounds?: { maxRows?: number | null; maxBytes?: number | null };
|
|
1406
|
+
/** Documents per assertion batch and per progress event (default 500). */
|
|
1407
|
+
batchSize?: number;
|
|
1408
|
+
onProgress?: (progress: MigrationProgress) => void;
|
|
1409
|
+
/** The key members of a collection's documents, which a transform may
|
|
1410
|
+
* keep but never move; a Store reads these from its model. */
|
|
1411
|
+
keys?: Record<string, readonly string[]>;
|
|
1412
|
+
/** The JSLT compiler a `jslt` step is compiled with (the suite's own
|
|
1413
|
+
* when absent). */
|
|
1414
|
+
compileJslt?: (stylesheet: unknown) => (document: unknown) => unknown;
|
|
1415
|
+
/** The query compiler a `query` step is compiled with. */
|
|
1416
|
+
compileQuery?: (query: unknown) => unknown;
|
|
1417
|
+
runtime?: Partial<Runtime>;
|
|
1418
|
+
/** Cancels between steps and batches (`JD2080`). */
|
|
1419
|
+
signal?: AbortSignal;
|
|
1420
|
+
/** An epoch-millisecond deadline on `runtime`'s clock (`JD2075`). */
|
|
1421
|
+
deadline?: number;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
/** Apply a migration's document steps to documents held in memory. The
|
|
1425
|
+
* source is rewindable, so the steps run exactly as a Store runs them —
|
|
1426
|
+
* every step over the whole collection, in step order — which is what
|
|
1427
|
+
* makes the answer, and the refusal, identical to the Store's. A step
|
|
1428
|
+
* that needs tables (`ddl`, `sql`, `rebuild`, `derive`) is refused
|
|
1429
|
+
* (`JD0023`) before the first document is read. */
|
|
1430
|
+
export declare function migrateDocuments(
|
|
1431
|
+
collections: Record<string, readonly unknown[]>,
|
|
1432
|
+
migrations: readonly unknown[],
|
|
1433
|
+
options?: DocumentMigrationOptions,
|
|
1434
|
+
): Promise<{ documents: Record<string, unknown[]>; report: DocumentMigrationReport }>;
|
|
1435
|
+
|
|
1436
|
+
/** Apply a migration's document steps to a source that can be walked
|
|
1437
|
+
* only once, writing each document out as it finishes: the input is
|
|
1438
|
+
* consumed exactly once and nothing beyond one batch is held. A
|
|
1439
|
+
* cross-document assertion, which needs every document at once, is
|
|
1440
|
+
* refused by name rather than silently buffering the collection. */
|
|
1441
|
+
export declare function streamDocuments(
|
|
1442
|
+
sources: Record<string, Iterable<unknown> | AsyncIterable<unknown>>,
|
|
1443
|
+
migrations: readonly unknown[],
|
|
1444
|
+
options: DocumentMigrationOptions & {
|
|
1445
|
+
write: (collection: string, document: unknown) => unknown;
|
|
1446
|
+
},
|
|
1447
|
+
): Promise<DocumentMigrationReport>;
|
|
1448
|
+
|
|
1449
|
+
/** The step kinds that act on documents, and so run on any host. */
|
|
1450
|
+
export declare const DOCUMENT_STEP_KINDS: ReadonlySet<string>;
|
|
1451
|
+
/** The step kinds that need a physical database and are refused without one. */
|
|
1452
|
+
export declare const PHYSICAL_STEP_KINDS: ReadonlySet<string>;
|
|
1453
|
+
/** Compile one document step into the operation every host runs. */
|
|
1454
|
+
export declare function compileDocumentStep(
|
|
1455
|
+
step: unknown, index: number, context: {
|
|
1456
|
+
migrationId: string;
|
|
1457
|
+
compileJslt: (stylesheet: unknown) => (document: unknown) => unknown;
|
|
1458
|
+
compileQuery: (query: unknown) => unknown;
|
|
1459
|
+
keys?: readonly string[];
|
|
1460
|
+
},
|
|
1461
|
+
): unknown;
|
|
1462
|
+
/** Structural validation of one migration document (`JD0023`/`JD0021`). */
|
|
1463
|
+
export declare function checkMigrationDocument(migration: unknown): void;
|
|
1464
|
+
/** The refusal a failing step raises, spelled the one way every host spells it. */
|
|
1465
|
+
export declare function stepFailure(
|
|
1466
|
+
migrationId: string, index: number, kind: string, reason: string, cause?: Error,
|
|
1467
|
+
): DbCompileError;
|
|
1468
|
+
|
|
622
1469
|
// ————— the machinery exports —————
|
|
623
1470
|
// The planner/emitter/residual/profile internals are public for tools
|
|
624
1471
|
// and tests; their documents have their own formats, so their types
|
|
@@ -628,11 +1475,25 @@ export declare function planCollection(name: string, collection: unknown, dialec
|
|
|
628
1475
|
export declare function compileIndexPath(expression: string, docPath: string): unknown;
|
|
629
1476
|
export declare function normalizeDeclaredSql(sql: string): string;
|
|
630
1477
|
export declare function comparableDeclaredSql(sql: string): string;
|
|
1478
|
+
/** The comparison kind a declared schema type implies — what a column
|
|
1479
|
+
* over that member holds, and how its expression must read it. */
|
|
1480
|
+
export declare function columnKindFor(
|
|
1481
|
+
schemaType: string | undefined,
|
|
1482
|
+
): 'text' | 'number' | 'boolean' | undefined;
|
|
631
1483
|
export declare function schemaTypeAt(schema: unknown, segments: unknown): unknown;
|
|
632
1484
|
export declare const KEY_COLUMN: string;
|
|
633
1485
|
export declare const DOC_COLUMN: string;
|
|
634
1486
|
export declare function planQuery(document: unknown, shape: unknown, options?: unknown): unknown;
|
|
635
1487
|
export declare function assertDecidedKind(node: unknown): void;
|
|
1488
|
+
/** The planner's reason vocabulary: every cause a plan can name for work
|
|
1489
|
+
* it left in the engine, under a stable identifier. Most entries are the
|
|
1490
|
+
* whole sentence; the four that quote the caller's own values carry the
|
|
1491
|
+
* stable opening they begin with. */
|
|
1492
|
+
export declare const PLANNER_REASONS: Readonly<Record<string,
|
|
1493
|
+
{ readonly text: string } | { readonly prefix: string }>>;
|
|
1494
|
+
/** The vocabulary identifier of one reason sentence, or `null` when no
|
|
1495
|
+
* entry claims it. */
|
|
1496
|
+
export declare function reasonId(reason: string): string | null;
|
|
636
1497
|
export declare function entityShape(entity: unknown, entityMapping: unknown): unknown;
|
|
637
1498
|
export declare function entityPathRef(node: unknown, slot: number, shape: unknown): unknown;
|
|
638
1499
|
export declare function planEntityPredicate(node: unknown, slot: number, shape: unknown): unknown;
|
|
@@ -645,12 +1506,80 @@ export declare function parseGraphRow(node: unknown, row: unknown, docField?: st
|
|
|
645
1506
|
export declare function selectPlan(collection: string): unknown;
|
|
646
1507
|
export declare function conjoin(plan: unknown, predicate: unknown): unknown;
|
|
647
1508
|
export declare function assertNoSqlText(plan: unknown): void;
|
|
1509
|
+
/** Whether an order term reads its value from a mapped column rather
|
|
1510
|
+
* than the document. */
|
|
1511
|
+
export declare function ordersByColumn(ref: unknown): boolean;
|
|
1512
|
+
/** The effective order a set of declared terms executes under: the terms,
|
|
1513
|
+
* then the tie-breaker the emitter appends — the primary key when
|
|
1514
|
+
* `keyColumns` is given (keyset mode), one row identity per binding
|
|
1515
|
+
* otherwise. */
|
|
1516
|
+
export declare function effectiveOrder(
|
|
1517
|
+
terms: unknown, options?: { bindings?: (string | null)[]; keyColumns?: readonly string[] },
|
|
1518
|
+
): EffectiveOrderTerm[];
|
|
1519
|
+
/** The effective order of one plan, in the same normalized form its
|
|
1520
|
+
* emitter renders; `null` for a statement that orders nothing. */
|
|
1521
|
+
export declare function planOrder(plan: unknown): EffectiveOrderTerm[] | null;
|
|
648
1522
|
export declare const PLAN_VERSION: number;
|
|
649
1523
|
export declare function typeOfPath(shape: unknown, segments: unknown): unknown;
|
|
650
1524
|
export declare function isNumericType(type: unknown): boolean;
|
|
651
1525
|
export declare function compileSetResidual(document: unknown, limits?: unknown): unknown;
|
|
652
1526
|
export declare function compileRowResidual(rowReturn: unknown, limits?: unknown): unknown;
|
|
1527
|
+
export declare function compilePackedResidual(document: unknown, limits?: unknown): unknown;
|
|
1528
|
+
/** The one cursor mechanism every engine builds on: a row source pulled
|
|
1529
|
+
* one row per `next()` and released exactly once, or a materialised
|
|
1530
|
+
* source that says so. */
|
|
1531
|
+
export declare function createCursor<T = unknown>(spec: {
|
|
1532
|
+
streaming: 'row' | 'buffered';
|
|
1533
|
+
barrier?: CursorBarrier | null;
|
|
1534
|
+
signal?: AbortSignal;
|
|
1535
|
+
materialize?: () => unknown;
|
|
1536
|
+
open?: () => unknown;
|
|
1537
|
+
items?: (row: unknown) => T[];
|
|
1538
|
+
}): QueryCursor<T>;
|
|
653
1539
|
export declare function sequenceResult(items: unknown[]): unknown;
|
|
1540
|
+
// ————— model-declared index expressions —————
|
|
1541
|
+
|
|
1542
|
+
/** The three node kinds, closed: `member`, `value`, `call`. */
|
|
1543
|
+
export declare const EXPRESSION_KINDS: readonly string[];
|
|
1544
|
+
/** How deep a declared expression may nest. */
|
|
1545
|
+
export declare const EXPRESSION_DEPTH: number;
|
|
1546
|
+
/** One host declaration for a function a model's index expression may
|
|
1547
|
+
* name. An engine that registers functions needs `apply`; one that
|
|
1548
|
+
* cannot needs the `sql` name of an IMMUTABLE function it already has. */
|
|
1549
|
+
export interface ExpressionFunction {
|
|
1550
|
+
arity: number;
|
|
1551
|
+
/** Required, and never inferred: an index over a function that may
|
|
1552
|
+
* answer differently for one row is an index that lies. */
|
|
1553
|
+
deterministic: true;
|
|
1554
|
+
apply?: (...args: any[]) => unknown;
|
|
1555
|
+
sql?: string;
|
|
1556
|
+
}
|
|
1557
|
+
/** Resolve one expression against the host's declarations, refusing an
|
|
1558
|
+
* unknown, wrong-arity or non-deterministic function with `JD0004`. */
|
|
1559
|
+
export declare function normalizeExpression(
|
|
1560
|
+
node: unknown, docPath: string, declarations: Record<string, ExpressionFunction>,
|
|
1561
|
+
depth?: number,
|
|
1562
|
+
): unknown;
|
|
1563
|
+
/** The identity two declarations of one expression share. */
|
|
1564
|
+
export declare function canonicalExpression(node: unknown): string;
|
|
1565
|
+
/** Every member path an expression reads, in order. */
|
|
1566
|
+
export declare function expressionMembers(node: unknown, out?: string[]): string[];
|
|
1567
|
+
/** Every function an expression calls, sorted. */
|
|
1568
|
+
export declare function expressionFunctions(node: unknown, out?: Set<string>): string[];
|
|
1569
|
+
/** The SQL an expression compiles to on one dialect. */
|
|
1570
|
+
export declare function expressionSql(
|
|
1571
|
+
node: unknown, dialect: Dialect, context: unknown,
|
|
1572
|
+
): string;
|
|
1573
|
+
/** A short, stable column stem for one expression. */
|
|
1574
|
+
export declare function expressionStem(node: unknown): string;
|
|
1575
|
+
/** The SQL name a declared function is registered under. */
|
|
1576
|
+
export declare function registeredName(name: string): string;
|
|
1577
|
+
/** Register every function a set of expressions calls, on one connection. */
|
|
1578
|
+
export declare function registerExpressionFunctions(
|
|
1579
|
+
connection: unknown, names: readonly string[],
|
|
1580
|
+
declarations: Record<string, ExpressionFunction>,
|
|
1581
|
+
): unknown;
|
|
1582
|
+
|
|
654
1583
|
export declare function deterministicFragment(fragment: unknown): unknown;
|
|
655
1584
|
export declare function registerFragment(connection: unknown, registered: Set<string>, fragment: unknown): void;
|
|
656
1585
|
export declare function createQueryEngine(context: unknown): unknown;
|
|
@@ -658,6 +1587,9 @@ export declare function createQueryState(bound?: number): unknown;
|
|
|
658
1587
|
export declare function createEntityQueryEngine(context: unknown): unknown;
|
|
659
1588
|
export declare function createLoadEngine(context: unknown, entityName: string): unknown;
|
|
660
1589
|
export declare const INCLUDE_DEPTH_DEFAULT: number;
|
|
1590
|
+
export declare const INCLUDE_ROWS_DEFAULT: number;
|
|
1591
|
+
export declare const INCLUDE_BYTES_DEFAULT: number;
|
|
1592
|
+
export declare const PAGE_LIMIT_DEFAULT: number;
|
|
661
1593
|
export declare function normalizeProfile(profile: unknown): unknown;
|
|
662
1594
|
export declare const SAFE_PROFILE: unknown;
|
|
663
1595
|
export declare function translateProfilePredicate(predicate: unknown, shape: unknown): unknown;
|
|
@@ -680,7 +1612,7 @@ export declare function createLiveRegistry(
|
|
|
680
1612
|
bounds: { maxQueries: number; maxMaintained: number }): unknown;
|
|
681
1613
|
export declare function diffRows(oldRows: readonly unknown[], newRows: readonly unknown[]):
|
|
682
1614
|
Array<{ op: string; path: string; value?: unknown }>;
|
|
683
|
-
export declare const LIVE_DEFAULTS: { maxQueries: number; maxMaintained: number };
|
|
1615
|
+
export declare const LIVE_DEFAULTS: { maxQueries: number; maxMaintained: number; maxBytes: number };
|
|
684
1616
|
export declare function createSortedWindow(
|
|
685
1617
|
terms: unknown[], limit: number | null): unknown;
|
|
686
1618
|
export declare function compareCodepoint(a: string, b: string): number;
|
|
@@ -721,49 +1653,133 @@ export declare function identityBatches(identities: unknown[]): unknown;
|
|
|
721
1653
|
|
|
722
1654
|
// ————— the job queue (JOBS-FORMAT) —————
|
|
723
1655
|
|
|
1656
|
+
/** A job's state: `cancelled` is terminal like `done` and `dead` and
|
|
1657
|
+
* is set only by `cancel()` (JOBS-FORMAT §10). */
|
|
1658
|
+
export type JobState = 'pending' | 'leased' | 'done' | 'failed' | 'dead' | 'cancelled';
|
|
1659
|
+
|
|
724
1660
|
export interface JobRecord {
|
|
725
1661
|
readonly id: string;
|
|
726
1662
|
readonly kind: string;
|
|
727
1663
|
readonly payload: unknown;
|
|
728
|
-
readonly state:
|
|
1664
|
+
readonly state: JobState;
|
|
729
1665
|
readonly runAt: number;
|
|
730
1666
|
readonly attempts: number;
|
|
731
1667
|
readonly maxAttempts: number;
|
|
732
1668
|
readonly leaseUntil: number | null;
|
|
733
1669
|
readonly leaseOwner: string | null;
|
|
1670
|
+
/** How many times this job has been claimed. It identifies the
|
|
1671
|
+
* ATTEMPT, which the owner cannot: one worker reuses one owner. */
|
|
1672
|
+
readonly leaseGeneration: number;
|
|
734
1673
|
readonly lastError: string | null;
|
|
735
1674
|
readonly result: unknown;
|
|
736
1675
|
readonly createdAt: number;
|
|
737
1676
|
readonly updatedAt: number;
|
|
738
1677
|
}
|
|
739
1678
|
|
|
1679
|
+
/**
|
|
1680
|
+
* The capability one claim mints: the right to settle THIS attempt of
|
|
1681
|
+
* this job, for as long as the lease is valid.
|
|
1682
|
+
*
|
|
1683
|
+
* It is a token rather than an owner, because an owner is reused by
|
|
1684
|
+
* every attempt one worker makes and so cannot say which attempt is
|
|
1685
|
+
* speaking. It is immutable: `renew` answers a NEW lease and retires
|
|
1686
|
+
* this one, so a reference kept across a renewal can never quietly
|
|
1687
|
+
* become valid again.
|
|
1688
|
+
*
|
|
1689
|
+
* Only `claim` and `renew` hand one out. `get` does not — a record
|
|
1690
|
+
* anyone can read must not carry the capability to settle it.
|
|
1691
|
+
*/
|
|
1692
|
+
export interface JobLease {
|
|
1693
|
+
readonly jobId: string;
|
|
1694
|
+
readonly token: string;
|
|
1695
|
+
readonly generation: number;
|
|
1696
|
+
readonly attempt: number;
|
|
1697
|
+
/** Diagnostics only: never a guard. */
|
|
1698
|
+
readonly owner: string | null;
|
|
1699
|
+
readonly expiresAt: number;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
/** What `claim` answers: the record, and the lease to settle it with. */
|
|
1703
|
+
export interface ClaimedJob extends JobRecord {
|
|
1704
|
+
readonly lease: JobLease;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
740
1707
|
export interface JobCounts {
|
|
741
1708
|
pending: number;
|
|
742
1709
|
leased: number;
|
|
743
1710
|
done: number;
|
|
744
1711
|
failed: number;
|
|
745
1712
|
dead: number;
|
|
1713
|
+
cancelled: number;
|
|
746
1714
|
/** Pending/failed totals per kind — how a handler-less kind REPORTS. */
|
|
747
1715
|
pendingKinds: Record<string, number>;
|
|
748
1716
|
}
|
|
749
1717
|
|
|
1718
|
+
/** What became of one attempt. A LOST settlement is its own outcome:
|
|
1719
|
+
* counting it as a completion is what let a corpse report success over
|
|
1720
|
+
* work another attempt was still doing, and counting it as a failure
|
|
1721
|
+
* would burn a retry the job never spent. */
|
|
1722
|
+
export interface JobOutcome {
|
|
1723
|
+
/** `cancelled`: the attempt was taken from this worker by `cancel()`
|
|
1724
|
+
* with its lease — neither a completion, a failure nor a loss. */
|
|
1725
|
+
readonly outcome: 'completed' | 'failed' | 'lost' | 'cancelled';
|
|
1726
|
+
/** Where the loss was noticed: settling the result, or settling the
|
|
1727
|
+
* failure that came before it. Absent on the other two outcomes. */
|
|
1728
|
+
readonly phase?: 'completion' | 'failure';
|
|
1729
|
+
readonly jobId: string;
|
|
1730
|
+
readonly kind: string;
|
|
1731
|
+
readonly attempt: number;
|
|
1732
|
+
readonly generation: number;
|
|
1733
|
+
/** The refusal code a lost settlement carries (`JD2065`/`JD2066`/
|
|
1734
|
+
* `JD2067`); `null` when the lease was lost some other way. */
|
|
1735
|
+
readonly code?: string | null;
|
|
1736
|
+
readonly reason?: string;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
750
1739
|
export interface JobWorker {
|
|
751
1740
|
start(): JobWorker;
|
|
752
1741
|
/** Stop claiming, signal in-flight handlers, and wait up to `graceMs`
|
|
753
1742
|
* (JOBS-FORMAT §6): the record says whether every loop drained. */
|
|
754
1743
|
stop(options?: { graceMs?: number }): Promise<{ drained: boolean; inFlight: number }>;
|
|
755
1744
|
stats(): { claims: number; completions: number; failures: number;
|
|
756
|
-
polls: number; wakes: number; claimErrors: number; inFlight: number
|
|
1745
|
+
polls: number; wakes: number; claimErrors: number; inFlight: number;
|
|
1746
|
+
/** Leases replaced while a handler was still running. */
|
|
1747
|
+
renewals: number;
|
|
1748
|
+
/** Attempts whose lease was lost mid-flight — never a completion,
|
|
1749
|
+
* never a failure. */
|
|
1750
|
+
lostSettlements: number;
|
|
1751
|
+
/** Attempts cancelled through `cancel()` while their handler ran. */
|
|
1752
|
+
cancellations: number };
|
|
1753
|
+
/** The leases this worker holds right now: one per in-flight attempt,
|
|
1754
|
+
* each the newest that attempt has been given. */
|
|
1755
|
+
leases(): readonly JobLease[];
|
|
757
1756
|
}
|
|
758
1757
|
|
|
759
1758
|
export interface JobWorkerOptions {
|
|
1759
|
+
/**
|
|
1760
|
+
* `checkpoints` is bound to THIS attempt and follows its current
|
|
1761
|
+
* lease, so a renewal does not strand it. `signal` aborts for either
|
|
1762
|
+
* reason a handler must wind up for: the worker is stopping, or the
|
|
1763
|
+
* job is no longer this attempt's to finish — in which case the
|
|
1764
|
+
* signal's `reason` is the coded refusal that says which.
|
|
1765
|
+
*/
|
|
760
1766
|
handlers: Record<string, (payload: unknown, context: {
|
|
761
|
-
job:
|
|
1767
|
+
job: ClaimedJob;
|
|
1768
|
+
checkpoints: { load(runId: string): unknown;
|
|
1769
|
+
save(runId: string, nodeId: string, value: unknown): unknown;
|
|
1770
|
+
complete(runId: string, result: unknown): unknown };
|
|
1771
|
+
signal: AbortSignal }) => unknown>;
|
|
762
1772
|
/** A positive integer; the loops claiming concurrently. */
|
|
763
1773
|
concurrency?: number;
|
|
764
1774
|
pollInterval?: number;
|
|
765
1775
|
leaseMs?: number;
|
|
766
1776
|
owner?: string;
|
|
1777
|
+
/** Renew each attempt's lease while its handler runs (the default).
|
|
1778
|
+
* `false` for a handler that must not outlive its lease. */
|
|
1779
|
+
renew?: boolean;
|
|
1780
|
+
/** Called once per settled attempt, including the lost ones. An
|
|
1781
|
+
* observer that throws never affects the loop. */
|
|
1782
|
+
onOutcome?: (event: JobOutcome) => void;
|
|
767
1783
|
backoffBase?: number;
|
|
768
1784
|
backoffCap?: number;
|
|
769
1785
|
/** How long `stop()` waits for in-flight handlers by default. */
|
|
@@ -775,13 +1791,30 @@ export interface JobsApi {
|
|
|
775
1791
|
options?: { id?: string; runAt?: number; maxAttempts?: number }): Promise<string>;
|
|
776
1792
|
get(id: string): Promise<JobRecord | undefined>;
|
|
777
1793
|
counts(): Promise<JobCounts>;
|
|
778
|
-
/** The low-level guarded claim the worker itself uses (§3).
|
|
1794
|
+
/** The low-level guarded claim the worker itself uses (§3). It mints
|
|
1795
|
+
* the fence: a fresh token and the next generation. */
|
|
779
1796
|
claim(options: { kinds: string[]; owner: string; leaseMs?: number }):
|
|
780
|
-
Promise<
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1797
|
+
Promise<ClaimedJob | undefined>;
|
|
1798
|
+
/**
|
|
1799
|
+
* Replace a lease with a later one (§3). A handler that runs longer
|
|
1800
|
+
* than its lease renews rather than hoping; the lease it is given
|
|
1801
|
+
* back supersedes the one it passed in, which then settles nothing.
|
|
1802
|
+
*
|
|
1803
|
+
* Refuses `JD2065` (the job is not leased — unknown, or already
|
|
1804
|
+
* settled), `JD2066` (the lease was superseded) or `JD2067` (it
|
|
1805
|
+
* expired), never a silent `false`.
|
|
1806
|
+
*/
|
|
1807
|
+
renew(lease: JobLease, options?: { leaseMs?: number }): Promise<JobLease>;
|
|
1808
|
+
/** Settle the attempt this lease holds. `true`, or one of the three
|
|
1809
|
+
* coded refusals above — a caller that cannot tell "already done"
|
|
1810
|
+
* from "you are stale" guesses, and guesses wrong. */
|
|
1811
|
+
complete(lease: JobLease, result?: unknown): Promise<boolean>;
|
|
1812
|
+
fail(lease: JobLease, error: unknown): Promise<boolean>;
|
|
1813
|
+
/** The per-attempt flow checkpoint store binding (§7). Rows are
|
|
1814
|
+
* stamped with the attempt's generation: `load` reads what was
|
|
1815
|
+
* written up to it, and a settlement prunes no further, so a stale
|
|
1816
|
+
* attempt cannot erase a live one's work. */
|
|
1817
|
+
checkpointsFor(job: ClaimedJob): {
|
|
785
1818
|
load(runId: string): unknown;
|
|
786
1819
|
save(runId: string, nodeId: string, value: unknown): unknown;
|
|
787
1820
|
complete(runId: string, result: unknown): unknown;
|
|
@@ -789,6 +1822,45 @@ export interface JobsApi {
|
|
|
789
1822
|
createWorker(options: JobWorkerOptions): JobWorker;
|
|
790
1823
|
}
|
|
791
1824
|
|
|
1825
|
+
export interface JobPageOptions {
|
|
1826
|
+
/** A closed state; every job when absent. */
|
|
1827
|
+
state?: JobState;
|
|
1828
|
+
kind?: string;
|
|
1829
|
+
/** The id to continue past (keyset by id). */
|
|
1830
|
+
after?: string;
|
|
1831
|
+
/** At most this many items (default 100). */
|
|
1832
|
+
limit?: number;
|
|
1833
|
+
/** Row-boundary cancellation, as every cursor (`JD2072` / `JD2075`). */
|
|
1834
|
+
signal?: AbortSignal;
|
|
1835
|
+
deadline?: number;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
/**
|
|
1839
|
+
* Job administration (JOBS-FORMAT §10) — root-only mechanism, never a
|
|
1840
|
+
* schedule: WHEN to sweep or cancel is the host's call.
|
|
1841
|
+
*/
|
|
1842
|
+
export interface JobsAdminApi {
|
|
1843
|
+
/** A keyset cursor over the queue by id, admitted per pull under the
|
|
1844
|
+
* store gate; each item is the record `get` answers. */
|
|
1845
|
+
page(options?: JobPageOptions): QueryCursor<JobRecord>;
|
|
1846
|
+
/** Cancel a queued job by its identity, or a claimed one through its
|
|
1847
|
+
* CURRENT lease (the fence's rule): the row settles as `cancelled`,
|
|
1848
|
+
* a local attempt's handler signal aborts, and the call resolves once
|
|
1849
|
+
* that attempt wound up. `true` when this call cancelled it, `false`
|
|
1850
|
+
* when it already was; `JD2065`/`JD2066`/`JD2067`/`JD2068` as a
|
|
1851
|
+
* settling call refuses. */
|
|
1852
|
+
cancel(id: string, options?: { lease?: JobLease; signal?: AbortSignal; deadline?: number }): Promise<boolean>;
|
|
1853
|
+
/** Return a failed, dead, cancelled or lease-expired job to the queue
|
|
1854
|
+
* with its attempt history intact; `false` when it already was
|
|
1855
|
+
* pending; a live lease refuses `JD2068`, unknown or done `JD2065`. */
|
|
1856
|
+
requeue(id: string, options?: { signal?: AbortSignal; deadline?: number }): Promise<boolean>;
|
|
1857
|
+
/** Delete settled jobs (done, dead, cancelled) last changed before
|
|
1858
|
+
* `settledBefore`, oldest first, at most `limit`, with their
|
|
1859
|
+
* checkpoints; a second identical sweep answers `{ removed: 0 }`. */
|
|
1860
|
+
sweep(options: { settledBefore: number; limit?: number; signal?: AbortSignal; deadline?: number }):
|
|
1861
|
+
Promise<{ removed: number }>;
|
|
1862
|
+
}
|
|
1863
|
+
|
|
792
1864
|
export interface JobsOptions {
|
|
793
1865
|
maxAttempts?: number;
|
|
794
1866
|
leaseMs?: number;
|
|
@@ -809,14 +1881,21 @@ export declare function createDagJobRunner(store: Store, options: {
|
|
|
809
1881
|
pollInterval?: number;
|
|
810
1882
|
leaseMs?: number;
|
|
811
1883
|
owner?: string;
|
|
1884
|
+
renew?: boolean;
|
|
1885
|
+
onOutcome?: (event: JobOutcome) => void;
|
|
812
1886
|
backoffBase?: number;
|
|
813
1887
|
backoffCap?: number;
|
|
814
1888
|
stopGraceMs?: number;
|
|
815
1889
|
}): JobWorker;
|
|
816
1890
|
|
|
1891
|
+
/** The checkpoint row a run's identity lives in — the workflow revision
|
|
1892
|
+
* and a hash of the input a resume must agree with (`JD2069` when it
|
|
1893
|
+
* does not). Pruned with the run it belongs to. */
|
|
1894
|
+
export declare const RUN_IDENTITY_NODE: string;
|
|
1895
|
+
|
|
817
1896
|
export declare function createJobEngine(options: {
|
|
818
1897
|
connection: unknown; now?: () => number; random?: () => number;
|
|
819
|
-
defaults?: JobsOptions }): unknown;
|
|
1898
|
+
defaults?: JobsOptions; runtime?: Partial<Runtime> }): unknown;
|
|
820
1899
|
export declare const JOBS_TABLE: string;
|
|
821
1900
|
export declare const JOB_CHECKPOINTS_TABLE: string;
|
|
822
1901
|
export declare const JOB_DEFAULTS: Readonly<{
|
|
@@ -826,3 +1905,55 @@ export declare const JOB_DEFAULTS: Readonly<{
|
|
|
826
1905
|
export declare function describeValue(value: unknown): string;
|
|
827
1906
|
/** A job result as the queue stores it: JSON text, or the reason it could not be. */
|
|
828
1907
|
export declare function serializeResult(value: unknown): unknown;
|
|
1908
|
+
|
|
1909
|
+
/** Transport-neutral, net logical operations in a single transaction. */
|
|
1910
|
+
export interface ReplicationOperation {
|
|
1911
|
+
table: string;
|
|
1912
|
+
key: string;
|
|
1913
|
+
before: Record<string, unknown> | null;
|
|
1914
|
+
after: Record<string, unknown> | null;
|
|
1915
|
+
}
|
|
1916
|
+
export type ReplicationFrontier = Record<string, number>;
|
|
1917
|
+
export interface ReplicationEnvelope {
|
|
1918
|
+
$replication: '0.1'; replica: string; seq: number; model: string;
|
|
1919
|
+
frontier: ReplicationFrontier; operations: ReplicationOperation[];
|
|
1920
|
+
}
|
|
1921
|
+
export interface ReplicationConflict {
|
|
1922
|
+
envelope: string; table: string; key: string;
|
|
1923
|
+
base: Record<string, unknown> | null;
|
|
1924
|
+
local: { value: Record<string, unknown> | null; frontier: ReplicationFrontier };
|
|
1925
|
+
remote: { value: Record<string, unknown> | null; replica: string; seq: number; frontier: ReplicationFrontier };
|
|
1926
|
+
resolver: string | null;
|
|
1927
|
+
resolution: { action: 'local' | 'remote' | 'merged'; value: Record<string, unknown> | null } | null;
|
|
1928
|
+
}
|
|
1929
|
+
export interface ReplicationOptions {
|
|
1930
|
+
replica: string; retention?: number; maxOperations?: number; maxBytes?: number;
|
|
1931
|
+
resolver?: { id: string; resolve(conflict: Readonly<ReplicationConflict>):
|
|
1932
|
+
{ action: 'local' | 'remote' } | { action: 'merged'; value: Record<string, unknown> | null } };
|
|
1933
|
+
}
|
|
1934
|
+
export interface ReplicationRequest { signal?: AbortSignal; deadline?: number }
|
|
1935
|
+
export interface Replication {
|
|
1936
|
+
snapshot(request?: ReplicationRequest): Promise<ReplicationSnapshot>;
|
|
1937
|
+
reset(snapshot: ReplicationSnapshot, request?: ReplicationRequest): Promise<{ status: 'reset'; frontier: ReplicationFrontier }>;
|
|
1938
|
+
frontier(): Promise<ReplicationFrontier>;
|
|
1939
|
+
apply(envelope: ReplicationEnvelope, request?: ReplicationRequest): Promise<{
|
|
1940
|
+
status: 'applied' | 'duplicate' | 'conflict'; frontier: ReplicationFrontier; conflicts: ReplicationConflict[];
|
|
1941
|
+
}>;
|
|
1942
|
+
page(request?: ReplicationRequest & { after?: number; limit?: number; maxBytes?: number }): Promise<{
|
|
1943
|
+
items: ReplicationEnvelope[]; earliestAvailable: number | null; highWatermark: number;
|
|
1944
|
+
next?: number; bytes?: number; hasMore: boolean; resetRequired: boolean;
|
|
1945
|
+
}>;
|
|
1946
|
+
conflicts(request?: ReplicationRequest & { limit?: number; maxBytes?: number }): Promise<ReplicationConflict[]>;
|
|
1947
|
+
}
|
|
1948
|
+
export declare const REPLICATION_VERSION: '0.1';
|
|
1949
|
+
export declare const REPLICATION_DEFAULTS: Readonly<{ retention: number; maxOperations: number; maxBytes: number }>;
|
|
1950
|
+
export declare function normalizeFrontier(value: unknown): ReplicationFrontier;
|
|
1951
|
+
export declare function replicationIdentity(replica: string, seq: number): string;
|
|
1952
|
+
export declare function normalizeReplication(document: unknown): ReplicationEnvelope;
|
|
1953
|
+
export declare function encodeReplication(document: unknown): string;
|
|
1954
|
+
export interface ReplicationSnapshot {
|
|
1955
|
+
$replicationSnapshot: '0.1'; model: string; frontier: ReplicationFrontier;
|
|
1956
|
+
rows: { table: string; key: string; value: Record<string, unknown> | null; frontier: ReplicationFrontier }[];
|
|
1957
|
+
receipts: ReplicationEnvelope[];
|
|
1958
|
+
}
|
|
1959
|
+
export declare function normalizeReplicationSnapshot(document: unknown): ReplicationSnapshot;
|