@workglow/storage 0.0.104 → 0.0.106

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 (34) hide show
  1. package/dist/browser.js +494 -219
  2. package/dist/browser.js.map +13 -12
  3. package/dist/bun.js +595 -288
  4. package/dist/bun.js.map +15 -14
  5. package/dist/common.d.ts +1 -0
  6. package/dist/common.d.ts.map +1 -1
  7. package/dist/credentials/EncryptedKvCredentialStore.d.ts.map +1 -1
  8. package/dist/node.js +595 -288
  9. package/dist/node.js.map +15 -14
  10. package/dist/tabular/BaseTabularStorage.d.ts +21 -7
  11. package/dist/tabular/BaseTabularStorage.d.ts.map +1 -1
  12. package/dist/tabular/CachedTabularStorage.d.ts +14 -10
  13. package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
  14. package/dist/tabular/FsFolderTabularStorage.d.ts +6 -6
  15. package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
  16. package/dist/tabular/HuggingFaceTabularStorage.d.ts +11 -6
  17. package/dist/tabular/HuggingFaceTabularStorage.d.ts.map +1 -1
  18. package/dist/tabular/ITabularStorage.d.ts +22 -3
  19. package/dist/tabular/ITabularStorage.d.ts.map +1 -1
  20. package/dist/tabular/InMemoryTabularStorage.d.ts +12 -10
  21. package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
  22. package/dist/tabular/IndexedDbTabularStorage.d.ts +12 -10
  23. package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
  24. package/dist/tabular/PostgresTabularStorage.d.ts +12 -11
  25. package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
  26. package/dist/tabular/SharedInMemoryTabularStorage.d.ts +12 -10
  27. package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -1
  28. package/dist/tabular/SqliteTabularStorage.d.ts +12 -11
  29. package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
  30. package/dist/tabular/StorageError.d.ts +31 -0
  31. package/dist/tabular/StorageError.d.ts.map +1 -0
  32. package/dist/tabular/SupabaseTabularStorage.d.ts +12 -10
  33. package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -1
  34. package/package.json +5 -5
package/dist/browser.js CHANGED
@@ -4,6 +4,58 @@ import {
4
4
  EventEmitter,
5
5
  makeFingerprint
6
6
  } from "@workglow/util";
7
+
8
+ // src/tabular/ITabularStorage.ts
9
+ function isSearchCondition(value) {
10
+ return typeof value === "object" && value !== null && "value" in value && "operator" in value && typeof value.operator === "string";
11
+ }
12
+
13
+ // src/tabular/StorageError.ts
14
+ import { BaseError } from "@workglow/util";
15
+
16
+ class StorageError extends BaseError {
17
+ static type = "StorageError";
18
+ constructor(message) {
19
+ super(message);
20
+ }
21
+ }
22
+
23
+ class StorageValidationError extends StorageError {
24
+ static type = "StorageValidationError";
25
+ constructor(message) {
26
+ super(message);
27
+ }
28
+ }
29
+
30
+ class StorageEmptyCriteriaError extends StorageValidationError {
31
+ static type = "StorageEmptyCriteriaError";
32
+ constructor() {
33
+ super("Query criteria must not be empty. Use getAll() to retrieve all records.");
34
+ }
35
+ }
36
+
37
+ class StorageInvalidLimitError extends StorageValidationError {
38
+ static type = "StorageInvalidLimitError";
39
+ constructor(limit) {
40
+ super(`Query limit must be greater than 0, got ${limit}`);
41
+ }
42
+ }
43
+
44
+ class StorageInvalidColumnError extends StorageValidationError {
45
+ static type = "StorageInvalidColumnError";
46
+ constructor(column) {
47
+ super(`Column "${column}" does not exist in the schema`);
48
+ }
49
+ }
50
+
51
+ class StorageUnsupportedError extends StorageError {
52
+ static type = "StorageUnsupportedError";
53
+ constructor(operation, backend) {
54
+ super(`${operation} is not supported for ${backend}`);
55
+ }
56
+ }
57
+
58
+ // src/tabular/BaseTabularStorage.ts
7
59
  var TABULAR_REPOSITORY = createServiceToken("storage.tabularRepository");
8
60
 
