@workglow/storage 0.2.25 → 0.2.27
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/dist/browser.js +512 -9
- package/dist/browser.js.map +23 -21
- package/dist/bun.js +1087 -21
- package/dist/bun.js.map +30 -27
- package/dist/common-server.d.ts +1 -0
- package/dist/common-server.d.ts.map +1 -1
- package/dist/common.d.ts +3 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/node.js +1087 -21
- package/dist/node.js.map +30 -27
- package/dist/queue/IQueueStorage.d.ts +25 -2
- package/dist/queue/IQueueStorage.d.ts.map +1 -1
- package/dist/queue/InMemoryQueueStorage.d.ts +1 -0
- package/dist/queue/InMemoryQueueStorage.d.ts.map +1 -1
- package/dist/queue/IndexedDbQueueStorage.d.ts +1 -0
- package/dist/queue/IndexedDbQueueStorage.d.ts.map +1 -1
- package/dist/queue/PostgresQueueStorage.d.ts +24 -3
- package/dist/queue/PostgresQueueStorage.d.ts.map +1 -1
- package/dist/queue/SqliteQueueStorage.d.ts +8 -0
- package/dist/queue/SqliteQueueStorage.d.ts.map +1 -1
- package/dist/queue/SupabaseQueueStorage.d.ts +1 -0
- package/dist/queue/SupabaseQueueStorage.d.ts.map +1 -1
- package/dist/queue/TelemetryQueueStorage.d.ts +2 -1
- package/dist/queue/TelemetryQueueStorage.d.ts.map +1 -1
- package/dist/queue-limiter/IRateLimiterStorage.d.ts +46 -0
- package/dist/queue-limiter/IRateLimiterStorage.d.ts.map +1 -1
- package/dist/queue-limiter/InMemoryRateLimiterStorage.d.ts +12 -1
- package/dist/queue-limiter/InMemoryRateLimiterStorage.d.ts.map +1 -1
- package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts +28 -1
- package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts.map +1 -1
- package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts +4 -1
- package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts.map +1 -1
- package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts +10 -1
- package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts.map +1 -1
- package/dist/queue-limiter/SupabaseRateLimiterStorage.d.ts +6 -1
- package/dist/queue-limiter/SupabaseRateLimiterStorage.d.ts.map +1 -1
- package/dist/tabular/BaseTabularStorage.d.ts +15 -1
- package/dist/tabular/BaseTabularStorage.d.ts.map +1 -1
- package/dist/tabular/CachedTabularStorage.d.ts +2 -1
- package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
- package/dist/tabular/CoveringIndexMissingError.d.ts +14 -0
- package/dist/tabular/CoveringIndexMissingError.d.ts.map +1 -0
- package/dist/tabular/FsFolderTabularStorage.d.ts +6 -1
- package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
- package/dist/tabular/ITabularStorage.d.ts +19 -1
- package/dist/tabular/ITabularStorage.d.ts.map +1 -1
- package/dist/tabular/InMemoryTabularStorage.d.ts +7 -1
- package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/IndexedDbTabularStorage.d.ts +10 -1
- package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
- package/dist/tabular/PostgresTabularStorage.d.ts +11 -1
- package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SharedInMemoryTabularStorage.d.ts +2 -1
- package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SqliteTabularStorage.d.ts +11 -1
- package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SupabaseTabularStorage.d.ts +2 -1
- package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -1
- package/dist/tabular/TelemetryTabularStorage.d.ts +2 -1
- package/dist/tabular/TelemetryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/coveringIndexPicker.d.ts +37 -0
- package/dist/tabular/coveringIndexPicker.d.ts.map +1 -0
- package/dist/vector/IVectorStorage.d.ts +3 -1
- package/dist/vector/IVectorStorage.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/browser.js
CHANGED
|
@@ -45,6 +45,21 @@ class StorageUnsupportedError extends StorageError {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// src/tabular/CoveringIndexMissingError.ts
|
|
49
|
+
class CoveringIndexMissingError extends StorageError {
|
|
50
|
+
static type = "CoveringIndexMissingError";
|
|
51
|
+
table;
|
|
52
|
+
requiredColumns;
|
|
53
|
+
registeredIndexes;
|
|
54
|
+
constructor(table, requiredColumns, registeredIndexes) {
|
|
55
|
+
const indexList = registeredIndexes.map((cols) => `[${cols.join(", ")}]`).join(", ");
|
|
56
|
+
super(`No covering index for table "${table}". ` + `Required columns: [${requiredColumns.join(", ")}]. ` + `Registered indexes: ${indexList || "(none)"}.`);
|
|
57
|
+
this.table = table;
|
|
58
|
+
this.requiredColumns = requiredColumns;
|
|
59
|
+
this.registeredIndexes = registeredIndexes;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
// src/tabular/BaseTabularStorage.ts
|
|
49
64
|
var TABULAR_REPOSITORY = createServiceToken("storage.tabularRepository");
|
|
50
65
|
|
|
@@ -168,6 +183,15 @@ class BaseTabularStorage {
|
|
|
168
183
|
const entities = await this.query(criteria);
|
|
169
184
|
return entities?.length ?? 0;
|
|
170
185
|
}
|
|
186
|
+
queryIndex(criteria, options) {
|
|
187
|
+
this.validateSelect(options);
|
|
188
|
+
const requiredColumns = [
|
|
189
|
+
...Object.keys(criteria),
|
|
190
|
+
...(options.orderBy ?? []).map((o) => String(o.column)),
|
|
191
|
+
...options.select.map(String)
|
|
192
|
+
];
|
|
193
|
+
throw new CoveringIndexMissingError(this.constructor.name, requiredColumns, []);
|
|
194
|
+
}
|
|
171
195
|
async* records(pageSize = 100) {
|
|
172
196
|
if (pageSize <= 0) {
|
|
173
197
|
throw new RangeError(`pageSize must be greater than 0, got ${pageSize}`);
|
|
@@ -263,6 +287,18 @@ class BaseTabularStorage {
|
|
|
263
287
|
}
|
|
264
288
|
}
|
|
265
289
|
}
|
|
290
|
+
validateSelect(options) {
|
|
291
|
+
if (!options.select || options.select.length === 0) {
|
|
292
|
+
throw new StorageValidationError("queryIndex requires a non-empty select array");
|
|
293
|
+
}
|
|
294
|
+
const schemaProps = Object.keys(this.schema.properties);
|
|
295
|
+
for (const col of options.select) {
|
|
296
|
+
const colStr = String(col);
|
|
297
|
+
if (!schemaProps.includes(colStr)) {
|
|
298
|
+
throw new StorageValidationError(`queryIndex select column "${colStr}" is not in schema`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
266
302
|
primaryKeyColumns() {
|
|
267
303
|
const columns = [];
|
|
268
304
|
for (const key of Object.keys(this.primaryKeySchema.properties)) {
|
|
@@ -383,6 +419,61 @@ import { createServiceToken as createServiceToken3, getLogger } from "@workglow/
|
|
|
383
419
|
|
|
384
420
|
// src/tabular/InMemoryTabularStorage.ts
|
|
385
421
|
import { createServiceToken as createServiceToken2, makeFingerprint as makeFingerprint2, uuid4 } from "@workglow/util";
|
|
422
|
+
|
|
423
|
+
// src/tabular/coveringIndexPicker.ts
|
|
424
|
+
function pickCoveringIndex(input) {
|
|
425
|
+
const { table, indexes, criteriaColumns, orderByColumns, selectColumns, primaryKeyColumns } = input;
|
|
426
|
+
const required = uniqueColumns([
|
|
427
|
+
...criteriaColumns,
|
|
428
|
+
...orderByColumns.map((o) => o.column),
|
|
429
|
+
...selectColumns
|
|
430
|
+
]);
|
|
431
|
+
const pkSet = new Set(primaryKeyColumns);
|
|
432
|
+
for (const idx of indexes) {
|
|
433
|
+
const fit = tryFitIndex(idx, criteriaColumns, orderByColumns, selectColumns, pkSet);
|
|
434
|
+
if (fit !== undefined) {
|
|
435
|
+
return { name: idx.name, keyPath: idx.keyPath, reverseDirection: fit.reverseDirection };
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
throw new CoveringIndexMissingError(table, required, indexes.map((i) => i.keyPath));
|
|
439
|
+
}
|
|
440
|
+
function tryFitIndex(index, criteria, orderBy, select, pkSet) {
|
|
441
|
+
const keyPath = index.keyPath;
|
|
442
|
+
const criteriaSet = new Set(criteria);
|
|
443
|
+
if (criteria.length > keyPath.length)
|
|
444
|
+
return;
|
|
445
|
+
for (let i = 0;i < criteria.length; i++) {
|
|
446
|
+
if (!criteriaSet.has(keyPath[i]))
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
let reverseDirection = false;
|
|
450
|
+
if (orderBy.length > 0) {
|
|
451
|
+
const start = criteria.length;
|
|
452
|
+
if (start + orderBy.length > keyPath.length)
|
|
453
|
+
return;
|
|
454
|
+
for (let i = 0;i < orderBy.length; i++) {
|
|
455
|
+
if (keyPath[start + i] !== orderBy[i].column)
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const allDesc = orderBy.every((o) => o.direction === "DESC");
|
|
459
|
+
const allAsc = orderBy.every((o) => o.direction === "ASC");
|
|
460
|
+
if (allDesc)
|
|
461
|
+
reverseDirection = true;
|
|
462
|
+
else if (!allAsc)
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const keyPathSet = new Set(keyPath);
|
|
466
|
+
for (const col of select) {
|
|
467
|
+
if (!keyPathSet.has(col) && !pkSet.has(col))
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
return { reverseDirection };
|
|
471
|
+
}
|
|
472
|
+
function uniqueColumns(cols) {
|
|
473
|
+
return Array.from(new Set(cols));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/tabular/InMemoryTabularStorage.ts
|
|
386
477
|
var MEMORY_TABULAR_REPOSITORY = createServiceToken2("storage.tabularRepository.inMemory");
|
|
387
478
|
|
|
388
479
|
class InMemoryTabularStorage extends BaseTabularStorage {
|
|
@@ -625,6 +716,38 @@ class InMemoryTabularStorage extends BaseTabularStorage {
|
|
|
625
716
|
this.events.emit("query", criteria, result);
|
|
626
717
|
return result;
|
|
627
718
|
}
|
|
719
|
+
async queryIndex(criteria, options) {
|
|
720
|
+
this.validateSelect(options);
|
|
721
|
+
this.validateQueryParams(criteria, options);
|
|
722
|
+
const registered = this.indexes.map((cols, i) => ({
|
|
723
|
+
name: `idx_${i}`,
|
|
724
|
+
keyPath: cols
|
|
725
|
+
}));
|
|
726
|
+
pickCoveringIndex({
|
|
727
|
+
table: "InMemoryTabularStorage",
|
|
728
|
+
indexes: registered,
|
|
729
|
+
criteriaColumns: Object.keys(criteria),
|
|
730
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
731
|
+
column: String(o.column),
|
|
732
|
+
direction: o.direction
|
|
733
|
+
})),
|
|
734
|
+
selectColumns: options.select.map(String),
|
|
735
|
+
primaryKeyColumns: this.primaryKeyNames.map(String)
|
|
736
|
+
});
|
|
737
|
+
const full = await this.query(criteria, {
|
|
738
|
+
orderBy: options.orderBy,
|
|
739
|
+
limit: options.limit,
|
|
740
|
+
offset: options.offset
|
|
741
|
+
});
|
|
742
|
+
if (!full)
|
|
743
|
+
return [];
|
|
744
|
+
return full.map((row) => {
|
|
745
|
+
const out = {};
|
|
746
|
+
for (const k of options.select)
|
|
747
|
+
out[k] = row[k];
|
|
748
|
+
return out;
|
|
749
|
+
});
|
|
750
|
+
}
|
|
628
751
|
subscribeToChanges(callback, options) {
|
|
629
752
|
const handlePut = (entity) => {
|
|
630
753
|
callback({ type: this._lastPutWasInsert ? "INSERT" : "UPDATE", new: entity });
|
|
@@ -767,6 +890,10 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
767
890
|
await this.initializeCache();
|
|
768
891
|
return await this.cache.query(criteria, options);
|
|
769
892
|
}
|
|
893
|
+
async queryIndex(criteria, options) {
|
|
894
|
+
await this.initializeCache();
|
|
895
|
+
return await this.cache.queryIndex(criteria, options);
|
|
896
|
+
}
|
|
770
897
|
async deleteSearch(criteria) {
|
|
771
898
|
await this.initializeCache();
|
|
772
899
|
await this.durable.deleteSearch(criteria);
|
|
@@ -1207,6 +1334,9 @@ class TelemetryTabularStorage {
|
|
|
1207
1334
|
query(criteria, options) {
|
|
1208
1335
|
return traced("workglow.storage.tabular.query", this.storageName, () => this.inner.query(criteria, options));
|
|
1209
1336
|
}
|
|
1337
|
+
queryIndex(criteria, options) {
|
|
1338
|
+
return traced("workglow.storage.tabular.queryIndex", this.storageName, () => this.inner.queryIndex(criteria, options));
|
|
1339
|
+
}
|
|
1210
1340
|
records(pageSize) {
|
|
1211
1341
|
return this.inner.records(pageSize);
|
|
1212
1342
|
}
|
|
@@ -1444,6 +1574,7 @@ var IN_MEMORY_QUEUE_STORAGE = createServiceToken9("jobqueue.storage.inMemory");
|
|
|
1444
1574
|
|
|
1445
1575
|
class InMemoryQueueStorage {
|
|
1446
1576
|
queueName;
|
|
1577
|
+
scope = "process";
|
|
1447
1578
|
prefixValues;
|
|
1448
1579
|
events = new EventEmitter3;
|
|
1449
1580
|
constructor(queueName, options) {
|
|
@@ -1653,6 +1784,9 @@ class TelemetryQueueStorage {
|
|
|
1653
1784
|
this.storageName = storageName;
|
|
1654
1785
|
this.inner = inner;
|
|
1655
1786
|
}
|
|
1787
|
+
get scope() {
|
|
1788
|
+
return this.inner.scope;
|
|
1789
|
+
}
|
|
1656
1790
|
add(job) {
|
|
1657
1791
|
return traced("workglow.storage.queue.add", this.storageName, () => this.inner.add(job));
|
|
1658
1792
|
}
|
|
@@ -1703,13 +1837,15 @@ class TelemetryQueueStorage {
|
|
|
1703
1837
|
}
|
|
1704
1838
|
}
|
|
1705
1839
|
// src/queue-limiter/InMemoryRateLimiterStorage.ts
|
|
1706
|
-
import { createServiceToken as createServiceToken10, sleep as sleep2 } from "@workglow/util";
|
|
1840
|
+
import { createServiceToken as createServiceToken10, sleep as sleep2, uuid4 as uuid43 } from "@workglow/util";
|
|
1707
1841
|
var IN_MEMORY_RATE_LIMITER_STORAGE = createServiceToken10("ratelimiter.storage.inMemory");
|
|
1708
1842
|
|
|
1709
1843
|
class InMemoryRateLimiterStorage {
|
|
1844
|
+
scope = "process";
|
|
1710
1845
|
prefixValues;
|
|
1711
1846
|
executions = new Map;
|
|
1712
1847
|
nextAvailableTimes = new Map;
|
|
1848
|
+
reserveChains = new Map;
|
|
1713
1849
|
constructor(options) {
|
|
1714
1850
|
this.prefixValues = options?.prefixValues ?? {};
|
|
1715
1851
|
}
|
|
@@ -1718,11 +1854,67 @@ class InMemoryRateLimiterStorage {
|
|
|
1718
1854
|
return prefixPart ? `${prefixPart}|${queueName}` : queueName;
|
|
1719
1855
|
}
|
|
1720
1856
|
async setupDatabase() {}
|
|
1857
|
+
async withKeyLock(key, fn) {
|
|
1858
|
+
const previous = this.reserveChains.get(key) ?? Promise.resolve();
|
|
1859
|
+
let release;
|
|
1860
|
+
const next = new Promise((resolve) => {
|
|
1861
|
+
release = resolve;
|
|
1862
|
+
});
|
|
1863
|
+
this.reserveChains.set(key, next);
|
|
1864
|
+
try {
|
|
1865
|
+
await previous;
|
|
1866
|
+
return await fn();
|
|
1867
|
+
} finally {
|
|
1868
|
+
release(undefined);
|
|
1869
|
+
if (this.reserveChains.get(key) === next) {
|
|
1870
|
+
this.reserveChains.delete(key);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
async tryReserveExecution(queueName, maxExecutions, windowMs) {
|
|
1875
|
+
const key = this.makeKey(queueName);
|
|
1876
|
+
return this.withKeyLock(key, () => {
|
|
1877
|
+
const now = Date.now();
|
|
1878
|
+
const windowStart = new Date(now - windowMs);
|
|
1879
|
+
const executions = this.executions.get(key) ?? [];
|
|
1880
|
+
const live = executions.filter((e) => e.executedAt > windowStart);
|
|
1881
|
+
if (live.length >= maxExecutions) {
|
|
1882
|
+
if (live.length !== executions.length) {
|
|
1883
|
+
this.executions.set(key, live);
|
|
1884
|
+
}
|
|
1885
|
+
return null;
|
|
1886
|
+
}
|
|
1887
|
+
const next = this.nextAvailableTimes.get(key);
|
|
1888
|
+
if (next && next.getTime() > now) {
|
|
1889
|
+
return null;
|
|
1890
|
+
}
|
|
1891
|
+
const id = uuid43();
|
|
1892
|
+
live.push({ id, queueName, executedAt: new Date(now) });
|
|
1893
|
+
this.executions.set(key, live);
|
|
1894
|
+
return id;
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
async releaseExecution(queueName, token) {
|
|
1898
|
+
if (token === null || token === undefined)
|
|
1899
|
+
return;
|
|
1900
|
+
const key = this.makeKey(queueName);
|
|
1901
|
+
await this.withKeyLock(key, () => {
|
|
1902
|
+
const executions = this.executions.get(key);
|
|
1903
|
+
if (!executions || executions.length === 0)
|
|
1904
|
+
return;
|
|
1905
|
+
const idx = executions.findIndex((e) => e.id === token);
|
|
1906
|
+
if (idx === -1)
|
|
1907
|
+
return;
|
|
1908
|
+
executions.splice(idx, 1);
|
|
1909
|
+
this.executions.set(key, executions);
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1721
1912
|
async recordExecution(queueName) {
|
|
1722
1913
|
await sleep2(0);
|
|
1723
1914
|
const key = this.makeKey(queueName);
|
|
1724
1915
|
const executions = this.executions.get(key) ?? [];
|
|
1725
1916
|
executions.push({
|
|
1917
|
+
id: uuid43(),
|
|
1726
1918
|
queueName,
|
|
1727
1919
|
executedAt: new Date
|
|
1728
1920
|
});
|
|
@@ -2304,7 +2496,7 @@ class LazyEncryptedCredentialStore {
|
|
|
2304
2496
|
}
|
|
2305
2497
|
}
|
|
2306
2498
|
// src/tabular/IndexedDbTabularStorage.ts
|
|
2307
|
-
import { createServiceToken as createServiceToken12, deepEqual as deepEqual2, makeFingerprint as makeFingerprint5, uuid4 as
|
|
2499
|
+
import { createServiceToken as createServiceToken12, deepEqual as deepEqual2, makeFingerprint as makeFingerprint5, uuid4 as uuid44 } from "@workglow/util";
|
|
2308
2500
|
|
|
2309
2501
|
// src/util/IndexedDbTable.ts
|
|
2310
2502
|
import { deepEqual } from "@workglow/util";
|
|
@@ -2695,7 +2887,7 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
2695
2887
|
}
|
|
2696
2888
|
generateKeyValue(columnName, strategy) {
|
|
2697
2889
|
if (strategy === "uuid") {
|
|
2698
|
-
return
|
|
2890
|
+
return uuid44();
|
|
2699
2891
|
}
|
|
2700
2892
|
throw new Error(`IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`);
|
|
2701
2893
|
}
|
|
@@ -3196,6 +3388,107 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
3196
3388
|
request.onerror = () => reject(request.error);
|
|
3197
3389
|
});
|
|
3198
3390
|
}
|
|
3391
|
+
async queryIndex(criteria, options) {
|
|
3392
|
+
this.validateSelect(options);
|
|
3393
|
+
this.validateQueryParams(criteria, options);
|
|
3394
|
+
const registered = this.indexes.map((cols) => {
|
|
3395
|
+
const cs = Array.isArray(cols) ? cols : [cols];
|
|
3396
|
+
return { name: cs.join("_"), keyPath: cs };
|
|
3397
|
+
});
|
|
3398
|
+
const picked = pickCoveringIndex({
|
|
3399
|
+
table: this.table,
|
|
3400
|
+
indexes: registered,
|
|
3401
|
+
criteriaColumns: Object.keys(criteria),
|
|
3402
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
3403
|
+
column: String(o.column),
|
|
3404
|
+
direction: o.direction
|
|
3405
|
+
})),
|
|
3406
|
+
selectColumns: options.select.map(String),
|
|
3407
|
+
primaryKeyColumns: this.primaryKeyColumns().map(String)
|
|
3408
|
+
});
|
|
3409
|
+
const db = await this.getDb();
|
|
3410
|
+
return new Promise((resolve, reject) => {
|
|
3411
|
+
const tx = db.transaction(this.table, "readonly");
|
|
3412
|
+
const store = tx.objectStore(this.table);
|
|
3413
|
+
const idx = store.index(picked.name);
|
|
3414
|
+
const prefix = [];
|
|
3415
|
+
for (const col of picked.keyPath) {
|
|
3416
|
+
const c = criteria[col];
|
|
3417
|
+
if (c === undefined && !(col in criteria))
|
|
3418
|
+
break;
|
|
3419
|
+
if (isSearchCondition(c)) {
|
|
3420
|
+
if (c.operator !== "=")
|
|
3421
|
+
break;
|
|
3422
|
+
prefix.push(c.value);
|
|
3423
|
+
} else {
|
|
3424
|
+
prefix.push(c);
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
const range = prefix.length === 0 ? undefined : prefix.length === picked.keyPath.length ? IDBKeyRange.only(prefix.length === 1 ? prefix[0] : prefix) : IDBKeyRange.bound(prefix, [...prefix, []]);
|
|
3428
|
+
const direction = picked.reverseDirection ? "prev" : "next";
|
|
3429
|
+
const request = idx.openKeyCursor(range, direction);
|
|
3430
|
+
const out = [];
|
|
3431
|
+
let toSkip = options.offset ?? 0;
|
|
3432
|
+
const keyPathPositions = new Map;
|
|
3433
|
+
picked.keyPath.forEach((col, i) => keyPathPositions.set(col, i));
|
|
3434
|
+
const pkCols = this.primaryKeyColumns().map(String);
|
|
3435
|
+
const pkPositions = new Map;
|
|
3436
|
+
pkCols.forEach((col, i) => pkPositions.set(col, i));
|
|
3437
|
+
request.onsuccess = () => {
|
|
3438
|
+
const cursor = request.result;
|
|
3439
|
+
if (!cursor) {
|
|
3440
|
+
resolve(out);
|
|
3441
|
+
return;
|
|
3442
|
+
}
|
|
3443
|
+
const key = cursor.key;
|
|
3444
|
+
const row = {};
|
|
3445
|
+
for (const col of options.select) {
|
|
3446
|
+
const colStr = String(col);
|
|
3447
|
+
const pos = keyPathPositions.get(colStr);
|
|
3448
|
+
if (pos !== undefined) {
|
|
3449
|
+
row[colStr] = Array.isArray(key) ? key[pos] : key;
|
|
3450
|
+
} else {
|
|
3451
|
+
if (pkCols.length === 1 && colStr === pkCols[0]) {
|
|
3452
|
+
row[colStr] = cursor.primaryKey;
|
|
3453
|
+
} else {
|
|
3454
|
+
const pkPos = pkPositions.get(colStr);
|
|
3455
|
+
if (pkPos !== undefined) {
|
|
3456
|
+
row[colStr] = Array.isArray(cursor.primaryKey) ? cursor.primaryKey[pkPos] : cursor.primaryKey;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
let matches = true;
|
|
3462
|
+
for (const [col, crit] of Object.entries(criteria)) {
|
|
3463
|
+
const pos = keyPathPositions.get(col);
|
|
3464
|
+
if (pos === undefined)
|
|
3465
|
+
continue;
|
|
3466
|
+
if (pos < prefix.length)
|
|
3467
|
+
continue;
|
|
3468
|
+
const valFromKey = Array.isArray(key) ? key[pos] : key;
|
|
3469
|
+
const op = isSearchCondition(crit) ? crit.operator : "=";
|
|
3470
|
+
const val = isSearchCondition(crit) ? crit.value : crit;
|
|
3471
|
+
if (!compareWithOperator(valFromKey, op, val)) {
|
|
3472
|
+
matches = false;
|
|
3473
|
+
break;
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
if (matches) {
|
|
3477
|
+
if (toSkip > 0) {
|
|
3478
|
+
toSkip -= 1;
|
|
3479
|
+
} else {
|
|
3480
|
+
out.push(row);
|
|
3481
|
+
if (options.limit !== undefined && out.length >= options.limit) {
|
|
3482
|
+
resolve(out);
|
|
3483
|
+
return;
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
cursor.continue();
|
|
3488
|
+
};
|
|
3489
|
+
request.onerror = () => reject(request.error);
|
|
3490
|
+
});
|
|
3491
|
+
}
|
|
3199
3492
|
getHybridManager() {
|
|
3200
3493
|
if (!this.hybridManager) {
|
|
3201
3494
|
const channelName = `indexeddb-tabular-${this.table}`;
|
|
@@ -3233,6 +3526,22 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
3233
3526
|
this.db?.close();
|
|
3234
3527
|
}
|
|
3235
3528
|
}
|
|
3529
|
+
function compareWithOperator(a, op, b) {
|
|
3530
|
+
const av = a;
|
|
3531
|
+
const bv = b;
|
|
3532
|
+
switch (op) {
|
|
3533
|
+
case "=":
|
|
3534
|
+
return av === bv;
|
|
3535
|
+
case "<":
|
|
3536
|
+
return av !== null && av !== undefined && av < bv;
|
|
3537
|
+
case "<=":
|
|
3538
|
+
return av !== null && av !== undefined && av <= bv;
|
|
3539
|
+
case ">":
|
|
3540
|
+
return av !== null && av !== undefined && av > bv;
|
|
3541
|
+
case ">=":
|
|
3542
|
+
return av !== null && av !== undefined && av >= bv;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3236
3545
|
// src/tabular/SharedInMemoryTabularStorage.ts
|
|
3237
3546
|
import { createServiceToken as createServiceToken13 } from "@workglow/util";
|
|
3238
3547
|
var SHARED_IN_MEMORY_TABULAR_REPOSITORY = createServiceToken13("storage.tabularRepository.sharedInMemory");
|
|
@@ -3406,6 +3715,9 @@ class SharedInMemoryTabularStorage extends BaseTabularStorage {
|
|
|
3406
3715
|
async query(criteria, options) {
|
|
3407
3716
|
return await this.inMemoryRepo.query(criteria, options);
|
|
3408
3717
|
}
|
|
3718
|
+
async queryIndex(criteria, options) {
|
|
3719
|
+
return await this.inMemoryRepo.queryIndex(criteria, options);
|
|
3720
|
+
}
|
|
3409
3721
|
async deleteSearch(criteria) {
|
|
3410
3722
|
await this.inMemoryRepo.deleteSearch(criteria);
|
|
3411
3723
|
this.broadcast({
|
|
@@ -4093,6 +4405,56 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
|
|
|
4093
4405
|
this.events.emit("query", criteria, undefined);
|
|
4094
4406
|
return;
|
|
4095
4407
|
}
|
|
4408
|
+
async queryIndex(criteria, options) {
|
|
4409
|
+
this.validateSelect(options);
|
|
4410
|
+
this.validateQueryParams(criteria, options);
|
|
4411
|
+
const registered = this.indexes.map((cols, i) => {
|
|
4412
|
+
const cs = Array.isArray(cols) ? cols : [cols];
|
|
4413
|
+
return { name: `idx_${i}`, keyPath: cs };
|
|
4414
|
+
});
|
|
4415
|
+
pickCoveringIndex({
|
|
4416
|
+
table: this.table,
|
|
4417
|
+
indexes: registered,
|
|
4418
|
+
criteriaColumns: Object.keys(criteria),
|
|
4419
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
4420
|
+
column: String(o.column),
|
|
4421
|
+
direction: o.direction
|
|
4422
|
+
})),
|
|
4423
|
+
selectColumns: options.select.map(String),
|
|
4424
|
+
primaryKeyColumns: this.primaryKeyNames.map(String)
|
|
4425
|
+
});
|
|
4426
|
+
const colList = options.select.map(String).join(",");
|
|
4427
|
+
let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);
|
|
4428
|
+
if (options.orderBy) {
|
|
4429
|
+
for (const { column, direction } of options.orderBy) {
|
|
4430
|
+
q = q.order(String(column), { ascending: direction === "ASC" });
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
if (options.offset !== undefined && options.limit === undefined) {
|
|
4434
|
+
throw new StorageValidationError("queryIndex with offset requires limit (no implicit cap)");
|
|
4435
|
+
}
|
|
4436
|
+
if (options.offset !== undefined || options.limit !== undefined) {
|
|
4437
|
+
const start = options.offset ?? 0;
|
|
4438
|
+
if (options.limit !== undefined) {
|
|
4439
|
+
q = q.range(start, start + options.limit - 1);
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
const { data, error } = await q;
|
|
4443
|
+
if (error)
|
|
4444
|
+
throw error;
|
|
4445
|
+
if (!data)
|
|
4446
|
+
return [];
|
|
4447
|
+
const rows = data;
|
|
4448
|
+
const sel = new Set(options.select.map(String));
|
|
4449
|
+
for (const row of rows) {
|
|
4450
|
+
for (const key of Object.keys(row)) {
|
|
4451
|
+
if (sel.has(key)) {
|
|
4452
|
+
row[key] = this.sqlToJsValue(key, row[key]);
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
return rows;
|
|
4457
|
+
}
|
|
4096
4458
|
convertRealtimeRow(row) {
|
|
4097
4459
|
const entity = { ...row };
|
|
4098
4460
|
const record = entity;
|
|
@@ -4158,11 +4520,12 @@ class SupabaseKvStorage extends KvViaTabularStorage {
|
|
|
4158
4520
|
}
|
|
4159
4521
|
}
|
|
4160
4522
|
// src/queue/IndexedDbQueueStorage.ts
|
|
4161
|
-
import { createServiceToken as createServiceToken17, deepEqual as deepEqual3, makeFingerprint as makeFingerprint6, uuid4 as
|
|
4523
|
+
import { createServiceToken as createServiceToken17, deepEqual as deepEqual3, makeFingerprint as makeFingerprint6, uuid4 as uuid45 } from "@workglow/util";
|
|
4162
4524
|
var INDEXED_DB_QUEUE_STORAGE = createServiceToken17("jobqueue.storage.indexedDb");
|
|
4163
4525
|
|
|
4164
4526
|
class IndexedDbQueueStorage {
|
|
4165
4527
|
queueName;
|
|
4528
|
+
scope = "process";
|
|
4166
4529
|
db;
|
|
4167
4530
|
tableName;
|
|
4168
4531
|
migrationOptions;
|
|
@@ -4239,8 +4602,8 @@ class IndexedDbQueueStorage {
|
|
|
4239
4602
|
const db = await this.getDb();
|
|
4240
4603
|
const now = new Date().toISOString();
|
|
4241
4604
|
const jobWithPrefixes = job;
|
|
4242
|
-
jobWithPrefixes.id = jobWithPrefixes.id ??
|
|
4243
|
-
jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ??
|
|
4605
|
+
jobWithPrefixes.id = jobWithPrefixes.id ?? uuid45();
|
|
4606
|
+
jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid45();
|
|
4244
4607
|
jobWithPrefixes.queue = this.queueName;
|
|
4245
4608
|
jobWithPrefixes.fingerprint = await makeFingerprint6(jobWithPrefixes.input);
|
|
4246
4609
|
jobWithPrefixes.status = JobStatus.PENDING;
|
|
@@ -4738,11 +5101,12 @@ class IndexedDbQueueStorage {
|
|
|
4738
5101
|
}
|
|
4739
5102
|
}
|
|
4740
5103
|
// src/queue/SupabaseQueueStorage.ts
|
|
4741
|
-
import { createServiceToken as createServiceToken18, deepEqual as deepEqual4, makeFingerprint as makeFingerprint7, uuid4 as
|
|
5104
|
+
import { createServiceToken as createServiceToken18, deepEqual as deepEqual4, makeFingerprint as makeFingerprint7, uuid4 as uuid46 } from "@workglow/util";
|
|
4742
5105
|
var SUPABASE_QUEUE_STORAGE = createServiceToken18("jobqueue.storage.supabase");
|
|
4743
5106
|
|
|
4744
5107
|
class SupabaseQueueStorage {
|
|
4745
5108
|
queueName;
|
|
5109
|
+
scope = "cluster";
|
|
4746
5110
|
client;
|
|
4747
5111
|
prefixes;
|
|
4748
5112
|
prefixValues;
|
|
@@ -4867,7 +5231,7 @@ class SupabaseQueueStorage {
|
|
|
4867
5231
|
async add(job) {
|
|
4868
5232
|
const now = new Date().toISOString();
|
|
4869
5233
|
job.queue = this.queueName;
|
|
4870
|
-
job.job_run_id = job.job_run_id ??
|
|
5234
|
+
job.job_run_id = job.job_run_id ?? uuid46();
|
|
4871
5235
|
job.fingerprint = await makeFingerprint7(job.input);
|
|
4872
5236
|
job.status = JobStatus.PENDING;
|
|
4873
5237
|
job.progress = 0;
|
|
@@ -5269,6 +5633,7 @@ import { createServiceToken as createServiceToken19 } from "@workglow/util";
|
|
|
5269
5633
|
var INDEXED_DB_RATE_LIMITER_STORAGE = createServiceToken19("ratelimiter.storage.indexedDb");
|
|
5270
5634
|
|
|
5271
5635
|
class IndexedDbRateLimiterStorage {
|
|
5636
|
+
scope = "process";
|
|
5272
5637
|
executionDb;
|
|
5273
5638
|
nextAvailableDb;
|
|
5274
5639
|
executionTableName;
|
|
@@ -5337,6 +5702,72 @@ class IndexedDbRateLimiterStorage {
|
|
|
5337
5702
|
];
|
|
5338
5703
|
this.nextAvailableDb = await ensureIndexedDbTable(this.nextAvailableTableName, buildKeyPath(["queue_name"]).join("_"), nextAvailableIndexes, this.migrationOptions);
|
|
5339
5704
|
}
|
|
5705
|
+
async tryReserveExecution(queueName, maxExecutions, windowMs) {
|
|
5706
|
+
const nextIso = await this.getNextAvailableTime(queueName);
|
|
5707
|
+
if (nextIso && new Date(nextIso).getTime() > Date.now()) {
|
|
5708
|
+
return null;
|
|
5709
|
+
}
|
|
5710
|
+
const execDb = await this.getExecutionDb();
|
|
5711
|
+
const prefixKeyValues = this.getPrefixKeyValues();
|
|
5712
|
+
const windowStartIso = new Date(Date.now() - windowMs).toISOString();
|
|
5713
|
+
const execTx = execDb.transaction(this.executionTableName, "readwrite");
|
|
5714
|
+
const execStore = execTx.objectStore(this.executionTableName);
|
|
5715
|
+
const insertedId = crypto.randomUUID();
|
|
5716
|
+
return new Promise((resolve, reject) => {
|
|
5717
|
+
let liveCount = 0;
|
|
5718
|
+
let didInsert = false;
|
|
5719
|
+
const liveRange = IDBKeyRange.bound([...prefixKeyValues, queueName, windowStartIso], [...prefixKeyValues, queueName, ""], true, false);
|
|
5720
|
+
const cursorReq = execStore.index("queue_executed_at").openCursor(liveRange);
|
|
5721
|
+
cursorReq.onsuccess = (event) => {
|
|
5722
|
+
const cursor = event.target.result;
|
|
5723
|
+
if (cursor) {
|
|
5724
|
+
const record2 = cursor.value;
|
|
5725
|
+
if (this.matchesPrefixes(record2)) {
|
|
5726
|
+
liveCount++;
|
|
5727
|
+
}
|
|
5728
|
+
cursor.continue();
|
|
5729
|
+
return;
|
|
5730
|
+
}
|
|
5731
|
+
if (liveCount >= maxExecutions) {
|
|
5732
|
+
execTx.abort();
|
|
5733
|
+
return;
|
|
5734
|
+
}
|
|
5735
|
+
const record = {
|
|
5736
|
+
id: insertedId,
|
|
5737
|
+
queue_name: queueName,
|
|
5738
|
+
executed_at: new Date().toISOString()
|
|
5739
|
+
};
|
|
5740
|
+
for (const [k, v] of Object.entries(this.prefixValues)) {
|
|
5741
|
+
record[k] = v;
|
|
5742
|
+
}
|
|
5743
|
+
const addReq = execStore.add(record);
|
|
5744
|
+
didInsert = true;
|
|
5745
|
+
addReq.onerror = () => {
|
|
5746
|
+
try {
|
|
5747
|
+
execTx.abort();
|
|
5748
|
+
} catch {}
|
|
5749
|
+
reject(addReq.error);
|
|
5750
|
+
};
|
|
5751
|
+
};
|
|
5752
|
+
cursorReq.onerror = () => reject(cursorReq.error);
|
|
5753
|
+
execTx.oncomplete = () => resolve(didInsert ? insertedId : null);
|
|
5754
|
+
execTx.onerror = () => reject(execTx.error);
|
|
5755
|
+
execTx.onabort = () => resolve(null);
|
|
5756
|
+
});
|
|
5757
|
+
}
|
|
5758
|
+
async releaseExecution(queueName, token) {
|
|
5759
|
+
if (token === null || token === undefined)
|
|
5760
|
+
return;
|
|
5761
|
+
const db = await this.getExecutionDb();
|
|
5762
|
+
const tx = db.transaction(this.executionTableName, "readwrite");
|
|
5763
|
+
const store = tx.objectStore(this.executionTableName);
|
|
5764
|
+
return new Promise((resolve, reject) => {
|
|
5765
|
+
const req = store.delete(token);
|
|
5766
|
+
req.onerror = () => reject(req.error);
|
|
5767
|
+
tx.oncomplete = () => resolve();
|
|
5768
|
+
tx.onerror = () => reject(tx.error);
|
|
5769
|
+
});
|
|
5770
|
+
}
|
|
5340
5771
|
async recordExecution(queueName) {
|
|
5341
5772
|
const db = await this.getExecutionDb();
|
|
5342
5773
|
const tx = db.transaction(this.executionTableName, "readwrite");
|
|
@@ -5490,6 +5921,7 @@ import { createServiceToken as createServiceToken20 } from "@workglow/util";
|
|
|
5490
5921
|
var SUPABASE_RATE_LIMITER_STORAGE = createServiceToken20("ratelimiter.storage.supabase");
|
|
5491
5922
|
|
|
5492
5923
|
class SupabaseRateLimiterStorage {
|
|
5924
|
+
scope = "cluster";
|
|
5493
5925
|
client;
|
|
5494
5926
|
prefixes;
|
|
5495
5927
|
prefixValues;
|
|
@@ -5572,6 +6004,75 @@ class SupabaseRateLimiterStorage {
|
|
|
5572
6004
|
if (nextTableError && nextTableError.code !== "42P07") {
|
|
5573
6005
|
throw nextTableError;
|
|
5574
6006
|
}
|
|
6007
|
+
const fnName = this.atomicReserveFunctionName();
|
|
6008
|
+
const prefixSig = this.prefixes.map((p) => `${p.name} ${this.getPrefixColumnType(p.type)}`).join(", ");
|
|
6009
|
+
const prefixSigPrefix = prefixSig ? prefixSig + ", " : "";
|
|
6010
|
+
const prefixWhere = this.prefixes.length > 0 ? " AND " + this.prefixes.map((p) => `${p.name} = _${p.name}`).join(" AND ") : "";
|
|
6011
|
+
const prefixInsertCols = this.prefixes.length > 0 ? this.prefixes.map((p) => p.name).join(", ") + ", " : "";
|
|
6012
|
+
const prefixInsertVals = this.prefixes.length > 0 ? this.prefixes.map((p) => `_${p.name}`).join(", ") + ", " : "";
|
|
6013
|
+
const lockKeyParts = [`'${this.executionTableName}'`, ...this.prefixes.map((p) => `_${p.name}::text`), `_queue_name::text`];
|
|
6014
|
+
const lockKeyExpr = `hashtextextended(${lockKeyParts.join(" || '|' || ")}, 0)`;
|
|
6015
|
+
const createFnSql = `
|
|
6016
|
+
CREATE OR REPLACE FUNCTION ${fnName}(
|
|
6017
|
+
${prefixSigPrefix}_queue_name TEXT, _window_start TIMESTAMPTZ, _max_exec INT
|
|
6018
|
+
) RETURNS BIGINT AS $fn$
|
|
6019
|
+
DECLARE
|
|
6020
|
+
_count INT;
|
|
6021
|
+
_next TIMESTAMPTZ;
|
|
6022
|
+
_new_id BIGINT;
|
|
6023
|
+
BEGIN
|
|
6024
|
+
PERFORM pg_advisory_xact_lock(${lockKeyExpr});
|
|
6025
|
+
SELECT COUNT(*) INTO _count FROM ${this.executionTableName}
|
|
6026
|
+
WHERE queue_name = _queue_name AND executed_at > _window_start${prefixWhere};
|
|
6027
|
+
IF _count >= _max_exec THEN RETURN NULL; END IF;
|
|
6028
|
+
SELECT next_available_at INTO _next FROM ${this.nextAvailableTableName}
|
|
6029
|
+
WHERE queue_name = _queue_name${prefixWhere};
|
|
6030
|
+
IF _next IS NOT NULL AND _next > NOW() THEN RETURN NULL; END IF;
|
|
6031
|
+
INSERT INTO ${this.executionTableName} (${prefixInsertCols}queue_name)
|
|
6032
|
+
VALUES (${prefixInsertVals}_queue_name)
|
|
6033
|
+
RETURNING id INTO _new_id;
|
|
6034
|
+
RETURN _new_id;
|
|
6035
|
+
END;
|
|
6036
|
+
$fn$ LANGUAGE plpgsql;
|
|
6037
|
+
`;
|
|
6038
|
+
const { error: fnError } = await this.client.rpc("exec_sql", { query: createFnSql });
|
|
6039
|
+
if (fnError) {
|
|
6040
|
+
throw fnError;
|
|
6041
|
+
}
|
|
6042
|
+
}
|
|
6043
|
+
atomicReserveFunctionName() {
|
|
6044
|
+
return `${this.executionTableName}_try_reserve`.slice(0, 63);
|
|
6045
|
+
}
|
|
6046
|
+
async tryReserveExecution(queueName, maxExecutions, windowMs) {
|
|
6047
|
+
const args = {
|
|
6048
|
+
_queue_name: queueName,
|
|
6049
|
+
_window_start: new Date(Date.now() - windowMs).toISOString(),
|
|
6050
|
+
_max_exec: maxExecutions
|
|
6051
|
+
};
|
|
6052
|
+
for (const p of this.prefixes) {
|
|
6053
|
+
args[`_${p.name}`] = this.prefixValues[p.name];
|
|
6054
|
+
}
|
|
6055
|
+
const { data, error } = await this.client.rpc(this.atomicReserveFunctionName(), args);
|
|
6056
|
+
if (error)
|
|
6057
|
+
throw error;
|
|
6058
|
+
if (data === null || data === undefined)
|
|
6059
|
+
return null;
|
|
6060
|
+
if (Array.isArray(data)) {
|
|
6061
|
+
if (data.length === 0)
|
|
6062
|
+
return null;
|
|
6063
|
+
const first = Object.values(data[0])[0];
|
|
6064
|
+
return first ?? null;
|
|
6065
|
+
}
|
|
6066
|
+
return data;
|
|
6067
|
+
}
|
|
6068
|
+
async releaseExecution(queueName, token) {
|
|
6069
|
+
if (token === null || token === undefined)
|
|
6070
|
+
return;
|
|
6071
|
+
let del = this.client.from(this.executionTableName).delete().eq("id", token).eq("queue_name", queueName);
|
|
6072
|
+
del = this.applyPrefixFilters(del);
|
|
6073
|
+
const { error: delError } = await del;
|
|
6074
|
+
if (delError)
|
|
6075
|
+
throw delError;
|
|
5575
6076
|
}
|
|
5576
6077
|
async recordExecution(queueName) {
|
|
5577
6078
|
const prefixInsertValues = this.getPrefixInsertValues();
|
|
@@ -5739,6 +6240,7 @@ class IndexedDbVectorStorage extends IndexedDbTabularStorage {
|
|
|
5739
6240
|
export {
|
|
5740
6241
|
traced,
|
|
5741
6242
|
registerTabularRepository,
|
|
6243
|
+
pickCoveringIndex,
|
|
5742
6244
|
isSearchCondition,
|
|
5743
6245
|
getVectorProperty,
|
|
5744
6246
|
getTabularRepository,
|
|
@@ -5801,9 +6303,10 @@ export {
|
|
|
5801
6303
|
EncryptedKvCredentialStore,
|
|
5802
6304
|
DefaultKeyValueSchema,
|
|
5803
6305
|
DefaultKeyValueKey,
|
|
6306
|
+
CoveringIndexMissingError,
|
|
5804
6307
|
CachedTabularStorage,
|
|
5805
6308
|
CACHED_TABULAR_REPOSITORY,
|
|
5806
6309
|
BaseTabularStorage
|
|
5807
6310
|
};
|
|
5808
6311
|
|
|
5809
|
-
//# debugId=
|
|
6312
|
+
//# debugId=E2D716C3197417F164756E2164756E21
|