@minnowdb/core 0.9.0 → 0.10.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.
Files changed (40) hide show
  1. package/dist/engine/auto-store.d.ts +40 -0
  2. package/dist/engine/auto-store.js +115 -0
  3. package/dist/engine/buffered-writer.d.ts +2 -0
  4. package/dist/engine/buffered-writer.js +15 -2
  5. package/dist/engine/client.d.ts +55 -6
  6. package/dist/engine/client.js +155 -40
  7. package/dist/engine/database.d.ts +15 -1
  8. package/dist/engine/database.js +1085 -227
  9. package/dist/engine/errors.d.ts +61 -2
  10. package/dist/engine/errors.js +116 -3
  11. package/dist/engine/index.d.ts +1 -0
  12. package/dist/engine/index.js +2 -0
  13. package/dist/engine/live.d.ts +24 -1
  14. package/dist/engine/live.js +33 -9
  15. package/dist/engine/scope-write-set.js +36 -0
  16. package/dist/engine/worker-auto.d.ts +1 -0
  17. package/dist/engine/worker-auto.js +3 -0
  18. package/dist/engine/worker-host.d.ts +2 -1
  19. package/dist/engine/worker-host.js +17 -1
  20. package/dist/engine/worker-server.d.ts +53 -1
  21. package/dist/engine/worker-server.js +118 -14
  22. package/dist/engine/worker-store-auto.js +36 -0
  23. package/dist/engine/worker-store-opfs.js +3 -2
  24. package/dist/engine/write-coordinator.js +24 -2
  25. package/dist/storage/indexeddb.js +494 -207
  26. package/dist/storage/opfs/leader.js +201 -14
  27. package/dist/storage/opfs/rpc.js +23 -43
  28. package/dist/storage/opfs/store.d.ts +20 -0
  29. package/dist/storage/opfs/store.js +501 -70
  30. package/dist/storage/toolkit/record-core.js +67 -38
  31. package/dist/storage/toolkit/wire.d.ts +1 -1
  32. package/dist/storage/toolkit/wire.js +1 -1
  33. package/dist/storage/types.d.ts +29 -8
  34. package/dist/storage/types.js +27 -16
  35. package/dist/testing/opfs-shim.js +14 -6
  36. package/dist/transactions/index.d.ts +12 -0
  37. package/dist/transactions/index.js +83 -23
  38. package/dist/worker-protocol/index.d.ts +50 -2
  39. package/dist/worker-protocol/index.js +106 -4
  40. package/package.json +7 -2
@@ -1,5 +1,5 @@
1
1
  import { dateIsoString, dateMilliseconds } from "../date-value.js";
2
- import { assertTransactionArtifactBatchLimits, assertTransactionArtifactJournalLimits, GarbageCollectionJobConflictError, LeaseConflictError, LeaseExpiredError, MAX_LEVEL_ZERO_SEGMENTS, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_LEASE_TTL_MS, MAX_TRANSACTION_STAGE_BLOCKS, MAX_TRANSACTION_STAGE_BYTES, MAX_TRANSACTION_STAGE_SEGMENTS, MAX_TRANSACTION_COMMIT_DELTA_BYTES, MAX_TRANSACTION_COMMIT_DELTA_ENTRIES, transactionCommitDeltaRetainedBytes, SnapshotManifestMissingError, TransactionRecordConflictError, WriteConflictError } from "../storage/types.js";
2
+ import { assertTransactionArtifactBatchLimits, GarbageCollectionJobConflictError, LeaseConflictError, LeaseExpiredError, MAX_LEVEL_ZERO_SEGMENTS, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_LEASE_TTL_MS, MAX_TRANSACTION_STAGE_BLOCKS, MAX_TRANSACTION_STAGE_BYTES, MAX_TRANSACTION_STAGE_SEGMENTS, MAX_TRANSACTION_COMMIT_DELTA_BYTES, MAX_TRANSACTION_COMMIT_DELTA_ENTRIES, transactionCommitDeltaRetainedBytes, SnapshotManifestMissingError, TransactionRecordConflictError, WriteConflictError } from "../storage/types.js";
3
3
  const DEFAULT_TRANSACTION_TTL_MS = 3e4;
