@workglow/storage 0.0.84 → 0.0.86

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 (108) hide show
  1. package/README.md +185 -53
  2. package/dist/browser.js +451 -188
  3. package/dist/browser.js.map +21 -18
  4. package/dist/bun.js +1069 -356
  5. package/dist/bun.js.map +29 -24
  6. package/dist/common-server.d.ts +17 -15
  7. package/dist/common-server.d.ts.map +1 -1
  8. package/dist/common.d.ts +13 -10
  9. package/dist/common.d.ts.map +1 -1
  10. package/dist/kv/{FsFolderJsonKvRepository.d.ts → FsFolderJsonKvStorage.d.ts} +8 -8
  11. package/dist/kv/FsFolderJsonKvStorage.d.ts.map +1 -0
  12. package/dist/kv/{FsFolderKvRepository.d.ts → FsFolderKvStorage.d.ts} +7 -7
  13. package/dist/kv/FsFolderKvStorage.d.ts.map +1 -0
  14. package/dist/kv/{IKvRepository.d.ts → IKvStorage.d.ts} +3 -3
  15. package/dist/kv/IKvStorage.d.ts.map +1 -0
  16. package/dist/kv/{InMemoryKvRepository.d.ts → InMemoryKvStorage.d.ts} +8 -8
  17. package/dist/kv/InMemoryKvStorage.d.ts.map +1 -0
  18. package/dist/kv/{IndexedDbKvRepository.d.ts → IndexedDbKvStorage.d.ts} +8 -8
  19. package/dist/kv/IndexedDbKvStorage.d.ts.map +1 -0
  20. package/dist/kv/{KvRepository.d.ts → KvStorage.d.ts} +7 -7
  21. package/dist/kv/KvStorage.d.ts.map +1 -0
  22. package/dist/kv/{KvViaTabularRepository.d.ts → KvViaTabularStorage.d.ts} +7 -7
  23. package/dist/kv/KvViaTabularStorage.d.ts.map +1 -0
  24. package/dist/kv/{PostgresKvRepository.d.ts → PostgresKvStorage.d.ts} +8 -8
  25. package/dist/kv/PostgresKvStorage.d.ts.map +1 -0
  26. package/dist/kv/{SqliteKvRepository.d.ts → SqliteKvStorage.d.ts} +8 -8
  27. package/dist/kv/SqliteKvStorage.d.ts.map +1 -0
  28. package/dist/kv/{SupabaseKvRepository.d.ts → SupabaseKvStorage.d.ts} +9 -9
  29. package/dist/kv/SupabaseKvStorage.d.ts.map +1 -0
  30. package/dist/node.js +1069 -356
  31. package/dist/node.js.map +29 -24
  32. package/dist/queue-limiter/IRateLimiterStorage.d.ts.map +1 -0
  33. package/dist/queue-limiter/InMemoryRateLimiterStorage.d.ts.map +1 -0
  34. package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts.map +1 -0
  35. package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts.map +1 -0
  36. package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts.map +1 -0
  37. package/dist/queue-limiter/SupabaseRateLimiterStorage.d.ts.map +1 -0
  38. package/dist/tabular/{BaseSqlTabularRepository.d.ts → BaseSqlTabularStorage.d.ts} +8 -7
  39. package/dist/tabular/BaseSqlTabularStorage.d.ts.map +1 -0
  40. package/dist/tabular/{TabularRepository.d.ts → BaseTabularStorage.d.ts} +52 -10
  41. package/dist/tabular/BaseTabularStorage.d.ts.map +1 -0
  42. package/dist/tabular/{CachedTabularRepository.d.ts → CachedTabularStorage.d.ts} +15 -14
  43. package/dist/tabular/CachedTabularStorage.d.ts.map +1 -0
  44. package/dist/tabular/{FsFolderTabularRepository.d.ts → FsFolderTabularStorage.d.ts} +22 -12
  45. package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -0
  46. package/dist/tabular/{ITabularRepository.d.ts → ITabularStorage.d.ts} +29 -6
  47. package/dist/tabular/ITabularStorage.d.ts.map +1 -0
  48. package/dist/tabular/{InMemoryTabularRepository.d.ts → InMemoryTabularStorage.d.ts} +24 -14
  49. package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -0
  50. package/dist/tabular/{IndexedDbTabularRepository.d.ts → IndexedDbTabularStorage.d.ts} +20 -11
  51. package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -0
  52. package/dist/tabular/{PostgresTabularRepository.d.ts → PostgresTabularStorage.d.ts} +37 -15
  53. package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -0
  54. package/dist/tabular/{SharedInMemoryTabularRepository.d.ts → SharedInMemoryTabularStorage.d.ts} +14 -13
  55. package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -0
  56. package/dist/tabular/{SqliteTabularRepository.d.ts → SqliteTabularStorage.d.ts} +25 -11
  57. package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -0
  58. package/dist/tabular/{SupabaseTabularRepository.d.ts → SupabaseTabularStorage.d.ts} +17 -15
  59. package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -0
  60. package/dist/tabular/TabularStorageRegistry.d.ts +29 -0
  61. package/dist/tabular/TabularStorageRegistry.d.ts.map +1 -0
  62. package/dist/util/IndexedDbTable.d.ts +1 -1
  63. package/dist/util/IndexedDbTable.d.ts.map +1 -1
  64. package/dist/vector/IVectorStorage.d.ts +83 -0
  65. package/dist/vector/IVectorStorage.d.ts.map +1 -0
  66. package/dist/vector/InMemoryVectorStorage.d.ts +41 -0
  67. package/dist/vector/InMemoryVectorStorage.d.ts.map +1 -0
  68. package/dist/vector/PostgresVectorStorage.d.ts +57 -0
  69. package/dist/vector/PostgresVectorStorage.d.ts.map +1 -0
  70. package/dist/vector/SqliteVectorStorage.d.ts +45 -0
  71. package/dist/vector/SqliteVectorStorage.d.ts.map +1 -0
  72. package/package.json +5 -5
  73. package/src/kv/README.md +3 -3
  74. package/src/tabular/README.md +186 -23
  75. package/src/vector/README.md +393 -0
  76. package/dist/kv/FsFolderJsonKvRepository.d.ts.map +0 -1
  77. package/dist/kv/FsFolderKvRepository.d.ts.map +0 -1
  78. package/dist/kv/IKvRepository.d.ts.map +0 -1
  79. package/dist/kv/InMemoryKvRepository.d.ts.map +0 -1
  80. package/dist/kv/IndexedDbKvRepository.d.ts.map +0 -1
  81. package/dist/kv/KvRepository.d.ts.map +0 -1
  82. package/dist/kv/KvViaTabularRepository.d.ts.map +0 -1
  83. package/dist/kv/PostgresKvRepository.d.ts.map +0 -1
  84. package/dist/kv/SqliteKvRepository.d.ts.map +0 -1
  85. package/dist/kv/SupabaseKvRepository.d.ts.map +0 -1
  86. package/dist/limiter/IRateLimiterStorage.d.ts.map +0 -1
  87. package/dist/limiter/InMemoryRateLimiterStorage.d.ts.map +0 -1
  88. package/dist/limiter/IndexedDbRateLimiterStorage.d.ts.map +0 -1
  89. package/dist/limiter/PostgresRateLimiterStorage.d.ts.map +0 -1
  90. package/dist/limiter/SqliteRateLimiterStorage.d.ts.map +0 -1
  91. package/dist/limiter/SupabaseRateLimiterStorage.d.ts.map +0 -1
  92. package/dist/tabular/BaseSqlTabularRepository.d.ts.map +0 -1
  93. package/dist/tabular/CachedTabularRepository.d.ts.map +0 -1
  94. package/dist/tabular/FsFolderTabularRepository.d.ts.map +0 -1
  95. package/dist/tabular/ITabularRepository.d.ts.map +0 -1
  96. package/dist/tabular/InMemoryTabularRepository.d.ts.map +0 -1
  97. package/dist/tabular/IndexedDbTabularRepository.d.ts.map +0 -1
  98. package/dist/tabular/PostgresTabularRepository.d.ts.map +0 -1
  99. package/dist/tabular/SharedInMemoryTabularRepository.d.ts.map +0 -1
  100. package/dist/tabular/SqliteTabularRepository.d.ts.map +0 -1
  101. package/dist/tabular/SupabaseTabularRepository.d.ts.map +0 -1
  102. package/dist/tabular/TabularRepository.d.ts.map +0 -1
  103. /package/dist/{limiter → queue-limiter}/IRateLimiterStorage.d.ts +0 -0
  104. /package/dist/{limiter → queue-limiter}/InMemoryRateLimiterStorage.d.ts +0 -0
  105. /package/dist/{limiter → queue-limiter}/IndexedDbRateLimiterStorage.d.ts +0 -0
  106. /package/dist/{limiter → queue-limiter}/PostgresRateLimiterStorage.d.ts +0 -0
  107. /package/dist/{limiter → queue-limiter}/SqliteRateLimiterStorage.d.ts +0 -0
  108. /package/dist/{limiter → queue-limiter}/SupabaseRateLimiterStorage.d.ts +0 -0