9
61
  class BaseTabularStorage {
@@ -162,6 +214,62 @@ class BaseTabularStorage {
162
214
  subscribeToChanges(_callback, _options) {
163
215
  throw new Error(`subscribeToChanges is not implemented for ${this.constructor.name}. ` + `All concrete repository implementations should override this method.`);
164
216
  }
217
+ validateQueryParams(criteria, options) {
218
+ const criteriaKeys = Object.keys(criteria);
219
+ if (criteriaKeys.length === 0) {
220
+ throw new StorageEmptyCriteriaError;
221
+ }
222
+ if (options?.limit !== undefined && options.limit <= 0) {
223
+ throw new StorageInvalidLimitError(options.limit);
224
+ }
225
+ if (options?.offset !== undefined && options.offset < 0) {
226
+ throw new StorageValidationError(`Query offset must be non-negative, got ${options.offset}`);
227
+ }
228
+ for (const column of criteriaKeys) {
229
+ if (!(column in this.schema.properties)) {
230
+ throw new StorageInvalidColumnError(String(column));
231
+ }
232
+ const criterion = criteria[column];
233
+ if (isSearchCondition(criterion)) {
234
+ const validOperators = ["=", "<", "<=", ">", ">="];
235
+ if (!validOperators.includes(criterion.operator)) {
236
+ throw new StorageValidationError(`Invalid operator "${criterion.operator}". Must be one of: ${validOperators.join(", ")}`);
237
+ }
238
+ }
239
+ }
240
+ if (options?.orderBy) {
241
+ const validDirections = ["ASC", "DESC"];
242
+ for (const { column, direction } of options.orderBy) {
243
+ if (!(column in this.schema.properties)) {
244
+ throw new StorageInvalidColumnError(String(column));
245
+ }
246
+ if (!validDirections.includes(direction)) {
247
+ throw new StorageValidationError(`Invalid sort direction "${direction}". Must be "ASC" or "DESC"`);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ validateGetAllOptions(options) {
253
+ if (!options)
254
+ return;
255
+ if (options.limit !== undefined && options.limit <= 0) {
256
+ throw new StorageInvalidLimitError(options.limit);
257
+ }
258
+ if (options.offset !== undefined && options.offset < 0) {
259
+ throw new StorageValidationError(`Query offset must be non-negative, got ${options.offset}`);
260
+ }
261
+ if (options.orderBy) {
262
+ const validDirections = ["ASC", "DESC"];
263
+ for (const { column, direction } of options.orderBy) {
264
+ if (!(column in this.schema.properties)) {
265
+ throw new StorageInvalidColumnError(String(column));
266
+ }
267
+ if (!validDirections.includes(direction)) {
268
+ throw new StorageValidationError(`Invalid sort direction "${direction}". Must be "ASC" or "DESC"`);
269
+ }
270
+ }
271
+ }
272
+ }
165
273
  primaryKeyColumns() {
166
274
  const columns = [];
167
275
  for (const key of Object.keys(this.primaryKeySchema.properties)) {
@@ -279,7 +387,8 @@ class BaseTabularStorage {
279
387
  }
280
388
  // src/tabular/CachedTabularStorage.ts
281
389
  import {
282
- createServiceToken as createServiceToken3
390
+ createServiceToken as createServiceToken3,
391
+ getLogger
283
392
  } from "@workglow/util";
284
393
 
285
394
  // src/tabular/InMemoryTabularStorage.ts
@@ -288,13 +397,6 @@ import {
288
397
  makeFingerprint as makeFingerprint2,
289
398
  uuid4
290
399
  } from "@workglow/util";
291
-
292
- // src/tabular/ITabularStorage.ts
293
- function isSearchCondition(value) {
294
- return typeof value === "object" && value !== null && "value" in value && "operator" in value && typeof value.operator === "string";
295
- }
296
-
297
- // src/tabular/InMemoryTabularStorage.ts
298
400
  var MEMORY_TABULAR_REPOSITORY = createServiceToken2("storage.tabularRepository.inMemory");
299
401
 
300
402
  class InMemoryTabularStorage extends BaseTabularStorage {
@@ -348,24 +450,6 @@ class InMemoryTabularStorage extends BaseTabularStorage {
348
450
  this.events.emit("get", key, out);
349
451
  return out;
350
452
  }
351
- async search(key) {
352
- const searchKeys = Object.keys(key);
353
- if (searchKeys.length === 0) {
354
- return;
355
- }
356
- const bestIndex = this.findBestMatchingIndex(searchKeys);
357
- if (!bestIndex) {
358
- throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.join("', '")}']`);
359
- }
360
- const results = Array.from(this.values.values()).filter((item) => Object.entries(key).every(([k, v]) => item[k] === v));
361
- if (results.length > 0) {
362
- this.events.emit("search", key, results);
363
- return results;
364
- } else {
365
- this.events.emit("search", key, undefined);
366
- return;
367
- }
368
- }
369
453
  async delete(value) {
370
454
  const { key } = this.separateKeyValueFromCombined(value);
371
455
  const id = await makeFingerprint2(key);
@@ -376,8 +460,34 @@ class InMemoryTabularStorage extends BaseTabularStorage {
376
460
  this.values.clear();
377
461
  this.events.emit("clearall");
378
462
  }
379
- async getAll() {
380
- const all = Array.from(this.values.values());
463
+ async getAll(options) {
464
+ this.validateGetAllOptions(options);
465
+ let all = Array.from(this.values.values());
466
+ if (options?.orderBy && options.orderBy.length > 0) {
467
+ all.sort((a, b) => {
468
+ for (const { column, direction } of options.orderBy) {
469
+ const aVal = a[column];
470
+ const bVal = b[column];
471
+ if (aVal == null && bVal == null)
472
+ continue;
473
+ if (aVal == null)
474
+ return direction === "ASC" ? -1 : 1;
475
+ if (bVal == null)
476
+ return direction === "ASC" ? 1 : -1;
477
+ if (aVal < bVal)
478
+ return direction === "ASC" ? -1 : 1;
479
+ if (aVal > bVal)
480
+ return direction === "ASC" ? 1 : -1;
481
+ }
482
+ return 0;
483
+ });
484
+ }
485
+ if (options?.offset !== undefined) {
486
+ all = all.slice(options.offset);
487
+ }
488
+ if (options?.limit !== undefined) {
489
+ all = all.slice(0, options.limit);
490
+ }
381
491
  return all.length > 0 ? all : undefined;
382
492
  }
383
493
  async size() {
@@ -450,6 +560,77 @@ class InMemoryTabularStorage extends BaseTabularStorage {
450
560
  this.events.emit("delete", key);
451
561
  }
452
562
  }
563
+ async query(criteria, options) {
564
+ this.validateQueryParams(criteria, options);
565
+ const criteriaKeys = Object.keys(criteria);
566
+ let results = Array.from(this.values.values()).filter((entity) => {
567
+ for (const column of criteriaKeys) {
568
+ const criterion = criteria[column];
569
+ const columnValue = entity[column];
570
+ if (isSearchCondition(criterion)) {
571
+ const { value, operator } = criterion;
572
+ const v = value;
573
+ const cv = columnValue;
574
+ switch (operator) {
575
+ case "=":
576
+ if (cv !== v)
577
+ return false;
578
+ break;
579
+ case "<":
580
+ if (cv === null || cv === undefined || !(cv < v))
581
+ return false;
582
+ break;
583
+ case "<=":
584
+ if (cv === null || cv === undefined || !(cv <= v))
585
+ return false;
586
+ break;
587
+ case ">":
588
+ if (cv === null || cv === undefined || !(cv > v))
589
+ return false;
590
+ break;
591
+ case ">=":
592
+ if (cv === null || cv === undefined || !(cv >= v))
593
+ return false;
594
+ break;
595
+ default:
596
+ return false;
597
+ }
598
+ } else {
599
+ if (columnValue !== criterion)
600
+ return false;
601
+ }
602
+ }
603
+ return true;
604
+ });
605
+ if (options?.orderBy && options.orderBy.length > 0) {
606
+ results.sort((a, b) => {
607
+ for (const { column, direction } of options.orderBy) {
608
+ const aVal = a[column];
609
+ const bVal = b[column];
610
+ if (aVal == null && bVal == null)
611
+ continue;
612
+ if (aVal == null)
613
+ return direction === "ASC" ? -1 : 1;
614
+ if (bVal == null)
615
+ return direction === "ASC" ? 1 : -1;
616
+ if (aVal < bVal)
617
+ return direction === "ASC" ? -1 : 1;
618
+ if (aVal > bVal)
619
+ return direction === "ASC" ? 1 : -1;
620
+ }
621
+ return 0;
622
+ });
623
+ }
624
+ if (options?.offset !== undefined) {
625
+ results = results.slice(options.offset);
626
+ }
627
+ if (options?.limit !== undefined) {
628
+ results = results.slice(0, options.limit);
629
+ }
630
+ const result = results.length > 0 ? results : undefined;
631
+ this.events.emit("query", criteria, result);
632
+ return result;
633
+ }
453
634
  subscribeToChanges(callback, options) {
454
635
  const handlePut = (entity) => {
455
636
  callback({ type: "UPDATE", new: entity });
@@ -501,8 +682,8 @@ class CachedTabularStorage extends BaseTabularStorage {
501
682
  this.cache.on("get", (key, entity) => {
502
683
  this.events.emit("get", key, entity);
503
684
  });
504
- this.cache.on("search", (key, entities) => {
505
- this.events.emit("search", key, entities);
685
+ this.cache.on("query", (key, entities) => {
686
+ this.events.emit("query", key, entities);
506
687
  });
507
688
  this.cache.on("delete", (key) => {
508
689
  this.events.emit("delete", key);
@@ -521,7 +702,7 @@ class CachedTabularStorage extends BaseTabularStorage {
521
702
  }
522
703
  this.cacheInitialized = true;
523
704
  } catch (error) {
524
- console.warn("Failed to initialize cache from durable repository:", error);
705
+ getLogger().warn("Failed to initialize cache from durable repository:", { error });
525
706
  this.cacheInitialized = true;
526
707
  }
527
708
  }
@@ -548,17 +729,6 @@ class CachedTabularStorage extends BaseTabularStorage {
548
729
  }
549
730
  return result;
550
731
  }
551
- async search(key) {
552
- await this.initializeCache();
553
- let results = await this.cache.search(key);
554
- if (results === undefined) {
555
- results = await this.durable.search(key);
556
- if (results && results.length > 0) {
557
- await this.cache.putBulk(results);
558
- }
559
- }
560
- return results;
561
- }
562
732
  async delete(value) {
563
733
  await this.initializeCache();
564
734
  await this.durable.delete(value);
@@ -569,7 +739,7 @@ class CachedTabularStorage extends BaseTabularStorage {
569
739
  await this.durable.deleteAll();
570
740
  await this.cache.deleteAll();
571
741
  }
572
- async getAll() {
742
+ async getAll(options) {
573
743
  await this.initializeCache();
574
744
  let results = await this.cache.getAll();
575
745
  if (!results || results.length === 0) {
@@ -578,6 +748,9 @@ class CachedTabularStorage extends BaseTabularStorage {
578
748
  await this.cache.putBulk(results);
579
749
  }
580
750
  }
751
+ if (options && results && results.length > 0) {
752
+ return await this.cache.getAll(options);
753
+ }
581
754
  return results;
582
755
  }
583
756
  async size() {
@@ -588,6 +761,10 @@ class CachedTabularStorage extends BaseTabularStorage {
588
761
  await this.initializeCache();
589
762
  return await this.durable.getBulk(offset, limit);
590
763
  }
764
+ async query(criteria, options) {
765
+ await this.initializeCache();
766
+ return await this.cache.query(criteria, options);
767
+ }
591
768
  async deleteSearch(criteria) {
592
769
  await this.initializeCache();
593
770
  await this.durable.deleteSearch(criteria);
@@ -708,7 +885,8 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
708
885
  this.events.emit("get", key, undefined);
709
886
  return;
710
887
  }
711
- async getAll() {
888
+ async getAll(options) {
889
+ this.validateGetAllOptions(options);
712
890
  const allEntities = [];
713
891
  let offset = 0;
714
892
  const pageSize = 100;
@@ -723,7 +901,36 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
723
901
  break;
724
902
  }
725
903
  }
726
- return allEntities.length > 0 ? allEntities : undefined;
904
+ if (allEntities.length === 0)
905
+ return;
906
+ let results = allEntities;
907
+ if (options?.orderBy && options.orderBy.length > 0) {
908
+ results = [...results];
909
+ results.sort((a, b) => {
910
+ for (const { column, direction } of options.orderBy) {
911
+ const aVal = a[column];
912
+ const bVal = b[column];
913
+ if (aVal == null && bVal == null)
914
+ continue;
915
+ if (aVal == null)
916
+ return direction === "ASC" ? -1 : 1;
917
+ if (bVal == null)
918
+ return direction === "ASC" ? 1 : -1;
919
+ if (aVal < bVal)
920
+ return direction === "ASC" ? -1 : 1;
921
+ if (aVal > bVal)
922
+ return direction === "ASC" ? 1 : -1;
923
+ }
924
+ return 0;
925
+ });
926
+ }
927
+ if (options?.offset !== undefined) {
928
+ results = results.slice(options.offset);
929
+ }
930
+ if (options?.limit !== undefined) {
931
+ results = results.slice(0, options.limit);
932
+ }
933
+ return results.length > 0 ? results : undefined;
727
934
  }
728
935
  async getBulk(offset, limit) {
729
936
  const data = await this.fetchApi("/rows", {
@@ -739,18 +946,40 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
739
946
  }
740
947
  return entities;
741
948
  }
742
- async search(key) {
743
- const searchKeys = Object.keys(key);
744
- if (searchKeys.length === 0) {
745
- return;
746
- }
747
- const bestIndex = this.findBestMatchingIndex(searchKeys);
748
- if (!bestIndex) {
749
- throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.map((idx) => idx.join(",")).join("', '")}'`);
750
- }
949
+ async size() {
950
+ const data = await this.fetchApi("/size", {});
951
+ return data.size.num_rows;
952
+ }
953
+ async put(_value) {
954
+ throw new Error("HuggingFaceTabularStorage is readonly");
955
+ }
956
+ async putBulk(_values) {
957
+ throw new Error("HuggingFaceTabularStorage is readonly");
958
+ }
959
+ async delete(_value) {
960
+ throw new Error("HuggingFaceTabularStorage is readonly");
961
+ }
962
+ async deleteAll() {
963
+ throw new Error("HuggingFaceTabularStorage is readonly");
964
+ }
965
+ async query(criteria, options) {
966
+ this.validateQueryParams(criteria, options);
751
967
  const whereConditions = [];
752
- for (const [k, v] of Object.entries(key)) {
753
- if (v !== undefined && v !== null) {
968
+ for (const [k, v] of Object.entries(criteria)) {
969
+ if (v === undefined || v === null)
970
+ continue;
971
+ if (isSearchCondition(v)) {
972
+ if (v.operator !== "=") {
973
+ throw new StorageUnsupportedError(`Operator "${v.operator}" in query`, "HuggingFaceTabularStorage");
974
+ }
975
+ const val = v.value;
976
+ if (typeof val === "string") {
977
+ const escaped = val.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
978
+ whereConditions.push(`${k}='${escaped}'`);
979
+ } else {
980
+ whereConditions.push(`${k}=${val}`);
981
+ }
982
+ } else {
754
983
  if (typeof v === "string") {
755
984
  const escaped = v.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
756
985
  whereConditions.push(`${k}='${escaped}'`);
@@ -760,50 +989,60 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
760
989
  }
761
990
  }
762
991
  if (whereConditions.length === 0) {
763
- throw new Error("Search criteria must include at least one non-null and non-undefined value to build a valid WHERE clause.");
992
+ return;
764
993
  }
765
994
  const where = whereConditions.join(" AND ");
766
995
  const allEntities = [];
767
- let offset = 0;
768
- const limit = 100;
996
+ let fetchOffset = 0;
997
+ const fetchLimit = 100;
769
998
  while (true) {
770
999
  const data = await this.fetchApi("/filter", {
771
1000
  where,
772
- offset: offset.toString(),
773
- limit: limit.toString()
1001
+ offset: fetchOffset.toString(),
1002
+ limit: fetchLimit.toString()
774
1003
  });
775
1004
  for (const row of data.rows) {
776
1005
  allEntities.push(this.rowToEntity(row));
777
1006
  }
778
- offset += data.rows.length;
779
- if (offset >= data.num_rows_total || data.rows.length < limit) {
1007
+ fetchOffset += data.rows.length;
1008
+ if (fetchOffset >= data.num_rows_total || data.rows.length < fetchLimit) {
780
1009
  break;
781
1010
  }
782
1011
  }
783
- if (allEntities.length > 0) {
784
- this.events.emit("search", key, allEntities);
785
- return allEntities;
1012
+ let results = allEntities;
1013
+ if (options?.orderBy && options.orderBy.length > 0) {
1014
+ results.sort((a, b) => {
1015
+ for (const { column, direction } of options.orderBy) {
1016
+ const aVal = a[column];
1017
+ const bVal = b[column];
1018
+ if (aVal == null && bVal == null)
1019
+ continue;
1020
+ if (aVal == null)
1021
+ return direction === "ASC" ? -1 : 1;
1022
+ if (bVal == null)
1023
+ return direction === "ASC" ? 1 : -1;
1024
+ if (aVal < bVal)
1025
+ return direction === "ASC" ? -1 : 1;
1026
+ if (aVal > bVal)
1027
+ return direction === "ASC" ? 1 : -1;
1028
+ }
1029
+ return 0;
1030
+ });
1031
+ }
1032
+ if (options?.offset !== undefined) {
1033
+ results = results.slice(options.offset);
1034
+ }
1035
+ if (options?.limit !== undefined) {
1036
+ results = results.slice(0, options.limit);
1037
+ }
1038
+ if (results.length > 0) {
1039
+ this.events.emit("query", criteria, results);
1040
+ return results;
786
1041
  } else {
787
- this.events.emit("search", key, undefined);
1042
+ this.events.emit("query", criteria, undefined);
788
1043
  return;
789
1044
  }
790
1045
  }
791
- async size() {
792
- const data = await this.fetchApi("/size", {});
793
- return data.size.num_rows;
794
- }
795
- async put(_value) {
796
- throw new Error("HuggingFaceTabularStorage is readonly");
797
- }
798
- async putBulk(_values) {
799
- throw new Error("HuggingFaceTabularStorage is readonly");
800
- }
801
- async delete(_value) {
802
- throw new Error("HuggingFaceTabularStorage is readonly");
803
- }
804
- async deleteAll() {
805
- throw new Error("HuggingFaceTabularStorage is readonly");
806
- }
807
1046
  async deleteSearch(_criteria) {
808
1047
  throw new Error("HuggingFaceTabularStorage is readonly");
809
1048
  }
@@ -1034,7 +1273,7 @@ class InMemoryKvStorage extends KvViaTabularStorage {
1034
1273
  import {
1035
1274
  createServiceToken as createServiceToken9,
1036
1275
  EventEmitter as EventEmitter3,
1037
- getLogger,
1276
+ getLogger as getLogger2,
1038
1277
  makeFingerprint as makeFingerprint4,
1039
1278
  sleep,
1040
1279
  uuid4 as uuid42
@@ -1133,7 +1372,7 @@ class InMemoryQueueStorage {
1133
1372
  const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));
1134
1373
  if (!job) {
1135
1374
  const jobWithAnyPrefix = this.jobQueue.find((j) => j.id === id);
1136
- getLogger().warn("Job not found for progress update", {
1375
+ getLogger2().warn("Job not found for progress update", {
1137
1376
  id,
1138
1377
  reason: jobWithAnyPrefix ? "prefix_mismatch" : "missing",
1139
1378
  existingStatus: jobWithAnyPrefix?.status,
@@ -1143,7 +1382,7 @@ class InMemoryQueueStorage {
1143
1382
  return;
1144
1383
  }
1145
1384
  if (job.status === JobStatus.COMPLETED || job.status === JobStatus.FAILED) {
1146
- getLogger().warn("Job already completed or failed for progress update", {
1385
+ getLogger2().warn("Job already completed or failed for progress update", {
1147
1386
  id,
1148
1387
  status: job.status,
1149
1388
  completedAt: job.completed_at,
@@ -2263,7 +2502,8 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
2263
2502
  };
2264
2503
  });
2265
2504
  }
2266
- async getAll() {
2505
+ async getAll(options) {
2506
+ this.validateGetAllOptions(options);
2267
2507
  const db = await this.getDb();
2268
2508
  const transaction = db.transaction(this.table, "readonly");
2269
2509
  const store = transaction.objectStore(this.table);
@@ -2271,96 +2511,38 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
2271
2511
  return new Promise((resolve, reject) => {
2272
2512
  request.onerror = () => reject(request.error);
2273
2513
  request.onsuccess = () => {
2274
- const values = request.result;
2275
- resolve(values.length > 0 ? values : undefined);
2276
- };
2277
- });
2278
- }
2279
- async search(key) {
2280
- const db = await this.getDb();
2281
- const searchKeys = Object.keys(key);
2282
- if (searchKeys.length === 0) {
2283
- return;
2284
- }
2285
- const bestIndex = this.findBestMatchingIndex(searchKeys);
2286
- if (!bestIndex) {
2287
- throw new Error("No suitable index found for the search criteria");
2288
- }
2289
- return new Promise((resolve, reject) => {
2290
- const transaction = db.transaction(this.table, "readonly");
2291
- const store = transaction.objectStore(this.table);
2292
- const indexName = bestIndex.join("_");
2293
- const primaryKeyName = this.primaryKeyColumns().join("_");
2294
- const isPrimaryKey = indexName === primaryKeyName;
2295
- const indexValues = [];
2296
- for (const col of bestIndex) {
2297
- const val = key[col];
2298
- if (val === undefined)
2299
- break;
2300
- if (typeof val !== "string" && typeof val !== "number") {
2301
- throw new Error(`Invalid value type for indexed column ${String(col)}`);
2514
+ let values = request.result;
2515
+ if (values.length === 0) {
2516
+ resolve(undefined);
2517
+ return;
2302
2518
  }
2303
- indexValues.push(val);
2304
- }
2305
- if (indexValues.length > 0) {
2306
- const index = isPrimaryKey ? store : store.index(indexName);
2307
- const isPartialMatch = indexValues.length < bestIndex.length;
2308
- if (isPartialMatch) {
2309
- const allColumnsRequired = bestIndex.every((col) => {
2310
- const colName = String(col);
2311
- return this.schema.required?.includes(colName);
2519
+ if (options?.orderBy && options.orderBy.length > 0) {
2520
+ values.sort((a, b) => {
2521
+ for (const { column, direction } of options.orderBy) {
2522
+ const aVal = a[column];
2523
+ const bVal = b[column];
2524
+ if (aVal == null && bVal == null)
2525
+ continue;
2526
+ if (aVal == null)
2527
+ return direction === "ASC" ? -1 : 1;
2528
+ if (bVal == null)
2529
+ return direction === "ASC" ? 1 : -1;
2530
+ if (aVal < bVal)
2531
+ return direction === "ASC" ? -1 : 1;
2532
+ if (aVal > bVal)
2533
+ return direction === "ASC" ? 1 : -1;
2534
+ }
2535
+ return 0;
2312
2536
  });
2313
- if (allColumnsRequired) {
2314
- const results = [];
2315
- const keyRange = IDBKeyRange.lowerBound(indexValues);
2316
- const cursorRequest = index.openCursor(keyRange);
2317
- cursorRequest.onsuccess = () => {
2318
- const cursor = cursorRequest.result;
2319
- if (cursor) {
2320
- const item = cursor.value;
2321
- const cursorKey = Array.isArray(cursor.key) ? cursor.key : [cursor.key];
2322
- const prefixMatches = indexValues.every((val, idx) => cursorKey[idx] === val);
2323
- if (!prefixMatches) {
2324
- resolve(results.length > 0 ? results : undefined);
2325
- return;
2326
- }
2327
- const matches = Object.entries(key).every(([k, v]) => item[k] === v);
2328
- if (matches) {
2329
- results.push(item);
2330
- }
2331
- cursor.continue();
2332
- } else {
2333
- resolve(results.length > 0 ? results : undefined);
2334
- }
2335
- };
2336
- cursorRequest.onerror = () => {
2337
- reject(cursorRequest.error);
2338
- };
2339
- } else {
2340
- const getAllRequest = store.getAll();
2341
- getAllRequest.onsuccess = () => {
2342
- const allRecords = getAllRequest.result;
2343
- const results = allRecords.filter((item) => Object.entries(key).every(([k, v]) => item[k] === v));
2344
- resolve(results.length > 0 ? results : undefined);
2345
- };
2346
- getAllRequest.onerror = () => {
2347
- reject(getAllRequest.error);
2348
- };
2349
- }
2350
- } else {
2351
- const request = index.getAll(indexValues.length === 1 ? indexValues[0] : indexValues);
2352
- request.onsuccess = () => {
2353
- const results = request.result.filter((item) => Object.entries(key).every(([k, v]) => item[k] === v));
2354
- resolve(results.length > 0 ? results : undefined);
2355
- };
2356
- request.onerror = () => {
2357
- console.error("Search error:", request.error);
2358
- reject(request.error);
2359
- };
2360
2537
  }
2361
- } else {
2362
- throw new Error(`No valid values provided for indexed columns: ${bestIndex.join(", ")}`);
2363
- }
2538
+ if (options?.offset !== undefined) {
2539
+ values = values.slice(options.offset);
2540
+ }
2541
+ if (options?.limit !== undefined) {
2542
+ values = values.slice(0, options.limit);
2543
+ }
2544
+ resolve(values.length > 0 ? values : undefined);
2545
+ };
2364
2546
  });
2365
2547
  }
2366
2548
  async delete(key) {
@@ -2526,6 +2708,50 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
2526
2708
  }
2527
2709
  });
2528
2710
  }
2711
+ async query(criteria, options) {
2712
+ this.validateQueryParams(criteria, options);
2713
+ const db = await this.getDb();
2714
+ return new Promise((resolve, reject) => {
2715
+ const transaction = db.transaction(this.table, "readonly");
2716
+ const store = transaction.objectStore(this.table);
2717
+ const getAllRequest = store.getAll();
2718
+ getAllRequest.onsuccess = () => {
2719
+ const allRecords = getAllRequest.result;
2720
+ let results = allRecords.filter((record) => this.matchesCriteria(record, criteria));
2721
+ if (options?.orderBy && options.orderBy.length > 0) {
2722
+ results.sort((a, b) => {
2723
+ for (const { column, direction } of options.orderBy) {
2724
+ const aVal = a[column];
2725
+ const bVal = b[column];
2726
+ if (aVal == null && bVal == null)
2727
+ continue;
2728
+ if (aVal == null)
2729
+ return direction === "ASC" ? -1 : 1;
2730
+ if (bVal == null)
2731
+ return direction === "ASC" ? 1 : -1;
2732
+ if (aVal < bVal)
2733
+ return direction === "ASC" ? -1 : 1;
2734
+ if (aVal > bVal)
2735
+ return direction === "ASC" ? 1 : -1;
2736
+ }
2737
+ return 0;
2738
+ });
2739
+ }
2740
+ if (options?.offset !== undefined) {
2741
+ results = results.slice(options.offset);
2742
+ }
2743
+ if (options?.limit !== undefined) {
2744
+ results = results.slice(0, options.limit);
2745
+ }
2746
+ const result = results.length > 0 ? results : undefined;
2747
+ this.events.emit("query", criteria, result);
2748
+ resolve(result);
2749
+ };
2750
+ getAllRequest.onerror = () => {
2751
+ reject(getAllRequest.error);
2752
+ };
2753
+ });
2754
+ }
2529
2755
  getHybridManager() {
2530
2756
  if (!this.hybridManager) {
2531
2757
  const channelName = `indexeddb-tabular-${this.table}`;
@@ -2607,8 +2833,8 @@ class SharedInMemoryTabularStorage extends BaseTabularStorage {
2607
2833
  this.inMemoryRepo.on("get", (key, entity) => {
2608
2834
  this.events.emit("get", key, entity);
2609
2835
  });
2610
- this.inMemoryRepo.on("search", (key, entities) => {
2611
- this.events.emit("search", key, entities);
2836
+ this.inMemoryRepo.on("query", (key, entities) => {
2837
+ this.events.emit("query", key, entities);
2612
2838
  });
2613
2839
  this.inMemoryRepo.on("delete", (key) => {
2614
2840
  this.events.emit("delete", key);
@@ -2693,9 +2919,6 @@ class SharedInMemoryTabularStorage extends BaseTabularStorage {
2693
2919
  async get(key) {
2694
2920
  return await this.inMemoryRepo.get(key);
2695
2921
  }
2696
- async search(key) {
2697
- return await this.inMemoryRepo.search(key);
2698
- }
2699
2922
  async delete(value) {
2700
2923
  await this.inMemoryRepo.delete(value);
2701
2924
  const { key } = this.separateKeyValueFromCombined(value);
@@ -2705,8 +2928,8 @@ class SharedInMemoryTabularStorage extends BaseTabularStorage {
2705
2928
  await this.inMemoryRepo.deleteAll();
2706
2929
  this.broadcast({ type: "DELETE_ALL" });
2707
2930
  }
2708
- async getAll() {
2709
- return await this.inMemoryRepo.getAll();
2931
+ async getAll(options) {
2932
+ return await this.inMemoryRepo.getAll(options);
2710
2933
  }
2711
2934
  async size() {
2712
2935
  return await this.inMemoryRepo.size();
@@ -2714,6 +2937,9 @@ class SharedInMemoryTabularStorage extends BaseTabularStorage {
2714
2937
  async getBulk(offset, limit) {
2715
2938
  return await this.inMemoryRepo.getBulk(offset, limit);
2716
2939
  }
2940
+ async query(criteria, options) {
2941
+ return await this.inMemoryRepo.query(criteria, options);
2942
+ }
2717
2943
  async deleteSearch(criteria) {
2718
2944
  await this.inMemoryRepo.deleteSearch(criteria);
2719
2945
  this.broadcast({
@@ -3191,41 +3417,6 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
3191
3417
  this.events.emit("get", key, val);
3192
3418
  return val;
3193
3419
  }
3194
- async search(searchCriteria) {
3195
- const searchKeys = Object.keys(searchCriteria);
3196
- if (searchKeys.length === 0) {
3197
- return;
3198
- }
3199
- const bestIndex = this.findBestMatchingIndex(searchKeys);
3200
- if (!bestIndex) {
3201
- throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.join("', '")}']`);
3202
- }
3203
- const validColumns = [...this.primaryKeyColumns(), ...this.valueColumns()];
3204
- const invalidColumns = searchKeys.filter((key) => !validColumns.includes(key));
3205
- if (invalidColumns.length > 0) {
3206
- throw new Error(`Invalid columns in search criteria: ${invalidColumns.join(", ")}`);
3207
- }
3208
- let query = this.client.from(this.table).select("*");
3209
- for (const [key, value] of Object.entries(searchCriteria)) {
3210
- query = query.eq(key, value);
3211
- }
3212
- const { data, error } = await query;
3213
- if (error)
3214
- throw error;
3215
- if (data && data.length > 0) {
3216
- for (const row of data) {
3217
- const record = row;
3218
- for (const key in this.schema.properties) {
3219
- record[key] = this.sqlToJsValue(key, record[key]);
3220
- }
3221
- }
3222
- this.events.emit("search", searchCriteria, data);
3223
- return data;
3224
- } else {
3225
- this.events.emit("search", searchCriteria, undefined);
3226
- return;
3227
- }
3228
- }
3229
3420
  async delete(value) {
3230
3421
  const { key } = this.separateKeyValueFromCombined(value);
3231
3422
  let query = this.client.from(this.table).delete();
@@ -3238,8 +3429,23 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
3238
3429
  throw error;
3239
3430
  this.events.emit("delete", key);
3240
3431
  }
3241
- async getAll() {
3242
- const { data, error } = await this.client.from(this.table).select("*");
3432
+ async getAll(options) {
3433
+ this.validateGetAllOptions(options);
3434
+ let query = this.client.from(this.table).select("*");
3435
+ if (options?.orderBy) {
3436
+ for (const { column, direction } of options.orderBy) {
3437
+ query = query.order(String(column), { ascending: direction === "ASC" });
3438
+ }
3439
+ }
3440
+ if (options?.offset !== undefined || options?.limit !== undefined) {
3441
+ const start = options?.offset ?? 0;
3442
+ if (options?.limit !== undefined) {
3443
+ query = query.range(start, start + options.limit - 1);
3444
+ } else if (options?.offset !== undefined) {
3445
+ query = query.range(start, start + 999999);
3446
+ }
3447
+ }
3448
+ const { data, error } = await query;
3243
3449
  if (error)
3244
3450
  throw error;
3245
3451
  if (data && data.length) {
@@ -3327,6 +3533,69 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
3327
3533
  throw error;
3328
3534
  this.events.emit("delete", criteriaKeys[0]);
3329
3535
  }
3536
+ async query(criteria, options) {
3537
+ this.validateQueryParams(criteria, options);
3538
+ const criteriaKeys = Object.keys(criteria);
3539
+ let query = this.client.from(this.table).select("*");
3540
+ for (const column of criteriaKeys) {
3541
+ const criterion = criteria[column];
3542
+ let operator = "=";
3543
+ let value;
3544
+ if (isSearchCondition(criterion)) {
3545
+ operator = criterion.operator;
3546
+ value = criterion.value;
3547
+ } else {
3548
+ value = criterion;
3549
+ }
3550
+ switch (operator) {
3551
+ case "=":
3552
+ query = query.eq(String(column), value);
3553
+ break;
3554
+ case "<":
3555
+ query = query.lt(String(column), value);
3556
+ break;
3557
+ case "<=":
3558
+ query = query.lte(String(column), value);
3559
+ break;
3560
+ case ">":
3561
+ query = query.gt(String(column), value);
3562
+ break;
3563
+ case ">=":
3564
+ query = query.gte(String(column), value);
3565
+ break;
3566
+ }
3567
+ }
3568
+ if (options?.orderBy) {
3569
+ for (const { column, direction } of options.orderBy) {
3570
+ query = query.order(String(column), { ascending: direction === "ASC" });
3571
+ }
3572
+ }
3573
+ if (options?.offset !== undefined || options?.limit !== undefined) {
3574
+ const start = options?.offset ?? 0;
3575
+ if (options?.limit !== undefined) {
3576
+ query = query.range(start, start + options.limit - 1);
3577
+ } else if (options?.offset !== undefined) {
3578
+ query = query.range(start, start + 999999);
3579
+ }
3580
+ } else if (options?.limit !== undefined) {
3581
+ query = query.limit(options.limit);
3582
+ }
3583
+ const { data, error } = await query;
3584
+ if (error)
3585
+ throw error;
3586
+ if (data && data.length > 0) {
3587
+ for (const row of data) {
3588
+ const record = row;
3589
+ for (const key in this.schema.properties) {
3590
+ record[key] = this.sqlToJsValue(key, record[key]);
3591
+ }
3592
+ }
3593
+ this.events.emit("query", criteria, data);
3594
+ return data;
3595
+ }
3596
+ this.events.emit("query", criteria, undefined);
3597
+ return;
3598
+ }
3330
3599
  convertRealtimeRow(row) {
3331
3600
  const entity = { ...row };
3332
3601
  const record = entity;
@@ -4948,6 +5217,12 @@ export {
4948
5217
  SupabaseRateLimiterStorage,
4949
5218
  SupabaseQueueStorage,
4950
5219
  SupabaseKvStorage,
5220
+ StorageValidationError,
5221
+ StorageUnsupportedError,
5222
+ StorageInvalidLimitError,
5223
+ StorageInvalidColumnError,
5224
+ StorageError,
5225
+ StorageEmptyCriteriaError,
4951
5226
  SharedInMemoryTabularStorage,
4952
5227
  SUPABASE_TABULAR_REPOSITORY,
4953
5228
  SUPABASE_RATE_LIMITER_STORAGE,
@@ -4991,4 +5266,4 @@ export {
4991
5266
  BaseTabularStorage
4992
5267
  };
4993
5268
 
4994
- //# debugId=6C77B36216FE8BAE64756E2164756E21
5269
+ //# debugId=E678A7B863107B3464756E2164756E21