@langchain/langgraph-checkpoint-redis 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/store.cjs CHANGED
@@ -1,7 +1,8 @@
1
- const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
- const require_v4 = require('./node_modules/uuid/dist/esm-node/v4.cjs');
3
- const __langchain_langgraph_checkpoint = require_rolldown_runtime.__toESM(require("@langchain/langgraph-checkpoint"));
4
- const redis = require_rolldown_runtime.__toESM(require("redis"));
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_utils = require('./utils.cjs');
3
+ let _langchain_langgraph_checkpoint = require("@langchain/langgraph-checkpoint");
4
+ let redis = require("redis");
5
+ let uuid = require("uuid");
5
6
 
6
7
  //#region src/store.ts
7
8
  function isPutOperation(op) {
@@ -105,7 +106,7 @@ var FilterBuilder = class {
105
106
  const keys = path.split(".");
106
107
  let current = obj;
107
108
  for (const key of keys) {
108
- if (current === null || current === void 0) return void 0;
109
+ if (current === null || current === void 0) return;
109
110
  current = current[key];
110
111
  }
111
112
  return current;
@@ -248,10 +249,7 @@ var RedisStore = class RedisStore {
248
249
  const prefixQuery = tokens.length > 0 ? `@prefix:(${tokens.join(" ")})` : "*";
249
250
  let query;
250
251
  if (key === "") query = prefixQuery;
251
- else {
252
- const escapedKey = this.escapeTagValue(key);
253
- query = `(${prefixQuery}) (@key:{${escapedKey}})`;
254
- }
252
+ else query = `(${prefixQuery}) (@key:{${this.escapeTagValue(key)}})`;
255
253
  try {
256
254
  const results = await this.client.ft.search("store", query, { LIMIT: {
257
255
  from: 0,
@@ -259,17 +257,17 @@ var RedisStore = class RedisStore {
259
257
  } });
260
258
  if (!results || !results.documents || results.documents.length === 0) return null;
261
259
  if (key === "") {
262
- for (const doc$1 of results.documents) {
263
- const jsonDoc$1 = doc$1.value;
264
- if (jsonDoc$1.key === "" && jsonDoc$1.prefix === prefix) {
265
- const docId$1 = doc$1.id;
266
- if (options?.refreshTTL) await this.refreshItemTTL(docId$1);
260
+ for (const doc of results.documents) {
261
+ const jsonDoc = doc.value;
262
+ if (jsonDoc.key === "" && jsonDoc.prefix === prefix) {
263
+ const docId = doc.id;
264
+ if (options?.refreshTTL) await this.refreshItemTTL(docId);
267
265
  return {
268
- value: jsonDoc$1.value,
269
- key: jsonDoc$1.key,
270
- namespace: jsonDoc$1.prefix.split("."),
271
- created_at: /* @__PURE__ */ new Date(jsonDoc$1.created_at / 1e6),
272
- updated_at: /* @__PURE__ */ new Date(jsonDoc$1.updated_at / 1e6)
266
+ value: jsonDoc.value,
267
+ key: jsonDoc.key,
268
+ namespace: jsonDoc.prefix.split("."),
269
+ created_at: /* @__PURE__ */ new Date(jsonDoc.created_at / 1e6),
270
+ updated_at: /* @__PURE__ */ new Date(jsonDoc.updated_at / 1e6)
273
271
  };
274
272
  }
275
273
  }
@@ -294,13 +292,11 @@ var RedisStore = class RedisStore {
294
292
  async put(namespace, key, value, options) {
295
293
  this.validateNamespace(namespace);
296
294
  const prefix = namespace.join(".");
297
- const docId = require_v4.default();
295
+ const docId = (0, uuid.v4)();
298
296
  const now = Date.now() * 1e6 + Math.floor(performance.now() * 1e3);
299
297
  let createdAt = now;
300
298
  const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);
301
- const prefixQuery = tokens.length > 0 ? `@prefix:(${tokens.join(" ")})` : "*";
302
- const escapedKey = this.escapeTagValue(key);
303
- const existingQuery = `(${prefixQuery}) (@key:{${escapedKey}})`;
299
+ const existingQuery = `(${tokens.length > 0 ? `@prefix:(${tokens.join(" ")})` : "*"}) (@key:{${this.escapeTagValue(key)}})`;
304
300
  try {
305
301
  const existing = await this.client.ft.search("store", existingQuery, { LIMIT: {
306
302
  from: 0,
@@ -312,8 +308,7 @@ var RedisStore = class RedisStore {
312
308
  if (existingDoc && typeof existingDoc === "object" && "created_at" in existingDoc) createdAt = existingDoc.created_at;
313
309
  await this.client.del(oldDocId);
314
310
  if (this.indexConfig) {
315
- const oldUuid = oldDocId.split(":").pop();
316
- const oldVectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${oldUuid}`;
311
+ const oldVectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${oldDocId.split(":").pop()}`;
317
312
  try {
318
313
  await this.client.del(oldVectorKey);
319
314
  } catch (error) {}
@@ -351,9 +346,9 @@ var RedisStore = class RedisStore {
351
346
  updated_at: now
352
347
  };
353
348
  await this.client.json.set(vectorKey, "$", vectorDoc);
354
- const ttlMinutes$1 = options?.ttl || this.ttlConfig?.defaultTTL;
355
- if (ttlMinutes$1) {
356
- const ttlSeconds = Math.floor(ttlMinutes$1 * 60);
349
+ const ttlMinutes = options?.ttl || this.ttlConfig?.defaultTTL;
350
+ if (ttlMinutes) {
351
+ const ttlSeconds = Math.floor(ttlMinutes * 60);
357
352
  await this.client.expire(vectorKey, ttlSeconds);
358
353
  }
359
354
  }
@@ -374,10 +369,10 @@ var RedisStore = class RedisStore {
374
369
  const offset = options?.offset || 0;
375
370
  if (options?.query && this.indexConfig && this.embeddings) {
376
371
  const [embedding] = await this.embeddings.embedDocuments([options.query]);
377
- let queryStr$1 = prefix ? `@prefix:${prefix.split(/[.-]/)[0]}*` : "*";
372
+ let queryStr = prefix ? `@prefix:${prefix.split(/[.-]/)[0]}*` : "*";
378
373
  const vectorBytes = Buffer.from(new Float32Array(embedding).buffer);
379
374
  try {
380
- const results = await this.client.ft.search("store_vectors", `(${queryStr$1})=>[KNN ${limit} @embedding $BLOB]`, {
375
+ const results = await this.client.ft.search("store_vectors", `(${queryStr})=>[KNN ${limit} @embedding $BLOB]`, {
381
376
  PARAMS: { BLOB: vectorBytes },
382
377
  DIALECT: 2,
383
378
  LIMIT: {
@@ -392,8 +387,7 @@ var RedisStore = class RedisStore {
392
387
  });
393
388
  const items = [];
394
389
  for (const doc of results.documents) {
395
- const docUuid = doc.id.split(":").pop();
396
- const storeKey = `${STORE_PREFIX}${REDIS_KEY_SEPARATOR}${docUuid}`;
390
+ const storeKey = `${STORE_PREFIX}${REDIS_KEY_SEPARATOR}${doc.id.split(":").pop()}`;
397
391
  const storeDoc = await this.client.json.get(storeKey);
398
392
  if (storeDoc) {
399
393
  if (options.filter) {
@@ -554,20 +548,17 @@ var RedisStore = class RedisStore {
554
548
  namespaceCount: 0
555
549
  };
556
550
  try {
557
- const countResult = await this.client.ft.search("store", "*", { LIMIT: {
551
+ stats.totalDocuments = (await this.client.ft.search("store", "*", { LIMIT: {
558
552
  from: 0,
559
553
  size: 0
560
- } });
561
- stats.totalDocuments = countResult.total || 0;
562
- const namespaces = await this.listNamespaces({ limit: 1e3 });
563
- stats.namespaceCount = namespaces.length;
554
+ } })).total || 0;
555
+ stats.namespaceCount = (await this.listNamespaces({ limit: 1e3 })).length;
564
556
  if (this.indexConfig) {
565
557
  try {
566
- const vectorResult = await this.client.ft.search("store_vectors", "*", { LIMIT: {
558
+ stats.vectorDocuments = (await this.client.ft.search("store_vectors", "*", { LIMIT: {
567
559
  from: 0,
568
560
  size: 0
569
- } });
570
- stats.vectorDocuments = vectorResult.total || 0;
561
+ } })).total || 0;
571
562
  } catch (error) {
572
563
  stats.vectorDocuments = 0;
573
564
  }
@@ -581,36 +572,33 @@ var RedisStore = class RedisStore {
581
572
  return stats;
582
573
  }
583
574
  validateNamespace(namespace) {
584
- if (namespace.length === 0) throw new __langchain_langgraph_checkpoint.InvalidNamespaceError("Namespace cannot be empty.");
575
+ if (namespace.length === 0) throw new _langchain_langgraph_checkpoint.InvalidNamespaceError("Namespace cannot be empty.");
585
576
  for (const label of namespace) {
586
- if (typeof label !== "string") throw new __langchain_langgraph_checkpoint.InvalidNamespaceError(`Invalid namespace label '${String(label)}' found in ${namespace}. Namespace labels must be strings.`);
587
- if (label.includes(".")) throw new __langchain_langgraph_checkpoint.InvalidNamespaceError(`Invalid namespace label '${label}' found in ${namespace}. Namespace labels cannot contain periods ('.').`);
588
- if (label === "") throw new __langchain_langgraph_checkpoint.InvalidNamespaceError(`Namespace labels cannot be empty strings. Got ${label} in ${namespace}`);
577
+ if (typeof label !== "string") throw new _langchain_langgraph_checkpoint.InvalidNamespaceError(`Invalid namespace label '${String(label)}' found in ${namespace}. Namespace labels must be strings.`);
578
+ if (label.includes(".")) throw new _langchain_langgraph_checkpoint.InvalidNamespaceError(`Invalid namespace label '${label}' found in ${namespace}. Namespace labels cannot contain periods ('.').`);
579
+ if (label === "") throw new _langchain_langgraph_checkpoint.InvalidNamespaceError(`Namespace labels cannot be empty strings. Got ${label} in ${namespace}`);
589
580
  }
590
- if (namespace[0] === "langgraph") throw new __langchain_langgraph_checkpoint.InvalidNamespaceError(`Root label for namespace cannot be "langgraph". Got: ${namespace}`);
581
+ if (namespace[0] === "langgraph") throw new _langchain_langgraph_checkpoint.InvalidNamespaceError(`Root label for namespace cannot be "langgraph". Got: ${namespace}`);
591
582
  }
592
583
  async refreshItemTTL(docId) {
593
584
  if (this.ttlConfig?.defaultTTL) {
594
585
  const ttlSeconds = Math.floor(this.ttlConfig.defaultTTL * 60);
595
586
  await this.client.expire(docId, ttlSeconds);
596
- const docUuid = docId.split(":").pop();
597
- const vectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${docUuid}`;
587
+ const vectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${docId.split(":").pop()}`;
598
588
  try {
599
589
  await this.client.expire(vectorKey, ttlSeconds);
600
590
  } catch (error) {}
601
591
  }
602
592
  }
603
593
  escapeTagValue(value) {
604
- if (value === "") return "__EMPTY_STRING__";
605
- return value.replace(/\\/g, "\\\\").replace(/[-\s,.:<>{}[\]"';!@#$%^&*()+=~|?/]/g, "\\$&");
594
+ return require_utils.escapeRediSearchTagValue(value);
606
595
  }
607
596
  /**
608
597
  * Calculate similarity score based on the distance metric.
609
598
  * Converts raw distance to a normalized similarity score [0,1].
610
599
  */
611
600
  calculateSimilarityScore(distance) {
612
- const metric = this.indexConfig?.distanceType || "cosine";
613
- switch (metric) {
601
+ switch (this.indexConfig?.distanceType || "cosine") {
614
602
  case "cosine": return Math.max(0, 1 - distance / 2);
615
603
  case "l2": return Math.exp(-distance);
616
604
  case "ip": return 1 / (1 + Math.exp(-distance));
@@ -1 +1 @@
1
- {"version":3,"file":"store.cjs","names":["queryParts: string[]","error: any","vectorSchema: Record<string, any>","query: string","doc","jsonDoc","docId","uuidv4","vectorDoc: VectorDocument","ttlMinutes","queryStr","items: SearchItem[]","results: any[]","prefix: string[] | undefined","suffix: string[] | undefined","stats: {\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }","InvalidNamespaceError"],"sources":["../src/store.ts"],"sourcesContent":["import { createClient, createCluster } from \"redis\";\n\n/** A conventional Redis connection. */\nexport type RedisClientConnection = ReturnType<typeof createClient>;\n\n/** A clustered Redis connection. */\nexport type RedisClusterConnection = ReturnType<typeof createCluster>;\n\n/** A Redis connection, clustered or conventional. */\nexport type RedisConnection = RedisClientConnection | RedisClusterConnection;\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n type GetOperation,\n InvalidNamespaceError,\n type ListNamespacesOperation,\n type Operation,\n type PutOperation,\n type SearchOperation,\n} from \"@langchain/langgraph-checkpoint\";\n\n// Type guard functions for operations\nexport function isPutOperation(op: Operation): op is PutOperation {\n return \"value\" in op && \"namespace\" in op && \"key\" in op;\n}\n\nexport function isGetOperation(op: Operation): op is GetOperation {\n return (\n \"namespace\" in op &&\n \"key\" in op &&\n !(\"value\" in op) &&\n !(\"namespacePrefix\" in op) &&\n !(\"matchConditions\" in op)\n );\n}\n\nexport function isSearchOperation(op: Operation): op is SearchOperation {\n return \"namespacePrefix\" in op;\n}\n\nexport function isListNamespacesOperation(\n op: Operation\n): op is ListNamespacesOperation {\n return \"matchConditions\" in op;\n}\n\n// Filter types for advanced search operations\nexport interface FilterOperators {\n $eq?: any;\n $ne?: any;\n $gt?: number;\n $gte?: number;\n $lt?: number;\n $lte?: number;\n $in?: any[];\n $nin?: any[];\n $exists?: boolean;\n}\n\nexport type FilterValue = any | FilterOperators;\nexport type Filter = Record<string, FilterValue>;\n\n/**\n * Internal class for evaluating filters against documents.\n * Supports MongoDB-style query operators.\n */\nclass FilterBuilder {\n /**\n * Evaluates if a document matches the given filter criteria.\n * Supports advanced operators like $gt, $lt, $in, etc.\n */\n static matchesFilter(doc: Record<string, any>, filter: Filter): boolean {\n for (const [key, filterValue] of Object.entries(filter)) {\n if (!this.matchesFieldFilter(doc, key, filterValue)) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Builds a Redis Search query string from filter criteria.\n * Note: This is limited by RediSearch capabilities and may not support all operators.\n */\n static buildRedisSearchQuery(\n filter: Filter,\n prefix?: string\n ): { query: string; useClientFilter: boolean } {\n let queryParts: string[] = [];\n let useClientFilter = false;\n\n // Add prefix filter if provided\n if (prefix) {\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n if (tokens.length > 0) {\n queryParts.push(`@prefix:(${tokens.join(\" \")})`);\n }\n }\n\n // Check if we have complex operators that require client-side filtering\n for (const [_key, value] of Object.entries(filter)) {\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value).some((k) => k.startsWith(\"$\"))\n ) {\n // Complex operators require client-side filtering\n useClientFilter = true;\n break;\n }\n }\n\n // If no prefix, at least search all documents\n if (queryParts.length === 0) {\n queryParts.push(\"*\");\n }\n\n return {\n query: queryParts.join(\" \"),\n useClientFilter,\n };\n }\n\n private static matchesFieldFilter(\n doc: Record<string, any>,\n key: string,\n filterValue: FilterValue\n ): boolean {\n // Handle nested keys (e.g., \"user.name\")\n const actualValue = this.getNestedValue(doc, key);\n\n // Check if it's an operator object\n if (\n typeof filterValue === \"object\" &&\n filterValue !== null &&\n !Array.isArray(filterValue) &&\n Object.keys(filterValue).some((k) => k.startsWith(\"$\"))\n ) {\n // Handle operator object\n return this.matchesOperators(actualValue, filterValue as FilterOperators);\n } else {\n // Simple equality check\n return this.isEqual(actualValue, filterValue);\n }\n }\n\n private static matchesOperators(\n actualValue: any,\n operators: FilterOperators\n ): boolean {\n for (const [operator, operatorValue] of Object.entries(operators)) {\n if (!this.matchesOperator(actualValue, operator, operatorValue)) {\n return false;\n }\n }\n return true;\n }\n\n private static matchesOperator(\n actualValue: any,\n operator: string,\n operatorValue: any\n ): boolean {\n switch (operator) {\n case \"$eq\":\n return this.isEqual(actualValue, operatorValue);\n\n case \"$ne\":\n return !this.isEqual(actualValue, operatorValue);\n\n case \"$gt\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) > Number(operatorValue)\n );\n\n case \"$gte\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) >= Number(operatorValue)\n );\n\n case \"$lt\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) < Number(operatorValue)\n );\n\n case \"$lte\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) <= Number(operatorValue)\n );\n\n case \"$in\":\n if (!Array.isArray(operatorValue)) return false;\n return operatorValue.some((val) => this.isEqual(actualValue, val));\n\n case \"$nin\":\n if (!Array.isArray(operatorValue)) return false;\n return !operatorValue.some((val) => this.isEqual(actualValue, val));\n\n case \"$exists\": {\n const exists = actualValue !== undefined;\n return operatorValue ? exists : !exists;\n }\n\n default:\n // Unknown operator, return false for safety\n return false;\n }\n }\n\n private static isEqual(a: any, b: any): boolean {\n // Handle null and undefined\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (a === undefined || b === undefined) return false;\n\n // Handle arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => this.isEqual(val, b[idx]));\n }\n if (Array.isArray(a) || Array.isArray(b)) {\n // Check if non-array value exists in array\n const arr = Array.isArray(a) ? a : b;\n const val = Array.isArray(a) ? b : a;\n return arr.includes(val);\n }\n\n // Handle objects\n if (typeof a === \"object\" && typeof b === \"object\") {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((key) => this.isEqual(a[key], b[key]));\n }\n\n // Primitive comparison (with type coercion for numbers)\n return a == b;\n }\n\n private static getNestedValue(obj: any, path: string): any {\n const keys = path.split(\".\");\n let current = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = current[key];\n }\n\n return current;\n }\n}\n\nexport interface Item {\n value: any;\n key: string;\n namespace: string[];\n created_at: Date;\n updated_at: Date;\n}\n\nexport interface SearchItem extends Item {\n score?: number;\n}\n\ninterface StoreDocument {\n key: string;\n prefix: string;\n value: any;\n created_at: number;\n updated_at: number;\n}\n\ninterface VectorDocument {\n prefix: string;\n key: string;\n field_name: string;\n embedding: number[];\n created_at: number;\n updated_at: number;\n}\n\nexport interface IndexConfig {\n dims: number;\n embed?: any;\n distanceType?: \"cosine\" | \"l2\" | \"ip\"; // cosine, L2 (Euclidean), inner product\n fields?: string[];\n vectorStorageType?: string;\n similarityThreshold?: number; // Minimum similarity score for results\n}\n\nexport interface TTLConfig {\n defaultTTL?: number;\n refreshOnRead?: boolean;\n}\n\nexport interface StoreConfig {\n index?: IndexConfig;\n ttl?: TTLConfig;\n}\n\nconst REDIS_KEY_SEPARATOR = \":\";\nconst STORE_PREFIX = \"store\";\nconst STORE_VECTOR_PREFIX = \"store_vectors\";\n\nconst SCHEMAS = [\n {\n index: \"store\",\n prefix: STORE_PREFIX + REDIS_KEY_SEPARATOR,\n schema: {\n \"$.prefix\": { type: \"TEXT\", AS: \"prefix\" },\n \"$.key\": { type: \"TAG\", AS: \"key\" },\n \"$.created_at\": { type: \"NUMERIC\", AS: \"created_at\" },\n \"$.updated_at\": { type: \"NUMERIC\", AS: \"updated_at\" },\n },\n },\n {\n index: \"store_vectors\",\n prefix: STORE_VECTOR_PREFIX + REDIS_KEY_SEPARATOR,\n schema: {\n \"$.prefix\": { type: \"TEXT\", AS: \"prefix\" },\n \"$.key\": { type: \"TAG\", AS: \"key\" },\n \"$.field_name\": { type: \"TAG\", AS: \"field_name\" },\n \"$.embedding\": { type: \"VECTOR\", AS: \"embedding\" },\n \"$.created_at\": { type: \"NUMERIC\", AS: \"created_at\" },\n \"$.updated_at\": { type: \"NUMERIC\", AS: \"updated_at\" },\n },\n },\n];\n\nexport class RedisStore {\n private readonly client: RedisConnection;\n private readonly indexConfig?: IndexConfig;\n private readonly ttlConfig?: TTLConfig;\n private readonly embeddings?: any;\n\n constructor(client: RedisConnection, config?: StoreConfig) {\n this.client = client;\n this.indexConfig = config?.index;\n this.ttlConfig = config?.ttl;\n\n if (this.indexConfig?.embed) {\n this.embeddings = this.indexConfig.embed;\n }\n }\n\n static async fromConnString(\n connString: string,\n config?: StoreConfig\n ): Promise<RedisStore> {\n const client = createClient({ url: connString });\n await client.connect();\n const store = new RedisStore(client, config);\n await store.setup();\n return store;\n }\n\n static async fromCluster(\n rootNodes: Array<{ url: string }>,\n config?: StoreConfig\n ): Promise<RedisStore> {\n const client = createCluster({ rootNodes });\n await client.connect();\n const store = new RedisStore(client, config);\n await store.setup();\n return store;\n }\n\n async setup(): Promise<void> {\n // Create store index\n try {\n await this.client.ft.create(SCHEMAS[0].index, SCHEMAS[0].schema as any, {\n ON: \"JSON\",\n PREFIX: SCHEMAS[0].prefix,\n });\n } catch (error: any) {\n if (!error.message?.includes(\"Index already exists\")) {\n console.error(\"Failed to create store index:\", error.message);\n }\n }\n\n // Create vector index if configured\n if (this.indexConfig) {\n const dims = this.indexConfig.dims;\n const distanceMetric =\n this.indexConfig.distanceType === \"cosine\"\n ? \"COSINE\"\n : this.indexConfig.distanceType === \"l2\"\n ? \"L2\"\n : this.indexConfig.distanceType === \"ip\"\n ? \"IP\"\n : \"COSINE\";\n\n // Build schema with correct vector syntax\n const vectorSchema: Record<string, any> = {\n \"$.prefix\": { type: \"TEXT\", AS: \"prefix\" },\n \"$.key\": { type: \"TAG\", AS: \"key\" },\n \"$.field_name\": { type: \"TAG\", AS: \"field_name\" },\n \"$.created_at\": { type: \"NUMERIC\", AS: \"created_at\" },\n \"$.updated_at\": { type: \"NUMERIC\", AS: \"updated_at\" },\n };\n\n // Add vector field with correct syntax\n vectorSchema[\"$.embedding\"] = {\n type: \"VECTOR\",\n ALGORITHM: \"FLAT\",\n TYPE: \"FLOAT32\",\n DIM: dims,\n DISTANCE_METRIC: distanceMetric,\n AS: \"embedding\",\n };\n\n try {\n await this.client.ft.create(SCHEMAS[1].index, vectorSchema as any, {\n ON: \"JSON\",\n PREFIX: SCHEMAS[1].prefix,\n });\n } catch (error: any) {\n if (!error.message?.includes(\"Index already exists\")) {\n console.error(\"Failed to create vector index:\", error.message);\n }\n }\n }\n }\n\n async get(\n namespace: string[],\n key: string,\n options?: { refreshTTL?: boolean }\n ): Promise<Item | null> {\n const prefix = namespace.join(\".\");\n // For TEXT fields, we need to match all tokens (split by dots and hyphens)\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n const prefixQuery =\n tokens.length > 0 ? `@prefix:(${tokens.join(\" \")})` : \"*\";\n\n // For TAG fields in curly braces, escape special characters\n // Handle empty string as a special case\n let query: string;\n if (key === \"\") {\n // For empty keys, search by prefix and filter results\n query = prefixQuery;\n } else {\n const escapedKey = this.escapeTagValue(key);\n query = `(${prefixQuery}) (@key:{${escapedKey}})`;\n }\n\n try {\n const results = await this.client.ft.search(\"store\", query, {\n LIMIT: { from: 0, size: key === \"\" ? 100 : 1 },\n });\n\n if (!results || !results.documents || results.documents.length === 0) {\n return null;\n }\n\n // For empty key, filter to find the exact match\n if (key === \"\") {\n for (const doc of results.documents) {\n const jsonDoc = doc.value as unknown as StoreDocument;\n if (jsonDoc.key === \"\" && jsonDoc.prefix === prefix) {\n const docId = doc.id;\n\n // Refresh TTL if requested\n if (options?.refreshTTL) {\n await this.refreshItemTTL(docId);\n }\n\n return {\n value: jsonDoc.value,\n key: jsonDoc.key,\n namespace: jsonDoc.prefix.split(\".\"),\n created_at: new Date(jsonDoc.created_at / 1000000),\n updated_at: new Date(jsonDoc.updated_at / 1000000),\n };\n }\n }\n return null;\n }\n\n const doc = results.documents[0];\n const jsonDoc = doc.value as unknown as StoreDocument;\n const docId = doc.id;\n\n // Refresh TTL if requested\n if (options?.refreshTTL) {\n await this.refreshItemTTL(docId);\n }\n\n return {\n value: jsonDoc.value,\n key: jsonDoc.key,\n namespace: jsonDoc.prefix.split(\".\"),\n created_at: new Date(jsonDoc.created_at / 1000000),\n updated_at: new Date(jsonDoc.updated_at / 1000000),\n };\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return null;\n }\n throw error;\n }\n }\n\n async put(\n namespace: string[],\n key: string,\n value: any,\n options?: { ttl?: number; index?: boolean | string[] }\n ): Promise<void> {\n // Validate namespace for put operations\n this.validateNamespace(namespace);\n const prefix = namespace.join(\".\");\n const docId = uuidv4();\n // Use high-resolution time for better timestamp precision\n const now = Date.now() * 1000000 + Math.floor(performance.now() * 1000); // Microseconds + nanoseconds component\n let createdAt = now; // Will be overridden if document exists\n\n // Delete existing document if it exists\n // For TEXT fields, we need to match all tokens (split by dots and hyphens)\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n const prefixQuery =\n tokens.length > 0 ? `@prefix:(${tokens.join(\" \")})` : \"*\";\n\n // For TAG fields in curly braces, escape special characters\n const escapedKey = this.escapeTagValue(key);\n const existingQuery = `(${prefixQuery}) (@key:{${escapedKey}})`;\n try {\n const existing = await this.client.ft.search(\"store\", existingQuery, {\n LIMIT: { from: 0, size: 1 },\n });\n\n if (existing && existing.documents && existing.documents.length > 0) {\n const oldDocId = existing.documents[0].id;\n // Preserve the original created_at timestamp\n const existingDoc = await this.client.json.get(oldDocId);\n if (\n existingDoc &&\n typeof existingDoc === \"object\" &&\n \"created_at\" in existingDoc\n ) {\n createdAt = (existingDoc as any).created_at;\n }\n await this.client.del(oldDocId);\n\n // Also delete associated vector if it exists\n if (this.indexConfig) {\n const oldUuid = oldDocId.split(\":\").pop();\n const oldVectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${oldUuid}`;\n try {\n await this.client.del(oldVectorKey);\n } catch (error) {\n // Vector might not exist\n }\n }\n }\n } catch (error) {\n // Index might not exist yet\n }\n\n // Handle delete operation\n if (value === null) {\n return;\n }\n\n // Store the document\n const storeKey = `${STORE_PREFIX}${REDIS_KEY_SEPARATOR}${docId}`;\n const doc = {\n prefix,\n key,\n value,\n created_at: createdAt,\n updated_at: now,\n };\n\n await this.client.json.set(storeKey, \"$\", doc);\n\n // Handle embeddings if configured\n if (this.indexConfig && this.embeddings && options?.index !== false) {\n const fieldsToIndex =\n options && Array.isArray(options.index)\n ? options.index\n : this.indexConfig.fields || [\"text\"];\n const textsToEmbed = [];\n const fieldNames = [];\n\n for (const field of fieldsToIndex) {\n if (value[field]) {\n textsToEmbed.push(value[field]);\n fieldNames.push(field);\n }\n }\n\n if (textsToEmbed.length > 0) {\n const embeddings = await this.embeddings.embedDocuments(textsToEmbed);\n\n for (let i = 0; i < embeddings.length; i++) {\n const vectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${docId}`;\n const vectorDoc: VectorDocument = {\n prefix,\n key,\n field_name: fieldNames[i],\n embedding: embeddings[i],\n created_at: now,\n updated_at: now,\n };\n\n await this.client.json.set(vectorKey, \"$\", vectorDoc as any);\n\n // Apply TTL to vector key if configured\n const ttlMinutes = options?.ttl || this.ttlConfig?.defaultTTL;\n if (ttlMinutes) {\n const ttlSeconds = Math.floor(ttlMinutes * 60);\n await this.client.expire(vectorKey, ttlSeconds);\n }\n }\n }\n }\n\n // Apply TTL if configured\n const ttlMinutes = options?.ttl || this.ttlConfig?.defaultTTL;\n if (ttlMinutes) {\n const ttlSeconds = Math.floor(ttlMinutes * 60);\n await this.client.expire(storeKey, ttlSeconds);\n }\n }\n\n async delete(namespace: string[], key: string): Promise<void> {\n await this.put(namespace, key, null);\n }\n\n async search(\n namespacePrefix: string[],\n options?: {\n filter?: Filter;\n query?: string;\n limit?: number;\n offset?: number;\n refreshTTL?: boolean;\n similarityThreshold?: number;\n }\n ): Promise<SearchItem[]> {\n const prefix = namespacePrefix.join(\".\");\n const limit = options?.limit || 10;\n const offset = options?.offset || 0;\n\n // Handle vector search if query is provided\n if (options?.query && this.indexConfig && this.embeddings) {\n const [embedding] = await this.embeddings.embedDocuments([options.query]);\n\n // Build KNN query\n // For prefix search, use wildcard since we want to match any document starting with this prefix\n let queryStr = prefix ? `@prefix:${prefix.split(/[.-]/)[0]}*` : \"*\";\n const vectorBytes = Buffer.from(new Float32Array(embedding).buffer);\n\n try {\n // Use KNN query with proper syntax\n const results = await this.client.ft.search(\n \"store_vectors\",\n `(${queryStr})=>[KNN ${limit} @embedding $BLOB]`,\n {\n PARAMS: {\n BLOB: vectorBytes,\n },\n DIALECT: 2,\n LIMIT: { from: offset, size: limit },\n RETURN: [\"prefix\", \"key\", \"__embedding_score\"],\n }\n );\n\n // Get matching store documents\n const items: SearchItem[] = [];\n for (const doc of results.documents) {\n const docUuid = doc.id.split(\":\").pop();\n const storeKey = `${STORE_PREFIX}${REDIS_KEY_SEPARATOR}${docUuid}`;\n\n const storeDoc = (await this.client.json.get(\n storeKey\n )) as StoreDocument | null;\n if (storeDoc) {\n // Apply advanced filter if provided\n if (options.filter) {\n if (\n !FilterBuilder.matchesFilter(\n storeDoc.value || {},\n options.filter\n )\n ) {\n continue;\n }\n }\n\n // Refresh TTL if requested\n if (options.refreshTTL) {\n await this.refreshItemTTL(storeKey);\n await this.refreshItemTTL(doc.id);\n }\n\n const score = (doc.value as any)?.__embedding_score\n ? this.calculateSimilarityScore(\n parseFloat((doc.value as any).__embedding_score as string)\n )\n : 0;\n\n // Apply similarity threshold if specified\n const threshold =\n options.similarityThreshold ??\n this.indexConfig?.similarityThreshold;\n if (threshold !== undefined && score < threshold) {\n continue;\n }\n\n items.push({\n value: storeDoc.value,\n key: storeDoc.key,\n namespace: storeDoc.prefix.split(\".\"),\n created_at: new Date(storeDoc.created_at / 1000000),\n updated_at: new Date(storeDoc.updated_at / 1000000),\n score,\n });\n }\n }\n\n return items;\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return [];\n }\n throw error;\n }\n }\n\n // Regular search without vectors\n let queryStr = \"*\";\n if (prefix) {\n // For prefix search, we need to match all tokens from the namespace prefix\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n if (tokens.length > 0) {\n // Match all tokens to ensure we get the right prefix\n queryStr = `@prefix:(${tokens.join(\" \")})`;\n }\n }\n\n try {\n const results = await this.client.ft.search(\"store\", queryStr, {\n LIMIT: { from: offset, size: limit },\n SORTBY: { BY: \"created_at\", DIRECTION: \"DESC\" },\n });\n\n const items: SearchItem[] = [];\n for (const doc of results.documents) {\n const jsonDoc = doc.value as unknown as StoreDocument;\n\n // Apply advanced filter\n if (options?.filter) {\n if (\n !FilterBuilder.matchesFilter(jsonDoc.value || {}, options.filter)\n ) {\n continue;\n }\n }\n\n // Refresh TTL if requested\n if (options?.refreshTTL) {\n await this.refreshItemTTL(doc.id);\n }\n\n items.push({\n value: jsonDoc.value,\n key: jsonDoc.key,\n namespace: jsonDoc.prefix.split(\".\"),\n created_at: new Date(jsonDoc.created_at / 1000000),\n updated_at: new Date(jsonDoc.updated_at / 1000000),\n });\n }\n\n return items;\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return [];\n }\n throw error;\n }\n }\n\n async listNamespaces(options?: {\n prefix?: string[];\n suffix?: string[];\n maxDepth?: number;\n limit?: number;\n offset?: number;\n }): Promise<string[][]> {\n let query = \"*\";\n\n try {\n const results = await this.client.ft.search(\"store\", query, {\n LIMIT: { from: 0, size: 1000 }, // Get many to deduplicate\n RETURN: [\"prefix\"],\n });\n\n // Extract unique namespaces and filter\n const namespaceSet = new Set<string>();\n for (const doc of results.documents) {\n const prefix = (doc.value as unknown as StoreDocument).prefix;\n const parts = prefix.split(\".\");\n\n // Apply prefix filter if specified\n if (options?.prefix) {\n // Check if this namespace starts with the specified prefix\n if (parts.length < options.prefix.length) continue;\n\n let matches = true;\n for (let i = 0; i < options.prefix.length; i++) {\n if (parts[i] !== options.prefix[i]) {\n matches = false;\n break;\n }\n }\n if (!matches) continue;\n }\n\n // Apply suffix filter if specified\n if (options?.suffix) {\n // Check if this namespace ends with the specified suffix\n if (parts.length < options.suffix.length) continue;\n\n let matches = true;\n const startIdx = parts.length - options.suffix.length;\n for (let i = 0; i < options.suffix.length; i++) {\n if (parts[startIdx + i] !== options.suffix[i]) {\n matches = false;\n break;\n }\n }\n if (!matches) continue;\n }\n\n // Apply max depth\n if (options?.maxDepth) {\n const truncated = parts.slice(0, options.maxDepth);\n namespaceSet.add(truncated.join(\".\"));\n } else {\n namespaceSet.add(prefix);\n }\n }\n\n // Convert to array of arrays and sort\n let namespaces = Array.from(namespaceSet)\n .map((ns) => ns.split(\".\"))\n .sort((a, b) => a.join(\".\").localeCompare(b.join(\".\")));\n\n // Apply pagination\n if (options?.offset || options?.limit) {\n const offset = options.offset || 0;\n const limit = options.limit || 10;\n namespaces = namespaces.slice(offset, offset + limit);\n }\n\n return namespaces;\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return [];\n }\n throw error;\n }\n }\n\n async batch(ops: Operation[]): Promise<any[]> {\n const results: any[] = new Array(ops.length).fill(null);\n\n // Process operations in order to maintain dependencies\n for (let idx = 0; idx < ops.length; idx++) {\n const op = ops[idx];\n\n // Execute operation based on type guards\n if (isPutOperation(op)) {\n // TypeScript now knows op is PutOperation\n await this.put(op.namespace, op.key, op.value);\n results[idx] = null;\n } else if (isSearchOperation(op)) {\n // TypeScript now knows op is SearchOperation\n results[idx] = await this.search(op.namespacePrefix, {\n filter: op.filter,\n query: op.query,\n limit: op.limit,\n offset: op.offset,\n });\n } else if (isListNamespacesOperation(op)) {\n // TypeScript now knows op is ListNamespacesOperation\n let prefix: string[] | undefined = undefined;\n let suffix: string[] | undefined = undefined;\n\n if (op.matchConditions) {\n for (const condition of op.matchConditions) {\n if (condition.matchType === \"prefix\") {\n prefix = condition.path;\n } else if (condition.matchType === \"suffix\") {\n suffix = condition.path;\n }\n }\n }\n\n results[idx] = await this.listNamespaces({\n prefix,\n suffix,\n maxDepth: op.maxDepth,\n limit: op.limit,\n offset: op.offset,\n });\n } else if (isGetOperation(op)) {\n // TypeScript now knows op is GetOperation\n results[idx] = await this.get(op.namespace, op.key);\n } else {\n // This should never happen with proper Operation type\n throw new Error(`Unknown operation type: ${JSON.stringify(op)}`);\n }\n }\n\n return results;\n }\n\n async close(): Promise<void> {\n await this.client.quit();\n }\n\n /**\n * Get statistics about the store.\n * Returns document counts and other metrics.\n */\n async getStatistics(): Promise<{\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }> {\n const stats: {\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n } = {\n totalDocuments: 0,\n namespaceCount: 0,\n };\n\n try {\n // Get total document count\n const countResult = await this.client.ft.search(\"store\", \"*\", {\n LIMIT: { from: 0, size: 0 },\n });\n stats.totalDocuments = countResult.total || 0;\n\n // Get unique namespace count\n const namespaces = await this.listNamespaces({ limit: 1000 });\n stats.namespaceCount = namespaces.length;\n\n // Get vector document count if index is configured\n if (this.indexConfig) {\n try {\n const vectorResult = await this.client.ft.search(\n \"store_vectors\",\n \"*\",\n {\n LIMIT: { from: 0, size: 0 },\n }\n );\n stats.vectorDocuments = vectorResult.total || 0;\n } catch (error) {\n // Vector index might not exist\n stats.vectorDocuments = 0;\n }\n\n // Get index info\n try {\n stats.indexInfo = await this.client.ft.info(\"store\");\n } catch (error) {\n // Index info might not be available\n }\n }\n } catch (error: any) {\n if (!error.message?.includes(\"no such index\")) {\n throw error;\n }\n }\n\n return stats;\n }\n\n private validateNamespace(namespace: string[]): void {\n if (namespace.length === 0) {\n throw new InvalidNamespaceError(\"Namespace cannot be empty.\");\n }\n for (const label of namespace) {\n // Runtime check for JavaScript users (TypeScript already ensures this)\n // This check is for runtime safety when called from JavaScript\n // noinspection SuspiciousTypeOfGuard\n if (typeof label !== \"string\") {\n throw new InvalidNamespaceError(\n `Invalid namespace label '${String(\n label\n )}' found in ${namespace}. Namespace labels must be strings.`\n );\n }\n if (label.includes(\".\")) {\n throw new InvalidNamespaceError(\n `Invalid namespace label '${label}' found in ${namespace}. Namespace labels cannot contain periods ('.').`\n );\n }\n if (label === \"\") {\n throw new InvalidNamespaceError(\n `Namespace labels cannot be empty strings. Got ${label} in ${namespace}`\n );\n }\n }\n if (namespace[0] === \"langgraph\") {\n throw new InvalidNamespaceError(\n `Root label for namespace cannot be \"langgraph\". Got: ${namespace}`\n );\n }\n }\n\n private async refreshItemTTL(docId: string): Promise<void> {\n if (this.ttlConfig?.defaultTTL) {\n const ttlSeconds = Math.floor(this.ttlConfig.defaultTTL * 60);\n await this.client.expire(docId, ttlSeconds);\n\n // Also refresh vector key if it exists\n const docUuid = docId.split(\":\").pop();\n const vectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${docUuid}`;\n try {\n await this.client.expire(vectorKey, ttlSeconds);\n } catch (error) {\n // Vector key might not exist\n }\n }\n }\n\n private escapeTagValue(value: string): string {\n // For TAG fields, we need to escape special characters\n // Based on RediSearch documentation, these characters need escaping in TAG fields\n // when used within curly braces: , . < > { } [ ] \" ' : ; ! @ # $ % ^ & * ( ) - + = ~ | \\ ? /\n // Handle empty string as a special case - use a placeholder\n if (value === \"\") {\n // Use a special placeholder for empty strings\n return \"__EMPTY_STRING__\";\n }\n // We'll escape the most common ones that appear in keys\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/[-\\s,.:<>{}[\\]\"';!@#$%^&*()+=~|?/]/g, \"\\\\$&\");\n }\n\n /**\n * Calculate similarity score based on the distance metric.\n * Converts raw distance to a normalized similarity score [0,1].\n */\n private calculateSimilarityScore(distance: number): number {\n const metric = this.indexConfig?.distanceType || \"cosine\";\n\n switch (metric) {\n case \"cosine\":\n // Cosine distance is in range [0,2], convert to similarity [0,1]\n return Math.max(0, 1 - distance / 2);\n\n case \"l2\":\n // L2 (Euclidean) distance, use exponential decay\n // Similarity = e^(-distance)\n return Math.exp(-distance);\n\n case \"ip\":\n // Inner product can be negative, use sigmoid function\n // Similarity = 1 / (1 + e^(-distance))\n return 1 / (1 + Math.exp(-distance));\n\n default:\n // Default to cosine similarity\n return Math.max(0, 1 - distance / 2);\n }\n }\n}\n\n// Export FilterBuilder for testing purposes\nexport { FilterBuilder };\n"],"mappings":"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"}
1
+ {"version":3,"file":"store.cjs","names":["InvalidNamespaceError","escapeRediSearchTagValue"],"sources":["../src/store.ts"],"sourcesContent":["import { createClient, createCluster } from \"redis\";\n\n/** A conventional Redis connection. */\nexport type RedisClientConnection = ReturnType<typeof createClient>;\n\n/** A clustered Redis connection. */\nexport type RedisClusterConnection = ReturnType<typeof createCluster>;\n\n/** A Redis connection, clustered or conventional. */\nexport type RedisConnection = RedisClientConnection | RedisClusterConnection;\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n type GetOperation,\n InvalidNamespaceError,\n type ListNamespacesOperation,\n type Operation,\n type PutOperation,\n type SearchOperation,\n} from \"@langchain/langgraph-checkpoint\";\n\nimport { escapeRediSearchTagValue } from \"./utils.js\";\n\n// Type guard functions for operations\nexport function isPutOperation(op: Operation): op is PutOperation {\n return \"value\" in op && \"namespace\" in op && \"key\" in op;\n}\n\nexport function isGetOperation(op: Operation): op is GetOperation {\n return (\n \"namespace\" in op &&\n \"key\" in op &&\n !(\"value\" in op) &&\n !(\"namespacePrefix\" in op) &&\n !(\"matchConditions\" in op)\n );\n}\n\nexport function isSearchOperation(op: Operation): op is SearchOperation {\n return \"namespacePrefix\" in op;\n}\n\nexport function isListNamespacesOperation(\n op: Operation\n): op is ListNamespacesOperation {\n return \"matchConditions\" in op;\n}\n\n// Filter types for advanced search operations\nexport interface FilterOperators {\n $eq?: any;\n $ne?: any;\n $gt?: number;\n $gte?: number;\n $lt?: number;\n $lte?: number;\n $in?: any[];\n $nin?: any[];\n $exists?: boolean;\n}\n\nexport type FilterValue = any | FilterOperators;\nexport type Filter = Record<string, FilterValue>;\n\n/**\n * Internal class for evaluating filters against documents.\n * Supports MongoDB-style query operators.\n */\nclass FilterBuilder {\n /**\n * Evaluates if a document matches the given filter criteria.\n * Supports advanced operators like $gt, $lt, $in, etc.\n */\n static matchesFilter(doc: Record<string, any>, filter: Filter): boolean {\n for (const [key, filterValue] of Object.entries(filter)) {\n if (!this.matchesFieldFilter(doc, key, filterValue)) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Builds a Redis Search query string from filter criteria.\n * Note: This is limited by RediSearch capabilities and may not support all operators.\n */\n static buildRedisSearchQuery(\n filter: Filter,\n prefix?: string\n ): { query: string; useClientFilter: boolean } {\n let queryParts: string[] = [];\n let useClientFilter = false;\n\n // Add prefix filter if provided\n if (prefix) {\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n if (tokens.length > 0) {\n queryParts.push(`@prefix:(${tokens.join(\" \")})`);\n }\n }\n\n // Check if we have complex operators that require client-side filtering\n for (const [_key, value] of Object.entries(filter)) {\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value).some((k) => k.startsWith(\"$\"))\n ) {\n // Complex operators require client-side filtering\n useClientFilter = true;\n break;\n }\n }\n\n // If no prefix, at least search all documents\n if (queryParts.length === 0) {\n queryParts.push(\"*\");\n }\n\n return {\n query: queryParts.join(\" \"),\n useClientFilter,\n };\n }\n\n private static matchesFieldFilter(\n doc: Record<string, any>,\n key: string,\n filterValue: FilterValue\n ): boolean {\n // Handle nested keys (e.g., \"user.name\")\n const actualValue = this.getNestedValue(doc, key);\n\n // Check if it's an operator object\n if (\n typeof filterValue === \"object\" &&\n filterValue !== null &&\n !Array.isArray(filterValue) &&\n Object.keys(filterValue).some((k) => k.startsWith(\"$\"))\n ) {\n // Handle operator object\n return this.matchesOperators(actualValue, filterValue as FilterOperators);\n } else {\n // Simple equality check\n return this.isEqual(actualValue, filterValue);\n }\n }\n\n private static matchesOperators(\n actualValue: any,\n operators: FilterOperators\n ): boolean {\n for (const [operator, operatorValue] of Object.entries(operators)) {\n if (!this.matchesOperator(actualValue, operator, operatorValue)) {\n return false;\n }\n }\n return true;\n }\n\n private static matchesOperator(\n actualValue: any,\n operator: string,\n operatorValue: any\n ): boolean {\n switch (operator) {\n case \"$eq\":\n return this.isEqual(actualValue, operatorValue);\n\n case \"$ne\":\n return !this.isEqual(actualValue, operatorValue);\n\n case \"$gt\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) > Number(operatorValue)\n );\n\n case \"$gte\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) >= Number(operatorValue)\n );\n\n case \"$lt\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) < Number(operatorValue)\n );\n\n case \"$lte\":\n return (\n actualValue !== undefined &&\n actualValue !== null &&\n Number(actualValue) <= Number(operatorValue)\n );\n\n case \"$in\":\n if (!Array.isArray(operatorValue)) return false;\n return operatorValue.some((val) => this.isEqual(actualValue, val));\n\n case \"$nin\":\n if (!Array.isArray(operatorValue)) return false;\n return !operatorValue.some((val) => this.isEqual(actualValue, val));\n\n case \"$exists\": {\n const exists = actualValue !== undefined;\n return operatorValue ? exists : !exists;\n }\n\n default:\n // Unknown operator, return false for safety\n return false;\n }\n }\n\n private static isEqual(a: any, b: any): boolean {\n // Handle null and undefined\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (a === undefined || b === undefined) return false;\n\n // Handle arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => this.isEqual(val, b[idx]));\n }\n if (Array.isArray(a) || Array.isArray(b)) {\n // Check if non-array value exists in array\n const arr = Array.isArray(a) ? a : b;\n const val = Array.isArray(a) ? b : a;\n return arr.includes(val);\n }\n\n // Handle objects\n if (typeof a === \"object\" && typeof b === \"object\") {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((key) => this.isEqual(a[key], b[key]));\n }\n\n // Primitive comparison (with type coercion for numbers)\n return a == b;\n }\n\n private static getNestedValue(obj: any, path: string): any {\n const keys = path.split(\".\");\n let current = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = current[key];\n }\n\n return current;\n }\n}\n\nexport interface Item {\n value: any;\n key: string;\n namespace: string[];\n created_at: Date;\n updated_at: Date;\n}\n\nexport interface SearchItem extends Item {\n score?: number;\n}\n\ninterface StoreDocument {\n key: string;\n prefix: string;\n value: any;\n created_at: number;\n updated_at: number;\n}\n\ninterface VectorDocument {\n prefix: string;\n key: string;\n field_name: string;\n embedding: number[];\n created_at: number;\n updated_at: number;\n}\n\nexport interface IndexConfig {\n dims: number;\n embed?: any;\n distanceType?: \"cosine\" | \"l2\" | \"ip\"; // cosine, L2 (Euclidean), inner product\n fields?: string[];\n vectorStorageType?: string;\n similarityThreshold?: number; // Minimum similarity score for results\n}\n\nexport interface TTLConfig {\n defaultTTL?: number;\n refreshOnRead?: boolean;\n}\n\nexport interface StoreConfig {\n index?: IndexConfig;\n ttl?: TTLConfig;\n}\n\nconst REDIS_KEY_SEPARATOR = \":\";\nconst STORE_PREFIX = \"store\";\nconst STORE_VECTOR_PREFIX = \"store_vectors\";\n\nconst SCHEMAS = [\n {\n index: \"store\",\n prefix: STORE_PREFIX + REDIS_KEY_SEPARATOR,\n schema: {\n \"$.prefix\": { type: \"TEXT\", AS: \"prefix\" },\n \"$.key\": { type: \"TAG\", AS: \"key\" },\n \"$.created_at\": { type: \"NUMERIC\", AS: \"created_at\" },\n \"$.updated_at\": { type: \"NUMERIC\", AS: \"updated_at\" },\n },\n },\n {\n index: \"store_vectors\",\n prefix: STORE_VECTOR_PREFIX + REDIS_KEY_SEPARATOR,\n schema: {\n \"$.prefix\": { type: \"TEXT\", AS: \"prefix\" },\n \"$.key\": { type: \"TAG\", AS: \"key\" },\n \"$.field_name\": { type: \"TAG\", AS: \"field_name\" },\n \"$.embedding\": { type: \"VECTOR\", AS: \"embedding\" },\n \"$.created_at\": { type: \"NUMERIC\", AS: \"created_at\" },\n \"$.updated_at\": { type: \"NUMERIC\", AS: \"updated_at\" },\n },\n },\n];\n\nexport class RedisStore {\n private readonly client: RedisConnection;\n private readonly indexConfig?: IndexConfig;\n private readonly ttlConfig?: TTLConfig;\n private readonly embeddings?: any;\n\n constructor(client: RedisConnection, config?: StoreConfig) {\n this.client = client;\n this.indexConfig = config?.index;\n this.ttlConfig = config?.ttl;\n\n if (this.indexConfig?.embed) {\n this.embeddings = this.indexConfig.embed;\n }\n }\n\n static async fromConnString(\n connString: string,\n config?: StoreConfig\n ): Promise<RedisStore> {\n const client = createClient({ url: connString });\n await client.connect();\n const store = new RedisStore(client, config);\n await store.setup();\n return store;\n }\n\n static async fromCluster(\n rootNodes: Array<{ url: string }>,\n config?: StoreConfig\n ): Promise<RedisStore> {\n const client = createCluster({ rootNodes });\n await client.connect();\n const store = new RedisStore(client, config);\n await store.setup();\n return store;\n }\n\n async setup(): Promise<void> {\n // Create store index\n try {\n await this.client.ft.create(SCHEMAS[0].index, SCHEMAS[0].schema as any, {\n ON: \"JSON\",\n PREFIX: SCHEMAS[0].prefix,\n });\n } catch (error: any) {\n if (!error.message?.includes(\"Index already exists\")) {\n console.error(\"Failed to create store index:\", error.message);\n }\n }\n\n // Create vector index if configured\n if (this.indexConfig) {\n const dims = this.indexConfig.dims;\n const distanceMetric =\n this.indexConfig.distanceType === \"cosine\"\n ? \"COSINE\"\n : this.indexConfig.distanceType === \"l2\"\n ? \"L2\"\n : this.indexConfig.distanceType === \"ip\"\n ? \"IP\"\n : \"COSINE\";\n\n // Build schema with correct vector syntax\n const vectorSchema: Record<string, any> = {\n \"$.prefix\": { type: \"TEXT\", AS: \"prefix\" },\n \"$.key\": { type: \"TAG\", AS: \"key\" },\n \"$.field_name\": { type: \"TAG\", AS: \"field_name\" },\n \"$.created_at\": { type: \"NUMERIC\", AS: \"created_at\" },\n \"$.updated_at\": { type: \"NUMERIC\", AS: \"updated_at\" },\n };\n\n // Add vector field with correct syntax\n vectorSchema[\"$.embedding\"] = {\n type: \"VECTOR\",\n ALGORITHM: \"FLAT\",\n TYPE: \"FLOAT32\",\n DIM: dims,\n DISTANCE_METRIC: distanceMetric,\n AS: \"embedding\",\n };\n\n try {\n await this.client.ft.create(SCHEMAS[1].index, vectorSchema as any, {\n ON: \"JSON\",\n PREFIX: SCHEMAS[1].prefix,\n });\n } catch (error: any) {\n if (!error.message?.includes(\"Index already exists\")) {\n console.error(\"Failed to create vector index:\", error.message);\n }\n }\n }\n }\n\n async get(\n namespace: string[],\n key: string,\n options?: { refreshTTL?: boolean }\n ): Promise<Item | null> {\n const prefix = namespace.join(\".\");\n // For TEXT fields, we need to match all tokens (split by dots and hyphens)\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n const prefixQuery =\n tokens.length > 0 ? `@prefix:(${tokens.join(\" \")})` : \"*\";\n\n // For TAG fields in curly braces, escape special characters\n // Handle empty string as a special case\n let query: string;\n if (key === \"\") {\n // For empty keys, search by prefix and filter results\n query = prefixQuery;\n } else {\n const escapedKey = this.escapeTagValue(key);\n query = `(${prefixQuery}) (@key:{${escapedKey}})`;\n }\n\n try {\n const results = await this.client.ft.search(\"store\", query, {\n LIMIT: { from: 0, size: key === \"\" ? 100 : 1 },\n });\n\n if (!results || !results.documents || results.documents.length === 0) {\n return null;\n }\n\n // For empty key, filter to find the exact match\n if (key === \"\") {\n for (const doc of results.documents) {\n const jsonDoc = doc.value as unknown as StoreDocument;\n if (jsonDoc.key === \"\" && jsonDoc.prefix === prefix) {\n const docId = doc.id;\n\n // Refresh TTL if requested\n if (options?.refreshTTL) {\n await this.refreshItemTTL(docId);\n }\n\n return {\n value: jsonDoc.value,\n key: jsonDoc.key,\n namespace: jsonDoc.prefix.split(\".\"),\n created_at: new Date(jsonDoc.created_at / 1000000),\n updated_at: new Date(jsonDoc.updated_at / 1000000),\n };\n }\n }\n return null;\n }\n\n const doc = results.documents[0];\n const jsonDoc = doc.value as unknown as StoreDocument;\n const docId = doc.id;\n\n // Refresh TTL if requested\n if (options?.refreshTTL) {\n await this.refreshItemTTL(docId);\n }\n\n return {\n value: jsonDoc.value,\n key: jsonDoc.key,\n namespace: jsonDoc.prefix.split(\".\"),\n created_at: new Date(jsonDoc.created_at / 1000000),\n updated_at: new Date(jsonDoc.updated_at / 1000000),\n };\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return null;\n }\n throw error;\n }\n }\n\n async put(\n namespace: string[],\n key: string,\n value: any,\n options?: { ttl?: number; index?: boolean | string[] }\n ): Promise<void> {\n // Validate namespace for put operations\n this.validateNamespace(namespace);\n const prefix = namespace.join(\".\");\n const docId = uuidv4();\n // Use high-resolution time for better timestamp precision\n const now = Date.now() * 1000000 + Math.floor(performance.now() * 1000); // Microseconds + nanoseconds component\n let createdAt = now; // Will be overridden if document exists\n\n // Delete existing document if it exists\n // For TEXT fields, we need to match all tokens (split by dots and hyphens)\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n const prefixQuery =\n tokens.length > 0 ? `@prefix:(${tokens.join(\" \")})` : \"*\";\n\n // For TAG fields in curly braces, escape special characters\n const escapedKey = this.escapeTagValue(key);\n const existingQuery = `(${prefixQuery}) (@key:{${escapedKey}})`;\n try {\n const existing = await this.client.ft.search(\"store\", existingQuery, {\n LIMIT: { from: 0, size: 1 },\n });\n\n if (existing && existing.documents && existing.documents.length > 0) {\n const oldDocId = existing.documents[0].id;\n // Preserve the original created_at timestamp\n const existingDoc = await this.client.json.get(oldDocId);\n if (\n existingDoc &&\n typeof existingDoc === \"object\" &&\n \"created_at\" in existingDoc\n ) {\n createdAt = (existingDoc as any).created_at;\n }\n await this.client.del(oldDocId);\n\n // Also delete associated vector if it exists\n if (this.indexConfig) {\n const oldUuid = oldDocId.split(\":\").pop();\n const oldVectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${oldUuid}`;\n try {\n await this.client.del(oldVectorKey);\n } catch (error) {\n // Vector might not exist\n }\n }\n }\n } catch (error) {\n // Index might not exist yet\n }\n\n // Handle delete operation\n if (value === null) {\n return;\n }\n\n // Store the document\n const storeKey = `${STORE_PREFIX}${REDIS_KEY_SEPARATOR}${docId}`;\n const doc = {\n prefix,\n key,\n value,\n created_at: createdAt,\n updated_at: now,\n };\n\n await this.client.json.set(storeKey, \"$\", doc);\n\n // Handle embeddings if configured\n if (this.indexConfig && this.embeddings && options?.index !== false) {\n const fieldsToIndex =\n options && Array.isArray(options.index)\n ? options.index\n : this.indexConfig.fields || [\"text\"];\n const textsToEmbed = [];\n const fieldNames = [];\n\n for (const field of fieldsToIndex) {\n if (value[field]) {\n textsToEmbed.push(value[field]);\n fieldNames.push(field);\n }\n }\n\n if (textsToEmbed.length > 0) {\n const embeddings = await this.embeddings.embedDocuments(textsToEmbed);\n\n for (let i = 0; i < embeddings.length; i++) {\n const vectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${docId}`;\n const vectorDoc: VectorDocument = {\n prefix,\n key,\n field_name: fieldNames[i],\n embedding: embeddings[i],\n created_at: now,\n updated_at: now,\n };\n\n await this.client.json.set(vectorKey, \"$\", vectorDoc as any);\n\n // Apply TTL to vector key if configured\n const ttlMinutes = options?.ttl || this.ttlConfig?.defaultTTL;\n if (ttlMinutes) {\n const ttlSeconds = Math.floor(ttlMinutes * 60);\n await this.client.expire(vectorKey, ttlSeconds);\n }\n }\n }\n }\n\n // Apply TTL if configured\n const ttlMinutes = options?.ttl || this.ttlConfig?.defaultTTL;\n if (ttlMinutes) {\n const ttlSeconds = Math.floor(ttlMinutes * 60);\n await this.client.expire(storeKey, ttlSeconds);\n }\n }\n\n async delete(namespace: string[], key: string): Promise<void> {\n await this.put(namespace, key, null);\n }\n\n async search(\n namespacePrefix: string[],\n options?: {\n filter?: Filter;\n query?: string;\n limit?: number;\n offset?: number;\n refreshTTL?: boolean;\n similarityThreshold?: number;\n }\n ): Promise<SearchItem[]> {\n const prefix = namespacePrefix.join(\".\");\n const limit = options?.limit || 10;\n const offset = options?.offset || 0;\n\n // Handle vector search if query is provided\n if (options?.query && this.indexConfig && this.embeddings) {\n const [embedding] = await this.embeddings.embedDocuments([options.query]);\n\n // Build KNN query\n // For prefix search, use wildcard since we want to match any document starting with this prefix\n let queryStr = prefix ? `@prefix:${prefix.split(/[.-]/)[0]}*` : \"*\";\n const vectorBytes = Buffer.from(new Float32Array(embedding).buffer);\n\n try {\n // Use KNN query with proper syntax\n const results = await this.client.ft.search(\n \"store_vectors\",\n `(${queryStr})=>[KNN ${limit} @embedding $BLOB]`,\n {\n PARAMS: {\n BLOB: vectorBytes,\n },\n DIALECT: 2,\n LIMIT: { from: offset, size: limit },\n RETURN: [\"prefix\", \"key\", \"__embedding_score\"],\n }\n );\n\n // Get matching store documents\n const items: SearchItem[] = [];\n for (const doc of results.documents) {\n const docUuid = doc.id.split(\":\").pop();\n const storeKey = `${STORE_PREFIX}${REDIS_KEY_SEPARATOR}${docUuid}`;\n\n const storeDoc = (await this.client.json.get(\n storeKey\n )) as StoreDocument | null;\n if (storeDoc) {\n // Apply advanced filter if provided\n if (options.filter) {\n if (\n !FilterBuilder.matchesFilter(\n storeDoc.value || {},\n options.filter\n )\n ) {\n continue;\n }\n }\n\n // Refresh TTL if requested\n if (options.refreshTTL) {\n await this.refreshItemTTL(storeKey);\n await this.refreshItemTTL(doc.id);\n }\n\n const score = (doc.value as any)?.__embedding_score\n ? this.calculateSimilarityScore(\n parseFloat((doc.value as any).__embedding_score as string)\n )\n : 0;\n\n // Apply similarity threshold if specified\n const threshold =\n options.similarityThreshold ??\n this.indexConfig?.similarityThreshold;\n if (threshold !== undefined && score < threshold) {\n continue;\n }\n\n items.push({\n value: storeDoc.value,\n key: storeDoc.key,\n namespace: storeDoc.prefix.split(\".\"),\n created_at: new Date(storeDoc.created_at / 1000000),\n updated_at: new Date(storeDoc.updated_at / 1000000),\n score,\n });\n }\n }\n\n return items;\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return [];\n }\n throw error;\n }\n }\n\n // Regular search without vectors\n let queryStr = \"*\";\n if (prefix) {\n // For prefix search, we need to match all tokens from the namespace prefix\n const tokens = prefix.split(/[.-]/).filter((t) => t.length > 0);\n if (tokens.length > 0) {\n // Match all tokens to ensure we get the right prefix\n queryStr = `@prefix:(${tokens.join(\" \")})`;\n }\n }\n\n try {\n const results = await this.client.ft.search(\"store\", queryStr, {\n LIMIT: { from: offset, size: limit },\n SORTBY: { BY: \"created_at\", DIRECTION: \"DESC\" },\n });\n\n const items: SearchItem[] = [];\n for (const doc of results.documents) {\n const jsonDoc = doc.value as unknown as StoreDocument;\n\n // Apply advanced filter\n if (options?.filter) {\n if (\n !FilterBuilder.matchesFilter(jsonDoc.value || {}, options.filter)\n ) {\n continue;\n }\n }\n\n // Refresh TTL if requested\n if (options?.refreshTTL) {\n await this.refreshItemTTL(doc.id);\n }\n\n items.push({\n value: jsonDoc.value,\n key: jsonDoc.key,\n namespace: jsonDoc.prefix.split(\".\"),\n created_at: new Date(jsonDoc.created_at / 1000000),\n updated_at: new Date(jsonDoc.updated_at / 1000000),\n });\n }\n\n return items;\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return [];\n }\n throw error;\n }\n }\n\n async listNamespaces(options?: {\n prefix?: string[];\n suffix?: string[];\n maxDepth?: number;\n limit?: number;\n offset?: number;\n }): Promise<string[][]> {\n let query = \"*\";\n\n try {\n const results = await this.client.ft.search(\"store\", query, {\n LIMIT: { from: 0, size: 1000 }, // Get many to deduplicate\n RETURN: [\"prefix\"],\n });\n\n // Extract unique namespaces and filter\n const namespaceSet = new Set<string>();\n for (const doc of results.documents) {\n const prefix = (doc.value as unknown as StoreDocument).prefix;\n const parts = prefix.split(\".\");\n\n // Apply prefix filter if specified\n if (options?.prefix) {\n // Check if this namespace starts with the specified prefix\n if (parts.length < options.prefix.length) continue;\n\n let matches = true;\n for (let i = 0; i < options.prefix.length; i++) {\n if (parts[i] !== options.prefix[i]) {\n matches = false;\n break;\n }\n }\n if (!matches) continue;\n }\n\n // Apply suffix filter if specified\n if (options?.suffix) {\n // Check if this namespace ends with the specified suffix\n if (parts.length < options.suffix.length) continue;\n\n let matches = true;\n const startIdx = parts.length - options.suffix.length;\n for (let i = 0; i < options.suffix.length; i++) {\n if (parts[startIdx + i] !== options.suffix[i]) {\n matches = false;\n break;\n }\n }\n if (!matches) continue;\n }\n\n // Apply max depth\n if (options?.maxDepth) {\n const truncated = parts.slice(0, options.maxDepth);\n namespaceSet.add(truncated.join(\".\"));\n } else {\n namespaceSet.add(prefix);\n }\n }\n\n // Convert to array of arrays and sort\n let namespaces = Array.from(namespaceSet)\n .map((ns) => ns.split(\".\"))\n .sort((a, b) => a.join(\".\").localeCompare(b.join(\".\")));\n\n // Apply pagination\n if (options?.offset || options?.limit) {\n const offset = options.offset || 0;\n const limit = options.limit || 10;\n namespaces = namespaces.slice(offset, offset + limit);\n }\n\n return namespaces;\n } catch (error: any) {\n if (error.message?.includes(\"no such index\")) {\n return [];\n }\n throw error;\n }\n }\n\n async batch(ops: Operation[]): Promise<any[]> {\n const results: any[] = new Array(ops.length).fill(null);\n\n // Process operations in order to maintain dependencies\n for (let idx = 0; idx < ops.length; idx++) {\n const op = ops[idx];\n\n // Execute operation based on type guards\n if (isPutOperation(op)) {\n // TypeScript now knows op is PutOperation\n await this.put(op.namespace, op.key, op.value);\n results[idx] = null;\n } else if (isSearchOperation(op)) {\n // TypeScript now knows op is SearchOperation\n results[idx] = await this.search(op.namespacePrefix, {\n filter: op.filter,\n query: op.query,\n limit: op.limit,\n offset: op.offset,\n });\n } else if (isListNamespacesOperation(op)) {\n // TypeScript now knows op is ListNamespacesOperation\n let prefix: string[] | undefined = undefined;\n let suffix: string[] | undefined = undefined;\n\n if (op.matchConditions) {\n for (const condition of op.matchConditions) {\n if (condition.matchType === \"prefix\") {\n prefix = condition.path;\n } else if (condition.matchType === \"suffix\") {\n suffix = condition.path;\n }\n }\n }\n\n results[idx] = await this.listNamespaces({\n prefix,\n suffix,\n maxDepth: op.maxDepth,\n limit: op.limit,\n offset: op.offset,\n });\n } else if (isGetOperation(op)) {\n // TypeScript now knows op is GetOperation\n results[idx] = await this.get(op.namespace, op.key);\n } else {\n // This should never happen with proper Operation type\n throw new Error(`Unknown operation type: ${JSON.stringify(op)}`);\n }\n }\n\n return results;\n }\n\n async close(): Promise<void> {\n await this.client.quit();\n }\n\n /**\n * Get statistics about the store.\n * Returns document counts and other metrics.\n */\n async getStatistics(): Promise<{\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }> {\n const stats: {\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n } = {\n totalDocuments: 0,\n namespaceCount: 0,\n };\n\n try {\n // Get total document count\n const countResult = await this.client.ft.search(\"store\", \"*\", {\n LIMIT: { from: 0, size: 0 },\n });\n stats.totalDocuments = countResult.total || 0;\n\n // Get unique namespace count\n const namespaces = await this.listNamespaces({ limit: 1000 });\n stats.namespaceCount = namespaces.length;\n\n // Get vector document count if index is configured\n if (this.indexConfig) {\n try {\n const vectorResult = await this.client.ft.search(\n \"store_vectors\",\n \"*\",\n {\n LIMIT: { from: 0, size: 0 },\n }\n );\n stats.vectorDocuments = vectorResult.total || 0;\n } catch (error) {\n // Vector index might not exist\n stats.vectorDocuments = 0;\n }\n\n // Get index info\n try {\n stats.indexInfo = await this.client.ft.info(\"store\");\n } catch (error) {\n // Index info might not be available\n }\n }\n } catch (error: any) {\n if (!error.message?.includes(\"no such index\")) {\n throw error;\n }\n }\n\n return stats;\n }\n\n private validateNamespace(namespace: string[]): void {\n if (namespace.length === 0) {\n throw new InvalidNamespaceError(\"Namespace cannot be empty.\");\n }\n for (const label of namespace) {\n // Runtime check for JavaScript users (TypeScript already ensures this)\n // This check is for runtime safety when called from JavaScript\n // noinspection SuspiciousTypeOfGuard\n if (typeof label !== \"string\") {\n throw new InvalidNamespaceError(\n `Invalid namespace label '${String(\n label\n )}' found in ${namespace}. Namespace labels must be strings.`\n );\n }\n if (label.includes(\".\")) {\n throw new InvalidNamespaceError(\n `Invalid namespace label '${label}' found in ${namespace}. Namespace labels cannot contain periods ('.').`\n );\n }\n if (label === \"\") {\n throw new InvalidNamespaceError(\n `Namespace labels cannot be empty strings. Got ${label} in ${namespace}`\n );\n }\n }\n if (namespace[0] === \"langgraph\") {\n throw new InvalidNamespaceError(\n `Root label for namespace cannot be \"langgraph\". Got: ${namespace}`\n );\n }\n }\n\n private async refreshItemTTL(docId: string): Promise<void> {\n if (this.ttlConfig?.defaultTTL) {\n const ttlSeconds = Math.floor(this.ttlConfig.defaultTTL * 60);\n await this.client.expire(docId, ttlSeconds);\n\n // Also refresh vector key if it exists\n const docUuid = docId.split(\":\").pop();\n const vectorKey = `${STORE_VECTOR_PREFIX}${REDIS_KEY_SEPARATOR}${docUuid}`;\n try {\n await this.client.expire(vectorKey, ttlSeconds);\n } catch (error) {\n // Vector key might not exist\n }\n }\n }\n\n private escapeTagValue(value: string): string {\n // Delegate to shared utility for RediSearch TAG field escaping\n return escapeRediSearchTagValue(value);\n }\n\n /**\n * Calculate similarity score based on the distance metric.\n * Converts raw distance to a normalized similarity score [0,1].\n */\n private calculateSimilarityScore(distance: number): number {\n const metric = this.indexConfig?.distanceType || \"cosine\";\n\n switch (metric) {\n case \"cosine\":\n // Cosine distance is in range [0,2], convert to similarity [0,1]\n return Math.max(0, 1 - distance / 2);\n\n case \"l2\":\n // L2 (Euclidean) distance, use exponential decay\n // Similarity = e^(-distance)\n return Math.exp(-distance);\n\n case \"ip\":\n // Inner product can be negative, use sigmoid function\n // Similarity = 1 / (1 + e^(-distance))\n return 1 / (1 + Math.exp(-distance));\n\n default:\n // Default to cosine similarity\n return Math.max(0, 1 - distance / 2);\n }\n }\n}\n\n// Export FilterBuilder for testing purposes\nexport { FilterBuilder };\n"],"mappings":"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"}
package/dist/store.d.cts CHANGED
@@ -8,12 +8,10 @@ type RedisClientConnection = ReturnType<typeof createClient>;
8
8
  type RedisClusterConnection = ReturnType<typeof createCluster>;
9
9
  /** A Redis connection, clustered or conventional. */
10
10
  type RedisConnection = RedisClientConnection | RedisClusterConnection;
11
- // Type guard functions for operations
12
11
  declare function isPutOperation(op: Operation): op is PutOperation;
13
12
  declare function isGetOperation(op: Operation): op is GetOperation;
14
13
  declare function isSearchOperation(op: Operation): op is SearchOperation;
15
14
  declare function isListNamespacesOperation(op: Operation): op is ListNamespacesOperation;
16
- // Filter types for advanced search operations
17
15
  interface FilterOperators {
18
16
  $eq?: any;
19
17
  $ne?: any;
@@ -64,10 +62,10 @@ interface SearchItem extends Item {
64
62
  interface IndexConfig {
65
63
  dims: number;
66
64
  embed?: any;
67
- distanceType?: "cosine" | "l2" | "ip"; // cosine, L2 (Euclidean), inner product
65
+ distanceType?: "cosine" | "l2" | "ip";
68
66
  fields?: string[];
69
67
  vectorStorageType?: string;
70
- similarityThreshold?: number; // Minimum similarity score for results
68
+ similarityThreshold?: number;
71
69
  }
72
70
  interface TTLConfig {
73
71
  defaultTTL?: number;
@@ -132,7 +130,6 @@ declare class RedisStore {
132
130
  */
133
131
  private calculateSimilarityScore;
134
132
  }
135
- // Export FilterBuilder for testing purposes
136
133
  //#endregion
137
134
  export { Filter, FilterBuilder, FilterOperators, FilterValue, IndexConfig, Item, RedisClientConnection, RedisClusterConnection, RedisConnection, RedisStore, SearchItem, StoreConfig, TTLConfig, isGetOperation, isListNamespacesOperation, isPutOperation, isSearchOperation };
138
135
  //# sourceMappingURL=store.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.cts","names":["createClient","createCluster","RedisClientConnection","ReturnType","RedisClusterConnection","RedisConnection","GetOperation","ListNamespacesOperation","Operation","PutOperation","SearchOperation","isPutOperation","isGetOperation","isSearchOperation","isListNamespacesOperation","FilterOperators","FilterValue","Filter","Record","FilterBuilder","Item","Date","SearchItem","IndexConfig","TTLConfig","StoreConfig","RedisStore","Promise","Array"],"sources":["../src/store.d.ts"],"sourcesContent":["import { createClient, createCluster } from \"redis\";\n/** A conventional Redis connection. */\nexport type RedisClientConnection = ReturnType<typeof createClient>;\n/** A clustered Redis connection. */\nexport type RedisClusterConnection = ReturnType<typeof createCluster>;\n/** A Redis connection, clustered or conventional. */\nexport type RedisConnection = RedisClientConnection | RedisClusterConnection;\nimport { type GetOperation, type ListNamespacesOperation, type Operation, type PutOperation, type SearchOperation } from \"@langchain/langgraph-checkpoint\";\n// Type guard functions for operations\nexport declare function isPutOperation(op: Operation): op is PutOperation;\nexport declare function isGetOperation(op: Operation): op is GetOperation;\nexport declare function isSearchOperation(op: Operation): op is SearchOperation;\nexport declare function isListNamespacesOperation(op: Operation): op is ListNamespacesOperation;\n// Filter types for advanced search operations\nexport interface FilterOperators {\n $eq?: any;\n $ne?: any;\n $gt?: number;\n $gte?: number;\n $lt?: number;\n $lte?: number;\n $in?: any[];\n $nin?: any[];\n $exists?: boolean;\n}\nexport type FilterValue = any | FilterOperators;\nexport type Filter = Record<string, FilterValue>;\n/**\n * Internal class for evaluating filters against documents.\n * Supports MongoDB-style query operators.\n */\ndeclare class FilterBuilder {\n /**\n * Evaluates if a document matches the given filter criteria.\n * Supports advanced operators like $gt, $lt, $in, etc.\n */\n static matchesFilter(doc: Record<string, any>, filter: Filter): boolean;\n /**\n * Builds a Redis Search query string from filter criteria.\n * Note: This is limited by RediSearch capabilities and may not support all operators.\n */\n static buildRedisSearchQuery(filter: Filter, prefix?: string): {\n query: string;\n useClientFilter: boolean;\n };\n private static matchesFieldFilter;\n private static matchesOperators;\n private static matchesOperator;\n private static isEqual;\n private static getNestedValue;\n}\nexport interface Item {\n value: any;\n key: string;\n namespace: string[];\n created_at: Date;\n updated_at: Date;\n}\nexport interface SearchItem extends Item {\n score?: number;\n}\nexport interface IndexConfig {\n dims: number;\n embed?: any;\n distanceType?: \"cosine\" | \"l2\" | \"ip\"; // cosine, L2 (Euclidean), inner product\n fields?: string[];\n vectorStorageType?: string;\n similarityThreshold?: number; // Minimum similarity score for results\n}\nexport interface TTLConfig {\n defaultTTL?: number;\n refreshOnRead?: boolean;\n}\nexport interface StoreConfig {\n index?: IndexConfig;\n ttl?: TTLConfig;\n}\nexport declare class RedisStore {\n private readonly client;\n private readonly indexConfig?;\n private readonly ttlConfig?;\n private readonly embeddings?;\n constructor(client: RedisConnection, config?: StoreConfig);\n static fromConnString(connString: string, config?: StoreConfig): Promise<RedisStore>;\n static fromCluster(rootNodes: Array<{\n url: string;\n }>, config?: StoreConfig): Promise<RedisStore>;\n setup(): Promise<void>;\n get(namespace: string[], key: string, options?: {\n refreshTTL?: boolean;\n }): Promise<Item | null>;\n put(namespace: string[], key: string, value: any, options?: {\n ttl?: number;\n index?: boolean | string[];\n }): Promise<void>;\n delete(namespace: string[], key: string): Promise<void>;\n search(namespacePrefix: string[], options?: {\n filter?: Filter;\n query?: string;\n limit?: number;\n offset?: number;\n refreshTTL?: boolean;\n similarityThreshold?: number;\n }): Promise<SearchItem[]>;\n listNamespaces(options?: {\n prefix?: string[];\n suffix?: string[];\n maxDepth?: number;\n limit?: number;\n offset?: number;\n }): Promise<string[][]>;\n batch(ops: Operation[]): Promise<any[]>;\n close(): Promise<void>;\n /**\n * Get statistics about the store.\n * Returns document counts and other metrics.\n */\n getStatistics(): Promise<{\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }>;\n private validateNamespace;\n private refreshItemTTL;\n private escapeTagValue;\n /**\n * Calculate similarity score based on the distance metric.\n * Converts raw distance to a normalized similarity score [0,1].\n */\n private calculateSimilarityScore;\n}\n// Export FilterBuilder for testing purposes\nexport { FilterBuilder };\n//# sourceMappingURL=store.d.ts.map"],"mappings":";;;;;KAEYE,qBAAAA,GAAwBC,kBAAkBH;;AAA1CE,KAEAE,sBAAAA,GAAyBD,UAFJ,CAAA,OAEsBF,aAFtB,CAAA;;AAAqBD,KAI1CK,eAAAA,GAAkBH,qBAJwBF,GAIAI,sBAJAJ;;AAE1CI,iBAKYO,cAAAA,CALU,EAAA,EAKSH,SALT,CAAA,EAAA,EAAA,IAK2BC,YAL3B;AAAA,iBAMVG,cAAAA,CANU,EAAA,EAMSJ,SANT,CAAA,EAAA,EAAA,IAM2BF,YAN3B;AAAqBL,iBAO/BY,iBAAAA,CAP+BZ,EAAAA,EAOTO,SAPSP,CAAAA,EAAAA,EAAAA,IAOSS,eAPTT;AAAlBE,iBAQbW,yBAAAA,CARaX,EAAAA,EAQiBK,SARjBL,CAAAA,EAAAA,EAAAA,IAQmCI,uBARnCJ;;AAEzBE,UAQKU,eAAAA,CARU;EAAA,GAAA,CAAA,EAAA,GAAA;KAAGb,CAAAA,EAAAA,GAAAA;KAAwBE,CAAAA,EAAAA,MAAAA;;EAG9BO,GAAAA,CAAAA,EAAAA,MAAAA;EAAc,IAAA,CAAA,EAAA,MAAA;KAAKH,CAAAA,EAAAA,GAAAA,EAAAA;MAAkBC,CAAAA,EAAAA,GAAAA,EAAAA;;AAC7D;AAAsC,KAe1BO,WAAAA,GAf0B,GAAA,GAeND,eAfM;AAAKP,KAgB/BS,MAAAA,GAASC,MAhBsBV,CAAAA,MAAAA,EAgBPQ,WAhBOR,CAAAA;;;AAC3C;;cAoBcW,aAAAA,CApBgCX;;;AAC9C;;SAAsDA,aAAAA,CAAAA,GAAAA,EAwBxBU,MAxBwBV,CAAAA,MAAAA,EAAAA,GAAAA,CAAAA,EAAAA,MAAAA,EAwBKS,MAxBLT,CAAAA,EAAAA,OAAAA;;;AAEtD;AAWA;EACYS,OAAAA,qBAAM,CAAA,MAAA,EAeuBA,MAfvB,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA;IAAA,KAAA,EAAA,MAAA;IAAkBD,eAAAA,EAAAA,OAAAA;;;EAKtBG,eAAAA,gBAAa;EAAA,eAAA,eAAA;iBAKGD,OAAAA;iBAA6BD,cAAAA;;UAe1CG,IAAAA;EAAAA,KAAAA,EAAI,GAAA;EAAA,GAAA,EAAA,MAAA;WAILC,EAAAA,MAAAA,EAAAA;YACAA,EADAA,IACAA;cAAAA;AAEhB;AAGiBE,UAHAD,UAAAA,SAAmBF,IAGR,CAAA;EAQXI,KAAAA,CAAAA,EAAAA,MAAS;AAI1B;AAA4B,UAZXD,WAAAA,CAYW;MAChBA,EAAAA,MAAAA;OACFC,CAAAA,EAAAA,GAAAA;;EAEWE,MAAAA,CAAAA,EAAAA,MAAU,EAAA;EAAA,iBAAA,CAAA,EAAA,MAAA;qBAKPrB,CAAAA,EAAAA,MAAAA,CAAAA,CAAAA;;AAC+BoB,UAdtCD,SAAAA,CAcsCC;YAAsBC,CAAAA,EAAAA,MAAAA;eAARC,CAAAA,EAAAA,OAAAA;;AAGpDF,UAbAA,WAAAA,CAaAA;OAAsBC,CAAAA,EAZ3BH,WAY2BG;KAARC,CAAAA,EAXrBH,SAWqBG;;AAIfP,cAbKM,UAAAA,CAaLN;mBAARO,MAAAA;mBAIAA,WAAAA;mBACsCA,SAAAA;mBAE7BV,UAAAA;aAMDK,CAAAA,MAAAA,EArBQjB,eAqBRiB,EAAAA,MAAAA,CAAAA,EArBkCG,WAqBlCH;SAARK,cAAAA,CAAAA,UAAAA,EAAAA,MAAAA,EAAAA,MAAAA,CAAAA,EApB+CF,WAoB/CE,CAAAA,EApB6DA,OAoB7DA,CApBqED,UAoBrEC,CAAAA;SAOAA,WAAAA,CAAAA,SAAAA,EA1B0BC,KA0B1BD,CAAAA;IACOnB,GAAAA,EAAAA,MAAAA;MAAcmB,MAAAA,CAAAA,EAzBZF,WAyBYE,CAAAA,EAzBEA,OAyBFA,CAzBUD,UAyBVC,CAAAA;OAChBA,CAAAA,CAAAA,EAzBAA,OAyBAA,CAAAA,IAAAA,CAAAA;KASOT,CAAAA,SAAAA,EAAAA,MAAAA,EAAAA,EAAAA,GAAAA,EAAAA,MAAAA,EAAAA,QAAAA,EAAAA;IAJCS,UAAAA,CAAAA,EAAAA,OAAAA;MA3BbA,QAAQP;;;;MAIRO;4CACsCA;;aAE7BV;;;;;;MAMTU,QAAQL;;;;;;;MAORK;aACOnB,cAAcmB;WAChBA;;;;;mBAKQA;;;;gBAIDT"}
1
+ {"version":3,"file":"store.d.cts","names":["createClient","createCluster","RedisClientConnection","ReturnType","RedisClusterConnection","RedisConnection","GetOperation","ListNamespacesOperation","Operation","PutOperation","SearchOperation","isPutOperation","isGetOperation","isSearchOperation","isListNamespacesOperation","FilterOperators","FilterValue","Filter","Record","FilterBuilder","Item","Date","SearchItem","IndexConfig","TTLConfig","StoreConfig","RedisStore","Promise","Array"],"sources":["../src/store.d.ts"],"sourcesContent":["import { createClient, createCluster } from \"redis\";\n/** A conventional Redis connection. */\nexport type RedisClientConnection = ReturnType<typeof createClient>;\n/** A clustered Redis connection. */\nexport type RedisClusterConnection = ReturnType<typeof createCluster>;\n/** A Redis connection, clustered or conventional. */\nexport type RedisConnection = RedisClientConnection | RedisClusterConnection;\nimport { type GetOperation, type ListNamespacesOperation, type Operation, type PutOperation, type SearchOperation } from \"@langchain/langgraph-checkpoint\";\nexport declare function isPutOperation(op: Operation): op is PutOperation;\nexport declare function isGetOperation(op: Operation): op is GetOperation;\nexport declare function isSearchOperation(op: Operation): op is SearchOperation;\nexport declare function isListNamespacesOperation(op: Operation): op is ListNamespacesOperation;\nexport interface FilterOperators {\n $eq?: any;\n $ne?: any;\n $gt?: number;\n $gte?: number;\n $lt?: number;\n $lte?: number;\n $in?: any[];\n $nin?: any[];\n $exists?: boolean;\n}\nexport type FilterValue = any | FilterOperators;\nexport type Filter = Record<string, FilterValue>;\n/**\n * Internal class for evaluating filters against documents.\n * Supports MongoDB-style query operators.\n */\ndeclare class FilterBuilder {\n /**\n * Evaluates if a document matches the given filter criteria.\n * Supports advanced operators like $gt, $lt, $in, etc.\n */\n static matchesFilter(doc: Record<string, any>, filter: Filter): boolean;\n /**\n * Builds a Redis Search query string from filter criteria.\n * Note: This is limited by RediSearch capabilities and may not support all operators.\n */\n static buildRedisSearchQuery(filter: Filter, prefix?: string): {\n query: string;\n useClientFilter: boolean;\n };\n private static matchesFieldFilter;\n private static matchesOperators;\n private static matchesOperator;\n private static isEqual;\n private static getNestedValue;\n}\nexport interface Item {\n value: any;\n key: string;\n namespace: string[];\n created_at: Date;\n updated_at: Date;\n}\nexport interface SearchItem extends Item {\n score?: number;\n}\nexport interface IndexConfig {\n dims: number;\n embed?: any;\n distanceType?: \"cosine\" | \"l2\" | \"ip\";\n fields?: string[];\n vectorStorageType?: string;\n similarityThreshold?: number;\n}\nexport interface TTLConfig {\n defaultTTL?: number;\n refreshOnRead?: boolean;\n}\nexport interface StoreConfig {\n index?: IndexConfig;\n ttl?: TTLConfig;\n}\nexport declare class RedisStore {\n private readonly client;\n private readonly indexConfig?;\n private readonly ttlConfig?;\n private readonly embeddings?;\n constructor(client: RedisConnection, config?: StoreConfig);\n static fromConnString(connString: string, config?: StoreConfig): Promise<RedisStore>;\n static fromCluster(rootNodes: Array<{\n url: string;\n }>, config?: StoreConfig): Promise<RedisStore>;\n setup(): Promise<void>;\n get(namespace: string[], key: string, options?: {\n refreshTTL?: boolean;\n }): Promise<Item | null>;\n put(namespace: string[], key: string, value: any, options?: {\n ttl?: number;\n index?: boolean | string[];\n }): Promise<void>;\n delete(namespace: string[], key: string): Promise<void>;\n search(namespacePrefix: string[], options?: {\n filter?: Filter;\n query?: string;\n limit?: number;\n offset?: number;\n refreshTTL?: boolean;\n similarityThreshold?: number;\n }): Promise<SearchItem[]>;\n listNamespaces(options?: {\n prefix?: string[];\n suffix?: string[];\n maxDepth?: number;\n limit?: number;\n offset?: number;\n }): Promise<string[][]>;\n batch(ops: Operation[]): Promise<any[]>;\n close(): Promise<void>;\n /**\n * Get statistics about the store.\n * Returns document counts and other metrics.\n */\n getStatistics(): Promise<{\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }>;\n private validateNamespace;\n private refreshItemTTL;\n private escapeTagValue;\n /**\n * Calculate similarity score based on the distance metric.\n * Converts raw distance to a normalized similarity score [0,1].\n */\n private calculateSimilarityScore;\n}\nexport { FilterBuilder };\n//# sourceMappingURL=store.d.ts.map"],"mappings":"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"}
package/dist/store.d.ts CHANGED
@@ -8,12 +8,10 @@ type RedisClientConnection = ReturnType<typeof createClient>;
8
8
  type RedisClusterConnection = ReturnType<typeof createCluster>;
9
9
  /** A Redis connection, clustered or conventional. */
10
10
  type RedisConnection = RedisClientConnection | RedisClusterConnection;
11
- // Type guard functions for operations
12
11
  declare function isPutOperation(op: Operation): op is PutOperation;
13
12
  declare function isGetOperation(op: Operation): op is GetOperation;
14
13
  declare function isSearchOperation(op: Operation): op is SearchOperation;
15
14
  declare function isListNamespacesOperation(op: Operation): op is ListNamespacesOperation;
16
- // Filter types for advanced search operations
17
15
  interface FilterOperators {
18
16
  $eq?: any;
19
17
  $ne?: any;
@@ -64,10 +62,10 @@ interface SearchItem extends Item {
64
62
  interface IndexConfig {
65
63
  dims: number;
66
64
  embed?: any;
67
- distanceType?: "cosine" | "l2" | "ip"; // cosine, L2 (Euclidean), inner product
65
+ distanceType?: "cosine" | "l2" | "ip";
68
66
  fields?: string[];
69
67
  vectorStorageType?: string;
70
- similarityThreshold?: number; // Minimum similarity score for results
68
+ similarityThreshold?: number;
71
69
  }
72
70
  interface TTLConfig {
73
71
  defaultTTL?: number;
@@ -132,7 +130,6 @@ declare class RedisStore {
132
130
  */
133
131
  private calculateSimilarityScore;
134
132
  }
135
- // Export FilterBuilder for testing purposes
136
133
  //#endregion
137
134
  export { Filter, FilterBuilder, FilterOperators, FilterValue, IndexConfig, Item, RedisClientConnection, RedisClusterConnection, RedisConnection, RedisStore, SearchItem, StoreConfig, TTLConfig, isGetOperation, isListNamespacesOperation, isPutOperation, isSearchOperation };
138
135
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","names":["createClient","createCluster","RedisClientConnection","ReturnType","RedisClusterConnection","RedisConnection","GetOperation","ListNamespacesOperation","Operation","PutOperation","SearchOperation","isPutOperation","isGetOperation","isSearchOperation","isListNamespacesOperation","FilterOperators","FilterValue","Filter","Record","FilterBuilder","Item","Date","SearchItem","IndexConfig","TTLConfig","StoreConfig","RedisStore","Promise","Array"],"sources":["../src/store.d.ts"],"sourcesContent":["import { createClient, createCluster } from \"redis\";\n/** A conventional Redis connection. */\nexport type RedisClientConnection = ReturnType<typeof createClient>;\n/** A clustered Redis connection. */\nexport type RedisClusterConnection = ReturnType<typeof createCluster>;\n/** A Redis connection, clustered or conventional. */\nexport type RedisConnection = RedisClientConnection | RedisClusterConnection;\nimport { type GetOperation, type ListNamespacesOperation, type Operation, type PutOperation, type SearchOperation } from \"@langchain/langgraph-checkpoint\";\n// Type guard functions for operations\nexport declare function isPutOperation(op: Operation): op is PutOperation;\nexport declare function isGetOperation(op: Operation): op is GetOperation;\nexport declare function isSearchOperation(op: Operation): op is SearchOperation;\nexport declare function isListNamespacesOperation(op: Operation): op is ListNamespacesOperation;\n// Filter types for advanced search operations\nexport interface FilterOperators {\n $eq?: any;\n $ne?: any;\n $gt?: number;\n $gte?: number;\n $lt?: number;\n $lte?: number;\n $in?: any[];\n $nin?: any[];\n $exists?: boolean;\n}\nexport type FilterValue = any | FilterOperators;\nexport type Filter = Record<string, FilterValue>;\n/**\n * Internal class for evaluating filters against documents.\n * Supports MongoDB-style query operators.\n */\ndeclare class FilterBuilder {\n /**\n * Evaluates if a document matches the given filter criteria.\n * Supports advanced operators like $gt, $lt, $in, etc.\n */\n static matchesFilter(doc: Record<string, any>, filter: Filter): boolean;\n /**\n * Builds a Redis Search query string from filter criteria.\n * Note: This is limited by RediSearch capabilities and may not support all operators.\n */\n static buildRedisSearchQuery(filter: Filter, prefix?: string): {\n query: string;\n useClientFilter: boolean;\n };\n private static matchesFieldFilter;\n private static matchesOperators;\n private static matchesOperator;\n private static isEqual;\n private static getNestedValue;\n}\nexport interface Item {\n value: any;\n key: string;\n namespace: string[];\n created_at: Date;\n updated_at: Date;\n}\nexport interface SearchItem extends Item {\n score?: number;\n}\nexport interface IndexConfig {\n dims: number;\n embed?: any;\n distanceType?: \"cosine\" | \"l2\" | \"ip\"; // cosine, L2 (Euclidean), inner product\n fields?: string[];\n vectorStorageType?: string;\n similarityThreshold?: number; // Minimum similarity score for results\n}\nexport interface TTLConfig {\n defaultTTL?: number;\n refreshOnRead?: boolean;\n}\nexport interface StoreConfig {\n index?: IndexConfig;\n ttl?: TTLConfig;\n}\nexport declare class RedisStore {\n private readonly client;\n private readonly indexConfig?;\n private readonly ttlConfig?;\n private readonly embeddings?;\n constructor(client: RedisConnection, config?: StoreConfig);\n static fromConnString(connString: string, config?: StoreConfig): Promise<RedisStore>;\n static fromCluster(rootNodes: Array<{\n url: string;\n }>, config?: StoreConfig): Promise<RedisStore>;\n setup(): Promise<void>;\n get(namespace: string[], key: string, options?: {\n refreshTTL?: boolean;\n }): Promise<Item | null>;\n put(namespace: string[], key: string, value: any, options?: {\n ttl?: number;\n index?: boolean | string[];\n }): Promise<void>;\n delete(namespace: string[], key: string): Promise<void>;\n search(namespacePrefix: string[], options?: {\n filter?: Filter;\n query?: string;\n limit?: number;\n offset?: number;\n refreshTTL?: boolean;\n similarityThreshold?: number;\n }): Promise<SearchItem[]>;\n listNamespaces(options?: {\n prefix?: string[];\n suffix?: string[];\n maxDepth?: number;\n limit?: number;\n offset?: number;\n }): Promise<string[][]>;\n batch(ops: Operation[]): Promise<any[]>;\n close(): Promise<void>;\n /**\n * Get statistics about the store.\n * Returns document counts and other metrics.\n */\n getStatistics(): Promise<{\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }>;\n private validateNamespace;\n private refreshItemTTL;\n private escapeTagValue;\n /**\n * Calculate similarity score based on the distance metric.\n * Converts raw distance to a normalized similarity score [0,1].\n */\n private calculateSimilarityScore;\n}\n// Export FilterBuilder for testing purposes\nexport { FilterBuilder };\n//# sourceMappingURL=store.d.ts.map"],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","names":["createClient","createCluster","RedisClientConnection","ReturnType","RedisClusterConnection","RedisConnection","GetOperation","ListNamespacesOperation","Operation","PutOperation","SearchOperation","isPutOperation","isGetOperation","isSearchOperation","isListNamespacesOperation","FilterOperators","FilterValue","Filter","Record","FilterBuilder","Item","Date","SearchItem","IndexConfig","TTLConfig","StoreConfig","RedisStore","Promise","Array"],"sources":["../src/store.d.ts"],"sourcesContent":["import { createClient, createCluster } from \"redis\";\n/** A conventional Redis connection. */\nexport type RedisClientConnection = ReturnType<typeof createClient>;\n/** A clustered Redis connection. */\nexport type RedisClusterConnection = ReturnType<typeof createCluster>;\n/** A Redis connection, clustered or conventional. */\nexport type RedisConnection = RedisClientConnection | RedisClusterConnection;\nimport { type GetOperation, type ListNamespacesOperation, type Operation, type PutOperation, type SearchOperation } from \"@langchain/langgraph-checkpoint\";\nexport declare function isPutOperation(op: Operation): op is PutOperation;\nexport declare function isGetOperation(op: Operation): op is GetOperation;\nexport declare function isSearchOperation(op: Operation): op is SearchOperation;\nexport declare function isListNamespacesOperation(op: Operation): op is ListNamespacesOperation;\nexport interface FilterOperators {\n $eq?: any;\n $ne?: any;\n $gt?: number;\n $gte?: number;\n $lt?: number;\n $lte?: number;\n $in?: any[];\n $nin?: any[];\n $exists?: boolean;\n}\nexport type FilterValue = any | FilterOperators;\nexport type Filter = Record<string, FilterValue>;\n/**\n * Internal class for evaluating filters against documents.\n * Supports MongoDB-style query operators.\n */\ndeclare class FilterBuilder {\n /**\n * Evaluates if a document matches the given filter criteria.\n * Supports advanced operators like $gt, $lt, $in, etc.\n */\n static matchesFilter(doc: Record<string, any>, filter: Filter): boolean;\n /**\n * Builds a Redis Search query string from filter criteria.\n * Note: This is limited by RediSearch capabilities and may not support all operators.\n */\n static buildRedisSearchQuery(filter: Filter, prefix?: string): {\n query: string;\n useClientFilter: boolean;\n };\n private static matchesFieldFilter;\n private static matchesOperators;\n private static matchesOperator;\n private static isEqual;\n private static getNestedValue;\n}\nexport interface Item {\n value: any;\n key: string;\n namespace: string[];\n created_at: Date;\n updated_at: Date;\n}\nexport interface SearchItem extends Item {\n score?: number;\n}\nexport interface IndexConfig {\n dims: number;\n embed?: any;\n distanceType?: \"cosine\" | \"l2\" | \"ip\";\n fields?: string[];\n vectorStorageType?: string;\n similarityThreshold?: number;\n}\nexport interface TTLConfig {\n defaultTTL?: number;\n refreshOnRead?: boolean;\n}\nexport interface StoreConfig {\n index?: IndexConfig;\n ttl?: TTLConfig;\n}\nexport declare class RedisStore {\n private readonly client;\n private readonly indexConfig?;\n private readonly ttlConfig?;\n private readonly embeddings?;\n constructor(client: RedisConnection, config?: StoreConfig);\n static fromConnString(connString: string, config?: StoreConfig): Promise<RedisStore>;\n static fromCluster(rootNodes: Array<{\n url: string;\n }>, config?: StoreConfig): Promise<RedisStore>;\n setup(): Promise<void>;\n get(namespace: string[], key: string, options?: {\n refreshTTL?: boolean;\n }): Promise<Item | null>;\n put(namespace: string[], key: string, value: any, options?: {\n ttl?: number;\n index?: boolean | string[];\n }): Promise<void>;\n delete(namespace: string[], key: string): Promise<void>;\n search(namespacePrefix: string[], options?: {\n filter?: Filter;\n query?: string;\n limit?: number;\n offset?: number;\n refreshTTL?: boolean;\n similarityThreshold?: number;\n }): Promise<SearchItem[]>;\n listNamespaces(options?: {\n prefix?: string[];\n suffix?: string[];\n maxDepth?: number;\n limit?: number;\n offset?: number;\n }): Promise<string[][]>;\n batch(ops: Operation[]): Promise<any[]>;\n close(): Promise<void>;\n /**\n * Get statistics about the store.\n * Returns document counts and other metrics.\n */\n getStatistics(): Promise<{\n totalDocuments: number;\n namespaceCount: number;\n vectorDocuments?: number;\n indexInfo?: Record<string, any>;\n }>;\n private validateNamespace;\n private refreshItemTTL;\n private escapeTagValue;\n /**\n * Calculate similarity score based on the distance metric.\n * Converts raw distance to a normalized similarity score [0,1].\n */\n private calculateSimilarityScore;\n}\nexport { FilterBuilder };\n//# sourceMappingURL=store.d.ts.map"],"mappings":";;;;;KAEYE,qBAAAA,GAAwBC,kBAAkBH;;AAA1CE,KAEAE,sBAAAA,GAAyBD,UAFJ,CAAA,OAEsBF,aAFtB,CAAA;;AAAqBD,KAI1CK,eAAAA,GAAkBH,qBAJwBF,GAIAI,sBAJAJ;AAAR,iBAMtBW,cAAAA,CANsB,EAAA,EAMHH,SANG,CAAA,EAAA,EAAA,IAMeC,YANf;AAElCL,iBAKYQ,cAAAA,CALU,EAAA,EAKSJ,SALT,CAAA,EAAA,EAAA,IAK2BF,YAL3B;AAAA,iBAMVO,iBAAAA,CANU,EAAA,EAMYL,SANZ,CAAA,EAAA,EAAA,IAM8BE,eAN9B;AAAqBT,iBAO/Ba,yBAAAA,CAP+Bb,EAAAA,EAODO,SAPCP,CAAAA,EAAAA,EAAAA,IAOiBM,uBAPjBN;AAAlBE,UAQpBY,eAAAA,CARoBZ;EAAU,GAAA,CAAA,EAAA,GAAA;EAEnCE,GAAAA,CAAAA,EAAAA,GAAAA;EAAe,GAAA,CAAA,EAAA,MAAA;MAAGH,CAAAA,EAAAA,MAAAA;KAAwBE,CAAAA,EAAAA,MAAAA;EAAsB,IAAA,CAAA,EAAA,MAAA;EAEpDO,GAAAA,CAAAA,EAAAA,GAAAA,EAAAA;EAAc,IAAA,CAAA,EAAA,GAAA,EAAA;SAAKH,CAAAA,EAAAA,OAAAA;;AAA8B,KAe7DQ,WAAAA,GAf6D,GAAA,GAezCD,eAfyC;AACjDH,KAeZK,MAAAA,GAASC,MAfiB,CAAA,MAAA,EAeFF,WAfE,CAAA;;;;;AACtC,cAmBcG,aAAAA,CAnB2B;EAAA;;;;EACjBL,OAAAA,aAAAA,CAAAA,GAAAA,EAuBMI,MAvBmB,CAAA,MAAA,EAAA,GAAA,CAAA,EAAA,MAAA,EAuBUD,MAvBV,CAAA,EAAA,OAAA;EAAA;;;;EAChCF,OAAAA,qBAAe,CAAA,MAAA,EA2BSE,MA3BT,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA;IAWpBD,KAAAA,EAAAA,MAAW;IACXC,eAAM,EAAA,OAAA;EAAA,CAAA;iBAAkBD,kBAAAA;iBAAfE,gBAAAA;EAAM,eAAA,eAAA;EAKbC,eAAAA,OAAa;EAAA,eAAA,cAAA;;AAKgCF,UAe1CG,IAAAA,CAf0CH;OAKlBA,EAAAA,GAAAA;EAAM,GAAA,EAAA,MAAA;EAU9BG,SAAI,EAAA,MAAA,EAAA;EAAA,UAAA,EAILC,IAJK;YAILA,EACAA,IADAA;;AACI,UAEHC,UAAAA,SAAmBF,IAFhB,CAAA;EAEHE,KAAAA,CAAAA,EAAAA,MAAU;AAG3B;AAQiBE,UARAD,WAAAA,CAQS;EAITE,IAAAA,EAAAA,MAAAA;EAAW,KAAA,CAAA,EAAA,GAAA;cAChBF,CAAAA,EAAAA,QAAAA,GAAAA,IAAAA,GAAAA,IAAAA;QACFC,CAAAA,EAAAA,MAAAA,EAAAA;EAAS,iBAAA,CAAA,EAAA,MAAA;EAEEE,mBAAU,CAAA,EAAA,MAAA;;AAKPrB,UAbPmB,SAAAA,CAaOnB;YAA0BoB,CAAAA,EAAAA,MAAAA;eACKA,CAAAA,EAAAA,OAAAA;;AAAcE,UAVpDF,WAAAA,CAUoDE;OACnCC,CAAAA,EAVtBL,WAUsBK;KAEjBH,CAAAA,EAXPD,SAWOC;;AAAcE,cATVD,UAAAA,CASUC;mBAClBA,MAAAA;mBAGGP,WAAAA;mBAARO,SAAAA;mBAIAA,UAAAA;aACsCA,CAAAA,MAAAA,EAbtBtB,eAasBsB,EAAAA,MAAAA,CAAAA,EAbIF,WAaJE;SAE7BV,cAAAA,CAAAA,UAAAA,EAAAA,MAAAA,EAAAA,MAAAA,CAAAA,EAdsCQ,WActCR,CAAAA,EAdoDU,OAcpDV,CAd4DS,UAc5DT,CAAAA;SAMDK,WAAAA,CAAAA,SAAAA,EAnBkBM,KAmBlBN,CAAAA;IAARK,GAAAA,EAAAA,MAAAA;MAOAA,MAAAA,CAAAA,EAxBSF,WAwBTE,CAAAA,EAxBuBA,OAwBvBA,CAxB+BD,UAwB/BC,CAAAA;OACOnB,CAAAA,CAAAA,EAxBFmB,OAwBEnB,CAAAA,IAAAA,CAAAA;KAAcmB,CAAAA,SAAAA,EAAAA,MAAAA,EAAAA,EAAAA,GAAAA,EAAAA,MAAAA,EAAAA,QAAAA,EAAAA;IAChBA,UAAAA,CAAAA,EAAAA,OAAAA;MAtBLA,OA+BYT,CA/BJE,IA+BIF,GAAAA,IAAAA,CAAAA;KAJCS,CAAAA,SAAAA,EAAAA,MAAAA,EAAAA,EAAAA,GAAAA,EAAAA,MAAAA,EAAAA,KAAAA,EAAAA,GAAAA,EAAAA,QAAAA,EAAAA;IAAO,GAAA,CAAA,EAAA,MAAA;;MAvBpBA;4CACsCA;;aAE7BV;;;;;;MAMTU,QAAQL;;;;;;;MAORK;aACOnB,cAAcmB;WAChBA;;;;;mBAKQA;;;;gBAIDT"}