package/dist/node.js CHANGED
@@ -1,18 +1,4 @@
1
- // src/tabular/CachedTabularRepository.ts
2
- import { createServiceToken as createServiceToken3 } from "@workglow/util";
3
-
4
- // src/tabular/InMemoryTabularRepository.ts
5
- import {
6
- createServiceToken as createServiceToken2,
7
- makeFingerprint as makeFingerprint2
8
- } from "@workglow/util";
9
-
10
- // src/tabular/ITabularRepository.ts
11
- function isSearchCondition(value) {
12
- return typeof value === "object" && value !== null && "value" in value && "operator" in value && typeof value.operator === "string";
13
- }
14
-
15
- // src/tabular/TabularRepository.ts
1
+ // src/tabular/BaseTabularStorage.ts
16
2
  import {
17
3
  createServiceToken,
18
4
  EventEmitter,
@@ -20,16 +6,20 @@ import {
20
6
  } from "@workglow/util";
21
7
  var TABULAR_REPOSITORY = createServiceToken("storage.tabularRepository");
22
8
 
23
- class TabularRepository {
9
+ class BaseTabularStorage {
24
10
  schema;
25
11
  primaryKeyNames;
26
12
  events = new EventEmitter;
27
13
  indexes;
28
14
  primaryKeySchema;
29
15
  valueSchema;
30
- constructor(schema, primaryKeyNames, indexes = []) {
16
+ autoGeneratedKeyName = null;
17
+ autoGeneratedKeyStrategy = null;
18
+ clientProvidedKeys;
19
+ constructor(schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
31
20
  this.schema = schema;
32
21
  this.primaryKeyNames = primaryKeyNames;
22
+ this.clientProvidedKeys = clientProvidedKeys;
33
23
  const primaryKeyProps = {};
34
24
  const valueProps = {};
35
25
  const primaryKeySet = new Set(primaryKeyNames);
@@ -72,6 +62,28 @@ class TabularRepository {
72
62
  }
73
63
  }
74
64
  }
65
+ const autoGeneratedKeys = [];
66
+ for (const key of primaryKeyNames) {
67
+ const keyStr = String(key);
68
+ const propDef = schema.properties[keyStr];
69
+ if (propDef && typeof propDef === "object" && "x-auto-generated" in propDef) {
70
+ if (propDef["x-auto-generated"] === true) {
71
+ autoGeneratedKeys.push(keyStr);
72
+ }
73
+ }
74
+ }
75
+ if (autoGeneratedKeys.length > 1) {
76
+ throw new Error(`Multiple auto-generated keys detected: ${autoGeneratedKeys.join(", ")}. ` + `Only the first primary key column can be auto-generated.`);
77
+ }
78
+ if (autoGeneratedKeys.length > 0) {
79
+ const autoGenKeyName = autoGeneratedKeys[0];
80
+ const firstPrimaryKey = String(primaryKeyNames[0]);
81
+ if (autoGenKeyName !== firstPrimaryKey) {
82
+ throw new Error(`Auto-generated key "${autoGenKeyName}" must be the first primary key column. ` + `Current first primary key is "${firstPrimaryKey}".`);
83
+ }
84
+ this.autoGeneratedKeyName = autoGenKeyName;
85
+ this.autoGeneratedKeyStrategy = this.determineGenerationStrategy(autoGenKeyName, schema.properties[autoGenKeyName]);
86
+ }
75
87
  }
76
88
  filterCompoundKeys(primaryKey, potentialKeys) {
77
89
  const isPrefix = (prefix, arr) => {
@@ -193,6 +205,32 @@ class TabularRepository {
193
205
  }
194
206
  return bestMatch;
195
207
  }
208
+ hasAutoGeneratedKey() {
209
+ return this.autoGeneratedKeyName !== null;
210
+ }
211
+ isAutoGeneratedKey(name) {
212
+ return this.autoGeneratedKeyName !== null && String(this.autoGeneratedKeyName) === name;
213
+ }
214
+ determineGenerationStrategy(columnName, typeDef) {
215
+ let actualType = typeDef;
216
+ if (typeDef && typeof typeDef === "object") {
217
+ if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {
218
+ actualType = typeDef.anyOf.find((t) => t.type !== "null") || typeDef;
219
+ } else if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {
220
+ actualType = typeDef.oneOf.find((t) => t.type !== "null") || typeDef;
221
+ }
222
+ }
223
+ if (typeof actualType !== "object") {
224
+ return "uuid";
225
+ }
226
+ if (actualType.type === "integer") {
227
+ return "autoincrement";
228
+ }
229
+ return "uuid";
230
+ }
231
+ generateKeyValue(columnName, strategy) {
232
+ throw new Error(`generateKeyValue not implemented for ${this.constructor.name}. ` + `Column: ${columnName}, Strategy: ${strategy}`);
233
+ }
196
234
  async setupDatabase() {}
197
235
  destroy() {}
198
236
  async[Symbol.asyncDispose]() {
@@ -202,22 +240,67 @@ class TabularRepository {
202
240
  this.destroy();
203
241
  }
204
242
  }
243
+ // src/tabular/CachedTabularStorage.ts
244
+ import {
245
+ createServiceToken as createServiceToken3
246
+ } from "@workglow/util";
205
247
 
206
- // src/tabular/InMemoryTabularRepository.ts
248
+ // src/tabular/InMemoryTabularStorage.ts
249
+ import {
250
+ createServiceToken as createServiceToken2,
251
+ makeFingerprint as makeFingerprint2,
252
+ uuid4
253
+ } from "@workglow/util";
254
+
255
+ // src/tabular/ITabularStorage.ts
256
+ function isSearchCondition(value) {
257
+ return typeof value === "object" && value !== null && "value" in value && "operator" in value && typeof value.operator === "string";
258
+ }
259
+
260
+ // src/tabular/InMemoryTabularStorage.ts
207
261
  var MEMORY_TABULAR_REPOSITORY = createServiceToken2("storage.tabularRepository.inMemory");
208
262
 
209
- class InMemoryTabularRepository extends TabularRepository {
263
+ class InMemoryTabularStorage extends BaseTabularStorage {
210
264
  values = new Map;
211
- constructor(schema, primaryKeyNames, indexes = []) {
212
- super(schema, primaryKeyNames, indexes);
265
+ autoIncrementCounter = 0;
266
+ constructor(schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
267
+ super(schema, primaryKeyNames, indexes, clientProvidedKeys);
213
268
  }
214
269
  async setupDatabase() {}
270
+ generateKeyValue(columnName, strategy) {
271
+ if (strategy === "autoincrement") {
272
+ return ++this.autoIncrementCounter;
273
+ } else {
274
+ return uuid4();
275
+ }
276
+ }
215
277
  async put(value) {
216
- const { key } = this.separateKeyValueFromCombined(value);
278
+ let entityToStore = value;
279
+ if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {
280
+ const keyName = this.autoGeneratedKeyName;
281
+ const clientProvidedValue = value[keyName];
282
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
283
+ let shouldGenerate = false;
284
+ if (this.clientProvidedKeys === "never") {
285
+ shouldGenerate = true;
286
+ } else if (this.clientProvidedKeys === "always") {
287
+ if (!hasClientValue) {
288
+ throw new Error(`Auto-generated key "${keyName}" is required when clientProvidedKeys is "always"`);
289
+ }
290
+ shouldGenerate = false;
291
+ } else {
292
+ shouldGenerate = !hasClientValue;
293
+ }
294
+ if (shouldGenerate) {
295
+ const generatedValue = this.generateKeyValue(keyName, this.autoGeneratedKeyStrategy);
296
+ entityToStore = { ...value, [keyName]: generatedValue };
297
+ }
298
+ }
299
+ const { key } = this.separateKeyValueFromCombined(entityToStore);
217
300
  const id = await makeFingerprint2(key);
218
- this.values.set(id, value);
219
- this.events.emit("put", value);
220
- return value;
301
+ this.values.set(id, entityToStore);
302
+ this.events.emit("put", entityToStore);
303
+ return entityToStore;
221
304
  }
222
305
  async putBulk(values) {
223
306
  return await Promise.all(values.map(async (value) => this.put(value)));
@@ -338,23 +421,23 @@ class InMemoryTabularRepository extends TabularRepository {
338
421
  }
339
422
  }
340
423
 
341
- // src/tabular/CachedTabularRepository.ts
424
+ // src/tabular/CachedTabularStorage.ts
342
425
  var CACHED_TABULAR_REPOSITORY = createServiceToken3("storage.tabularRepository.cached");
343
426
 
344
- class CachedTabularRepository extends TabularRepository {
427
+ class CachedTabularStorage extends BaseTabularStorage {
345
428
  cache;
346
429
  durable;
347
430
  cacheInitialized = false;
348
- constructor(durable, cache, schema, primaryKeyNames, indexes) {
431
+ constructor(durable, cache, schema, primaryKeyNames, indexes, clientProvidedKeys = "if-missing") {
349
432
  if (!schema || !primaryKeyNames) {
350
- throw new Error("Schema and primaryKeyNames must be provided when creating CachedTabularRepository");
433
+ throw new Error("Schema and primaryKeyNames must be provided when creating CachedTabularStorage");
351
434
  }
352
- super(schema, primaryKeyNames, indexes || []);
435
+ super(schema, primaryKeyNames, indexes || [], clientProvidedKeys);
353
436
  this.durable = durable;
354
437
  if (cache) {
355
438
  this.cache = cache;
356
439
  } else {
357
- this.cache = new InMemoryTabularRepository(schema, primaryKeyNames, indexes || []);
440
+ this.cache = new InMemoryTabularStorage(schema, primaryKeyNames, indexes || [], clientProvidedKeys);
358
441
  }
359
442
  this.setupEventForwarding();
360
443
  }
@@ -481,7 +564,36 @@ class CachedTabularRepository extends TabularRepository {
481
564
  this.cache.destroy();
482
565
  }
483
566
  }
484
- // src/kv/IKvRepository.ts
567
+ // src/tabular/TabularStorageRegistry.ts
568
+ import {
569
+ createServiceToken as createServiceToken4,
570
+ globalServiceRegistry,
571
+ registerInputResolver
572
+ } from "@workglow/util";
573
+ var TABULAR_REPOSITORIES = createServiceToken4("storage.tabular.repositories");
574
+ if (!globalServiceRegistry.has(TABULAR_REPOSITORIES)) {
575
+ globalServiceRegistry.register(TABULAR_REPOSITORIES, () => new Map, true);
576
+ }
577
+ function getGlobalTabularRepositories() {
578
+ return globalServiceRegistry.get(TABULAR_REPOSITORIES);
579
+ }
580
+ function registerTabularRepository(id, repository) {
581
+ const repos = getGlobalTabularRepositories();
582
+ repos.set(id, repository);
583
+ }
584
+ function getTabularRepository(id) {
585
+ return getGlobalTabularRepositories().get(id);
586
+ }
587
+ function resolveRepositoryFromRegistry(id, format, registry) {
588
+ const repos = registry.has(TABULAR_REPOSITORIES) ? registry.get(TABULAR_REPOSITORIES) : getGlobalTabularRepositories();
589
+ const repo = repos.get(id);
590
+ if (!repo) {
591
+ throw new Error(`Tabular storage "${id}" not found in registry`);
592
+ }
593
+ return repo;
594
+ }
595
+ registerInputResolver("storage:tabular", resolveRepositoryFromRegistry);
596
+ // src/kv/IKvStorage.ts
485
597
  var DefaultKeyValueSchema = {
486
598
  type: "object",
487
599
  properties: {
@@ -491,14 +603,14 @@ var DefaultKeyValueSchema = {
491
603
  additionalProperties: false
492
604
  };
493
605
  var DefaultKeyValueKey = ["key"];
494
- // src/kv/InMemoryKvRepository.ts
495
- import { createServiceToken as createServiceToken5 } from "@workglow/util";
606
+ // src/kv/InMemoryKvStorage.ts
607
+ import { createServiceToken as createServiceToken6 } from "@workglow/util";
496
608
 
497
- // src/kv/KvRepository.ts
498
- import { createServiceToken as createServiceToken4, EventEmitter as EventEmitter2, makeFingerprint as makeFingerprint3 } from "@workglow/util";
499
- var KV_REPOSITORY = createServiceToken4("storage.kvRepository");
609
+ // src/kv/KvStorage.ts
610
+ import { createServiceToken as createServiceToken5, EventEmitter as EventEmitter2, makeFingerprint as makeFingerprint3 } from "@workglow/util";
611
+ var KV_REPOSITORY = createServiceToken5("storage.kvRepository");
500
612
 
501
- class KvRepository {
613
+ class KvStorage {
502
614
  keySchema;
503
615
  valueSchema;
504
616
  events = new EventEmitter2;
@@ -526,8 +638,8 @@ class KvRepository {
526
638
  }
527
639
  }
528
640
 
529
- // src/kv/KvViaTabularRepository.ts
530
- class KvViaTabularRepository extends KvRepository {
641
+ // src/kv/KvViaTabularStorage.ts
642
+ class KvViaTabularStorage extends KvStorage {
531
643
  async setupDatabase() {
532
644
  await this.tabularRepository.setupDatabase?.();
533
645
  }
@@ -602,22 +714,22 @@ class KvViaTabularRepository extends KvRepository {
602
714
  }
603
715
  }
604
716
 
605
- // src/kv/InMemoryKvRepository.ts
606
- var MEMORY_KV_REPOSITORY = createServiceToken5("storage.kvRepository.inMemory");
717
+ // src/kv/InMemoryKvStorage.ts
718
+ var MEMORY_KV_REPOSITORY = createServiceToken6("storage.kvRepository.inMemory");
607
719
 
608
- class InMemoryKvRepository extends KvViaTabularRepository {
720
+ class InMemoryKvStorage extends KvViaTabularStorage {
609
721
  tabularRepository;
610
722
  constructor(keySchema = { type: "string" }, valueSchema = {}) {
611
723
  super(keySchema, valueSchema);
612
- this.tabularRepository = new InMemoryTabularRepository(DefaultKeyValueSchema, DefaultKeyValueKey);
724
+ this.tabularRepository = new InMemoryTabularStorage(DefaultKeyValueSchema, DefaultKeyValueKey);
613
725
  }
614
726
  }
615
727
  // src/queue/InMemoryQueueStorage.ts
616
- import { createServiceToken as createServiceToken7, EventEmitter as EventEmitter3, makeFingerprint as makeFingerprint4, sleep, uuid4 } from "@workglow/util";
728
+ import { createServiceToken as createServiceToken8, EventEmitter as EventEmitter3, makeFingerprint as makeFingerprint4, sleep, uuid4 as uuid42 } from "@workglow/util";
617
729
 
618
730
  // src/queue/IQueueStorage.ts
619
- import { createServiceToken as createServiceToken6 } from "@workglow/util";
620
- var QUEUE_STORAGE = createServiceToken6("jobqueue.storage");
731
+ import { createServiceToken as createServiceToken7 } from "@workglow/util";
732
+ var QUEUE_STORAGE = createServiceToken7("jobqueue.storage");
621
733
  var JobStatus = {
622
734
  PENDING: "PENDING",
623
735
  PROCESSING: "PROCESSING",
@@ -628,7 +740,7 @@ var JobStatus = {
628
740
  };
629
741
 
630
742
  // src/queue/InMemoryQueueStorage.ts
631
- var IN_MEMORY_QUEUE_STORAGE = createServiceToken7("jobqueue.storage.inMemory");
743
+ var IN_MEMORY_QUEUE_STORAGE = createServiceToken8("jobqueue.storage.inMemory");
632
744
 
633
745
  class InMemoryQueueStorage {
634
746
  queueName;
@@ -656,8 +768,8 @@ class InMemoryQueueStorage {
656
768
  await sleep(0);
657
769
  const now = new Date().toISOString();
658
770
  const jobWithPrefixes = job;
659
- jobWithPrefixes.id = jobWithPrefixes.id ?? uuid4();
660
- jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid4();
771
+ jobWithPrefixes.id = jobWithPrefixes.id ?? uuid42();
772
+ jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid42();
661
773
  jobWithPrefixes.queue = this.queueName;
662
774
  jobWithPrefixes.fingerprint = await makeFingerprint4(jobWithPrefixes.input);
663
775
  jobWithPrefixes.status = JobStatus.PENDING;
@@ -804,9 +916,9 @@ class InMemoryQueueStorage {
804
916
  return this.events.subscribe("change", filteredCallback);
805
917
  }
806
918
  }
807
- // src/limiter/InMemoryRateLimiterStorage.ts
808
- import { createServiceToken as createServiceToken8, sleep as sleep2 } from "@workglow/util";
809
- var IN_MEMORY_RATE_LIMITER_STORAGE = createServiceToken8("ratelimiter.storage.inMemory");
919
+ // src/queue-limiter/InMemoryRateLimiterStorage.ts
920
+ import { createServiceToken as createServiceToken9, sleep as sleep2 } from "@workglow/util";
921
+ var IN_MEMORY_RATE_LIMITER_STORAGE = createServiceToken9("ratelimiter.storage.inMemory");
810
922
 
811
923
  class InMemoryRateLimiterStorage {
812
924
  prefixValues;
@@ -863,9 +975,9 @@ class InMemoryRateLimiterStorage {
863
975
  this.nextAvailableTimes.delete(key);
864
976
  }
865
977
  }
866
- // src/limiter/IRateLimiterStorage.ts
867
- import { createServiceToken as createServiceToken9 } from "@workglow/util";
868
- var RATE_LIMITER_STORAGE = createServiceToken9("ratelimiter.storage");
978
+ // src/queue-limiter/IRateLimiterStorage.ts
979
+ import { createServiceToken as createServiceToken10 } from "@workglow/util";
980
+ var RATE_LIMITER_STORAGE = createServiceToken10("ratelimiter.storage");
869
981
  // src/util/HybridSubscriptionManager.ts
870
982
  class HybridSubscriptionManager {
871
983
  subscribers = new Set;
@@ -1139,21 +1251,141 @@ class PollingSubscriptionManager {
1139
1251
  this.initialized = false;
1140
1252
  }
1141
1253
  }
1142
- // src/tabular/FsFolderTabularRepository.ts
1254
+ // src/vector/InMemoryVectorStorage.ts
1255
+ import { cosineSimilarity } from "@workglow/util";
1256
+
1257
+ // src/vector/IVectorStorage.ts
1258
+ function getVectorProperty(schema) {
1259
+ for (const [key, value] of Object.entries(schema.properties)) {
1260
+ if (typeof value !== "boolean" && value.type === "array" && (value.format === "TypedArray" || value.format?.startsWith("TypedArray:"))) {
1261
+ return key;
1262
+ }
1263
+ }
1264
+ return;
1265
+ }
1266
+ function getMetadataProperty(schema) {
1267
+ for (const [key, value] of Object.entries(schema.properties)) {
1268
+ if (typeof value !== "boolean" && value.type === "object" && value.format === "metadata") {
1269
+ return key;
1270
+ }
1271
+ }
1272
+ return;
1273
+ }
1274
+
1275
+ // src/vector/InMemoryVectorStorage.ts
1276
+ function matchesFilter(metadata, filter) {
1277
+ for (const [key, value] of Object.entries(filter)) {
1278
+ if (metadata[key] !== value) {
1279
+ return false;
1280
+ }
1281
+ }
1282
+ return true;
1283
+ }
1284
+ function textRelevance(text, query) {
1285
+ const textLower = text.toLowerCase();
1286
+ const queryLower = query.toLowerCase();
1287
+ const queryWords = queryLower.split(/\s+/).filter((w) => w.length > 0);
1288
+ if (queryWords.length === 0) {
1289
+ return 0;
1290
+ }
1291
+ let matches = 0;
1292
+ for (const word of queryWords) {
1293
+ if (textLower.includes(word)) {
1294
+ matches++;
1295
+ }
1296
+ }
1297
+ return matches / queryWords.length;
1298
+ }
1299
+
1300
+ class InMemoryVectorStorage extends InMemoryTabularStorage {
1301
+ vectorDimensions;
1302
+ VectorType;
1303
+ vectorPropertyName;
1304
+ metadataPropertyName;
1305
+ constructor(schema, primaryKeyNames, indexes = [], dimensions, VectorType = Float32Array) {
1306
+ super(schema, primaryKeyNames, indexes);
1307
+ this.vectorDimensions = dimensions;
1308
+ this.VectorType = VectorType;
1309
+ const vectorProp = getVectorProperty(schema);
1310
+ if (!vectorProp) {
1311
+ throw new Error("Schema must have a property with type array and format TypedArray");
1312
+ }
1313
+ this.vectorPropertyName = vectorProp;
1314
+ this.metadataPropertyName = getMetadataProperty(schema);
1315
+ }
1316
+ getVectorDimensions() {
1317
+ return this.vectorDimensions;
1318
+ }
1319
+ async similaritySearch(query, options = {}) {
1320
+ const { topK = 10, filter, scoreThreshold = 0 } = options;
1321
+ const results = [];
1322
+ const allEntities = await this.getAll() || [];
1323
+ for (const entity of allEntities) {
1324
+ const vector = entity[this.vectorPropertyName];
1325
+ const metadata = this.metadataPropertyName ? entity[this.metadataPropertyName] : {};
1326
+ if (filter && !matchesFilter(metadata, filter)) {
1327
+ continue;
1328
+ }
1329
+ const score = cosineSimilarity(query, vector);
1330
+ if (score < scoreThreshold) {
1331
+ continue;
1332
+ }
1333
+ results.push({
1334
+ ...entity,
1335
+ score
1336
+ });
1337
+ }
1338
+ results.sort((a, b) => b.score - a.score);
1339
+ const topResults = results.slice(0, topK);
1340
+ return topResults;
1341
+ }
1342
+ async hybridSearch(query, options) {
1343
+ const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;
1344
+ if (!textQuery || textQuery.trim().length === 0) {
1345
+ return this.similaritySearch(query, { topK, filter, scoreThreshold });
1346
+ }
1347
+ const results = [];
1348
+ const allEntities = await this.getAll() || [];
1349
+ for (const entity of allEntities) {
1350
+ const vector = entity[this.vectorPropertyName];
1351
+ const metadata = this.metadataPropertyName ? entity[this.metadataPropertyName] : {};
1352
+ if (filter && !matchesFilter(metadata, filter)) {
1353
+ continue;
1354
+ }
1355
+ const vectorScore = cosineSimilarity(query, vector);
1356
+ const metadataText = Object.values(metadata).join(" ").toLowerCase();
1357
+ const textScore = textRelevance(metadataText, textQuery);
1358
+ const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;
1359
+ if (combinedScore < scoreThreshold) {
1360
+ continue;
1361
+ }
1362
+ results.push({
1363
+ ...entity,
1364
+ score: combinedScore
1365
+ });
1366
+ }
1367
+ results.sort((a, b) => b.score - a.score);
1368
+ const topResults = results.slice(0, topK);
1369
+ return topResults;
1370
+ }
1371
+ }
1372
+ // src/tabular/FsFolderTabularStorage.ts
1143
1373
  import {
1144
- createServiceToken as createServiceToken10,
1374
+ createServiceToken as createServiceToken11,
1145
1375
  makeFingerprint as makeFingerprint5,
1146
- sleep as sleep3
1376
+ sleep as sleep3,
1377
+ uuid4 as uuid43
1147
1378
  } from "@workglow/util";
1148
1379
  import { mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
1149
1380
  import path from "node:path";
1150
- var FS_FOLDER_TABULAR_REPOSITORY = createServiceToken10("storage.tabularRepository.fsFolder");
1381
+ var FS_FOLDER_TABULAR_REPOSITORY = createServiceToken11("storage.tabularRepository.fsFolder");
1151
1382
 
1152
- class FsFolderTabularRepository extends TabularRepository {
1383
+ class FsFolderTabularStorage extends BaseTabularStorage {
1153
1384
  folderPath;
1385
+ autoIncrementCounter = 0;
1154
1386
  pollingManager = null;
1155
- constructor(folderPath, schema, primaryKeyNames, indexes = []) {
1156
- super(schema, primaryKeyNames, indexes);
1387
+ constructor(folderPath, schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
1388
+ super(schema, primaryKeyNames, indexes, clientProvidedKeys);
1157
1389
  this.folderPath = path.join(folderPath);
1158
1390
  }
1159
1391
  async setupDirectory() {
@@ -1166,11 +1398,39 @@ class FsFolderTabularRepository extends TabularRepository {
1166
1398
  } catch {}
1167
1399
  }
1168
1400
  }
1401
+ generateKeyValue(columnName, strategy) {
1402
+ if (strategy === "autoincrement") {
1403
+ return ++this.autoIncrementCounter;
1404
+ } else {
1405
+ return uuid43();
1406
+ }
1407
+ }
1169
1408
  async put(entity) {
1409
+ let entityToStore = entity;
1410
+ if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {
1411
+ const keyName = this.autoGeneratedKeyName;
1412
+ const clientProvidedValue = entity[keyName];
1413
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
1414
+ let shouldGenerate = false;
1415
+ if (this.clientProvidedKeys === "never") {
1416
+ shouldGenerate = true;
1417
+ } else if (this.clientProvidedKeys === "always") {
1418
+ if (!hasClientValue) {
1419
+ throw new Error(`Auto-generated key "${keyName}" is required when clientProvidedKeys is "always"`);
1420
+ }
1421
+ shouldGenerate = false;
1422
+ } else {
1423
+ shouldGenerate = !hasClientValue;
1424
+ }
1425
+ if (shouldGenerate) {
1426
+ const generatedValue = this.generateKeyValue(keyName, this.autoGeneratedKeyStrategy);
1427
+ entityToStore = { ...entity, [keyName]: generatedValue };
1428
+ }
1429
+ }
1170
1430
  await this.setupDirectory();
1171
- const filePath = await this.getFilePath(entity);
1431
+ const filePath = await this.getFilePath(entityToStore);
1172
1432
  try {
1173
- await writeFile(filePath, JSON.stringify(entity));
1433
+ await writeFile(filePath, JSON.stringify(entityToStore));
1174
1434
  } catch (error) {
1175
1435
  try {
1176
1436
  await sleep3(1);
@@ -1179,8 +1439,8 @@ class FsFolderTabularRepository extends TabularRepository {
1179
1439
  console.error("Error writing file", filePath, error2);
1180
1440
  }
1181
1441
  }
1182
- this.events.emit("put", entity);
1183
- return entity;
1442
+ this.events.emit("put", entityToStore);
1443
+ return entityToStore;
1184
1444
  }
1185
1445
  async putBulk(entities) {
1186
1446
  await this.setupDirectory();
@@ -1244,7 +1504,7 @@ class FsFolderTabularRepository extends TabularRepository {
1244
1504
  return jsonFiles.length;
1245
1505
  }
1246
1506
  async search(key) {
1247
- throw new Error("Search not supported for FsFolderTabularRepository");
1507
+ throw new Error("Search not supported for FsFolderTabularStorage");
1248
1508
  }
1249
1509
  async getFilePath(value) {
1250
1510
  const { key } = this.separateKeyValueFromCombined(value);
@@ -1253,7 +1513,7 @@ class FsFolderTabularRepository extends TabularRepository {
1253
1513
  return fullPath;
1254
1514
  }
1255
1515
  async deleteSearch(_criteria) {
1256
- throw new Error("deleteSearch is not supported for FsFolderTabularRepository");
1516
+ throw new Error("deleteSearch is not supported for FsFolderTabularStorage");
1257
1517
  }
1258
1518
  getPollingManager() {
1259
1519
  if (!this.pollingManager) {
@@ -1287,14 +1547,16 @@ class FsFolderTabularRepository extends TabularRepository {
1287
1547
  super.destroy();
1288
1548
  }
1289
1549
  }
1290
- // src/tabular/PostgresTabularRepository.ts
1291
- import { createServiceToken as createServiceToken11 } from "@workglow/util";
1550
+ // src/tabular/PostgresTabularStorage.ts
1551
+ import {
1552
+ createServiceToken as createServiceToken12
1553
+ } from "@workglow/util";
1292
1554
 
1293
- // src/tabular/BaseSqlTabularRepository.ts
1294
- class BaseSqlTabularRepository extends TabularRepository {
1555
+ // src/tabular/BaseSqlTabularStorage.ts
1556
+ class BaseSqlTabularStorage extends BaseTabularStorage {
1295
1557
  table;
1296
- constructor(table = "tabular_store", schema, primaryKeyNames, indexes = []) {
1297
- super(schema, primaryKeyNames, indexes);
1558
+ constructor(table = "tabular_store", schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
1559
+ super(schema, primaryKeyNames, indexes, clientProvidedKeys);
1298
1560
  this.table = table;
1299
1561
  this.validateTableAndSchema();
1300
1562
  }
@@ -1473,13 +1735,13 @@ class BaseSqlTabularRepository extends TabularRepository {
1473
1735
  }
1474
1736
  }
1475
1737
 
1476
- // src/tabular/PostgresTabularRepository.ts
1477
- var POSTGRES_TABULAR_REPOSITORY = createServiceToken11("storage.tabularRepository.postgres");
1738
+ // src/tabular/PostgresTabularStorage.ts
1739
+ var POSTGRES_TABULAR_REPOSITORY = createServiceToken12("storage.tabularRepository.postgres");
1478
1740
 
1479
- class PostgresTabularRepository extends BaseSqlTabularRepository {
1741
+ class PostgresTabularStorage extends BaseSqlTabularStorage {
1480
1742
  db;
1481
- constructor(db, table = "tabular_store", schema, primaryKeyNames, indexes = []) {
1482
- super(table, schema, primaryKeyNames, indexes);
1743
+ constructor(db, table = "tabular_store", schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
1744
+ super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);
1483
1745
  this.db = db;
1484
1746
  }
1485
1747
  async setupDatabase() {
@@ -1490,6 +1752,7 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1490
1752
  )
1491
1753
  `;
1492
1754
  await this.db.query(sql);
1755
+ await this.createVectorIndexes();
1493
1756
  const pkColumns = this.primaryKeyColumns();
1494
1757
  const createdIndexes = new Set;
1495
1758
  for (const columns of this.indexes) {
@@ -1513,6 +1776,14 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1513
1776
  }
1514
1777
  }
1515
1778
  }
1779
+ isVectorFormat(format) {
1780
+ if (!format)
1781
+ return false;
1782
+ return format.startsWith("TypedArray:") || format === "TypedArray";
1783
+ }
1784
+ getVectorDimensions(typeDef) {
1785
+ return;
1786
+ }
1516
1787
  mapTypeToSQL(typeDef) {
1517
1788
  const actualType = this.getNonNullType(typeDef);
1518
1789
  if (typeof actualType === "boolean") {
@@ -1532,6 +1803,12 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1532
1803
  return "VARCHAR(2048)";
1533
1804
  if (actualType.format === "uuid")
1534
1805
  return "UUID";
1806
+ if (this.isVectorFormat(actualType.format)) {
1807
+ const dimension = this.getVectorDimensions(actualType);
1808
+ if (typeof dimension === "number") {
1809
+ return `vector(${dimension})`;
1810
+ }
1811
+ }
1535
1812
  if (typeof actualType.maxLength === "number") {
1536
1813
  return `VARCHAR(${actualType.maxLength})`;
1537
1814
  }
@@ -1599,6 +1876,17 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1599
1876
  }
1600
1877
  constructPrimaryKeyColumns($delimiter = "") {
1601
1878
  const cols = Object.entries(this.primaryKeySchema.properties).map(([key, typeDef]) => {
1879
+ if (this.isAutoGeneratedKey(key)) {
1880
+ if (this.autoGeneratedKeyStrategy === "autoincrement") {
1881
+ const sqlType2 = this.mapTypeToSQL(typeDef);
1882
+ const isSmallInt = sqlType2.includes("SMALLINT");
1883
+ const isBigInt = sqlType2.includes("BIGINT");
1884
+ const serialType = isBigInt ? "BIGSERIAL" : isSmallInt ? "SMALLSERIAL" : "SERIAL";
1885
+ return `${$delimiter}${key}${$delimiter} ${serialType}`;
1886
+ } else if (this.autoGeneratedKeyStrategy === "uuid") {
1887
+ return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;
1888
+ }
1889
+ }
1602
1890
  const sqlType = this.mapTypeToSQL(typeDef);
1603
1891
  let constraints = "NOT NULL";
1604
1892
  if (this.shouldBeUnsigned(typeDef)) {
@@ -1626,6 +1914,22 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1626
1914
  return "";
1627
1915
  }
1628
1916
  }
1917
+ jsToSqlValue(column, value) {
1918
+ const typeDef = this.schema.properties[column];
1919
+ if (typeDef) {
1920
+ const actualType = this.getNonNullType(typeDef);
1921
+ if (typeof actualType !== "boolean" && this.isVectorFormat(actualType.format)) {
1922
+ if (value && ArrayBuffer.isView(value) && !(value instanceof DataView)) {
1923
+ const array = Array.from(value);
1924
+ return `[${array.join(",")}]`;
1925
+ }
1926
+ if (typeof value === "string") {
1927
+ return value;
1928
+ }
1929
+ }
1930
+ }
1931
+ return super.jsToSqlValue(column, value);
1932
+ }
1629
1933
  sqlToJsValue(column, value) {
1630
1934
  const typeDef = this.schema.properties[column];
1631
1935
  if (typeDef) {
@@ -1633,6 +1937,19 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1633
1937
  return null;
1634
1938
  }
1635
1939
  const actualType = this.getNonNullType(typeDef);
1940
+ if (typeof actualType !== "boolean" && this.isVectorFormat(actualType.format)) {
1941
+ if (typeof value === "string") {
1942
+ try {
1943
+ const array = JSON.parse(value);
1944
+ return new Float32Array(array);
1945
+ } catch (e) {
1946
+ console.warn(`Failed to parse vector for column ${column}:`, e);
1947
+ }
1948
+ }
1949
+ if (value && typeof value === "object") {
1950
+ return value;
1951
+ }
1952
+ }
1636
1953
  if (typeof actualType !== "boolean" && (actualType.type === "number" || actualType.type === "integer")) {
1637
1954
  const v = value;
1638
1955
  if (typeof v === "number")
@@ -1656,30 +1973,105 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1656
1973
  }
1657
1974
  return false;
1658
1975
  }
1976
+ getVectorColumns() {
1977
+ const vectorColumns = [];
1978
+ for (const [key, typeDef] of Object.entries(this.schema.properties)) {
1979
+ const actualType = this.getNonNullType(typeDef);
1980
+ if (typeof actualType !== "boolean" && this.isVectorFormat(actualType.format)) {
1981
+ const dimension = this.getVectorDimensions(actualType);
1982
+ if (typeof dimension === "number") {
1983
+ vectorColumns.push({ column: key, dimension });
1984
+ } else {
1985
+ console.warn(`Invalid vector format for column ${key}: ${actualType.format}, skipping`);
1986
+ }
1987
+ }
1988
+ }
1989
+ return vectorColumns;
1990
+ }
1991
+ async createVectorIndexes() {
1992
+ const vectorColumns = this.getVectorColumns();
1993
+ if (vectorColumns.length === 0) {
1994
+ return;
1995
+ }
1996
+ try {
1997
+ await this.db.query("CREATE EXTENSION IF NOT EXISTS vector");
1998
+ } catch (error) {
1999
+ console.warn("pgvector extension not available, vector columns will use TEXT fallback:", error);
2000
+ return;
2001
+ }
2002
+ for (const { column } of vectorColumns) {
2003
+ const indexName = `${this.table}_${column}_hnsw_idx`;
2004
+ try {
2005
+ await this.db.query(`
2006
+ CREATE INDEX IF NOT EXISTS "${indexName}"
2007
+ ON "${this.table}"
2008
+ USING hnsw ("${column}" vector_cosine_ops)
2009
+ `);
2010
+ } catch (error) {
2011
+ console.warn(`Failed to create HNSW index on ${column}:`, error);
2012
+ }
2013
+ }
2014
+ }
1659
2015
  async put(entity) {
1660
2016
  const db = this.db;
1661
- const { key, value } = this.separateKeyValueFromCombined(entity);
1662
- const sql = `
1663
- INSERT INTO "${this.table}" (
1664
- ${this.primaryKeyColumnList('"')} ${this.valueColumnList() ? ", " + this.valueColumnList('"') : ""}
1665
- )
1666
- VALUES (
1667
- ${[...this.primaryKeyColumns(), ...this.valueColumns()].map((_, i) => `$${i + 1}`).join(", ")}
1668
- )
1669
- ${!this.valueColumnList() ? "" : `
2017
+ const columnsToInsert = [];
2018
+ const paramsToInsert = [];
2019
+ let paramIndex = 1;
2020
+ const pkColumns = this.primaryKeyColumns();
2021
+ for (const col of pkColumns) {
2022
+ const colStr = String(col);
2023
+ if (this.isAutoGeneratedKey(colStr)) {
2024
+ const clientProvidedValue = entity[col];
2025
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
2026
+ let shouldUseClientValue = false;
2027
+ if (this.clientProvidedKeys === "never") {
2028
+ shouldUseClientValue = false;
2029
+ } else if (this.clientProvidedKeys === "always") {
2030
+ if (!hasClientValue) {
2031
+ throw new Error(`Auto-generated key "${colStr}" is required when clientProvidedKeys is "always"`);
2032
+ }
2033
+ shouldUseClientValue = true;
2034
+ } else {
2035
+ shouldUseClientValue = hasClientValue;
2036
+ }
2037
+ if (shouldUseClientValue) {
2038
+ columnsToInsert.push(colStr);
2039
+ paramsToInsert.push(this.jsToSqlValue(colStr, clientProvidedValue));
2040
+ }
2041
+ continue;
2042
+ }
2043
+ columnsToInsert.push(colStr);
2044
+ const value = entity[col];
2045
+ paramsToInsert.push(this.jsToSqlValue(colStr, value));
2046
+ }
2047
+ const valueColumns = this.valueColumns();
2048
+ for (const col of valueColumns) {
2049
+ const colStr = String(col);
2050
+ columnsToInsert.push(colStr);
2051
+ const value = entity[col];
2052
+ paramsToInsert.push(this.jsToSqlValue(colStr, value));
2053
+ }
2054
+ const columnList = columnsToInsert.map((c) => `"${c}"`).join(", ");
2055
+ const placeholders = columnsToInsert.map((_, i) => `$${i + 1}`).join(", ");
2056
+ const conflictClause = valueColumns.length > 0 ? `
1670
2057
  ON CONFLICT (${this.primaryKeyColumnList('"')}) DO UPDATE
1671
2058
  SET
1672
- ${this.valueColumns().map((col, i) => `"${col}" = $${i + this.primaryKeyColumns().length + 1}`).join(", ")}
1673
- `}
2059
+ ${valueColumns.map((col) => {
2060
+ const colIdx = columnsToInsert.indexOf(String(col));
2061
+ return `"${col}" = $${colIdx + 1}`;
2062
+ }).join(", ")}
2063
+ ` : "";
2064
+ const sql = `
2065
+ INSERT INTO "${this.table}" (${columnList})
2066
+ VALUES (${placeholders})
2067
+ ${conflictClause}
1674
2068
  RETURNING *
1675
2069
  `;
1676
- const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);
1677
- const valueParams = this.getValueAsOrderedArray(value);
1678
- const params = [...primaryKeyParams, ...valueParams];
2070
+ const params = paramsToInsert;
1679
2071
  const result = await db.query(sql, params);
1680
2072
  const updatedEntity = result.rows[0];
1681
- for (const key2 in this.schema.properties) {
1682
- updatedEntity[key2] = this.sqlToJsValue(key2, updatedEntity[key2]);
2073
+ for (const key in this.schema.properties) {
2074
+ updatedEntity[key] = this.sqlToJsValue(key, updatedEntity[key]);
1683
2075
  }
1684
2076
  this.events.emit("put", updatedEntity);
1685
2077
  return updatedEntity;
@@ -1687,45 +2079,7 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1687
2079
  async putBulk(entities) {
1688
2080
  if (entities.length === 0)
1689
2081
  return [];
1690
- const db = this.db;
1691
- const allParams = [];
1692
- const valuesPerRow = this.primaryKeyColumns().length + this.valueColumns().length;
1693
- let paramIndex = 1;
1694
- const valuesClauses = entities.map((entity) => {
1695
- const { key, value } = this.separateKeyValueFromCombined(entity);
1696
- const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);
1697
- const valueParams = this.getValueAsOrderedArray(value);
1698
- const entityParams = [...primaryKeyParams, ...valueParams];
1699
- allParams.push(...entityParams);
1700
- const placeholders = Array(valuesPerRow).fill(0).map(() => `$${paramIndex++}`).join(", ");
1701
- return `(${placeholders})`;
1702
- }).join(", ");
1703
- const sql = `
1704
- INSERT INTO "${this.table}" (
1705
- ${this.primaryKeyColumnList('"')} ${this.valueColumnList() ? ", " + this.valueColumnList('"') : ""}
1706
- )
1707
- VALUES ${valuesClauses}
1708
- ${!this.valueColumnList() ? "" : `
1709
- ON CONFLICT (${this.primaryKeyColumnList('"')}) DO UPDATE
1710
- SET
1711
- ${this.valueColumns().map((col) => {
1712
- return `"${col}" = EXCLUDED."${col}"`;
1713
- }).join(", ")}
1714
- `}
1715
- RETURNING *
1716
- `;
1717
- const result = await db.query(sql, allParams);
1718
- const updatedEntities = result.rows.map((row) => {
1719
- const entity = row;
1720
- for (const key in this.schema.properties) {
1721
- entity[key] = this.sqlToJsValue(key, entity[key]);
1722
- }
1723
- return entity;
1724
- });
1725
- for (const entity of updatedEntities) {
1726
- this.events.emit("put", entity);
1727
- }
1728
- return updatedEntities;
2082
+ return await Promise.all(entities.map((entity) => this.put(entity)));
1729
2083
  }
1730
2084
  async get(key) {
1731
2085
  const db = this.db;
@@ -1846,35 +2200,53 @@ class PostgresTabularRepository extends BaseSqlTabularRepository {
1846
2200
  this.events.emit("delete", criteriaKeys[0]);
1847
2201
  }
1848
2202
  subscribeToChanges(callback, options) {
1849
- throw new Error("subscribeToChanges is not supported for PostgresTabularRepository");
2203
+ throw new Error("subscribeToChanges is not supported for PostgresTabularStorage");
1850
2204
  }
1851
2205
  destroy() {
1852
2206
  super.destroy();
1853
2207
  }
1854
2208
  }
1855
- // src/tabular/SqliteTabularRepository.ts
2209
+ // src/tabular/SqliteTabularStorage.ts
1856
2210
  import { Sqlite } from "@workglow/sqlite";
1857
- import { createServiceToken as createServiceToken12 } from "@workglow/util";
1858
- var SQLITE_TABULAR_REPOSITORY = createServiceToken12("storage.tabularRepository.sqlite");
2211
+ import {
2212
+ createServiceToken as createServiceToken13,
2213
+ uuid4 as uuid44
2214
+ } from "@workglow/util";
2215
+ var SQLITE_TABULAR_REPOSITORY = createServiceToken13("storage.tabularRepository.sqlite");
1859
2216
  var Database = Sqlite.Database;
1860
2217
 
1861
- class SqliteTabularRepository extends BaseSqlTabularRepository {
2218
+ class SqliteTabularStorage extends BaseSqlTabularStorage {
1862
2219
  db;
1863
- constructor(dbOrPath, table = "tabular_store", schema, primaryKeyNames, indexes = []) {
1864
- super(table, schema, primaryKeyNames, indexes);
2220
+ constructor(dbOrPath, table = "tabular_store", schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
2221
+ super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);
1865
2222
  if (typeof dbOrPath === "string") {
1866
2223
  this.db = new Database(dbOrPath);
1867
2224
  } else {
1868
2225
  this.db = dbOrPath;
1869
2226
  }
1870
2227
  }
2228
+ constructPrimaryKeyColumns($delimiter = "") {
2229
+ const cols = Object.entries(this.primaryKeySchema.properties).map(([key, typeDef]) => {
2230
+ if (this.isAutoGeneratedKey(key) && this.autoGeneratedKeyStrategy === "autoincrement") {
2231
+ return `${$delimiter}${key}${$delimiter} INTEGER PRIMARY KEY AUTOINCREMENT`;
2232
+ }
2233
+ const sqlType = this.mapTypeToSQL(typeDef);
2234
+ return `${$delimiter}${key}${$delimiter} ${sqlType} NOT NULL`;
2235
+ }).join(", ");
2236
+ return cols;
2237
+ }
1871
2238
  async setupDatabase() {
1872
- const sql = `
1873
- CREATE TABLE IF NOT EXISTS \`${this.table}\` (
1874
- ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()},
1875
- PRIMARY KEY (${this.primaryKeyColumnList()})
1876
- )
1877
- `;
2239
+ const hasAutoIncrementKey = this.hasAutoGeneratedKey() && this.autoGeneratedKeyStrategy === "autoincrement";
2240
+ const sql = hasAutoIncrementKey ? `
2241
+ CREATE TABLE IF NOT EXISTS \`${this.table}\` (
2242
+ ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()}
2243
+ )
2244
+ ` : `
2245
+ CREATE TABLE IF NOT EXISTS \`${this.table}\` (
2246
+ ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()},
2247
+ PRIMARY KEY (${this.primaryKeyColumnList()})
2248
+ )
2249
+ `;
1878
2250
  this.db.exec(sql);
1879
2251
  const pkColumns = this.primaryKeyColumns();
1880
2252
  const createdIndexes = new Set;
@@ -2015,21 +2387,71 @@ class SqliteTabularRepository extends BaseSqlTabularRepository {
2015
2387
  return "TEXT /* unknown type */";
2016
2388
  }
2017
2389
  }
2390
+ generateKeyValue(columnName, strategy) {
2391
+ if (strategy === "uuid") {
2392
+ return uuid44();
2393
+ }
2394
+ throw new Error(`SQLite autoincrement keys are generated by the database, not client-side. Column: ${columnName}`);
2395
+ }
2018
2396
  async put(entity) {
2019
2397
  const db = this.db;
2020
- const { key, value } = this.separateKeyValueFromCombined(entity);
2398
+ let entityToInsert = entity;
2399
+ if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {
2400
+ const keyName = String(this.autoGeneratedKeyName);
2401
+ const clientProvidedValue = entity[keyName];
2402
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
2403
+ let shouldUseClientValue = false;
2404
+ if (this.clientProvidedKeys === "never") {
2405
+ shouldUseClientValue = false;
2406
+ } else if (this.clientProvidedKeys === "always") {
2407
+ if (!hasClientValue) {
2408
+ throw new Error(`Auto-generated key "${keyName}" is required when clientProvidedKeys is "always"`);
2409
+ }
2410
+ shouldUseClientValue = true;
2411
+ } else {
2412
+ shouldUseClientValue = hasClientValue;
2413
+ }
2414
+ if (this.autoGeneratedKeyStrategy === "uuid" && !shouldUseClientValue) {
2415
+ const generatedValue = this.generateKeyValue(keyName, "uuid");
2416
+ entityToInsert = { ...entity, [keyName]: generatedValue };
2417
+ } else if (this.autoGeneratedKeyStrategy === "uuid" && shouldUseClientValue) {
2418
+ entityToInsert = entity;
2419
+ }
2420
+ }
2421
+ let columnsToInsert = [];
2422
+ let paramsToInsert = [];
2423
+ const pkColumns = this.primaryKeyColumns();
2424
+ for (const col of pkColumns) {
2425
+ const colStr = String(col);
2426
+ if (this.isAutoGeneratedKey(colStr) && this.autoGeneratedKeyStrategy === "autoincrement" && this.clientProvidedKeys !== "always") {
2427
+ const clientProvidedValue = entityToInsert[colStr];
2428
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
2429
+ if (this.clientProvidedKeys === "if-missing" && hasClientValue) {
2430
+ columnsToInsert.push(colStr);
2431
+ paramsToInsert.push(this.jsToSqlValue(colStr, clientProvidedValue));
2432
+ }
2433
+ continue;
2434
+ }
2435
+ columnsToInsert.push(colStr);
2436
+ const value = entityToInsert[colStr];
2437
+ paramsToInsert.push(this.jsToSqlValue(colStr, value));
2438
+ }
2439
+ const valueColumns = this.valueColumns();
2440
+ for (const col of valueColumns) {
2441
+ const colStr = String(col);
2442
+ columnsToInsert.push(colStr);
2443
+ const value = entityToInsert[colStr];
2444
+ paramsToInsert.push(this.jsToSqlValue(colStr, value));
2445
+ }
2446
+ const columnList = columnsToInsert.map((c) => `\`${c}\``).join(", ");
2447
+ const placeholders = columnsToInsert.map(() => "?").join(", ");
2021
2448
  const sql = `
2022
- INSERT OR REPLACE INTO \`${this.table}\` (${this.primaryKeyColumnList()} ${this.valueColumnList() ? ", " + this.valueColumnList() : ""})
2023
- VALUES (
2024
- ${this.primaryKeyColumns().map((i) => "?")}
2025
- ${this.valueColumns().length > 0 ? ", " + this.valueColumns().map((i) => "?") : ""}
2026
- )
2449
+ INSERT OR REPLACE INTO \`${this.table}\` (${columnList})
2450
+ VALUES (${placeholders})
2027
2451
  RETURNING *
2028
2452
  `;
2029
2453
  const stmt = db.prepare(sql);
2030
- const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);
2031
- const valueParams = this.getValueAsOrderedArray(value);
2032
- const params = [...primaryKeyParams, ...valueParams];
2454
+ const params = paramsToInsert;
2033
2455
  for (let i = 0;i < params.length; i++) {
2034
2456
  let param = params[i];
2035
2457
  if (param === undefined) {
@@ -2084,46 +2506,7 @@ class SqliteTabularRepository extends BaseSqlTabularRepository {
2084
2506
  async putBulk(entities) {
2085
2507
  if (entities.length === 0)
2086
2508
  return [];
2087
- const db = this.db;
2088
- const updatedEntities = [];
2089
- const transaction = db.transaction((entitiesToInsert) => {
2090
- for (const entity of entitiesToInsert) {
2091
- const { key, value } = this.separateKeyValueFromCombined(entity);
2092
- const sql = `
2093
- INSERT OR REPLACE INTO \`${this.table}\` (${this.primaryKeyColumnList()} ${this.valueColumnList() ? ", " + this.valueColumnList() : ""})
2094
- VALUES (
2095
- ${this.primaryKeyColumns().map(() => "?").join(", ")}
2096
- ${this.valueColumns().length > 0 ? ", " + this.valueColumns().map(() => "?").join(", ") : ""}
2097
- )
2098
- RETURNING *
2099
- `;
2100
- const stmt = db.prepare(sql);
2101
- const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);
2102
- const valueParams = this.getValueAsOrderedArray(value);
2103
- const params = [...primaryKeyParams, ...valueParams];
2104
- for (let i = 0;i < params.length; i++) {
2105
- let param = params[i];
2106
- if (param === undefined) {
2107
- params[i] = null;
2108
- } else if (param !== null && typeof param === "object") {
2109
- const paramObj = param;
2110
- if (!(paramObj instanceof Uint8Array) && (typeof Buffer === "undefined" || !(paramObj instanceof Buffer))) {
2111
- params[i] = JSON.stringify(paramObj);
2112
- }
2113
- }
2114
- }
2115
- const updatedEntity = stmt.get(...params);
2116
- for (const k in this.schema.properties) {
2117
- updatedEntity[k] = this.sqlToJsValue(k, updatedEntity[k]);
2118
- }
2119
- updatedEntities.push(updatedEntity);
2120
- }
2121
- });
2122
- transaction(entities);
2123
- for (const entity of updatedEntities) {
2124
- this.events.emit("put", entity);
2125
- }
2126
- return updatedEntities;
2509
+ return await Promise.all(entities.map((entity) => this.put(entity)));
2127
2510
  }
2128
2511
  async get(key) {
2129
2512
  const db = this.db;
@@ -2248,21 +2631,23 @@ class SqliteTabularRepository extends BaseSqlTabularRepository {
2248
2631
  this.events.emit("delete", criteriaKeys[0]);
2249
2632
  }
2250
2633
  subscribeToChanges(callback, options) {
2251
- throw new Error("subscribeToChanges is not supported for SqliteTabularRepository");
2634
+ throw new Error("subscribeToChanges is not supported for SqliteTabularStorage");
2252
2635
  }
2253
2636
  destroy() {
2254
2637
  super.destroy();
2255
2638
  }
2256
2639
  }
2257
- // src/tabular/SupabaseTabularRepository.ts
2258
- import { createServiceToken as createServiceToken13 } from "@workglow/util";
2259
- var SUPABASE_TABULAR_REPOSITORY = createServiceToken13("storage.tabularRepository.supabase");
2640
+ // src/tabular/SupabaseTabularStorage.ts
2641
+ import {
2642
+ createServiceToken as createServiceToken14
2643
+ } from "@workglow/util";
2644
+ var SUPABASE_TABULAR_REPOSITORY = createServiceToken14("storage.tabularRepository.supabase");
2260
2645
 
2261
- class SupabaseTabularRepository extends BaseSqlTabularRepository {
2646
+ class SupabaseTabularStorage extends BaseSqlTabularStorage {
2262
2647
  client;
2263
2648
  realtimeChannel = null;
2264
- constructor(client, table = "tabular_store", schema, primaryKeyNames, indexes = []) {
2265
- super(table, schema, primaryKeyNames, indexes);
2649
+ constructor(client, table = "tabular_store", schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
2650
+ super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);
2266
2651
  this.client = client;
2267
2652
  }
2268
2653
  async setupDatabase() {
@@ -2389,6 +2774,17 @@ class SupabaseTabularRepository extends BaseSqlTabularRepository {
2389
2774
  }
2390
2775
  constructPrimaryKeyColumns($delimiter = "") {
2391
2776
  const cols = Object.entries(this.primaryKeySchema.properties).map(([key, typeDef]) => {
2777
+ if (this.isAutoGeneratedKey(key)) {
2778
+ if (this.autoGeneratedKeyStrategy === "autoincrement") {
2779
+ const sqlType2 = this.mapTypeToSQL(typeDef);
2780
+ const isSmallInt = sqlType2.includes("SMALLINT");
2781
+ const isBigInt = sqlType2.includes("BIGINT");
2782
+ const serialType = isBigInt ? "BIGSERIAL" : isSmallInt ? "SMALLSERIAL" : "SERIAL";
2783
+ return `${$delimiter}${key}${$delimiter} ${serialType}`;
2784
+ } else if (this.autoGeneratedKeyStrategy === "uuid") {
2785
+ return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;
2786
+ }
2787
+ }
2392
2788
  const sqlType = this.mapTypeToSQL(typeDef);
2393
2789
  let constraints = "NOT NULL";
2394
2790
  if (this.shouldBeUnsigned(typeDef)) {
@@ -2448,7 +2844,27 @@ class SupabaseTabularRepository extends BaseSqlTabularRepository {
2448
2844
  return false;
2449
2845
  }
2450
2846
  async put(entity) {
2451
- const normalizedEntity = { ...entity };
2847
+ let entityToInsert = { ...entity };
2848
+ if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {
2849
+ const keyName = String(this.autoGeneratedKeyName);
2850
+ const clientProvidedValue = entity[keyName];
2851
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
2852
+ let shouldOmitKey = false;
2853
+ if (this.clientProvidedKeys === "never") {
2854
+ shouldOmitKey = true;
2855
+ } else if (this.clientProvidedKeys === "always") {
2856
+ if (!hasClientValue) {
2857
+ throw new Error(`Auto-generated key "${keyName}" is required when clientProvidedKeys is "always"`);
2858
+ }
2859
+ shouldOmitKey = false;
2860
+ } else {
2861
+ shouldOmitKey = !hasClientValue;
2862
+ }
2863
+ if (shouldOmitKey) {
2864
+ delete entityToInsert[keyName];
2865
+ }
2866
+ }
2867
+ const normalizedEntity = { ...entityToInsert };
2452
2868
  const requiredSet = new Set(this.valueSchema.required ?? []);
2453
2869
  for (const key in this.valueSchema.properties) {
2454
2870
  if (!(key in normalizedEntity) || normalizedEntity[key] === undefined) {
@@ -2470,29 +2886,7 @@ class SupabaseTabularRepository extends BaseSqlTabularRepository {
2470
2886
  async putBulk(entities) {
2471
2887
  if (entities.length === 0)
2472
2888
  return [];
2473
- const requiredSet = new Set(this.valueSchema.required ?? []);
2474
- const normalizedEntities = entities.map((entity) => {
2475
- const normalized = { ...entity };
2476
- for (const key in this.valueSchema.properties) {
2477
- if (!(key in normalized) || normalized[key] === undefined) {
2478
- if (!requiredSet.has(key)) {
2479
- normalized[key] = null;
2480
- }
2481
- }
2482
- }
2483
- return normalized;
2484
- });
2485
- const { data, error } = await this.client.from(this.table).upsert(normalizedEntities, { onConflict: this.primaryKeyColumnList() }).select();
2486
- if (error)
2487
- throw error;
2488
- const updatedEntities = data;
2489
- for (const entity of updatedEntities) {
2490
- for (const key in this.schema.properties) {
2491
- entity[key] = this.sqlToJsValue(key, entity[key]);
2492
- }
2493
- this.events.emit("put", entity);
2494
- }
2495
- return updatedEntities;
2889
+ return await Promise.all(entities.map((entity) => this.put(entity)));
2496
2890
  }
2497
2891
  async get(key) {
2498
2892
  let query = this.client.from(this.table).select("*");
@@ -2665,26 +3059,26 @@ class SupabaseTabularRepository extends BaseSqlTabularRepository {
2665
3059
  }
2666
3060
  }
2667
3061
  }
2668
- // src/kv/FsFolderJsonKvRepository.ts
2669
- import { createServiceToken as createServiceToken14 } from "@workglow/util";
2670
- var FS_FOLDER_JSON_KV_REPOSITORY = createServiceToken14("storage.kvRepository.fsFolderJson");
3062
+ // src/kv/FsFolderJsonKvStorage.ts
3063
+ import { createServiceToken as createServiceToken15 } from "@workglow/util";
3064
+ var FS_FOLDER_JSON_KV_REPOSITORY = createServiceToken15("storage.kvRepository.fsFolderJson");
2671
3065
 
2672
- class FsFolderJsonKvRepository extends KvViaTabularRepository {
3066
+ class FsFolderJsonKvStorage extends KvViaTabularStorage {
2673
3067
  folderPath;
2674
3068
  tabularRepository;
2675
3069
  constructor(folderPath, keySchema = { type: "string" }, valueSchema = {}) {
2676
3070
  super(keySchema, valueSchema);
2677
3071
  this.folderPath = folderPath;
2678
- this.tabularRepository = new FsFolderTabularRepository(folderPath, DefaultKeyValueSchema, DefaultKeyValueKey);
3072
+ this.tabularRepository = new FsFolderTabularStorage(folderPath, DefaultKeyValueSchema, DefaultKeyValueKey);
2679
3073
  }
2680
3074
  }
2681
- // src/kv/FsFolderKvRepository.ts
2682
- import { createServiceToken as createServiceToken15 } from "@workglow/util";
3075
+ // src/kv/FsFolderKvStorage.ts
3076
+ import { createServiceToken as createServiceToken16 } from "@workglow/util";
2683
3077
  import { mkdir as mkdir2, readFile as readFile2, rm as rm2, unlink, writeFile as writeFile2 } from "fs/promises";
2684
3078
  import path2 from "path";
2685
- var FS_FOLDER_KV_REPOSITORY = createServiceToken15("storage.kvRepository.fsFolder");
3079
+ var FS_FOLDER_KV_REPOSITORY = createServiceToken16("storage.kvRepository.fsFolder");
2686
3080
 
2687
- class FsFolderKvRepository extends KvRepository {
3081
+ class FsFolderKvStorage extends KvStorage {
2688
3082
  folderPath;
2689
3083
  pathWriter;
2690
3084
  constructor(folderPath, pathWriter, keySchema = { type: "string" }, valueSchema = { contentEncoding: "blob" }) {
@@ -2758,11 +3152,11 @@ class FsFolderKvRepository extends KvRepository {
2758
3152
  throw new Error("Not implemented");
2759
3153
  }
2760
3154
  }
2761
- // src/kv/PostgresKvRepository.ts
2762
- import { createServiceToken as createServiceToken16 } from "@workglow/util";
2763
- var POSTGRES_KV_REPOSITORY = createServiceToken16("storage.kvRepository.postgres");
3155
+ // src/kv/PostgresKvStorage.ts
3156
+ import { createServiceToken as createServiceToken17 } from "@workglow/util";
3157
+ var POSTGRES_KV_REPOSITORY = createServiceToken17("storage.kvRepository.postgres");
2764
3158
 
2765
- class PostgresKvRepository extends KvViaTabularRepository {
3159
+ class PostgresKvStorage extends KvViaTabularStorage {
2766
3160
  db;
2767
3161
  dbName;
2768
3162
  tabularRepository;
@@ -2770,14 +3164,14 @@ class PostgresKvRepository extends KvViaTabularRepository {
2770
3164
  super(keySchema, valueSchema);
2771
3165
  this.db = db;
2772
3166
  this.dbName = dbName;
2773
- this.tabularRepository = new PostgresTabularRepository(db, dbName, DefaultKeyValueSchema, DefaultKeyValueKey);
3167
+ this.tabularRepository = new PostgresTabularStorage(db, dbName, DefaultKeyValueSchema, DefaultKeyValueKey);
2774
3168
  }
2775
3169
  }
2776
- // src/kv/SqliteKvRepository.ts
2777
- import { createServiceToken as createServiceToken17 } from "@workglow/util";
2778
- var SQLITE_KV_REPOSITORY = createServiceToken17("storage.kvRepository.sqlite");
3170
+ // src/kv/SqliteKvStorage.ts
3171
+ import { createServiceToken as createServiceToken18 } from "@workglow/util";
3172
+ var SQLITE_KV_REPOSITORY = createServiceToken18("storage.kvRepository.sqlite");
2779
3173
 
2780
- class SqliteKvRepository extends KvViaTabularRepository {
3174
+ class SqliteKvStorage extends KvViaTabularStorage {
2781
3175
  db;
2782
3176
  dbName;
2783
3177
  tabularRepository;
@@ -2785,14 +3179,14 @@ class SqliteKvRepository extends KvViaTabularRepository {
2785
3179
  super(keySchema, valueSchema);
2786
3180
  this.db = db;
2787
3181
  this.dbName = dbName;
2788
- this.tabularRepository = new SqliteTabularRepository(db, dbName, DefaultKeyValueSchema, DefaultKeyValueKey);
3182
+ this.tabularRepository = new SqliteTabularStorage(db, dbName, DefaultKeyValueSchema, DefaultKeyValueKey);
2789
3183
  }
2790
3184
  }
2791
- // src/kv/SupabaseKvRepository.ts
2792
- import { createServiceToken as createServiceToken18 } from "@workglow/util";
2793
- var SUPABASE_KV_REPOSITORY = createServiceToken18("storage.kvRepository.supabase");
3185
+ // src/kv/SupabaseKvStorage.ts
3186
+ import { createServiceToken as createServiceToken19 } from "@workglow/util";
3187
+ var SUPABASE_KV_REPOSITORY = createServiceToken19("storage.kvRepository.supabase");
2794
3188
 
2795
- class SupabaseKvRepository extends KvViaTabularRepository {
3189
+ class SupabaseKvStorage extends KvViaTabularStorage {
2796
3190
  client;
2797
3191
  tableName;
2798
3192
  tabularRepository;
@@ -2800,12 +3194,12 @@ class SupabaseKvRepository extends KvViaTabularRepository {
2800
3194
  super(keySchema, valueSchema);
2801
3195
  this.client = client;
2802
3196
  this.tableName = tableName;
2803
- this.tabularRepository = tabularRepository ?? new SupabaseTabularRepository(client, tableName, DefaultKeyValueSchema, DefaultKeyValueKey);
3197
+ this.tabularRepository = tabularRepository ?? new SupabaseTabularStorage(client, tableName, DefaultKeyValueSchema, DefaultKeyValueKey);
2804
3198
  }
2805
3199
  }
2806
3200
  // src/queue/PostgresQueueStorage.ts
2807
- import { createServiceToken as createServiceToken19, makeFingerprint as makeFingerprint6, uuid4 as uuid42 } from "@workglow/util";
2808
- var POSTGRES_QUEUE_STORAGE = createServiceToken19("jobqueue.storage.postgres");
3201
+ import { createServiceToken as createServiceToken20, makeFingerprint as makeFingerprint6, uuid4 as uuid45 } from "@workglow/util";
3202
+ var POSTGRES_QUEUE_STORAGE = createServiceToken20("jobqueue.storage.postgres");
2809
3203
 
2810
3204
  class PostgresQueueStorage {
2811
3205
  db;
@@ -2902,7 +3296,7 @@ class PostgresQueueStorage {
2902
3296
  async add(job) {
2903
3297
  const now = new Date().toISOString();
2904
3298
  job.queue = this.queueName;
2905
- job.job_run_id = job.job_run_id ?? uuid42();
3299
+ job.job_run_id = job.job_run_id ?? uuid45();
2906
3300
  job.fingerprint = await makeFingerprint6(job.input);
2907
3301
  job.status = JobStatus.PENDING;
2908
3302
  job.progress = 0;
@@ -3134,8 +3528,8 @@ class PostgresQueueStorage {
3134
3528
  }
3135
3529
  }
3136
3530
  // src/queue/SqliteQueueStorage.ts
3137
- import { createServiceToken as createServiceToken20, makeFingerprint as makeFingerprint7, sleep as sleep4, uuid4 as uuid43 } from "@workglow/util";
3138
- var SQLITE_QUEUE_STORAGE = createServiceToken20("jobqueue.storage.sqlite");
3531
+ import { createServiceToken as createServiceToken21, makeFingerprint as makeFingerprint7, sleep as sleep4, uuid4 as uuid46 } from "@workglow/util";
3532
+ var SQLITE_QUEUE_STORAGE = createServiceToken21("jobqueue.storage.sqlite");
3139
3533
 
3140
3534
  class SqliteQueueStorage {
3141
3535
  db;
@@ -3217,7 +3611,7 @@ class SqliteQueueStorage {
3217
3611
  }
3218
3612
  async add(job) {
3219
3613
  const now = new Date().toISOString();
3220
- job.job_run_id = job.job_run_id ?? uuid43();
3614
+ job.job_run_id = job.job_run_id ?? uuid46();
3221
3615
  job.queue = this.queueName;
3222
3616
  job.fingerprint = await makeFingerprint7(job.input);
3223
3617
  job.status = JobStatus.PENDING;
@@ -3470,8 +3864,8 @@ class SqliteQueueStorage {
3470
3864
  }
3471
3865
  }
3472
3866
  // src/queue/SupabaseQueueStorage.ts
3473
- import { createServiceToken as createServiceToken21, makeFingerprint as makeFingerprint8, uuid4 as uuid44 } from "@workglow/util";
3474
- var SUPABASE_QUEUE_STORAGE = createServiceToken21("jobqueue.storage.supabase");
3867
+ import { createServiceToken as createServiceToken22, makeFingerprint as makeFingerprint8, uuid4 as uuid47 } from "@workglow/util";
3868
+ var SUPABASE_QUEUE_STORAGE = createServiceToken22("jobqueue.storage.supabase");
3475
3869
 
3476
3870
  class SupabaseQueueStorage {
3477
3871
  client;
@@ -3587,7 +3981,7 @@ class SupabaseQueueStorage {
3587
3981
  async add(job) {
3588
3982
  const now = new Date().toISOString();
3589
3983
  job.queue = this.queueName;
3590
- job.job_run_id = job.job_run_id ?? uuid44();
3984
+ job.job_run_id = job.job_run_id ?? uuid47();
3591
3985
  job.fingerprint = await makeFingerprint8(job.input);
3592
3986
  job.status = JobStatus.PENDING;
3593
3987
  job.progress = 0;
@@ -3969,9 +4363,9 @@ class SupabaseQueueStorage {
3969
4363
  return manager.subscribe(callback, { intervalMs });
3970
4364
  }
3971
4365
  }
3972
- // src/limiter/PostgresRateLimiterStorage.ts
3973
- import { createServiceToken as createServiceToken22 } from "@workglow/util";
3974
- var POSTGRES_RATE_LIMITER_STORAGE = createServiceToken22("ratelimiter.storage.postgres");
4366
+ // src/queue-limiter/PostgresRateLimiterStorage.ts
4367
+ import { createServiceToken as createServiceToken23 } from "@workglow/util";
4368
+ var POSTGRES_RATE_LIMITER_STORAGE = createServiceToken23("ratelimiter.storage.postgres");
3975
4369
 
3976
4370
  class PostgresRateLimiterStorage {
3977
4371
  db;
@@ -4107,9 +4501,9 @@ class PostgresRateLimiterStorage {
4107
4501
  await this.db.query(`DELETE FROM ${this.nextAvailableTableName} WHERE queue_name = $1${prefixConditions}`, [queueName, ...prefixParams]);
4108
4502
  }
4109
4503
  }
4110
- // src/limiter/SqliteRateLimiterStorage.ts
4111
- import { createServiceToken as createServiceToken23, sleep as sleep5, toSQLiteTimestamp } from "@workglow/util";
4112
- var SQLITE_RATE_LIMITER_STORAGE = createServiceToken23("ratelimiter.storage.sqlite");
4504
+ // src/queue-limiter/SqliteRateLimiterStorage.ts
4505
+ import { createServiceToken as createServiceToken24, sleep as sleep5, toSQLiteTimestamp } from "@workglow/util";
4506
+ var SQLITE_RATE_LIMITER_STORAGE = createServiceToken24("ratelimiter.storage.sqlite");
4113
4507
 
4114
4508
  class SqliteRateLimiterStorage {
4115
4509
  db;
@@ -4246,9 +4640,9 @@ class SqliteRateLimiterStorage {
4246
4640
  this.db.prepare(`DELETE FROM ${this.nextAvailableTableName} WHERE queue_name = ?${prefixConditions}`).run(queueName, ...prefixParams);
4247
4641
  }
4248
4642
  }
4249
- // src/limiter/SupabaseRateLimiterStorage.ts
4250
- import { createServiceToken as createServiceToken24 } from "@workglow/util";
4251
- var SUPABASE_RATE_LIMITER_STORAGE = createServiceToken24("ratelimiter.storage.supabase");
4643
+ // src/queue-limiter/SupabaseRateLimiterStorage.ts
4644
+ import { createServiceToken as createServiceToken25 } from "@workglow/util";
4645
+ var SUPABASE_RATE_LIMITER_STORAGE = createServiceToken25("ratelimiter.storage.supabase");
4252
4646
 
4253
4647
  class SupabaseRateLimiterStorage {
4254
4648
  client;
@@ -4399,13 +4793,311 @@ class SupabaseRateLimiterStorage {
4399
4793
  throw nextError;
4400
4794
  }
4401
4795
  }
4402
- // src/kv/IndexedDbKvRepository.ts
4403
- import { createServiceToken as createServiceToken26 } from "@workglow/util";
4796
+ // src/vector/PostgresVectorStorage.ts
4797
+ import { cosineSimilarity as cosineSimilarity2 } from "@workglow/util";
4798
+ class PostgresVectorStorage extends PostgresTabularStorage {
4799
+ vectorDimensions;
4800
+ VectorType;
4801
+ vectorPropertyName;
4802
+ metadataPropertyName;
4803
+ constructor(db, table, schema, primaryKeyNames, indexes = [], dimensions, VectorType = Float32Array) {
4804
+ super(db, table, schema, primaryKeyNames, indexes);
4805
+ this.vectorDimensions = dimensions;
4806
+ this.VectorType = VectorType;
4807
+ const vectorProp = getVectorProperty(schema);
4808
+ if (!vectorProp) {
4809
+ throw new Error("Schema must have a property with type array and format TypedArray");
4810
+ }
4811
+ this.vectorPropertyName = vectorProp;
4812
+ this.metadataPropertyName = getMetadataProperty(schema);
4813
+ }
4814
+ getVectorDimensions() {
4815
+ return this.vectorDimensions;
4816
+ }
4817
+ async similaritySearch(query, options = {}) {
4818
+ const { topK = 10, filter, scoreThreshold = 0 } = options;
4819
+ try {
4820
+ const queryVector = `[${Array.from(query).join(",")}]`;
4821
+ const vectorCol = String(this.vectorPropertyName);
4822
+ const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;
4823
+ let sql = `
4824
+ SELECT
4825
+ *,
4826
+ 1 - (${vectorCol} <=> $1::vector) as score
4827
+ FROM "${this.table}"
4828
+ `;
4829
+ const params = [queryVector];
4830
+ let paramIndex = 2;
4831
+ if (filter && Object.keys(filter).length > 0 && metadataCol) {
4832
+ const conditions = [];
4833
+ for (const [key, value] of Object.entries(filter)) {
4834
+ conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);
4835
+ params.push(String(value));
4836
+ paramIndex++;
4837
+ }
4838
+ sql += ` WHERE ${conditions.join(" AND ")}`;
4839
+ }
4840
+ if (scoreThreshold > 0) {
4841
+ sql += filter ? " AND" : " WHERE";
4842
+ sql += ` (1 - (${vectorCol} <=> $1::vector)) >= $${paramIndex}`;
4843
+ params.push(scoreThreshold);
4844
+ paramIndex++;
4845
+ }
4846
+ sql += ` ORDER BY ${vectorCol} <=> $1::vector LIMIT $${paramIndex}`;
4847
+ params.push(topK);
4848
+ const result = await this.db.query(sql, params);
4849
+ const results = [];
4850
+ for (const row of result.rows) {
4851
+ const vectorResult = await this.db.query(`SELECT ${vectorCol}::text FROM "${this.table}" WHERE ${this.getPrimaryKeyWhereClause(row)}`, this.getPrimaryKeyValues(row));
4852
+ const vectorStr = vectorResult.rows[0]?.[vectorCol] || "[]";
4853
+ const vectorArray = JSON.parse(vectorStr);
4854
+ results.push({
4855
+ ...row,
4856
+ [this.vectorPropertyName]: new this.VectorType(vectorArray),
4857
+ score: parseFloat(row.score)
4858
+ });
4859
+ }
4860
+ return results;
4861
+ } catch (error) {
4862
+ console.warn("pgvector query failed, falling back to in-memory search:", error);
4863
+ return this.searchFallback(query, options);
4864
+ }
4865
+ }
4866
+ async hybridSearch(query, options) {
4867
+ const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;
4868
+ if (!textQuery || textQuery.trim().length === 0) {
4869
+ return this.similaritySearch(query, { topK, filter, scoreThreshold });
4870
+ }
4871
+ try {
4872
+ const queryVector = `[${Array.from(query).join(",")}]`;
4873
+ const tsQuery = textQuery.split(/\s+/).join(" & ");
4874
+ const vectorCol = String(this.vectorPropertyName);
4875
+ const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;
4876
+ let sql = `
4877
+ SELECT
4878
+ *,
4879
+ (
4880
+ $2 * (1 - (${vectorCol} <=> $1::vector)) +
4881
+ $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), to_tsquery('english', $4))
4882
+ ) as score
4883
+ FROM "${this.table}"
4884
+ `;
4885
+ const params = [queryVector, vectorWeight, 1 - vectorWeight, tsQuery];
4886
+ let paramIndex = 5;
4887
+ if (filter && Object.keys(filter).length > 0 && metadataCol) {
4888
+ const conditions = [];
4889
+ for (const [key, value] of Object.entries(filter)) {
4890
+ conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);
4891
+ params.push(String(value));
4892
+ paramIndex++;
4893
+ }
4894
+ sql += ` WHERE ${conditions.join(" AND ")}`;
4895
+ }
4896
+ if (scoreThreshold > 0) {
4897
+ sql += filter ? " AND" : " WHERE";
4898
+ sql += ` (
4899
+ $2 * (1 - (${vectorCol} <=> $1::vector)) +
4900
+ $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), to_tsquery('english', $4))
4901
+ ) >= $${paramIndex}`;
4902
+ params.push(scoreThreshold);
4903
+ paramIndex++;
4904
+ }
4905
+ sql += ` ORDER BY score DESC LIMIT $${paramIndex}`;
4906
+ params.push(topK);
4907
+ const result = await this.db.query(sql, params);
4908
+ const results = [];
4909
+ for (const row of result.rows) {
4910
+ const vectorResult = await this.db.query(`SELECT ${vectorCol}::text FROM "${this.table}" WHERE ${this.getPrimaryKeyWhereClause(row)}`, this.getPrimaryKeyValues(row));
4911
+ const vectorStr = vectorResult.rows[0]?.[vectorCol] || "[]";
4912
+ const vectorArray = JSON.parse(vectorStr);
4913
+ results.push({
4914
+ ...row,
4915
+ [this.vectorPropertyName]: new this.VectorType(vectorArray),
4916
+ score: parseFloat(row.score)
4917
+ });
4918
+ }
4919
+ return results;
4920
+ } catch (error) {
4921
+ console.warn("pgvector hybrid query failed, falling back to in-memory search:", error);
4922
+ return this.hybridSearchFallback(query, options);
4923
+ }
4924
+ }
4925
+ async searchFallback(query, options) {
4926
+ const { topK = 10, filter, scoreThreshold = 0 } = options;
4927
+ const allRows = await this.getAll() || [];
4928
+ const results = [];
4929
+ for (const row of allRows) {
4930
+ const vector = row[this.vectorPropertyName];
4931
+ const metadata = this.metadataPropertyName ? row[this.metadataPropertyName] : {};
4932
+ if (filter && !this.matchesFilter(metadata, filter)) {
4933
+ continue;
4934
+ }
4935
+ const score = cosineSimilarity2(query, vector);
4936
+ if (score >= scoreThreshold) {
4937
+ results.push({ ...row, score });
4938
+ }
4939
+ }
4940
+ results.sort((a, b) => b.score - a.score);
4941
+ const topResults = results.slice(0, topK);
4942
+ return topResults;
4943
+ }
4944
+ async hybridSearchFallback(query, options) {
4945
+ const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;
4946
+ const allRows = await this.getAll() || [];
4947
+ const results = [];
4948
+ const queryLower = textQuery.toLowerCase();
4949
+ const queryWords = queryLower.split(/\s+/).filter((w) => w.length > 0);
4950
+ for (const row of allRows) {
4951
+ const vector = row[this.vectorPropertyName];
4952
+ const metadata = this.metadataPropertyName ? row[this.metadataPropertyName] : {};
4953
+ if (filter && !this.matchesFilter(metadata, filter)) {
4954
+ continue;
4955
+ }
4956
+ const vectorScore = cosineSimilarity2(query, vector);
4957
+ const metadataText = JSON.stringify(metadata).toLowerCase();
4958
+ let textScore = 0;
4959
+ if (queryWords.length > 0) {
4960
+ let matches = 0;
4961
+ for (const word of queryWords) {
4962
+ if (metadataText.includes(word)) {
4963
+ matches++;
4964
+ }
4965
+ }
4966
+ textScore = matches / queryWords.length;
4967
+ }
4968
+ const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;
4969
+ if (combinedScore >= scoreThreshold) {
4970
+ results.push({ ...row, score: combinedScore });
4971
+ }
4972
+ }
4973
+ results.sort((a, b) => b.score - a.score);
4974
+ const topResults = results.slice(0, topK);
4975
+ return topResults;
4976
+ }
4977
+ getPrimaryKeyWhereClause(row) {
4978
+ const conditions = this.primaryKeyNames.map((key, idx) => `${String(key)} = $${idx + 1}`);
4979
+ return conditions.join(" AND ");
4980
+ }
4981
+ getPrimaryKeyValues(row) {
4982
+ return this.primaryKeyNames.map((key) => row[key]);
4983
+ }
4984
+ matchesFilter(metadata, filter) {
4985
+ for (const [key, value] of Object.entries(filter)) {
4986
+ if (metadata[key] !== value) {
4987
+ return false;
4988
+ }
4989
+ }
4990
+ return true;
4991
+ }
4992
+ }
4993
+ // src/vector/SqliteVectorStorage.ts
4994
+ import { cosineSimilarity as cosineSimilarity3 } from "@workglow/util";
4995
+ function matchesFilter2(metadata, filter) {
4996
+ for (const [key, value] of Object.entries(filter)) {
4997
+ if (metadata[key] !== value) {
4998
+ return false;
4999
+ }
5000
+ }
5001
+ return true;
5002
+ }
4404
5003
 
4405
- // src/tabular/IndexedDbTabularRepository.ts
5004
+ class SqliteVectorStorage extends SqliteTabularStorage {
5005
+ vectorDimensions;
5006
+ VectorType;
5007
+ vectorPropertyName;
5008
+ metadataPropertyName;
5009
+ constructor(dbOrPath, table = "vectors", schema, primaryKeyNames, indexes = [], dimensions, VectorType = Float32Array) {
5010
+ super(dbOrPath, table, schema, primaryKeyNames, indexes);
5011
+ this.vectorDimensions = dimensions;
5012
+ this.VectorType = VectorType;
5013
+ const vectorProp = getVectorProperty(schema);
5014
+ if (!vectorProp) {
5015
+ throw new Error("Schema must have a property with type array and format TypedArray");
5016
+ }
5017
+ this.vectorPropertyName = vectorProp;
5018
+ this.metadataPropertyName = getMetadataProperty(schema);
5019
+ }
5020
+ getVectorDimensions() {
5021
+ return this.vectorDimensions;
5022
+ }
5023
+ deserializeVector(vectorJson) {
5024
+ const array = JSON.parse(vectorJson);
5025
+ return new this.VectorType(array);
5026
+ }
5027
+ async similaritySearch(query, options = {}) {
5028
+ const { topK = 10, filter, scoreThreshold = 0 } = options;
5029
+ const results = [];
5030
+ const allEntities = await this.getAll() || [];
5031
+ for (const entity of allEntities) {
5032
+ const vectorRaw = entity[this.vectorPropertyName];
5033
+ const vector = this.deserializeVector(vectorRaw);
5034
+ const metadata = this.metadataPropertyName ? entity[this.metadataPropertyName] : {};
5035
+ if (filter && !matchesFilter2(metadata, filter)) {
5036
+ continue;
5037
+ }
5038
+ const score = cosineSimilarity3(query, vector);
5039
+ if (score < scoreThreshold) {
5040
+ continue;
5041
+ }
5042
+ results.push({
5043
+ ...entity,
5044
+ score
5045
+ });
5046
+ }
5047
+ results.sort((a, b) => b.score - a.score);
5048
+ const topResults = results.slice(0, topK);
5049
+ return topResults;
5050
+ }
5051
+ async hybridSearch(query, options) {
5052
+ const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;
5053
+ if (!textQuery || textQuery.trim().length === 0) {
5054
+ return this.similaritySearch(query, { topK, filter, scoreThreshold });
5055
+ }
5056
+ const results = [];
5057
+ const allEntities = await this.getAll() || [];
5058
+ const queryLower = textQuery.toLowerCase();
5059
+ const queryWords = queryLower.split(/\s+/).filter((w) => w.length > 0);
5060
+ for (const entity of allEntities) {
5061
+ const vectorRaw = entity[this.vectorPropertyName];
5062
+ const vector = this.deserializeVector(vectorRaw);
5063
+ const metadata = this.metadataPropertyName ? entity[this.metadataPropertyName] : {};
5064
+ if (filter && !matchesFilter2(metadata, filter)) {
5065
+ continue;
5066
+ }
5067
+ const vectorScore = cosineSimilarity3(query, vector);
5068
+ const metadataText = JSON.stringify(metadata).toLowerCase();
5069
+ let textScore = 0;
5070
+ if (queryWords.length > 0) {
5071
+ let matches = 0;
5072
+ for (const word of queryWords) {
5073
+ if (metadataText.includes(word)) {
5074
+ matches++;
5075
+ }
5076
+ }
5077
+ textScore = matches / queryWords.length;
5078
+ }
5079
+ const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;
5080
+ if (combinedScore < scoreThreshold) {
5081
+ continue;
5082
+ }
5083
+ results.push({
5084
+ ...entity,
5085
+ score: combinedScore
5086
+ });
5087
+ }
5088
+ results.sort((a, b) => b.score - a.score);
5089
+ const topResults = results.slice(0, topK);
5090
+ return topResults;
5091
+ }
5092
+ }
5093
+ // src/kv/IndexedDbKvStorage.ts
5094
+ import { createServiceToken as createServiceToken27 } from "@workglow/util";
5095
+
5096
+ // src/tabular/IndexedDbTabularStorage.ts
4406
5097
  import {
4407
- createServiceToken as createServiceToken25,
4408
- makeFingerprint as makeFingerprint9
5098
+ createServiceToken as createServiceToken26,
5099
+ makeFingerprint as makeFingerprint9,
5100
+ uuid4 as uuid48
4409
5101
  } from "@workglow/util";
4410
5102
 
4411
5103
  // src/util/IndexedDbTable.ts
@@ -4554,7 +5246,7 @@ async function performIncrementalMigration(db, tableName, diff, options = {}) {
4554
5246
  options.onMigrationProgress?.(`Migration complete`, 1);
4555
5247
  });
4556
5248
  }
4557
- async function performDestructiveMigration(db, tableName, primaryKey, expectedIndexes, options = {}) {
5249
+ async function performDestructiveMigration(db, tableName, primaryKey, expectedIndexes, options = {}, autoIncrement = false) {
4558
5250
  if (!options.allowDestructiveMigration) {
4559
5251
  throw new Error(`Destructive migration required for ${tableName} but not allowed. ` + `Primary key has changed. Set allowDestructiveMigration=true to proceed with data loss, ` + `or provide a dataTransformer to migrate data.`);
4560
5252
  }
@@ -4599,7 +5291,7 @@ async function performDestructiveMigration(db, tableName, primaryKey, expectedIn
4599
5291
  if (db2.objectStoreNames.contains(tableName)) {
4600
5292
  db2.deleteObjectStore(tableName);
4601
5293
  }
4602
- const store = db2.createObjectStore(tableName, { keyPath: primaryKey });
5294
+ const store = db2.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });
4603
5295
  for (const idx of expectedIndexes) {
4604
5296
  store.createIndex(idx.name, idx.keyPath, idx.options);
4605
5297
  }
@@ -4617,7 +5309,7 @@ async function performDestructiveMigration(db, tableName, primaryKey, expectedIn
4617
5309
  options.onMigrationProgress?.(`Destructive migration complete`, 1);
4618
5310
  return newDb;
4619
5311
  }
4620
- async function createNewDatabase(tableName, primaryKey, expectedIndexes, options = {}) {
5312
+ async function createNewDatabase(tableName, primaryKey, expectedIndexes, options = {}, autoIncrement = false) {
4621
5313
  options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);
4622
5314
  try {
4623
5315
  await deleteIndexedDbTable(tableName);
@@ -4629,7 +5321,7 @@ async function createNewDatabase(tableName, primaryKey, expectedIndexes, options
4629
5321
  if (!db2.objectStoreNames.contains(METADATA_STORE_NAME)) {
4630
5322
  db2.createObjectStore(METADATA_STORE_NAME, { keyPath: "tableName" });
4631
5323
  }
4632
- const store = db2.createObjectStore(tableName, { keyPath: primaryKey });
5324
+ const store = db2.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });
4633
5325
  for (const idx of expectedIndexes) {
4634
5326
  store.createIndex(idx.name, idx.keyPath, idx.options);
4635
5327
  }
@@ -4645,7 +5337,7 @@ async function createNewDatabase(tableName, primaryKey, expectedIndexes, options
4645
5337
  options.onMigrationProgress?.(`Database created successfully`, 1);
4646
5338
  return db;
4647
5339
  }
4648
- async function ensureIndexedDbTable(tableName, primaryKey, expectedIndexes = [], options = {}) {
5340
+ async function ensureIndexedDbTable(tableName, primaryKey, expectedIndexes = [], options = {}, autoIncrement = false) {
4649
5341
  try {
4650
5342
  let db;
4651
5343
  let wasJustCreated = false;
@@ -4657,7 +5349,7 @@ async function ensureIndexedDbTable(tableName, primaryKey, expectedIndexes = [],
4657
5349
  }
4658
5350
  } catch (err) {
4659
5351
  options.onMigrationProgress?.(`Database ${tableName} does not exist or has version conflict, creating...`, 0);
4660
- return await createNewDatabase(tableName, primaryKey, expectedIndexes, options);
5352
+ return await createNewDatabase(tableName, primaryKey, expectedIndexes, options, autoIncrement);
4661
5353
  }
4662
5354
  if (wasJustCreated) {
4663
5355
  options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);
@@ -4670,7 +5362,7 @@ async function ensureIndexedDbTable(tableName, primaryKey, expectedIndexes = [],
4670
5362
  if (!db2.objectStoreNames.contains(METADATA_STORE_NAME)) {
4671
5363
  db2.createObjectStore(METADATA_STORE_NAME, { keyPath: "tableName" });
4672
5364
  }
4673
- const store2 = db2.createObjectStore(tableName, { keyPath: primaryKey });
5365
+ const store2 = db2.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });
4674
5366
  for (const idx of expectedIndexes) {
4675
5367
  store2.createIndex(idx.name, idx.keyPath, idx.options);
4676
5368
  }
@@ -4700,7 +5392,7 @@ async function ensureIndexedDbTable(tableName, primaryKey, expectedIndexes = [],
4700
5392
  if (!db.objectStoreNames.contains(tableName)) {
4701
5393
  options.onMigrationProgress?.(`Object store ${tableName} does not exist, creating...`, 0);
4702
5394
  db.close();
4703
- return await createNewDatabase(tableName, primaryKey, expectedIndexes, options);
5395
+ return await createNewDatabase(tableName, primaryKey, expectedIndexes, options, autoIncrement);
4704
5396
  }
4705
5397
  const transaction = db.transaction(tableName, "readonly");
4706
5398
  const store = transaction.objectStore(tableName);
@@ -4723,7 +5415,7 @@ async function ensureIndexedDbTable(tableName, primaryKey, expectedIndexes = [],
4723
5415
  }
4724
5416
  if (diff.needsObjectStoreRecreation) {
4725
5417
  options.onMigrationProgress?.(`Schema change requires object store recreation for ${tableName}`, 0);
4726
- db = await performDestructiveMigration(db, tableName, primaryKey, expectedIndexes, options);
5418
+ db = await performDestructiveMigration(db, tableName, primaryKey, expectedIndexes, options, autoIncrement);
4727
5419
  } else {
4728
5420
  options.onMigrationProgress?.(`Performing incremental migration for ${tableName}`, 0);
4729
5421
  db = await performIncrementalMigration(db, tableName, diff, options);
@@ -4745,18 +5437,18 @@ async function dropIndexedDbTable(tableName) {
4745
5437
  return deleteIndexedDbTable(tableName);
4746
5438
  }
4747
5439
 
4748
- // src/tabular/IndexedDbTabularRepository.ts
4749
- var IDB_TABULAR_REPOSITORY = createServiceToken25("storage.tabularRepository.indexedDb");
5440
+ // src/tabular/IndexedDbTabularStorage.ts
5441
+ var IDB_TABULAR_REPOSITORY = createServiceToken26("storage.tabularRepository.indexedDb");
4750
5442
 
4751
- class IndexedDbTabularRepository extends TabularRepository {
5443
+ class IndexedDbTabularStorage extends BaseTabularStorage {
4752
5444
  table;
4753
5445
  db;
4754
5446
  setupPromise = null;
4755
5447
  migrationOptions;
4756
5448
  hybridManager = null;
4757
5449
  hybridOptions;
4758
- constructor(table = "tabular_store", schema, primaryKeyNames, indexes = [], migrationOptions = {}) {
4759
- super(schema, primaryKeyNames, indexes);
5450
+ constructor(table = "tabular_store", schema, primaryKeyNames, indexes = [], migrationOptions = {}, clientProvidedKeys = "if-missing") {
5451
+ super(schema, primaryKeyNames, indexes, clientProvidedKeys);
4760
5452
  this.table = table;
4761
5453
  this.migrationOptions = migrationOptions;
4762
5454
  this.hybridOptions = {
@@ -4803,21 +5495,64 @@ class IndexedDbTabularRepository extends TabularRepository {
4803
5495
  });
4804
5496
  }
4805
5497
  const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;
4806
- return await ensureIndexedDbTable(this.table, primaryKey, expectedIndexes, this.migrationOptions);
5498
+ const useAutoIncrement = this.hasAutoGeneratedKey() && this.autoGeneratedKeyStrategy === "autoincrement" && pkColumns.length === 1;
5499
+ return await ensureIndexedDbTable(this.table, primaryKey, expectedIndexes, this.migrationOptions, useAutoIncrement);
5500
+ }
5501
+ generateKeyValue(columnName, strategy) {
5502
+ if (strategy === "uuid") {
5503
+ return uuid48();
5504
+ }
5505
+ throw new Error(`IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`);
4807
5506
  }
4808
5507
  async put(record) {
4809
5508
  const db = await this.getDb();
4810
- const { key } = this.separateKeyValueFromCombined(record);
5509
+ let recordToStore = record;
5510
+ if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {
5511
+ const keyName = String(this.autoGeneratedKeyName);
5512
+ const clientProvidedValue = record[keyName];
5513
+ const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;
5514
+ if (this.autoGeneratedKeyStrategy === "uuid") {
5515
+ let shouldGenerate = false;
5516
+ if (this.clientProvidedKeys === "never") {
5517
+ shouldGenerate = true;
5518
+ } else if (this.clientProvidedKeys === "always") {
5519
+ if (!hasClientValue) {
5520
+ throw new Error(`Auto-generated key "${keyName}" is required when clientProvidedKeys is "always"`);
5521
+ }
5522
+ shouldGenerate = false;
5523
+ } else {
5524
+ shouldGenerate = !hasClientValue;
5525
+ }
5526
+ if (shouldGenerate) {
5527
+ const generatedValue = this.generateKeyValue(keyName, "uuid");
5528
+ recordToStore = { ...record, [keyName]: generatedValue };
5529
+ }
5530
+ } else if (this.autoGeneratedKeyStrategy === "autoincrement") {
5531
+ if (this.clientProvidedKeys === "always" && !hasClientValue) {
5532
+ throw new Error(`Auto-generated key "${keyName}" is required when clientProvidedKeys is "always"`);
5533
+ }
5534
+ if (this.clientProvidedKeys === "never") {
5535
+ const { [keyName]: _, ...rest } = record;
5536
+ recordToStore = rest;
5537
+ }
5538
+ }
5539
+ }
4811
5540
  return new Promise((resolve, reject) => {
4812
5541
  const transaction = db.transaction(this.table, "readwrite");
4813
5542
  const store = transaction.objectStore(this.table);
4814
- const request = store.put(record);
5543
+ const request = store.put(recordToStore);
4815
5544
  request.onerror = () => {
4816
5545
  reject(request.error);
4817
5546
  };
4818
5547
  request.onsuccess = () => {
4819
- this.events.emit("put", record);
4820
- resolve(record);
5548
+ if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName && this.autoGeneratedKeyStrategy === "autoincrement") {
5549
+ const keyName = String(this.autoGeneratedKeyName);
5550
+ if (recordToStore[keyName] === undefined) {
5551
+ recordToStore = { ...recordToStore, [keyName]: request.result };
5552
+ }
5553
+ }
5554
+ this.events.emit("put", recordToStore);
5555
+ resolve(recordToStore);
4821
5556
  };
4822
5557
  transaction.oncomplete = () => {
4823
5558
  this.hybridManager?.notifyLocalChange();
@@ -4825,38 +5560,7 @@ class IndexedDbTabularRepository extends TabularRepository {
4825
5560
  });
4826
5561
  }
4827
5562
  async putBulk(records) {
4828
- const db = await this.getDb();
4829
- return new Promise((resolve, reject) => {
4830
- const transaction = db.transaction(this.table, "readwrite");
4831
- const store = transaction.objectStore(this.table);
4832
- let completed = 0;
4833
- let hasError = false;
4834
- transaction.onerror = () => {
4835
- if (!hasError) {
4836
- hasError = true;
4837
- reject(transaction.error);
4838
- }
4839
- };
4840
- transaction.oncomplete = () => {
4841
- if (!hasError) {
4842
- this.hybridManager?.notifyLocalChange();
4843
- resolve(records);
4844
- }
4845
- };
4846
- for (const record of records) {
4847
- const request = store.put(record);
4848
- request.onsuccess = () => {
4849
- this.events.emit("put", record);
4850
- completed++;
4851
- };
4852
- request.onerror = () => {
4853
- if (!hasError) {
4854
- hasError = true;
4855
- reject(request.error);
4856
- }
4857
- };
4858
- }
4859
- });
5563
+ return await Promise.all(records.map((record) => this.put(record)));
4860
5564
  }
4861
5565
  getPrimaryKeyAsOrderedArray(key) {
4862
5566
  return super.getPrimaryKeyAsOrderedArray(key).map((value) => typeof value === "bigint" ? value.toString() : value);
@@ -5149,21 +5853,21 @@ class IndexedDbTabularRepository extends TabularRepository {
5149
5853
  }
5150
5854
  }
5151
5855
 
5152
- // src/kv/IndexedDbKvRepository.ts
5153
- var IDB_KV_REPOSITORY = createServiceToken26("storage.kvRepository.indexedDb");
5856
+ // src/kv/IndexedDbKvStorage.ts
5857
+ var IDB_KV_REPOSITORY = createServiceToken27("storage.kvRepository.indexedDb");
5154
5858
 
5155
- class IndexedDbKvRepository extends KvViaTabularRepository {
5859
+ class IndexedDbKvStorage extends KvViaTabularStorage {
5156
5860
  dbName;
5157
5861
  tabularRepository;
5158
5862
  constructor(dbName, keySchema = { type: "string" }, valueSchema = {}) {
5159
5863
  super(keySchema, valueSchema);
5160
5864
  this.dbName = dbName;
5161
- this.tabularRepository = new IndexedDbTabularRepository(dbName, DefaultKeyValueSchema, DefaultKeyValueKey);
5865
+ this.tabularRepository = new IndexedDbTabularStorage(dbName, DefaultKeyValueSchema, DefaultKeyValueKey);
5162
5866
  }
5163
5867
  }
5164
- // src/limiter/IndexedDbRateLimiterStorage.ts
5165
- import { createServiceToken as createServiceToken27 } from "@workglow/util";
5166
- var INDEXED_DB_RATE_LIMITER_STORAGE = createServiceToken27("ratelimiter.storage.indexedDb");
5868
+ // src/queue-limiter/IndexedDbRateLimiterStorage.ts
5869
+ import { createServiceToken as createServiceToken28 } from "@workglow/util";
5870
+ var INDEXED_DB_RATE_LIMITER_STORAGE = createServiceToken28("ratelimiter.storage.indexedDb");
5167
5871
 
5168
5872
  class IndexedDbRateLimiterStorage {
5169
5873
  executionDb;
@@ -5383,8 +6087,8 @@ class IndexedDbRateLimiterStorage {
5383
6087
  }
5384
6088
  }
5385
6089
  // src/queue/IndexedDbQueueStorage.ts
5386
- import { createServiceToken as createServiceToken28, makeFingerprint as makeFingerprint10, uuid4 as uuid45 } from "@workglow/util";
5387
- var INDEXED_DB_QUEUE_STORAGE = createServiceToken28("jobqueue.storage.indexedDb");
6090
+ import { createServiceToken as createServiceToken29, makeFingerprint as makeFingerprint10, uuid4 as uuid49 } from "@workglow/util";
6091
+ var INDEXED_DB_QUEUE_STORAGE = createServiceToken29("jobqueue.storage.indexedDb");
5388
6092
 
5389
6093
  class IndexedDbQueueStorage {
5390
6094
  queueName;
@@ -5464,8 +6168,8 @@ class IndexedDbQueueStorage {
5464
6168
  const db = await this.getDb();
5465
6169
  const now = new Date().toISOString();
5466
6170
  const jobWithPrefixes = job;
5467
- jobWithPrefixes.id = jobWithPrefixes.id ?? uuid45();
5468
- jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid45();
6171
+ jobWithPrefixes.id = jobWithPrefixes.id ?? uuid49();
6172
+ jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid49();
5469
6173
  jobWithPrefixes.queue = this.queueName;
5470
6174
  jobWithPrefixes.fingerprint = await makeFingerprint10(jobWithPrefixes.input);
5471
6175
  jobWithPrefixes.status = JobStatus.PENDING;
@@ -5952,19 +6656,25 @@ class IndexedDbQueueStorage {
5952
6656
  }
5953
6657
  }
5954
6658
  export {
6659
+ registerTabularRepository,
5955
6660
  isSearchCondition,
6661
+ getVectorProperty,
6662
+ getTabularRepository,
6663
+ getMetadataProperty,
6664
+ getGlobalTabularRepositories,
5956
6665
  ensureIndexedDbTable,
5957
6666
  dropIndexedDbTable,
5958
- TabularRepository,
5959
6667
  TABULAR_REPOSITORY,
5960
- SupabaseTabularRepository,
6668
+ TABULAR_REPOSITORIES,
6669
+ SupabaseTabularStorage,
5961
6670
  SupabaseRateLimiterStorage,
5962
6671
  SupabaseQueueStorage,
5963
- SupabaseKvRepository,
5964
- SqliteTabularRepository,
6672
+ SupabaseKvStorage,
6673
+ SqliteVectorStorage,
6674
+ SqliteTabularStorage,
5965
6675
  SqliteRateLimiterStorage,
5966
6676
  SqliteQueueStorage,
5967
- SqliteKvRepository,
6677
+ SqliteKvStorage,
5968
6678
  SUPABASE_TABULAR_REPOSITORY,
5969
6679
  SUPABASE_RATE_LIMITER_STORAGE,
5970
6680
  SUPABASE_QUEUE_STORAGE,
@@ -5975,10 +6685,11 @@ export {
5975
6685
  SQLITE_KV_REPOSITORY,
5976
6686
  RATE_LIMITER_STORAGE,
5977
6687
  QUEUE_STORAGE,
5978
- PostgresTabularRepository,
6688
+ PostgresVectorStorage,
6689
+ PostgresTabularStorage,
5979
6690
  PostgresRateLimiterStorage,
5980
6691
  PostgresQueueStorage,
5981
- PostgresKvRepository,
6692
+ PostgresKvStorage,
5982
6693
  PollingSubscriptionManager,
5983
6694
  POSTGRES_TABULAR_REPOSITORY,
5984
6695
  POSTGRES_RATE_LIMITER_STORAGE,
@@ -5986,18 +6697,19 @@ export {
5986
6697
  POSTGRES_KV_REPOSITORY,
5987
6698
  MEMORY_TABULAR_REPOSITORY,
5988
6699
  MEMORY_KV_REPOSITORY,
5989
- KvViaTabularRepository,
5990
- KvRepository,
6700
+ KvViaTabularStorage,
6701
+ KvStorage,
5991
6702
  KV_REPOSITORY,
5992
6703
  JobStatus,
5993
- IndexedDbTabularRepository,
6704
+ IndexedDbTabularStorage,
5994
6705
  IndexedDbRateLimiterStorage,
5995
6706
  IndexedDbQueueStorage,
5996
- IndexedDbKvRepository,
5997
- InMemoryTabularRepository,
6707
+ IndexedDbKvStorage,
6708
+ InMemoryVectorStorage,
6709
+ InMemoryTabularStorage,
5998
6710
  InMemoryRateLimiterStorage,
5999
6711
  InMemoryQueueStorage,
6000
- InMemoryKvRepository,
6712
+ InMemoryKvStorage,
6001
6713
  IN_MEMORY_RATE_LIMITER_STORAGE,
6002
6714
  IN_MEMORY_QUEUE_STORAGE,
6003
6715
  INDEXED_DB_RATE_LIMITER_STORAGE,
@@ -6005,16 +6717,17 @@ export {
6005
6717
  IDB_TABULAR_REPOSITORY,
6006
6718
  IDB_KV_REPOSITORY,
6007
6719
  HybridSubscriptionManager,
6008
- FsFolderTabularRepository,
6009
- FsFolderKvRepository,
6010
- FsFolderJsonKvRepository,
6720
+ FsFolderTabularStorage,
6721
+ FsFolderKvStorage,
6722
+ FsFolderJsonKvStorage,
6011
6723
  FS_FOLDER_TABULAR_REPOSITORY,
6012
6724
  FS_FOLDER_KV_REPOSITORY,
6013
6725
  FS_FOLDER_JSON_KV_REPOSITORY,
6014
6726
  DefaultKeyValueSchema,
6015
6727
  DefaultKeyValueKey,
6016
- CachedTabularRepository,
6017
- CACHED_TABULAR_REPOSITORY
6728
+ CachedTabularStorage,
6729
+ CACHED_TABULAR_REPOSITORY,
6730
+ BaseTabularStorage
6018
6731
  };
6019
6732
 
6020
- //# debugId=B146DFB53B6D14EB64756E2164756E21
6733
+ //# debugId=CDE752B27E94EEDB64756E2164756E21