@workglow/indexeddb 0.2.31 → 0.2.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/job-queue/IndexedDbQueueStorage.d.ts +16 -11
- package/dist/job-queue/IndexedDbQueueStorage.d.ts.map +1 -1
- package/dist/job-queue/IndexedDbRateLimiterStorage.d.ts +15 -4
- package/dist/job-queue/IndexedDbRateLimiterStorage.d.ts.map +1 -1
- package/dist/job-queue/browser.js +399 -351
- package/dist/job-queue/browser.js.map +9 -6
- package/dist/job-queue/common.d.ts +3 -0
- package/dist/job-queue/common.d.ts.map +1 -1
- package/dist/job-queue/node.js +399 -351
- package/dist/job-queue/node.js.map +9 -6
- package/dist/migrations/IndexedDbMigrationRunner.d.ts +93 -0
- package/dist/migrations/IndexedDbMigrationRunner.d.ts.map +1 -0
- package/dist/migrations/indexedDbQueueMigrations.d.ts +24 -0
- package/dist/migrations/indexedDbQueueMigrations.d.ts.map +1 -0
- package/dist/migrations/indexedDbRateLimiterMigrations.d.ts +37 -0
- package/dist/migrations/indexedDbRateLimiterMigrations.d.ts.map +1 -0
- package/dist/storage/IndexedDbTable.d.ts.map +1 -1
- package/dist/storage/IndexedDbTabularMigrationApplier.d.ts +84 -0
- package/dist/storage/IndexedDbTabularMigrationApplier.d.ts.map +1 -0
- package/dist/storage/IndexedDbTabularStorage.d.ts +21 -2
- package/dist/storage/IndexedDbTabularStorage.d.ts.map +1 -1
- package/dist/storage/browser.js +472 -30
- package/dist/storage/browser.js.map +8 -5
- package/dist/storage/common.d.ts +3 -0
- package/dist/storage/common.d.ts.map +1 -1
- package/dist/storage/node.js +472 -30
- package/dist/storage/node.js.map +8 -5
- package/dist/storage/openIdb.d.ts +19 -0
- package/dist/storage/openIdb.d.ts.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { type IMigration, type IMigrationRunner, type RunMigrationsOptions } from "@workglow/storage";
|
|
7
|
+
/**
|
|
8
|
+
* Context handed to an IndexedDB migration's `up()` body. IDB's spec only
|
|
9
|
+
* permits schema changes (createObjectStore, createIndex, etc.) inside an
|
|
10
|
+
* `onupgradeneeded` callback, so migrations receive both the {@link IDBDatabase}
|
|
11
|
+
* and the version-change {@link IDBTransaction} active during that callback.
|
|
12
|
+
*
|
|
13
|
+
* `up()` MUST be synchronous — IDB upgrade transactions auto-commit as soon as
|
|
14
|
+
* the callback returns control to the event loop, so any awaited Promise
|
|
15
|
+
* between IDB requests would silently lose the rest of the migration.
|
|
16
|
+
*/
|
|
17
|
+
export interface IndexedDbUpgradeContext {
|
|
18
|
+
readonly db: IDBDatabase;
|
|
19
|
+
readonly tx: IDBTransaction;
|
|
20
|
+
readonly oldVersion: number;
|
|
21
|
+
readonly newVersion: number;
|
|
22
|
+
}
|
|
23
|
+
/** Convenience alias for IndexedDB-flavoured migrations. */
|
|
24
|
+
export type IndexedDbMigration = IMigration<IndexedDbUpgradeContext>;
|
|
25
|
+
/**
|
|
26
|
+
* Thrown when an in-flight migration is interrupted by another tab opening
|
|
27
|
+
* the same database at a higher version. Surfaces as the `run()` rejection
|
|
28
|
+
* so callers can distinguish a tab-coordination failure from a programming
|
|
29
|
+
* error in `up()`.
|
|
30
|
+
*/
|
|
31
|
+
export declare class MigrationAbortedByOtherTabError extends Error {
|
|
32
|
+
constructor(dbName: string);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Runs versioned migrations against a single IndexedDB database.
|
|
36
|
+
*
|
|
37
|
+
* Bookkeeping-driven dispatch (NOT IDB-version-ordinal driven). The runner:
|
|
38
|
+
* 1. Probes the DB to read the `_storage_migrations` object store, building
|
|
39
|
+
* a set of already-applied `(component, version)` pairs. The probe
|
|
40
|
+
* registers an `onupgradeneeded` handler so that if the DB doesn't yet
|
|
41
|
+
* exist, IDB's auto-creation path also creates the bookkeeping store
|
|
42
|
+
* atomically (rather than leaving an empty v1 DB with no schema).
|
|
43
|
+
* 2. Computes the pending migrations as `sorted \ alreadyApplied` —
|
|
44
|
+
* identifying each migration by `(component, version)`, NOT by its
|
|
45
|
+
* position in the sorted array. This means inserting a new migration
|
|
46
|
+
* that sorts BEFORE existing ones (e.g. a new component name that's
|
|
47
|
+
* lexicographically earlier) is still correctly detected as pending.
|
|
48
|
+
* 3. If pending is empty, returns without bumping the IDB version.
|
|
49
|
+
* 4. Otherwise reopens at `currentVersion + 1` and runs every pending
|
|
50
|
+
* migration inside the upgrade transaction, recording each in the
|
|
51
|
+
* bookkeeping store as it goes.
|
|
52
|
+
*
|
|
53
|
+
* Concurrent `run()` calls against the same dbName (across instances) are
|
|
54
|
+
* serialized via {@link RUN_LOCKS} so that two callers don't deadlock each
|
|
55
|
+
* other on the open-at-higher-version handshake.
|
|
56
|
+
*
|
|
57
|
+
* The IDB database version is treated purely as a monotonic trigger for
|
|
58
|
+
* `onupgradeneeded`; we never use it to decide which migrations to apply.
|
|
59
|
+
*
|
|
60
|
+
* Caveats:
|
|
61
|
+
* - `up()` must be synchronous. IDB upgrade transactions auto-commit as
|
|
62
|
+
* soon as control returns to the event loop, so awaited Promises between
|
|
63
|
+
* IDB requests would silently lose the rest of the migration. The runner
|
|
64
|
+
* throws if `up()` returns a Promise.
|
|
65
|
+
*/
|
|
66
|
+
export declare class IndexedDbMigrationRunner implements IMigrationRunner<IndexedDbUpgradeContext> {
|
|
67
|
+
private readonly dbName;
|
|
68
|
+
private readonly idb;
|
|
69
|
+
constructor(dbName: string, idb?: IDBFactory);
|
|
70
|
+
private probe;
|
|
71
|
+
/** Ensures the bookkeeping object store exists (created lazily by {@link probe}). */
|
|
72
|
+
ensureBookkeepingTable(): Promise<void>;
|
|
73
|
+
appliedVersions(component: string): Promise<Set<number>>;
|
|
74
|
+
run(migrations: ReadonlyArray<IndexedDbMigration>, options?: RunMigrationsOptions): Promise<ReadonlyArray<IndexedDbMigration>>;
|
|
75
|
+
private runLocked;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Convenience helper used by storage classes — runs the supplied migration
|
|
79
|
+
* groups (one per IDB database) against fresh runners and returns an array
|
|
80
|
+
* of the applied migrations across all groups.
|
|
81
|
+
*
|
|
82
|
+
* IndexedDB groups exist because some storages (e.g. the rate limiter) span
|
|
83
|
+
* multiple databases and expose them as separate `(dbName, migrations)` pairs
|
|
84
|
+
* via `getMigrations()`.
|
|
85
|
+
*/
|
|
86
|
+
export interface IndexedDbMigrationGroup {
|
|
87
|
+
readonly dbName: string;
|
|
88
|
+
readonly migrations: ReadonlyArray<IndexedDbMigration>;
|
|
89
|
+
}
|
|
90
|
+
export declare function runIndexedDbMigrationGroups(groups: ReadonlyArray<IndexedDbMigrationGroup>, options?: RunMigrationsOptions & {
|
|
91
|
+
idb?: IDBFactory;
|
|
92
|
+
}): Promise<ReadonlyArray<IndexedDbMigration>>;
|
|
93
|
+
//# sourceMappingURL=IndexedDbMigrationRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexedDbMigrationRunner.d.ts","sourceRoot":"","sources":["../../src/migrations/IndexedDbMigrationRunner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,4DAA4D;AAC5D,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,uBAAuB,CAAC,CAAC;AAerE;;;;;GAKG;AACH,qBAAa,+BAAgC,SAAQ,KAAK;IACxD,YAAY,MAAM,EAAE,MAAM,EAGzB;CACF;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB,CAAC,uBAAuB,CAAC;IAEtF,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAFtB,YACmB,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,UAA2B,EAC/C;YAQU,KAAK;IAiFnB,qFAAqF;IAC/E,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C;IAEK,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAW7D;IAEK,GAAG,CACP,UAAU,EAAE,aAAa,CAAC,kBAAkB,CAAC,EAC7C,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAS5C;YAQa,SAAS;CAgKxB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACxD;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,aAAa,CAAC,uBAAuB,CAAC,EAC9C,OAAO,GAAE,oBAAoB,GAAG;IAAE,GAAG,CAAC,EAAE,UAAU,CAAA;CAAO,GACxD,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAW5C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { PrefixColumn } from "@workglow/job-queue";
|
|
7
|
+
import type { IndexedDbMigration, IndexedDbMigrationGroup } from "./IndexedDbMigrationRunner";
|
|
8
|
+
/**
|
|
9
|
+
* Initial migration set for the IndexedDB queue object store identified by
|
|
10
|
+
* `tableName`.
|
|
11
|
+
*
|
|
12
|
+
* Component name is `queue:indexeddb:<tableName>` so two queues with
|
|
13
|
+
* different table names get tracked independently in `_storage_migrations`.
|
|
14
|
+
*
|
|
15
|
+
* Schema: a single object store keyed by `id` plus four compound indexes
|
|
16
|
+
* (queue/status, queue/status/run_after, queue/job_run_id,
|
|
17
|
+
* queue/fingerprint/status). When `prefixes` is non-empty the prefix columns
|
|
18
|
+
* are prepended to every index key path so per-tenant queries can be served
|
|
19
|
+
* directly by the index.
|
|
20
|
+
*/
|
|
21
|
+
export declare function indexedDbQueueMigrations(tableName: string, prefixes: readonly PrefixColumn[]): IndexedDbMigration[];
|
|
22
|
+
/** Returns the queue migrations packaged with their target IDB database name. */
|
|
23
|
+
export declare function indexedDbQueueMigrationGroup(tableName: string, prefixes: readonly PrefixColumn[]): IndexedDbMigrationGroup;
|
|
24
|
+
//# sourceMappingURL=indexedDbQueueMigrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexedDbQueueMigrations.d.ts","sourceRoot":"","sources":["../../src/migrations/indexedDbQueueMigrations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAE9F;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,YAAY,EAAE,GAChC,kBAAkB,EAAE,CAyBtB;AAED,iFAAiF;AACjF,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,YAAY,EAAE,GAChC,uBAAuB,CAKzB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { PrefixColumn } from "@workglow/job-queue";
|
|
7
|
+
import type { IndexedDbMigration, IndexedDbMigrationGroup } from "./IndexedDbMigrationRunner";
|
|
8
|
+
/**
|
|
9
|
+
* Initial migrations for the IndexedDB rate-limiter execution table.
|
|
10
|
+
*
|
|
11
|
+
* Schema: an object store keyed by `id` (autoincrement-style; we generate
|
|
12
|
+
* UUIDs at the storage layer) plus a compound index `queue_executed_at` for
|
|
13
|
+
* windowed counts. Prefix columns are prepended to every index key path.
|
|
14
|
+
*/
|
|
15
|
+
export declare function indexedDbRateLimiterExecutionMigrations(executionTableName: string, prefixes: readonly PrefixColumn[]): IndexedDbMigration[];
|
|
16
|
+
/**
|
|
17
|
+
* Initial migrations for the IndexedDB rate-limiter `next_available` table.
|
|
18
|
+
*
|
|
19
|
+
* Schema: object store keyed by a single synthetic field whose name is
|
|
20
|
+
* `prefixCols.concat(["queue_name"]).join("_")`. The storage layer writes
|
|
21
|
+
* a record where this field holds `prefixValues.concat([queueName]).join("_")`
|
|
22
|
+
* — i.e. tenant-qualified — so the same physical store can hold rows for
|
|
23
|
+
* multiple tenants without collisions. Without this, two tenants with the
|
|
24
|
+
* same queue name would silently overwrite each other's row (the
|
|
25
|
+
* `next_available_at` of one would be returned for the other).
|
|
26
|
+
*
|
|
27
|
+
* No `queue_name = "myqueue"` index is created because the storage's read
|
|
28
|
+
* path (`store.get(syntheticKey)`) goes through the primary key directly.
|
|
29
|
+
*/
|
|
30
|
+
export declare function indexedDbRateLimiterNextAvailableMigrations(nextAvailableTableName: string, prefixes: readonly PrefixColumn[]): IndexedDbMigration[];
|
|
31
|
+
/**
|
|
32
|
+
* Returns the rate-limiter migrations packaged as IDB migration groups —
|
|
33
|
+
* one group per database, since `IndexedDbRateLimiterStorage` keeps the
|
|
34
|
+
* execution and next-available tables in separate databases.
|
|
35
|
+
*/
|
|
36
|
+
export declare function indexedDbRateLimiterMigrationGroups(executionTableName: string, nextAvailableTableName: string, prefixes: readonly PrefixColumn[]): IndexedDbMigrationGroup[];
|
|
37
|
+
//# sourceMappingURL=indexedDbRateLimiterMigrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexedDbRateLimiterMigrations.d.ts","sourceRoot":"","sources":["../../src/migrations/indexedDbRateLimiterMigrations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAE9F;;;;;;GAMG;AACH,wBAAgB,uCAAuC,CACrD,kBAAkB,EAAE,MAAM,EAC1B,QAAQ,EAAE,SAAS,YAAY,EAAE,GAChC,kBAAkB,EAAE,CAoBtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2CAA2C,CACzD,sBAAsB,EAAE,MAAM,EAC9B,QAAQ,EAAE,SAAS,YAAY,EAAE,GAChC,kBAAkB,EAAE,CAoBtB;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CACjD,kBAAkB,EAAE,MAAM,EAC1B,sBAAsB,EAAE,MAAM,EAC9B,QAAQ,EAAE,SAAS,YAAY,EAAE,GAChC,uBAAuB,EAAE,CAW3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IndexedDbTable.d.ts","sourceRoot":"","sources":["../../src/storage/IndexedDbTable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"IndexedDbTable.d.ts","sourceRoot":"","sources":["../../src/storage/IndexedDbTable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,WAAW,CAAC;IAChB,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,oFAAoF;IACpF,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,yDAAyD;IACzD,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/D;AA6WD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,EAC7B,eAAe,GAAE,uBAAuB,EAAO,EAC/C,OAAO,GAAE,gBAAqB,EAC9B,aAAa,GAAE,OAAe,GAC7B,OAAO,CAAC,WAAW,CAAC,CA6KtB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { type ITabularMigrationApplier, type TabularMigrationOp } from "@workglow/storage";
|
|
7
|
+
import { IndexedDbMigrationRunner } from "../migrations/IndexedDbMigrationRunner";
|
|
8
|
+
interface BackfillCapableStorage {
|
|
9
|
+
getPage: (req?: {
|
|
10
|
+
limit?: number;
|
|
11
|
+
cursor?: unknown;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
items: Array<Record<string, unknown>>;
|
|
14
|
+
nextCursor?: unknown;
|
|
15
|
+
}>;
|
|
16
|
+
put: (row: Record<string, unknown>) => Promise<unknown>;
|
|
17
|
+
delete: (row: Record<string, unknown>) => Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read-only existence probe shared by `IndexedDbTabularMigrationApplier.tableExists`
|
|
21
|
+
* and `IndexedDbTabularStorage.probeObjectStoreExists`. Opens the IDB
|
|
22
|
+
* database without a version (which is the only documented way to read the
|
|
23
|
+
* existing version + object stores) and inspects `objectStoreNames`.
|
|
24
|
+
*
|
|
25
|
+
* **Side effect:** if the database does not yet exist, IDB's spec says
|
|
26
|
+
* `open(name)` *creates* it at version 1 with no object stores. The caller
|
|
27
|
+
* must be prepared to handle that — `ensureIndexedDbTable` already does, by
|
|
28
|
+
* deleting and recreating the empty DB before bumping its version.
|
|
29
|
+
*/
|
|
30
|
+
export declare function idbObjectStoreExists(dbName: string, storeName: string): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* IndexedDB applier for tabular migrations.
|
|
33
|
+
*
|
|
34
|
+
* Op handling matches `InMemoryTabularMigrationApplier`'s schemaless model
|
|
35
|
+
* (column ops are no-ops) and `SqlTabularMigrationApplier`'s SQL-backed
|
|
36
|
+
* model (DDL is real) where each makes sense:
|
|
37
|
+
*
|
|
38
|
+
* - `addColumn` / `dropColumn` / `renameColumn` — **no-ops.** IDB stores
|
|
39
|
+
* arbitrary JS objects, so there is no schema to evolve. Authors who
|
|
40
|
+
* need to populate or rewrite a property on existing rows must pair
|
|
41
|
+
* the column op with an explicit `backfill` op (which runs on every
|
|
42
|
+
* backend, including SQL, where the backfill is in addition to the
|
|
43
|
+
* real ALTER TABLE). This keeps a single migration spec portable
|
|
44
|
+
* across backends.
|
|
45
|
+
* - `addIndex` / `dropIndex` — **real DDL.** Run inside an upgrade
|
|
46
|
+
* transaction issued by {@link IndexedDbMigrationRunner}, which writes
|
|
47
|
+
* the `_storage_migrations` row in the same transaction so DDL +
|
|
48
|
+
* bookkeeping commit atomically. `createIndex` / `deleteIndex` are
|
|
49
|
+
* guarded by `objectStore.indexNames.contains` so a re-run does not
|
|
50
|
+
* throw on already-existing / already-deleted indexes — mirroring
|
|
51
|
+
* SQL's `IF NOT EXISTS` / `IF EXISTS` semantics.
|
|
52
|
+
* - `backfill` — runs on a **separate** readwrite transaction *before*
|
|
53
|
+
* the upgrade tx, because IDB upgrade transactions cannot span async
|
|
54
|
+
* work. This means the backfill and the bookkeeping write are NOT
|
|
55
|
+
* atomic on this backend: if the upgrade tx fails after a partial
|
|
56
|
+
* backfill, the row mutations persist while no `(component, version)`
|
|
57
|
+
* row is written, and the next run re-invokes `transform()` on the
|
|
58
|
+
* already-mutated rows. **Backfill `transform`s on this applier MUST
|
|
59
|
+
* therefore be idempotent.** SQL backends wrap everything in
|
|
60
|
+
* `withTransaction` and do not have this requirement.
|
|
61
|
+
*
|
|
62
|
+
* Order of execution within a single migration: backfill first, then DDL.
|
|
63
|
+
* This means a `[backfill, addIndex]` pair sees the new index applied to
|
|
64
|
+
* the rewritten rows; the reverse order (`[addIndex, backfill]`) would
|
|
65
|
+
* still execute backfill first because the runner buffers DDL until the
|
|
66
|
+
* upgrade tx.
|
|
67
|
+
*/
|
|
68
|
+
export declare class IndexedDbTabularMigrationApplier implements ITabularMigrationApplier {
|
|
69
|
+
private readonly dbName;
|
|
70
|
+
private readonly storeName;
|
|
71
|
+
private readonly storage;
|
|
72
|
+
private readonly runner;
|
|
73
|
+
constructor(dbName: string, storeName: string, storage: BackfillCapableStorage, runner?: IndexedDbMigrationRunner);
|
|
74
|
+
ensureBookkeeping(): Promise<void>;
|
|
75
|
+
appliedVersions(component: string): Promise<Set<number>>;
|
|
76
|
+
tableExists(): Promise<boolean>;
|
|
77
|
+
markAllApplied(component: string, versions: ReadonlyArray<{
|
|
78
|
+
version: number;
|
|
79
|
+
description: string | undefined;
|
|
80
|
+
}>): Promise<void>;
|
|
81
|
+
applyMigration(component: string, version: number, description: string | undefined, ops: ReadonlyArray<TabularMigrationOp>, onProgress?: (fraction: number) => void): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=IndexedDbTabularMigrationApplier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexedDbTabularMigrationApplier.d.ts","sourceRoot":"","sources":["../../src/storage/IndexedDbTabularMigrationApplier.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EACL,wBAAwB,EAEzB,MAAM,wCAAwC,CAAC;AAEhD,UAAU,sBAAsB;IAC9B,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;QAC/D,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QACtC,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC,CAAC;IACH,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAe9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,gCAAiC,YAAW,wBAAwB;IAG7E,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,YACmB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,sBAAsB,EAChD,MAAM,CAAC,EAAE,wBAAwB,EAGlC;IAEK,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvC;IAEK,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAE7D;IAEK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAEpC;IAEK,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,GAC5E,OAAO,CAAC,IAAI,CAAC,CAUf;IAEK,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,GAAG,EAAE,aAAa,CAAC,kBAAkB,CAAC,EACtC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACtC,OAAO,CAAC,IAAI,CAAC,CA2Ff;CACF"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from "@workglow/util/schema";
|
|
7
|
-
import { BaseTabularStorage, ClientProvidedKeysOption, KeyGenerationStrategy, AnyTabularStorage, AutoGeneratedKeys, CoveringIndexQueryOptions, DeleteSearchCriteria, InsertEntity, QueryOptions, SearchCriteria, SimplifyPrimaryKey, TabularChangePayload, TabularSubscribeOptions } from "@workglow/storage";
|
|
7
|
+
import { BaseTabularStorage, ClientProvidedKeysOption, KeyGenerationStrategy, AnyTabularStorage, AutoGeneratedKeys, CoveringIndexQueryOptions, DeleteSearchCriteria, InsertEntity, QueryOptions, SearchCriteria, SimplifyPrimaryKey, TabularChangePayload, TabularSubscribeOptions, type ITabularMigration, type ITabularMigrationApplier } from "@workglow/storage";
|
|
8
8
|
import { MigrationOptions } from "./IndexedDbTable";
|
|
9
9
|
export declare const IDB_TABULAR_REPOSITORY: import("@workglow/util").ServiceToken<AnyTabularStorage>;
|
|
10
10
|
/**
|
|
@@ -17,6 +17,15 @@ export declare class IndexedDbTabularStorage<Schema extends DataPortSchemaObject
|
|
|
17
17
|
table: string;
|
|
18
18
|
/** Promise that resolves to the IndexedDB database instance */
|
|
19
19
|
private db;
|
|
20
|
+
/**
|
|
21
|
+
* True between `setupDatabase`'s call to `applyTabularMigrations` and its
|
|
22
|
+
* completion. Backfill ops inside the orchestrator may close `this.db`
|
|
23
|
+
* (via `onversionchange` from the next migration's upgrade) and trigger
|
|
24
|
+
* a re-entrant `setupDatabase` call from `getDb()`. The re-entrant call
|
|
25
|
+
* must only re-open the IDB connection — it MUST NOT recurse into the
|
|
26
|
+
* orchestrator, or migrations will be replayed mid-flight.
|
|
27
|
+
*/
|
|
28
|
+
private applyingMigrations;
|
|
20
29
|
/** Promise to track ongoing database setup to prevent concurrent setup calls */
|
|
21
30
|
private setupPromise;
|
|
22
31
|
/** Migration options for database schema changes */
|
|
@@ -46,14 +55,24 @@ export declare class IndexedDbTabularStorage<Schema extends DataPortSchemaObject
|
|
|
46
55
|
constructor(table: string | undefined, schema: Schema, primaryKeyNames: PrimaryKeyNames, indexes?: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[], migrationOptions?: MigrationOptions & {
|
|
47
56
|
readonly useBroadcastChannel?: boolean;
|
|
48
57
|
readonly backupPollingIntervalMs?: number;
|
|
49
|
-
}, clientProvidedKeys?: ClientProvidedKeysOption);
|
|
58
|
+
}, clientProvidedKeys?: ClientProvidedKeysOption, tabularMigrations?: ReadonlyArray<ITabularMigration>);
|
|
50
59
|
private getDb;
|
|
51
60
|
/**
|
|
52
61
|
* Sets up the IndexedDB database table with the required schema and indexes.
|
|
53
62
|
* Must be called before using any other methods.
|
|
54
63
|
*/
|
|
55
64
|
setupDatabase(): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Wires `onversionchange` so that when the migration runner bumps the IDB
|
|
67
|
+
* version (currentVersion + 1 to trigger onupgradeneeded), the current
|
|
68
|
+
* open connection is both closed AND cleared from `this.db`. Without the
|
|
69
|
+
* clear, getDb() would return a stale closed connection and throw
|
|
70
|
+
* InvalidStateError on the next transaction attempt (e.g. during backfill).
|
|
71
|
+
*/
|
|
72
|
+
private rewireOnVersionChange;
|
|
73
|
+
private probeObjectStoreExists;
|
|
56
74
|
private performSetup;
|
|
75
|
+
getMigrationApplier(): ITabularMigrationApplier | null;
|
|
57
76
|
/**
|
|
58
77
|
* Generates a key value for UUID keys
|
|
59
78
|
* Integer autoincrement keys are handled by IndexedDB's autoIncrement
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IndexedDbTabularStorage.d.ts","sourceRoot":"","sources":["../../src/storage/IndexedDbTabularStorage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAEL,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EAEZ,YAAY,EACZ,cAAc,EAEd,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"IndexedDbTabularStorage.d.ts","sourceRoot":"","sources":["../../src/storage/IndexedDbTabularStorage.ts"],"names":[],"mappings":"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"}
|