4
4
  class TransactionClosedError extends Error {
5
5
  transactionId;
@@ -118,6 +118,7 @@ class DatabaseTransaction {
118
118
  #deferredBlocks = [];
119
119
  #deferredSegments = [];
120
120
  #knownSegments = /* @__PURE__ */ new Map();
121
+ #stagedSegmentsView;
121
122
  #persisted;
122
123
  #coalesceArtifacts;
123
124
  #snapshotLease;
@@ -156,14 +157,56 @@ class DatabaseTransaction {
156
157
  get snapshotVersion() {
157
158
  return this.#record.snapshotVersion;
158
159
  }
160
+ #journalView;
161
+ #journal() {
162
+ const view = this.#journalView;
163
+ if (view?.record === this.#record && view.deferredBlocks === this.#deferredBlocks.length && view.deferredSegments === this.#deferredSegments.length) {
164
+ return view;
165
+ }
166
+ const journaledBlocks = view?.record === this.#record ? view.journaledBlocks : new Set(this.#record.pendingBlockIds);
167
+ const next = {
168
+ record: this.#record,
169
+ deferredBlocks: this.#deferredBlocks.length,
170
+ deferredSegments: this.#deferredSegments.length,
171
+ blockIds: [...this.#record.pendingBlockIds, ...this.#deferredBlocks.map((block) => block.id)],
172
+ segmentIds: [
173
+ ...this.#record.pendingSegmentIds,
174
+ ...this.#deferredSegments.map((segment) => segment.id)
175
+ ],
176
+ journaledBlocks
177
+ };
178
+ this.#journalView = next;
179
+ return next;
180
+ }
181
+ #journalAppended(previous, blockIds) {
182
+ const view = this.#journalView;
183
+ if (view?.record !== previous || this.#record.pendingBlockIds.length !== previous.pendingBlockIds.length + blockIds.length) {
184
+ this.#journalView = void 0;
185
+ return;
186
+ }
187
+ for (const id of blockIds)
188
+ view.journaledBlocks.add(id);
189
+ view.record = this.#record;
190
+ view.deferredBlocks = -1;
191
+ }
159
192
  get pendingBlockIds() {
160
- return [...this.#record.pendingBlockIds, ...this.#deferredBlocks.map((block) => block.id)];
193
+ return [...this.#journal().blockIds];
161
194
  }
162
195
  get pendingSegmentIds() {
163
- return [
164
- ...this.#record.pendingSegmentIds,
165
- ...this.#deferredSegments.map((segment) => segment.id)
166
- ];
196
+ return [...this.#journal().segmentIds];
197
+ }
198
+ hasPendingBlock(id) {
199
+ return this.#journal().journaledBlocks.has(id) || this.#deferredBlocks.some((block) => block.id === id);
200
+ }
201
+ get stagedSegments() {
202
+ this.#stagedSegmentsView ??= [...this.#knownSegments.values()];
203
+ return this.#stagedSegmentsView;
204
+ }
205
+ get pendingBlockCount() {
206
+ return this.#record.pendingBlockIds.length + this.#deferredBlocks.length;
207
+ }
208
+ get pendingSegmentCount() {
209
+ return this.#record.pendingSegmentIds.length + this.#deferredSegments.length;
167
210
  }
168
211
  get deferredSegments() {
169
212
  return structuredClone(this.#deferredSegments);
@@ -191,7 +234,7 @@ class DatabaseTransaction {
191
234
  await this.#renewOwnership(true);
192
235
  }
193
236
  get stagedWorkCount() {
194
- return this.pendingBlockIds.length + this.pendingSegmentIds.length + this.#uniqueKeyChanges.length + this.#ftsChanges.size + this.#compactionSourceBlockIds.size;
237
+ return this.pendingBlockCount + this.pendingSegmentCount + this.#uniqueKeyChanges.length + this.#ftsChanges.size + this.#compactionSourceBlockIds.size;
195
238
  }
196
239
  checkpoint() {
197
240
  this.#assertActive();
@@ -218,9 +261,9 @@ class DatabaseTransaction {
218
261
  bytes = checkpointByteSum(bytes, 16 + value.length * 2);
219
262
  };
220
263
  addString(this.id);
221
- for (const id of this.pendingBlockIds)
264
+ for (const id of this.#journal().blockIds)
222
265
  addString(id);
223
- for (const id of this.pendingSegmentIds)
266
+ for (const id of this.#journal().segmentIds)
224
267
  addString(id);
225
268
  for (const change of this.#uniqueKeyChanges) {
226
269
  addString(change.tableId);
@@ -258,9 +301,11 @@ class DatabaseTransaction {
258
301
  const segmentPrefix = checkpoint.pendingSegmentIds;
259
302
  const retainedBlocks = new Set(blockPrefix);
260
303
  const retainedSegments = new Set(segmentPrefix);
261
- const currentBlockIds = this.pendingBlockIds;
262
- const currentSegmentIds = this.pendingSegmentIds;
263
- if (blockPrefix.some((id) => !currentBlockIds.includes(id)) || segmentPrefix.some((id) => !currentSegmentIds.includes(id))) {
304
+ const currentBlockIds = this.#journal().blockIds;
305
+ const currentSegmentIds = this.#journal().segmentIds;
306
+ const currentBlocks = new Set(currentBlockIds);
307
+ const currentSegments = new Set(currentSegmentIds);
308
+ if (blockPrefix.some((id) => !currentBlocks.has(id)) || segmentPrefix.some((id) => !currentSegments.has(id))) {
264
309
  throw new TypeError("A transaction checkpoint is no longer reachable");
265
310
  }
266
311
  const removedBlockIds = currentBlockIds.filter((id) => !retainedBlocks.has(id));
@@ -290,6 +335,7 @@ class DatabaseTransaction {
290
335
  }
291
336
  for (const id of removedSegmentIds)
292
337
  this.#knownSegments.delete(id);
338
+ this.#stagedSegmentsView = void 0;
293
339
  this.#uniqueKeyChanges.splice(0);
294
340
  this.#ftsChanges.clear();
295
341
  this.#commitDeltaBytes = 0;
@@ -319,20 +365,23 @@ class DatabaseTransaction {
319
365
  const deferred = this.#deferredBlocks.find((block) => block.id === id);
320
366
  if (deferred !== void 0)
321
367
  return new Uint8Array(deferred.bytes);
322
- if (this.#record.pendingBlockIds.includes(id))
368
+ if (this.#journal().journaledBlocks.has(id))
323
369
  return this.store.getBlock(id);
324
370
  return (await this.snapshot()).getBlock(id);
325
371
  }
326
372
  #assertProspectiveArtifactJournal(blocks, segments) {
327
- const blockIds = new Set(this.pendingBlockIds);
328
- const segmentIds = new Set(this.pendingSegmentIds);
373
+ const journal = this.#journal();
374
+ const blockIds = /* @__PURE__ */ new Set();
375
+ const deferredBlocks = new Set(this.#deferredBlocks.map((block) => block.id));
329
376
  for (const block of blocks) {
330
377
  if (block.id.length === 0)
331
378
  throw new TypeError("Block ID cannot be empty");
332
- if (blockIds.has(block.id))
379
+ if (journal.journaledBlocks.has(block.id) || deferredBlocks.has(block.id) || blockIds.has(block.id)) {
333
380
  throw new Error(`Block already exists: ${block.id}`);
381
+ }
334
382
  blockIds.add(block.id);
335
383
  }
384
+ const segmentIds = new Set(journal.segmentIds);
336
385
  for (const segment of segments) {
337
386
  if (segment.id.length === 0)
338
387
  throw new TypeError("Segment ID cannot be empty");
@@ -340,7 +389,6 @@ class DatabaseTransaction {
340
389
  throw new Error(`Segment already exists: ${segment.id}`);
341
390
  segmentIds.add(segment.id);
342
391
  }
343
- assertTransactionArtifactJournalLimits([...blockIds], [...segmentIds]);
344
392
  }
345
393
  async #stageArtifactBatch(blocks, segments) {
346
394
  if (blocks.length === 0 && segments.length === 0)
@@ -348,6 +396,7 @@ class DatabaseTransaction {
348
396
  assertTransactionArtifactBatchLimits(blocks, segments);
349
397
  await this.#ensurePersisted();
350
398
  await this.#renewOwnership();
399
+ const previous = this.#record;
351
400
  try {
352
401
  this.#record = await this.store.stageTransactionArtifacts({
353
402
  transactionId: this.id,
@@ -359,6 +408,7 @@ class DatabaseTransaction {
359
408
  } catch (error) {
360
409
  await this.#recoverStagedAcknowledgement(error, blocks, segments);
361
410
  }
411
+ this.#journalAppended(previous, blocks.map((block) => block.id));
362
412
  }
363
413
  async stageBlock(id, bytes) {
364
414
  return this.stageBlocks([{ id, bytes }]);
@@ -376,7 +426,7 @@ class DatabaseTransaction {
376
426
  throw new Error(`Segment ${segment.id} belongs to another transaction`);
377
427
  }
378
428
  }
379
- const ordinalBase = this.pendingSegmentIds.length;
429
+ const ordinalBase = this.pendingSegmentCount;
380
430
  const ordered = segments.map((segment, index) => ({
381
431
  ...segment,
382
432
  commitOrdinal: ordinalBase + index
@@ -392,6 +442,7 @@ class DatabaseTransaction {
392
442
  this.#deferredSegments.push(...structuredClone(ordered));
393
443
  for (const segment of ordered)
394
444
  this.#knownSegments.set(segment.id, structuredClone(segment));
445
+ this.#stagedSegmentsView = void 0;
395
446
  for (const segment of ordered)
396
447
  this.#changedTableIds.add(segment.tableId);
397
448
  return;
@@ -402,6 +453,7 @@ class DatabaseTransaction {
402
453
  }
403
454
  for (const segment of ordered)
404
455
  this.#knownSegments.set(segment.id, structuredClone(segment));
456
+ this.#stagedSegmentsView = void 0;
405
457
  for (const segment of ordered)
406
458
  this.#changedTableIds.add(segment.tableId);
407
459
  }
@@ -412,6 +464,17 @@ class DatabaseTransaction {
412
464
  throw new Error(`Segment ${segment.id} belongs to another transaction`);
413
465
  }
414
466
  }
467
+ if (this.#deferredBlocks.length > 0 || this.#deferredSegments.length > 0) {
468
+ const combined = transactionArtifactBatches([...this.#deferredBlocks, ...blocks], [...this.#deferredSegments, ...segments]);
469
+ if (combined.length === 1) {
470
+ blocks = [...this.#deferredBlocks, ...blocks];
471
+ segments = [...this.#deferredSegments, ...segments];
472
+ this.#deferredBlocks.length = 0;
473
+ this.#deferredSegments.length = 0;
474
+ } else {
475
+ await this.#persistDeferredArtifacts();
476
+ }
477
+ }
415
478
  const pendingBlockIds = new Set(this.#record.pendingBlockIds);
416
479
  const pendingSegmentIds = new Set(this.#record.pendingSegmentIds);
417
480
  await this.#assertRetainedArtifactsUnchanged(blocks.filter((block) => pendingBlockIds.has(block.id)), segments.filter((segment) => pendingSegmentIds.has(segment.id)));
@@ -446,6 +509,7 @@ class DatabaseTransaction {
446
509
  const ftsChanges = this.#materializedFtsChanges();
447
510
  for (const segment of ordered)
448
511
  this.#knownSegments.set(segment.id, structuredClone(segment));
512
+ this.#stagedSegmentsView = void 0;
449
513
  for (const segment of ordered)
450
514
  this.#changedTableIds.add(segment.tableId);
451
515
  try {
@@ -496,7 +560,6 @@ class DatabaseTransaction {
496
560
  if (additions.some((id) => id.length === 0)) {
497
561
  throw new TypeError("Block ID cannot be empty");
498
562
  }
499
- assertTransactionArtifactJournalLimits([...this.#record.pendingBlockIds, ...additions], this.#record.pendingSegmentIds);
500
563
  for (const id of additions) {
501
564
  if (await this.store.getBlock(id) === void 0) {
502
565
  throw new Error(`Cannot stage a missing existing block: ${id}`);
@@ -530,10 +593,6 @@ class DatabaseTransaction {
530
593
  if (record.commitOrdinal !== this.#record.pendingSegmentIds.length) {
531
594
  throw new Error(`Existing segment ${segmentId} is not the next journal ordinal`);
532
595
  }
533
- assertTransactionArtifactJournalLimits(this.#record.pendingBlockIds, [
534
- ...this.#record.pendingSegmentIds,
535
- segmentId
536
- ]);
537
596
  this.#registerLevelZeroSegments([record]);
538
597
  this.#changedTableIds.add(record.tableId);
539
598
  await this.#ensurePersisted();
@@ -821,6 +880,7 @@ class DatabaseTransaction {
821
880
  this.#deferredBlocks.length = 0;
822
881
  this.#deferredSegments.length = 0;
823
882
  this.#knownSegments.clear();
883
+ this.#stagedSegmentsView = void 0;
824
884
  this.#record = { ...this.#record, status: "aborted", updatedAt: dateIsoString(this.now()) };
825
885
  this.#stopHeartbeat();
826
886
  await this.#releaseSnapshotLease().catch(() => void 0);
@@ -40,15 +40,63 @@ export type RpcResponse = {
40
40
  };
41
41
  /**
42
42
  * A structured-clone-safe error carrying the constructor name and every cloneable own property,
43
- * so typed engine errors survive the channel and can be rehydrated for instanceof checks.
43
+ * so typed engine errors survive the channel and can be rehydrated for instanceof checks. The
44
+ * `cause` chain travels to a bounded depth, and a platform exception keeps its `DOMException`
45
+ * identity, so a quota refusal is still a `DOMException` named `QuotaExceededError` on the
46
+ * other side.
44
47
  */
45
48
  export interface SerializedError {
46
49
  name: string;
47
50
  message: string;
48
51
  stack?: string;
49
52
  props?: Record<string, unknown>;
53
+ /** True for platform exceptions, which rehydrate as `DOMException` rather than `Error`. */
54
+ domException?: true;
55
+ cause?: SerializedError;
50
56
  }
51
- export declare function serializeError(error: unknown): SerializedError;
57
+ /** How many `cause` links a serialized error carries before the chain is cut. */
58
+ export declare const MAX_SERIALIZED_CAUSE_DEPTH = 8;
59
+ export declare function serializeError(error: unknown, depth?: number): SerializedError;
60
+ /** Constructors whose prototype a rehydrated error adopts, keyed by the `name` they carry. */
61
+ export type ErrorRegistry = ReadonlyMap<string, new (...args: never[]) => Error>;
62
+ /**
63
+ * Rebuilds an `Error` from its serialized form: a registry hit adopts that class's prototype,
64
+ * a platform exception becomes a `DOMException`, a built-in subclass name (`TypeError`) keeps
65
+ * its built-in prototype, and anything else is a plain `Error` carrying the original name.
66
+ * Own properties and the `cause` chain are restored; the stack stays the worker's.
67
+ */
68
+ export declare function rehydrateError(serialized: SerializedError, registry: ErrorRegistry): Error;
69
+ /** The event-frame handle id that carries worker diagnostics. Never issued for a real handle. */
70
+ export declare const WORKER_DIAGNOSTIC_HANDLE_ID = "$worker";
71
+ export type WorkerErrorKind =
72
+ /** A script error nobody caught, in a timer, a channel listener, or another callback. */
73
+ "uncaught"
74
+ /** A promise rejected with no handler attached. */
75
+ | "unhandled-rejection"
76
+ /** A frame the worker could not deserialize. */
77
+ | "messageerror"
78
+ /** Background maintenance: a checkpoint, cleanup, or collection step that failed. */
79
+ | "maintenance"
80
+ /** Multi-tab coordination: an election, handover, or served request that failed. */
81
+ | "coordination";
82
+ export interface WorkerErrorReport {
83
+ kind: WorkerErrorKind;
84
+ /** Where in the worker it happened, for a log line: "opfs election", "auto collection". */
85
+ context: string;
86
+ error: SerializedError;
87
+ }
88
+ export declare function workerErrorEvent(report: WorkerErrorReport): RpcResponse;
89
+ /**
90
+ * How often the worker tells the client that a call is still being worked on. The client's
91
+ * request deadline counts silence, not wall time, so a large batch write is not cut off — and
92
+ * its client left permanently failed — merely for being large.
93
+ */
94
+ export declare const WORKER_KEEPALIVE_INTERVAL_MS = 5000;
95
+ /** The shortest pace a client may ask for; below this the reports would be the load. */
96
+ export declare const MIN_WORKER_KEEPALIVE_INTERVAL_MS = 100;
97
+ /** A keepalive for one in-flight request: the worker is alive and still holds it. */
98
+ export declare function workerKeepaliveEvent(requestId: string): RpcResponse;
99
+ export declare function isWorkerErrorReport(value: unknown): value is WorkerErrorReport;
52
100
  export declare function rpcResult(requestId: string, result: unknown): RpcResponse;
53
101
  export declare function rpcFailure(requestId: string, error: unknown): RpcResponse;
54
102
  export declare function rpcEvent(handleId: string, event: string, payload: unknown): RpcResponse;
@@ -1,12 +1,21 @@
1
1
  const protocolVersion = 7;
2
2
  const MAX_DATABASE_RPC_IN_FLIGHT = 256;
3
- function serializeError(error) {
3
+ const MAX_SERIALIZED_CAUSE_DEPTH = 8;
4
+ function serializeError(error, depth = 0) {
5
+ if (typeof DOMException !== "undefined" && error instanceof DOMException) {
6
+ return {
7
+ name: error.name,
8
+ message: error.message,
9
+ domException: true,
10
+ ...typeof error.stack === "string" ? { stack: error.stack } : {}
11
+ };
12
+ }
4
13
  if (!(error instanceof Error)) {
5
14
  return { name: "Error", message: String(error) };
6
15
  }
7
16
  const props = {};
8
17
  for (const key of Object.keys(error)) {
9
- if (key === "name" || key === "message" || key === "stack")
18
+ if (key === "name" || key === "message" || key === "stack" || key === "cause")
10
19
  continue;
11
20
  const value = error[key];
12
21
  try {
@@ -15,13 +24,98 @@ function serializeError(error) {
15
24
  } catch {
16
25
  }
17
26
  }
27
+ const cause = error.cause === void 0 || depth >= MAX_SERIALIZED_CAUSE_DEPTH ? void 0 : serializeError(error.cause, depth + 1);
18
28
  return {
19
29
  name: error.name,
20
30
  message: error.message,
21
31
  ...error.stack === void 0 ? {} : { stack: error.stack },
22
- ...Object.keys(props).length === 0 ? {} : { props }
32
+ ...Object.keys(props).length === 0 ? {} : { props },
33
+ ...cause === void 0 ? {} : { cause }
23
34
  };
24
35
  }
36
+ const builtinErrorNames = /* @__PURE__ */ new Set([
37
+ "TypeError",
38
+ "RangeError",
39
+ "SyntaxError",
40
+ "ReferenceError",
41
+ "EvalError",
42
+ "URIError",
43
+ "AggregateError"
44
+ ]);
45
+ function rehydrateError(serialized, registry) {
46
+ const cause = serialized.cause === void 0 ? void 0 : rehydrateError(serialized.cause, registry);
47
+ if (serialized.domException === true) {
48
+ const exception = new DOMException(serialized.message, serialized.name);
49
+ if (cause !== void 0) {
50
+ Object.defineProperty(exception, "cause", {
51
+ value: cause,
52
+ writable: true,
53
+ configurable: true
54
+ });
55
+ }
56
+ return exception;
57
+ }
58
+ const constructor = registry.get(serialized.name);
59
+ let error;
60
+ if (constructor !== void 0) {
61
+ error = Object.create(constructor.prototype);
62
+ } else if (builtinErrorNames.has(serialized.name)) {
63
+ const builtin = globalThis[serialized.name];
64
+ error = typeof builtin === "function" ? Object.create(builtin.prototype) : new Error(serialized.message);
65
+ } else {
66
+ error = new Error(serialized.message);
67
+ }
68
+ Object.defineProperty(error, "message", {
69
+ value: serialized.message,
70
+ writable: true,
71
+ configurable: true
72
+ });
73
+ Object.defineProperty(error, "name", {
74
+ value: serialized.name,
75
+ writable: true,
76
+ configurable: true
77
+ });
78
+ if (serialized.stack !== void 0) {
79
+ Object.defineProperty(error, "stack", {
80
+ value: serialized.stack,
81
+ writable: true,
82
+ configurable: true
83
+ });
84
+ }
85
+ if (cause !== void 0) {
86
+ Object.defineProperty(error, "cause", { value: cause, writable: true, configurable: true });
87
+ }
88
+ if (serialized.props !== void 0)
89
+ Object.assign(error, serialized.props);
90
+ return error;
91
+ }
92
+ const WORKER_DIAGNOSTIC_HANDLE_ID = "$worker";
93
+ function workerErrorEvent(report) {
94
+ return rpcEvent(WORKER_DIAGNOSTIC_HANDLE_ID, "error", report);
95
+ }
96
+ const WORKER_KEEPALIVE_INTERVAL_MS = 5e3;
97
+ const MIN_WORKER_KEEPALIVE_INTERVAL_MS = 100;
98
+ function workerKeepaliveEvent(requestId) {
99
+ return {
100
+ version: protocolVersion,
101
+ requestId,
102
+ kind: "rpc-event",
103
+ handleId: WORKER_DIAGNOSTIC_HANDLE_ID,
104
+ event: "keepalive",
105
+ payload: null
106
+ };
107
+ }
108
+ function isWorkerErrorReport(value) {
109
+ if (typeof value !== "object" || value === null)
110
+ return false;
111
+ const report = value;
112
+ if (typeof report.kind !== "string" || typeof report.context !== "string")
113
+ return false;
114
+ if (typeof report.error !== "object" || report.error === null)
115
+ return false;
116
+ const error = report.error;
117
+ return typeof error.name === "string" && typeof error.message === "string";
118
+ }
25
119
  function rpcResult(requestId, result) {
26
120
  return { version: protocolVersion, requestId, kind: "rpc-result", result };
27
121
  }
@@ -69,11 +163,19 @@ function parseRpcResponse(value) {
69
163
  }
70
164
  export {
71
165
  MAX_DATABASE_RPC_IN_FLIGHT,
166
+ MAX_SERIALIZED_CAUSE_DEPTH,
167
+ MIN_WORKER_KEEPALIVE_INTERVAL_MS,
168
+ WORKER_DIAGNOSTIC_HANDLE_ID,
169
+ WORKER_KEEPALIVE_INTERVAL_MS,
170
+ isWorkerErrorReport,
72
171
  parseRpcRequest,
73
172
  parseRpcResponse,
74
173
  protocolVersion,
174
+ rehydrateError,
75
175
  rpcEvent,
76
176
  rpcFailure,
77
177
  rpcResult,
78
- serializeError
178
+ serializeError,
179
+ workerErrorEvent,
180
+ workerKeepaliveEvent
79
181
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minnowdb/core",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "A columnar SQL database for the browser: PostgreSQL-style SQL over durable IndexedDB or OPFS data, with no server or WebAssembly module.",
5
5
  "license": "MIT",
6
6
  "author": "Eric Wilhite",
@@ -29,7 +29,8 @@
29
29
  "./dist/engine/worker.js",
30
30
  "./dist/engine/worker-indexeddb.js",
31
31
  "./dist/engine/worker-opfs.js",
32
- "./dist/engine/worker-memory.js"
32
+ "./dist/engine/worker-memory.js",
33
+ "./dist/engine/worker-auto.js"
33
34
  ],
34
35
  "scripts": {
35
36
  "prepack": "node ../../scripts/prepare-package.mjs --strip-comments"
@@ -79,6 +80,10 @@
79
80
  "types": "./dist/engine/worker-memory.d.ts",
80
81
  "default": "./dist/engine/worker-memory.js"
81
82
  },
83
+ "./worker/auto": {
84
+ "types": "./dist/engine/worker-auto.d.ts",
85
+ "default": "./dist/engine/worker-auto.js"
86
+ },
82
87
  "./worker-host": {
83
88
  "types": "./dist/engine/worker-host.d.ts",
84
89
  "default": "./dist/engine/worker-host.js"