@workglow/storage 0.0.125 → 0.1.0

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 (76) hide show
  1. package/README.md +15 -6
  2. package/dist/browser.d.ts +18 -0
  3. package/dist/browser.d.ts.map +1 -0
  4. package/dist/browser.js +58 -23
  5. package/dist/browser.js.map +13 -13
  6. package/dist/{types.d.ts → bun.d.ts} +1 -1
  7. package/dist/bun.d.ts.map +1 -0
  8. package/dist/bun.js +106 -45
  9. package/dist/bun.js.map +22 -22
  10. package/dist/node.d.ts +7 -0
  11. package/dist/node.d.ts.map +1 -0
  12. package/dist/node.js +106 -45
  13. package/dist/node.js.map +22 -22
  14. package/dist/postgres/browser.d.ts +32 -0
  15. package/dist/postgres/browser.d.ts.map +1 -0
  16. package/dist/postgres/browser.js +150 -0
  17. package/dist/postgres/browser.js.map +11 -0
  18. package/dist/postgres/node-bun.d.ts +26 -0
  19. package/dist/postgres/node-bun.d.ts.map +1 -0
  20. package/dist/postgres/node-bun.js +41 -0
  21. package/dist/postgres/node-bun.js.map +10 -0
  22. package/dist/postgres/pglite-pool.d.ts +21 -0
  23. package/dist/postgres/pglite-pool.d.ts.map +1 -0
  24. package/dist/queue/InMemoryQueueStorage.d.ts.map +1 -1
  25. package/dist/queue/IndexedDbQueueStorage.d.ts.map +1 -1
  26. package/dist/queue/PostgresQueueStorage.d.ts +1 -1
  27. package/dist/queue/PostgresQueueStorage.d.ts.map +1 -1
  28. package/dist/queue/SqliteQueueStorage.d.ts +1 -1
  29. package/dist/queue/SqliteQueueStorage.d.ts.map +1 -1
  30. package/dist/queue/SupabaseQueueStorage.d.ts +11 -0
  31. package/dist/queue/SupabaseQueueStorage.d.ts.map +1 -1
  32. package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts.map +1 -1
  33. package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts +1 -1
  34. package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts.map +1 -1
  35. package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts +1 -1
  36. package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts.map +1 -1
  37. package/dist/sqlite/browser.d.ts +37 -0
  38. package/dist/sqlite/browser.d.ts.map +1 -0
  39. package/dist/sqlite/browser.js +125 -0
  40. package/dist/sqlite/browser.js.map +10 -0
  41. package/dist/sqlite/bun.d.ts +32 -0
  42. package/dist/sqlite/bun.d.ts.map +1 -0
  43. package/dist/sqlite/bun.js +84 -0
  44. package/dist/sqlite/bun.js.map +10 -0
  45. package/dist/sqlite/canonical-api.d.ts +34 -0
  46. package/dist/sqlite/canonical-api.d.ts.map +1 -0
  47. package/dist/sqlite/node.d.ts +34 -0
  48. package/dist/sqlite/node.d.ts.map +1 -0
  49. package/dist/sqlite/node.js +65 -0
  50. package/dist/sqlite/node.js.map +10 -0
  51. package/dist/tabular/CachedTabularStorage.d.ts +1 -0
  52. package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
  53. package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
  54. package/dist/tabular/InMemoryTabularStorage.d.ts +2 -0
  55. package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
  56. package/dist/tabular/PostgresTabularStorage.d.ts +1 -1
  57. package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
  58. package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -1
  59. package/dist/tabular/SqliteTabularStorage.d.ts +1 -1
  60. package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
  61. package/dist/tabular/TelemetryTabularStorage.d.ts.map +1 -1
  62. package/dist/util/HybridSubscriptionManager.d.ts.map +1 -1
  63. package/dist/util/PollingSubscriptionManager.d.ts +2 -0
  64. package/dist/util/PollingSubscriptionManager.d.ts.map +1 -1
  65. package/dist/vector/PostgresVectorStorage.d.ts +1 -13
  66. package/dist/vector/PostgresVectorStorage.d.ts.map +1 -1
  67. package/dist/vector/SqliteAiVectorStorage.d.ts +1 -1
  68. package/dist/vector/SqliteAiVectorStorage.d.ts.map +1 -1
  69. package/dist/vector/SqliteVectorStorage.d.ts +1 -1
  70. package/dist/vector/SqliteVectorStorage.d.ts.map +1 -1
  71. package/package.json +85 -21
  72. package/src/kv/README.md +4 -3
  73. package/src/queue/README.md +1 -1
  74. package/src/tabular/README.md +8 -1
  75. package/src/vector/README.md +6 -6
  76. package/dist/types.d.ts.map +0 -1
