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