@@ -4,4 +4,4 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  export * from "./common-server";
7
- //# sourceMappingURL=types.d.ts.map
7
+ //# sourceMappingURL=bun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../src/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,iBAAiB,CAAC"}
package/dist/bun.js CHANGED
@@ -394,6 +394,7 @@ var MEMORY_TABULAR_REPOSITORY = createServiceToken2("storage.tabularRepository.i
394
394
  class InMemoryTabularStorage extends BaseTabularStorage {
395
395
  values = new Map;
396
396
  autoIncrementCounter = 0;
397
+ _lastPutWasInsert = false;
397
398
  constructor(schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
398
399
  super(schema, primaryKeyNames, indexes, clientProvidedKeys);
399
400
  }
@@ -429,6 +430,7 @@ class InMemoryTabularStorage extends BaseTabularStorage {
429
430
  }
430
431
  const { key } = this.separateKeyValueFromCombined(entityToStore);
431
432
  const id = await makeFingerprint2(key);
433
+ this._lastPutWasInsert = !this.values.has(id);
432
434
  this.values.set(id, entityToStore);
433
435
  this.events.emit("put", entityToStore);
434
436
  return entityToStore;
@@ -625,7 +627,7 @@ class InMemoryTabularStorage extends BaseTabularStorage {
625
627
  }
626
628
  subscribeToChanges(callback, options) {
627
629
  const handlePut = (entity) => {
628
- callback({ type: "UPDATE", new: entity });
630
+ callback({ type: this._lastPutWasInsert ? "INSERT" : "UPDATE", new: entity });
629
631
  };
630
632
  const handleDelete = (_key) => {
631
633
  callback({ type: "DELETE" });
@@ -654,6 +656,7 @@ class CachedTabularStorage extends BaseTabularStorage {
654
656
  cache;
655
657
  durable;
656
658
  cacheInitialized = false;
659
+ cacheInitPromise = null;
657
660
  constructor(durable, cache, schema, primaryKeyNames, indexes, clientProvidedKeys = "if-missing") {
658
661
  if (!schema || !primaryKeyNames) {
659
662
  throw new Error("Schema and primaryKeyNames must be provided when creating CachedTabularStorage");
@@ -687,16 +690,23 @@ class CachedTabularStorage extends BaseTabularStorage {
687
690
  async initializeCache() {
688
691
  if (this.cacheInitialized)
689
692
  return;
690
- try {
691
- const all = await this.durable.getAll();
692
- if (all && all.length > 0) {
693
- await this.cache.putBulk(all);
694
- }
695
- this.cacheInitialized = true;
696
- } catch (error) {
697
- getLogger().warn("Failed to initialize cache from durable repository:", { error });
698
- this.cacheInitialized = true;
693
+ if (this.cacheInitPromise) {
694
+ return this.cacheInitPromise;
699
695
  }
696
+ this.cacheInitPromise = (async () => {
697
+ try {
698
+ const all = await this.durable.getAll();
699
+ if (all && all.length > 0) {
700
+ await this.cache.putBulk(all);
701
+ }
702
+ this.cacheInitialized = true;
703
+ } catch (error) {
704
+ getLogger().warn("Failed to initialize cache from durable repository:", { error });
705
+ } finally {
706
+ this.cacheInitPromise = null;
707
+ }
708
+ })();
709
+ return this.cacheInitPromise;
700
710
  }
701
711
  async put(value) {
702
712
  await this.initializeCache();
@@ -1532,13 +1542,17 @@ class InMemoryQueueStorage {
1532
1542
  }
1533
1543
  async complete(job) {
1534
1544
  await sleep(0);
1535
- const index = this.jobQueue.findIndex((j) => j.id === job.id);
1545
+ const jobWithPrefixes = job;
1546
+ const index = this.jobQueue.findIndex((j) => j.id === job.id && this.matchesPrefixes(j));
1536
1547
  if (index !== -1) {
1537
1548
  const existing = this.jobQueue[index];
1538
1549
  const currentAttempts = existing?.run_attempts ?? 0;
1539
- job.run_attempts = currentAttempts + 1;
1540
- this.jobQueue[index] = job;
1541
- this.events.emit("change", { type: "UPDATE", old: existing, new: job });
1550
+ jobWithPrefixes.run_attempts = currentAttempts + 1;
1551
+ for (const [key, value] of Object.entries(this.prefixValues)) {
1552
+ jobWithPrefixes[key] = value;
1553
+ }
1554
+ this.jobQueue[index] = jobWithPrefixes;
1555
+ this.events.emit("change", { type: "UPDATE", old: existing, new: jobWithPrefixes });
1542
1556
  }
1543
1557
  }
1544
1558
  async abort(id) {
@@ -1893,6 +1907,7 @@ class PollingSubscriptionManager {
1893
1907
  intervals = new Map;
1894
1908
  lastKnownState = new Map;
1895
1909
  initialized = false;
1910
+ initializing = false;
1896
1911
  fetchState;
1897
1912
  compareItems;
1898
1913
  payloadFactory;
@@ -1917,7 +1932,8 @@ class PollingSubscriptionManager {
1917
1932
  this.intervals.set(interval, intervalGroup);
1918
1933
  if (!this.initialized) {
1919
1934
  this.initialized = true;
1920
- this.initAndPoll(subscribers, subscription);
1935
+ this.initializing = true;
1936
+ this.initAndPoll(subscription);
1921
1937
  } else {
1922
1938
  this.pollForNewSubscriber(subscription);
1923
1939
  }
@@ -1936,7 +1952,7 @@ class PollingSubscriptionManager {
1936
1952
  }
1937
1953
  };
1938
1954
  }
1939
- async initAndPoll(subscribers, newSubscription) {
1955
+ async initAndPoll(newSubscription) {
1940
1956
  try {
1941
1957
  this.lastKnownState = await this.fetchState();
1942
1958
  for (const [, item] of this.lastKnownState) {
@@ -1945,7 +1961,9 @@ class PollingSubscriptionManager {
1945
1961
  newSubscription.callback(payload);
1946
1962
  } catch {}
1947
1963
  }
1948
- } catch {}
1964
+ } catch {} finally {
1965
+ this.initializing = false;
1966
+ }
1949
1967
  }
1950
1968
  pollForNewSubscriber(subscription) {
1951
1969
  for (const [, item] of this.lastKnownState) {
@@ -1958,6 +1976,8 @@ class PollingSubscriptionManager {
1958
1976
  async poll(subscribers) {
1959
1977
  if (subscribers.size === 0)
1960
1978
  return;
1979
+ if (this.initializing)
1980
+ return;
1961
1981
  try {
1962
1982
  const currentState = await this.fetchState();
1963
1983
  const changes = [];
@@ -2001,6 +2021,7 @@ class PollingSubscriptionManager {
2001
2021
  this.intervals.clear();
2002
2022
  this.lastKnownState.clear();
2003
2023
  this.initialized = false;
2024
+ this.initializing = false;
2004
2025
  }
2005
2026
  }
2006
2027
  // src/vector/InMemoryVectorStorage.ts
@@ -2105,7 +2126,7 @@ class InMemoryVectorStorage extends InMemoryTabularStorage {
2105
2126
  continue;
2106
2127
  }
2107
2128
  const vectorScore = cosineSimilarity(query, vector);
2108
- const metadataText = Object.values(metadata).join(" ").toLowerCase();
2129
+ const metadataText = Object.values(metadata ?? {}).join(" ").toLowerCase();
2109
2130
  const textScore = textRelevance(metadataText, textQuery);
2110
2131
  const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;
2111
2132
  if (combinedScore < scoreThreshold) {
@@ -2217,7 +2238,7 @@ class EncryptedKvCredentialStore {
2217
2238
  }
2218
2239
  }
2219
2240
  // src/tabular/FsFolderTabularStorage.ts
2220
- import { createServiceToken as createServiceToken12, makeFingerprint as makeFingerprint5, sleep as sleep3, uuid4 as uuid43 } from "@workglow/util";
2241
+ import { createServiceToken as createServiceToken12, getLogger as getLogger3, makeFingerprint as makeFingerprint5, sleep as sleep3, uuid4 as uuid43 } from "@workglow/util";
2221
2242
  import { mkdir, readdir, readFile, rm, writeFile } from "fs/promises";
2222
2243
  import path from "path";
2223
2244
  var FS_FOLDER_TABULAR_REPOSITORY = createServiceToken12("storage.tabularRepository.fsFolder");
@@ -2274,11 +2295,11 @@ class FsFolderTabularStorage extends BaseTabularStorage {
2274
2295
  try {
2275
2296
  await writeFile(filePath, JSON.stringify(entityToStore));
2276
2297
  } catch (error) {
2298
+ await sleep3(1);
2277
2299
  try {
2278
- await sleep3(1);
2279
- await writeFile(filePath, JSON.stringify(entity));
2280
- } catch (error2) {
2281
- console.error("Error writing file", filePath, error2);
2300
+ await writeFile(filePath, JSON.stringify(entityToStore));
2301
+ } catch (retryError) {
2302
+ throw new Error(`Failed to write file "${filePath}" after retry: ${retryError instanceof Error ? retryError.message : String(retryError)}`, { cause: retryError });
2282
2303
  }
2283
2304
  }
2284
2305
  this.events.emit("put", entityToStore);
@@ -2357,11 +2378,24 @@ class FsFolderTabularStorage extends BaseTabularStorage {
2357
2378
  if (jsonFiles.length === 0) {
2358
2379
  return;
2359
2380
  }
2360
- const allEntities = await Promise.all(jsonFiles.map(async (file) => {
2381
+ const results = await Promise.allSettled(jsonFiles.map(async (file) => {
2361
2382
  const filePath = path.join(this.folderPath, file);
2362
- const content = await readFile(filePath, "utf8");
2363
- return JSON.parse(content);
2383
+ try {
2384
+ const content = await readFile(filePath, "utf8");
2385
+ return JSON.parse(content);
2386
+ } catch (err) {
2387
+ const message = err instanceof Error ? err.message : String(err);
2388
+ throw new Error(`Failed to read or parse "${filePath}": ${message}`);
2389
+ }
2364
2390
  }));
2391
+ const allEntities = [];
2392
+ for (const result of results) {
2393
+ if (result.status === "fulfilled") {
2394
+ allEntities.push(result.value);
2395
+ } else {
2396
+ getLogger3().warn(`Skipping corrupted file in getBulk: ${result.reason?.message ?? result.reason}`);
2397
+ }
2398
+ }
2365
2399
  allEntities.sort((a, b) => {
2366
2400
  for (const key of this.primaryKeyNames) {
2367
2401
  const aVal = a[key];
@@ -3108,10 +3142,9 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
3108
3142
  }
3109
3143
  }
3110
3144
  // src/tabular/SqliteTabularStorage.ts
3111
- import { Sqlite } from "@workglow/sqlite";
3145
+ import { Sqlite } from "@workglow/storage/sqlite";
3112
3146
  import { createServiceToken as createServiceToken14, uuid4 as uuid44 } from "@workglow/util";
3113
3147
  var SQLITE_TABULAR_REPOSITORY = createServiceToken14("storage.tabularRepository.sqlite");
3114
- var Database = Sqlite.Database;
3115
3148
 
3116
3149
  class SqliteTabularStorage extends BaseSqlTabularStorage {
3117
3150
  db;
@@ -3121,7 +3154,7 @@ class SqliteTabularStorage extends BaseSqlTabularStorage {
3121
3154
  constructor(dbOrPath, table = "tabular_store", schema, primaryKeyNames, indexes = [], clientProvidedKeys = "if-missing") {
3122
3155
  super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);
3123
3156
  if (typeof dbOrPath === "string") {
3124
- this.db = new Database(dbOrPath);
3157
+ this.db = new Sqlite.Database(dbOrPath);
3125
3158
  } else {
3126
3159
  this.db = dbOrPath;
3127
3160
  }
@@ -4676,7 +4709,7 @@ class SqliteQueueStorage {
4676
4709
  return result;
4677
4710
  }
4678
4711
  async peek(status = JobStatus.PENDING, num = 100) {
4679
- num = Number(num) || 100;
4712
+ num = Math.max(1, Math.min(1e4, Math.floor(Number(num) || 100)));
4680
4713
  const prefixConditions = this.buildPrefixWhereClause();
4681
4714
  const prefixParams = this.getPrefixParamValues();
4682
4715
  const FutureJobQuery = `
@@ -4931,12 +4964,24 @@ class SupabaseQueueStorage {
4931
4964
  const conditions = this.prefixes.map((p) => {
4932
4965
  const value = this.prefixValues[p.name];
4933
4966
  if (p.type === "uuid") {
4934
- return `${p.name} = '${this.escapeSqlString(String(value))}'`;
4967
+ const validated = this.validateSqlValue(String(value), `prefix "${p.name}"`);
4968
+ return `${p.name} = '${this.escapeSqlString(validated)}'`;
4969
+ }
4970
+ const numValue = Number(value ?? 0);
4971
+ if (!Number.isFinite(numValue)) {
4972
+ throw new Error(`Invalid numeric prefix value for "${p.name}": ${value}`);
4935
4973
  }
4936
- return `${p.name} = ${Number(value ?? 0)}`;
4974
+ return `${p.name} = ${numValue}`;
4937
4975
  }).join(" AND ");
4938
4976
  return " AND " + conditions;
4939
4977
  }
4978
+ static SAFE_SQL_VALUE_RE = /^[a-zA-Z0-9_\-.:]+$/;
4979
+ validateSqlValue(value, context) {
4980
+ if (!SupabaseQueueStorage.SAFE_SQL_VALUE_RE.test(value)) {
4981
+ throw new Error(`Unsafe value for ${context}: "${value}". Values must match /^[a-zA-Z0-9_\\-.:]+$/.`);
4982
+ }
4983
+ return value;
4984
+ }
4940
4985
  escapeSqlString(value) {
4941
4986
  return value.replace(/'/g, "''");
4942
4987
  }
@@ -5043,8 +5088,10 @@ class SupabaseQueueStorage {
5043
5088
  }
5044
5089
  async next(workerId) {
5045
5090
  const prefixConditions = this.buildPrefixWhereSql();
5046
- const escapedQueueName = this.escapeSqlString(this.queueName);
5047
- const escapedWorkerId = this.escapeSqlString(workerId);
5091
+ const validatedQueueName = this.validateSqlValue(this.queueName, "queueName");
5092
+ const validatedWorkerId = this.validateSqlValue(workerId, "workerId");
5093
+ const escapedQueueName = this.escapeSqlString(validatedQueueName);
5094
+ const escapedWorkerId = this.escapeSqlString(validatedWorkerId);
5048
5095
  const sql = `
5049
5096
  UPDATE ${this.tableName}
5050
5097
  SET status = '${JobStatus.PROCESSING}', last_ran_at = NOW() AT TIME ZONE 'UTC', worker_id = '${escapedWorkerId}'
@@ -5805,6 +5852,8 @@ class SupabaseRateLimiterStorage {
5805
5852
  }
5806
5853
  // src/vector/PostgresVectorStorage.ts
5807
5854
  import { cosineSimilarity as cosineSimilarity2 } from "@workglow/util/schema";
5855
+ var SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
5856
+
5808
5857
  class PostgresVectorStorage extends PostgresTabularStorage {
5809
5858
  vectorDimensions;
5810
5859
  VectorType;
@@ -5841,6 +5890,9 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5841
5890
  if (filter && Object.keys(filter).length > 0 && metadataCol) {
5842
5891
  const conditions = [];
5843
5892
  for (const [key, value] of Object.entries(filter)) {
5893
+ if (!SAFE_IDENTIFIER_RE.test(key)) {
5894
+ throw new StorageValidationError(`Invalid metadata filter key: "${key}". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`);
5895
+ }
5844
5896
  conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);
5845
5897
  params.push(String(value));
5846
5898
  paramIndex++;
@@ -5869,7 +5921,10 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5869
5921
  }
5870
5922
  return results;
5871
5923
  } catch (error) {
5872
- console.warn("pgvector query failed, falling back to in-memory search:", error);
5924
+ if (error instanceof StorageValidationError) {
5925
+ throw error;
5926
+ }
5927
+ console.error("pgvector query failed, falling back to in-memory search:", error);
5873
5928
  return this.searchFallback(query, options);
5874
5929
  }
5875
5930
  }
@@ -5880,7 +5935,7 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5880
5935
  }
5881
5936
  try {
5882
5937
  const queryVector = `[${Array.from(query).join(",")}]`;
5883
- const tsQuery = textQuery.split(/\s+/).join(" & ");
5938
+ const tsQueryText = textQuery;
5884
5939
  const vectorCol = String(this.vectorPropertyName);
5885
5940
  const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;
5886
5941
  let sql = `
@@ -5888,15 +5943,18 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5888
5943
  *,
5889
5944
  (
5890
5945
  $2 * (1 - (${vectorCol} <=> $1::vector)) +
5891
- $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), to_tsquery('english', $4))
5946
+ $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), plainto_tsquery('english', $4))
5892
5947
  ) as score
5893
5948
  FROM "${this.table}"
5894
5949
  `;
5895
- const params = [queryVector, vectorWeight, 1 - vectorWeight, tsQuery];
5950
+ const params = [queryVector, vectorWeight, 1 - vectorWeight, tsQueryText];
5896
5951
  let paramIndex = 5;
5897
5952
  if (filter && Object.keys(filter).length > 0 && metadataCol) {
5898
5953
  const conditions = [];
5899
5954
  for (const [key, value] of Object.entries(filter)) {
5955
+ if (!SAFE_IDENTIFIER_RE.test(key)) {
5956
+ throw new StorageValidationError(`Invalid metadata filter key: "${key}". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`);
5957
+ }
5900
5958
  conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);
5901
5959
  params.push(String(value));
5902
5960
  paramIndex++;
@@ -5907,7 +5965,7 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5907
5965
  sql += filter ? " AND" : " WHERE";
5908
5966
  sql += ` (
5909
5967
  $2 * (1 - (${vectorCol} <=> $1::vector)) +
5910
- $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), to_tsquery('english', $4))
5968
+ $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), plainto_tsquery('english', $4))
5911
5969
  ) >= $${paramIndex}`;
5912
5970
  params.push(scoreThreshold);
5913
5971
  paramIndex++;
@@ -5928,7 +5986,10 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5928
5986
  }
5929
5987
  return results;
5930
5988
  } catch (error) {
5931
- console.warn("pgvector hybrid query failed, falling back to in-memory search:", error);
5989
+ if (error instanceof StorageValidationError) {
5990
+ throw error;
5991
+ }
5992
+ console.error("pgvector hybrid query failed, falling back to in-memory search:", error);
5932
5993
  return this.hybridSearchFallback(query, options);
5933
5994
  }
5934
5995
  }
@@ -5964,7 +6025,7 @@ class PostgresVectorStorage extends PostgresTabularStorage {
5964
6025
  continue;
5965
6026
  }
5966
6027
  const vectorScore = cosineSimilarity2(query, vector);
5967
- const metadataText = JSON.stringify(metadata).toLowerCase();
6028
+ const metadataText = Object.values(metadata ?? {}).join(" ").toLowerCase();
5968
6029
  let textScore = 0;
5969
6030
  if (queryWords.length > 0) {
5970
6031
  let matches = 0;
@@ -6075,7 +6136,7 @@ class SqliteVectorStorage extends SqliteTabularStorage {
6075
6136
  continue;
6076
6137
  }
6077
6138
  const vectorScore = cosineSimilarity3(query, vector);
6078
- const metadataText = JSON.stringify(metadata).toLowerCase();
6139
+ const metadataText = Object.values(metadata ?? {}).join(" ").toLowerCase();
6079
6140
  let textScore = 0;
6080
6141
  if (queryWords.length > 0) {
6081
6142
  let matches = 0;
@@ -6409,7 +6470,7 @@ class SqliteAiVectorStorage extends SqliteTabularStorage {
6409
6470
  if (filter && !matchesFilter3(metadata, filter)) {
6410
6471
  continue;
6411
6472
  }
6412
- const metadataText = JSON.stringify(metadata).toLowerCase();
6473
+ const metadataText = Object.values(metadata ?? {}).join(" ").toLowerCase();
6413
6474
  let textScore = 0;
6414
6475
  if (queryWords.length > 0) {
6415
6476
  let matches = 0;
@@ -6464,7 +6525,7 @@ class SqliteAiVectorStorage extends SqliteTabularStorage {
6464
6525
  continue;
6465
6526
  }
6466
6527
  const vectorScore = cosineSimilarity4(query, vector);
6467
- const metadataText = JSON.stringify(metadata).toLowerCase();
6528
+ const metadataText = Object.values(metadata ?? {}).join(" ").toLowerCase();
6468
6529
  let textScore = 0;
6469
6530
  if (queryWords.length > 0) {
6470
6531
  let matches = 0;
@@ -8259,4 +8320,4 @@ export {
8259
8320
  BaseTabularStorage
8260
8321
  };
8261
8322
 
8262
- //# debugId=1B6C712B3A2F880E64756E2164756E21
8323
+ //# debugId=962404C01663B8E764756E2164756E21