@warlock.js/cache 4.0.171 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +85 -0
  2. package/cjs/index.cjs +4088 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/cache-manager.d.mts +314 -0
  5. package/esm/cache-manager.d.mts.map +1 -0
  6. package/esm/cache-manager.mjs +486 -0
  7. package/esm/cache-manager.mjs.map +1 -0
  8. package/esm/cached/auto-key.d.mts +25 -0
  9. package/esm/cached/auto-key.d.mts.map +1 -0
  10. package/esm/cached/auto-key.mjs +55 -0
  11. package/esm/cached/auto-key.mjs.map +1 -0
  12. package/esm/cached/cached.d.mts +54 -0
  13. package/esm/cached/cached.d.mts.map +1 -0
  14. package/esm/cached/cached.mjs +25 -0
  15. package/esm/cached/cached.mjs.map +1 -0
  16. package/esm/cached/index.d.mts +3 -0
  17. package/esm/cached/index.mjs +5 -0
  18. package/esm/cached/normalize-args.d.mts +51 -0
  19. package/esm/cached/normalize-args.d.mts.map +1 -0
  20. package/esm/cached/normalize-args.mjs +26 -0
  21. package/esm/cached/normalize-args.mjs.map +1 -0
  22. package/esm/drivers/base-cache-driver.d.mts +322 -0
  23. package/esm/drivers/base-cache-driver.d.mts.map +1 -0
  24. package/esm/drivers/base-cache-driver.mjs +522 -0
  25. package/esm/drivers/base-cache-driver.mjs.map +1 -0
  26. package/esm/drivers/file-cache-driver.d.mts +68 -0
  27. package/esm/drivers/file-cache-driver.d.mts.map +1 -0
  28. package/esm/drivers/file-cache-driver.mjs +174 -0
  29. package/esm/drivers/file-cache-driver.mjs.map +1 -0
  30. package/esm/drivers/index.d.mts +9 -0
  31. package/esm/drivers/index.mjs +11 -0
  32. package/esm/drivers/lru-memory-cache-driver.d.mts +136 -0
  33. package/esm/drivers/lru-memory-cache-driver.d.mts.map +1 -0
  34. package/esm/drivers/lru-memory-cache-driver.mjs +317 -0
  35. package/esm/drivers/lru-memory-cache-driver.mjs.map +1 -0
  36. package/esm/drivers/memory-cache-driver.d.mts +112 -0
  37. package/esm/drivers/memory-cache-driver.d.mts.map +1 -0
  38. package/esm/drivers/memory-cache-driver.mjs +241 -0
  39. package/esm/drivers/memory-cache-driver.mjs.map +1 -0
  40. package/esm/drivers/memory-extended-cache-driver.d.mts +17 -0
  41. package/esm/drivers/memory-extended-cache-driver.d.mts.map +1 -0
  42. package/esm/drivers/memory-extended-cache-driver.mjs +34 -0
  43. package/esm/drivers/memory-extended-cache-driver.mjs.map +1 -0
  44. package/esm/drivers/mock-cache-driver.d.mts +137 -0
  45. package/esm/drivers/mock-cache-driver.d.mts.map +1 -0
  46. package/esm/drivers/mock-cache-driver.mjs +226 -0
  47. package/esm/drivers/mock-cache-driver.mjs.map +1 -0
  48. package/esm/drivers/null-cache-driver.d.mts +69 -0
  49. package/esm/drivers/null-cache-driver.d.mts.map +1 -0
  50. package/esm/drivers/null-cache-driver.mjs +92 -0
  51. package/esm/drivers/null-cache-driver.mjs.map +1 -0
  52. package/esm/drivers/pg-cache-driver.d.mts +148 -0
  53. package/esm/drivers/pg-cache-driver.d.mts.map +1 -0
  54. package/esm/drivers/pg-cache-driver.mjs +437 -0
  55. package/esm/drivers/pg-cache-driver.mjs.map +1 -0
  56. package/esm/drivers/redis-cache-driver.d.mts +86 -0
  57. package/esm/drivers/redis-cache-driver.d.mts.map +1 -0
  58. package/esm/drivers/redis-cache-driver.mjs +312 -0
  59. package/esm/drivers/redis-cache-driver.mjs.map +1 -0
  60. package/esm/index.d.mts +21 -0
  61. package/esm/index.mjs +24 -0
  62. package/esm/list/index.d.mts +1 -0
  63. package/esm/list/memory-cache-list.d.mts +77 -0
  64. package/esm/list/memory-cache-list.d.mts.map +1 -0
  65. package/esm/list/memory-cache-list.mjs +119 -0
  66. package/esm/list/memory-cache-list.mjs.map +1 -0
  67. package/esm/metrics.d.mts +118 -0
  68. package/esm/metrics.d.mts.map +1 -0
  69. package/esm/metrics.mjs +197 -0
  70. package/esm/metrics.mjs.map +1 -0
  71. package/esm/scoped-cache.d.mts +205 -0
  72. package/esm/scoped-cache.d.mts.map +1 -0
  73. package/esm/scoped-cache.mjs +274 -0
  74. package/esm/scoped-cache.mjs.map +1 -0
  75. package/esm/tagged-cache.d.mts +89 -0
  76. package/esm/tagged-cache.d.mts.map +1 -0
  77. package/esm/tagged-cache.mjs +147 -0
  78. package/esm/tagged-cache.mjs.map +1 -0
  79. package/esm/tagged-scoped-cache.d.mts +111 -0
  80. package/esm/tagged-scoped-cache.d.mts.map +1 -0
  81. package/esm/tagged-scoped-cache.mjs +142 -0
  82. package/esm/tagged-scoped-cache.mjs.map +1 -0
  83. package/esm/types.d.mts +1067 -0
  84. package/esm/types.d.mts.map +1 -0
  85. package/esm/types.mjs +62 -0
  86. package/esm/types.mjs.map +1 -0
  87. package/esm/utils.d.mts +161 -0
  88. package/esm/utils.d.mts.map +1 -0
  89. package/esm/utils.mjs +222 -0
  90. package/esm/utils.mjs.map +1 -0
  91. package/llms-full.txt +2071 -0
  92. package/llms.txt +28 -0
  93. package/package.json +53 -39
  94. package/skills/apply-cache-patterns/SKILL.md +97 -0
  95. package/skills/cache-basics/SKILL.md +121 -0
  96. package/skills/configure-pg-cache/SKILL.md +115 -0
  97. package/skills/configure-set-options/SKILL.md +96 -0
  98. package/skills/handle-cache-errors/SKILL.md +91 -0
  99. package/skills/observe-cache/SKILL.md +103 -0
  100. package/skills/overview/SKILL.md +69 -0
  101. package/skills/pick-cache-driver/SKILL.md +115 -0
  102. package/skills/test-cache-code/SKILL.md +219 -0
  103. package/skills/use-cache-atomic/SKILL.md +67 -0
  104. package/skills/use-cache-bulk/SKILL.md +57 -0
  105. package/skills/use-cache-list/SKILL.md +85 -0
  106. package/skills/use-cache-lock/SKILL.md +104 -0
  107. package/skills/use-cache-namespace/SKILL.md +88 -0
  108. package/skills/use-cache-similarity/SKILL.md +94 -0
  109. package/skills/use-cache-tags/SKILL.md +85 -0
  110. package/skills/use-cache-update-merge/SKILL.md +84 -0
  111. package/skills/use-cache-utils/SKILL.md +89 -0
  112. package/skills/use-cached-hof/SKILL.md +102 -0
  113. package/skills/use-swr/SKILL.md +104 -0
  114. package/cjs/cache-manager.d.ts +0 -163
  115. package/cjs/cache-manager.d.ts.map +0 -1
  116. package/cjs/cache-manager.js +0 -322
  117. package/cjs/cache-manager.js.map +0 -1
  118. package/cjs/drivers/base-cache-driver.d.ts +0 -152
  119. package/cjs/drivers/base-cache-driver.d.ts.map +0 -1
  120. package/cjs/drivers/base-cache-driver.js +0 -321
  121. package/cjs/drivers/base-cache-driver.js.map +0 -1
  122. package/cjs/drivers/file-cache-driver.d.ts +0 -45
  123. package/cjs/drivers/file-cache-driver.d.ts.map +0 -1
  124. package/cjs/drivers/file-cache-driver.js +0 -133
  125. package/cjs/drivers/file-cache-driver.js.map +0 -1
  126. package/cjs/drivers/index.d.ts +0 -8
  127. package/cjs/drivers/index.d.ts.map +0 -1
  128. package/cjs/drivers/lru-memory-cache-driver.d.ts +0 -98
  129. package/cjs/drivers/lru-memory-cache-driver.d.ts.map +0 -1
  130. package/cjs/drivers/lru-memory-cache-driver.js +0 -252
  131. package/cjs/drivers/lru-memory-cache-driver.js.map +0 -1
  132. package/cjs/drivers/memory-cache-driver.d.ts +0 -82
  133. package/cjs/drivers/memory-cache-driver.d.ts.map +0 -1
  134. package/cjs/drivers/memory-cache-driver.js +0 -218
  135. package/cjs/drivers/memory-cache-driver.js.map +0 -1
  136. package/cjs/drivers/memory-extended-cache-driver.d.ts +0 -13
  137. package/cjs/drivers/memory-extended-cache-driver.d.ts.map +0 -1
  138. package/cjs/drivers/memory-extended-cache-driver.js +0 -25
  139. package/cjs/drivers/memory-extended-cache-driver.js.map +0 -1
  140. package/cjs/drivers/null-cache-driver.d.ts +0 -58
  141. package/cjs/drivers/null-cache-driver.d.ts.map +0 -1
  142. package/cjs/drivers/null-cache-driver.js +0 -84
  143. package/cjs/drivers/null-cache-driver.js.map +0 -1
  144. package/cjs/drivers/redis-cache-driver.d.ts +0 -57
  145. package/cjs/drivers/redis-cache-driver.d.ts.map +0 -1
  146. package/cjs/drivers/redis-cache-driver.js +0 -263
  147. package/cjs/drivers/redis-cache-driver.js.map +0 -1
  148. package/cjs/index.d.ts +0 -6
  149. package/cjs/index.d.ts.map +0 -1
  150. package/cjs/index.js +0 -1
  151. package/cjs/index.js.map +0 -1
  152. package/cjs/tagged-cache.d.ts +0 -77
  153. package/cjs/tagged-cache.d.ts.map +0 -1
  154. package/cjs/tagged-cache.js +0 -160
  155. package/cjs/tagged-cache.js.map +0 -1
  156. package/cjs/types.d.ts +0 -391
  157. package/cjs/types.d.ts.map +0 -1
  158. package/cjs/types.js +0 -36
  159. package/cjs/types.js.map +0 -1
  160. package/cjs/utils.d.ts +0 -50
  161. package/cjs/utils.d.ts.map +0 -1
  162. package/cjs/utils.js +0 -55
  163. package/cjs/utils.js.map +0 -1
  164. package/esm/cache-manager.d.ts +0 -163
  165. package/esm/cache-manager.d.ts.map +0 -1
  166. package/esm/cache-manager.js +0 -322
  167. package/esm/cache-manager.js.map +0 -1
  168. package/esm/drivers/base-cache-driver.d.ts +0 -152
  169. package/esm/drivers/base-cache-driver.d.ts.map +0 -1
  170. package/esm/drivers/base-cache-driver.js +0 -321
  171. package/esm/drivers/base-cache-driver.js.map +0 -1
  172. package/esm/drivers/file-cache-driver.d.ts +0 -45
  173. package/esm/drivers/file-cache-driver.d.ts.map +0 -1
  174. package/esm/drivers/file-cache-driver.js +0 -133
  175. package/esm/drivers/file-cache-driver.js.map +0 -1
  176. package/esm/drivers/index.d.ts +0 -8
  177. package/esm/drivers/index.d.ts.map +0 -1
  178. package/esm/drivers/lru-memory-cache-driver.d.ts +0 -98
  179. package/esm/drivers/lru-memory-cache-driver.d.ts.map +0 -1
  180. package/esm/drivers/lru-memory-cache-driver.js +0 -252
  181. package/esm/drivers/lru-memory-cache-driver.js.map +0 -1
  182. package/esm/drivers/memory-cache-driver.d.ts +0 -82
  183. package/esm/drivers/memory-cache-driver.d.ts.map +0 -1
  184. package/esm/drivers/memory-cache-driver.js +0 -218
  185. package/esm/drivers/memory-cache-driver.js.map +0 -1
  186. package/esm/drivers/memory-extended-cache-driver.d.ts +0 -13
  187. package/esm/drivers/memory-extended-cache-driver.d.ts.map +0 -1
  188. package/esm/drivers/memory-extended-cache-driver.js +0 -25
  189. package/esm/drivers/memory-extended-cache-driver.js.map +0 -1
  190. package/esm/drivers/null-cache-driver.d.ts +0 -58
  191. package/esm/drivers/null-cache-driver.d.ts.map +0 -1
  192. package/esm/drivers/null-cache-driver.js +0 -84
  193. package/esm/drivers/null-cache-driver.js.map +0 -1
  194. package/esm/drivers/redis-cache-driver.d.ts +0 -57
  195. package/esm/drivers/redis-cache-driver.d.ts.map +0 -1
  196. package/esm/drivers/redis-cache-driver.js +0 -263
  197. package/esm/drivers/redis-cache-driver.js.map +0 -1
  198. package/esm/index.d.ts +0 -6
  199. package/esm/index.d.ts.map +0 -1
  200. package/esm/index.js +0 -1
  201. package/esm/index.js.map +0 -1
  202. package/esm/tagged-cache.d.ts +0 -77
  203. package/esm/tagged-cache.d.ts.map +0 -1
  204. package/esm/tagged-cache.js +0 -160
  205. package/esm/tagged-cache.js.map +0 -1
  206. package/esm/types.d.ts +0 -391
  207. package/esm/types.d.ts.map +0 -1
  208. package/esm/types.js +0 -36
  209. package/esm/types.js.map +0 -1
  210. package/esm/utils.d.ts +0 -50
  211. package/esm/utils.d.ts.map +0 -1
  212. package/esm/utils.js +0 -55
  213. package/esm/utils.js.map +0 -1
@@ -0,0 +1,174 @@
1
+ import { CacheConfigurationError, CacheUnsupportedError } from "../types.mjs";
2
+ import { BaseCacheDriver } from "./base-cache-driver.mjs";
3
+ import { ensureDirectoryAsync, getJsonFileAsync, putJsonFileAsync, removeDirectoryAsync } from "@warlock.js/fs";
4
+ import path from "path";
5
+
6
+ //#region ../../@warlock.js/cache/src/drivers/file-cache-driver.ts
7
+ var FileCacheDriver = class extends BaseCacheDriver {
8
+ constructor(..._args) {
9
+ super(..._args);
10
+ this.name = "file";
11
+ }
12
+ /**
13
+ * {@inheritdoc}
14
+ */
15
+ setOptions(options) {
16
+ if (!options.directory) throw new CacheConfigurationError("File driver requires 'directory' option to be configured.");
17
+ return super.setOptions(options);
18
+ }
19
+ /**
20
+ * Get the cache directory
21
+ */
22
+ get directory() {
23
+ const directory = this.options.directory;
24
+ if (typeof directory === "function") return directory();
25
+ throw new CacheConfigurationError("Cache directory is not defined, please define it in the file driver options");
26
+ }
27
+ /**
28
+ * Get file name
29
+ */
30
+ get fileName() {
31
+ const fileName = this.options.fileName;
32
+ if (typeof fileName === "function") return fileName();
33
+ return "cache.json";
34
+ }
35
+ /**
36
+ * {@inheritdoc}
37
+ */
38
+ async removeNamespace(namespace) {
39
+ this.log("clearing", namespace);
40
+ try {
41
+ await removeDirectoryAsync(path.resolve(this.directory, namespace));
42
+ this.log("cleared", namespace);
43
+ } catch (error) {}
44
+ return this;
45
+ }
46
+ /**
47
+ * {@inheritdoc}
48
+ */
49
+ async set(key, value, ttlOrOptions) {
50
+ const parsedKey = this.parseKey(key);
51
+ const { ttl, tags, onConflict, vector, staleAt } = this.resolveSetOptions(ttlOrOptions);
52
+ if (vector) throw new CacheUnsupportedError("'file' driver does not support similarity retrieval — use a memory driver, 'pg' (with pgvector), or 'redis' (with RediSearch).");
53
+ this.log("caching", parsedKey);
54
+ const existing = onConflict === "upsert" ? null : await this.get(key);
55
+ const exists = existing !== null;
56
+ if (onConflict === "create" && exists) return {
57
+ wasSet: false,
58
+ existing
59
+ };
60
+ if (onConflict === "update" && !exists) return {
61
+ wasSet: false,
62
+ existing: null
63
+ };
64
+ const data = this.prepareDataForStorage(value, ttl, staleAt);
65
+ const fileDirectory = path.resolve(this.directory, parsedKey);
66
+ await ensureDirectoryAsync(fileDirectory);
67
+ await putJsonFileAsync(path.resolve(fileDirectory, this.fileName), data);
68
+ if (tags && tags.length > 0) await this.applyTags(parsedKey, tags);
69
+ this.log("cached", parsedKey);
70
+ await this.emit("set", {
71
+ key: parsedKey,
72
+ value,
73
+ ttl
74
+ });
75
+ if (onConflict === "create" || onConflict === "update") return {
76
+ wasSet: true,
77
+ existing: null
78
+ };
79
+ return this;
80
+ }
81
+ /**
82
+ * {@inheritdoc}
83
+ *
84
+ * File driver does not yet ship with a file-lock primitive, so concurrent
85
+ * writers could clobber each other. Rather than ship an unsafe default, we
86
+ * throw — consumers can fall back to memory/redis for `update` until a
87
+ * proper file lock lands (tracked in `domains/cache/backlog.md`).
88
+ */
89
+ async update() {
90
+ throw new CacheUnsupportedError("`update()` is not supported on the file driver. Use the memory or redis driver, or wait for the file-lock primitive (see domains/cache/backlog.md).");
91
+ }
92
+ /**
93
+ * {@inheritdoc}
94
+ */
95
+ async merge() {
96
+ throw new CacheUnsupportedError("`merge()` is not supported on the file driver. Use the memory or redis driver.");
97
+ }
98
+ /**
99
+ * Read the raw {@link CacheData} wrapper from disk, including `staleAt`
100
+ * metadata. Returns `null` for missing or expired files — `swr()`
101
+ * consumes this to branch on freshness.
102
+ */
103
+ async getEntry(key) {
104
+ const parsedKey = this.parseKey(key);
105
+ const fileDirectory = path.resolve(this.directory, parsedKey);
106
+ try {
107
+ const entry = await getJsonFileAsync(path.resolve(fileDirectory, this.fileName));
108
+ if (!entry) return null;
109
+ if (entry.expiresAt !== void 0 && entry.expiresAt <= Date.now()) return null;
110
+ return entry;
111
+ } catch {
112
+ return null;
113
+ }
114
+ }
115
+ /**
116
+ * {@inheritdoc}
117
+ */
118
+ async get(key) {
119
+ const parsedKey = this.parseKey(key);
120
+ this.log("fetching", parsedKey);
121
+ const fileDirectory = path.resolve(this.directory, parsedKey);
122
+ try {
123
+ const value = await getJsonFileAsync(path.resolve(fileDirectory, this.fileName));
124
+ const result = await this.parseCachedData(parsedKey, value);
125
+ if (result === null) await this.emit("miss", { key: parsedKey });
126
+ else await this.emit("hit", {
127
+ key: parsedKey,
128
+ value: result
129
+ });
130
+ return result;
131
+ } catch (error) {
132
+ this.log("notFound", parsedKey);
133
+ await this.emit("miss", { key: parsedKey });
134
+ await this.remove(key);
135
+ return null;
136
+ }
137
+ }
138
+ /**
139
+ * {@inheritdoc}
140
+ */
141
+ async remove(key) {
142
+ const parsedKey = this.parseKey(key);
143
+ this.log("removing", parsedKey);
144
+ const fileDirectory = path.resolve(this.directory, parsedKey);
145
+ try {
146
+ await removeDirectoryAsync(fileDirectory);
147
+ this.log("removed", parsedKey);
148
+ await this.emit("removed", { key: parsedKey });
149
+ } catch (error) {}
150
+ }
151
+ /**
152
+ * {@inheritdoc}
153
+ */
154
+ async flush() {
155
+ this.log("flushing");
156
+ if (this.options.globalPrefix) await this.removeNamespace("");
157
+ else await removeDirectoryAsync(this.directory);
158
+ this.log("flushed");
159
+ await this.emit("flushed");
160
+ }
161
+ /**
162
+ * {@inheritdoc}
163
+ */
164
+ async connect() {
165
+ this.log("connecting");
166
+ await ensureDirectoryAsync(this.directory);
167
+ this.log("connected");
168
+ await this.emit("connected");
169
+ }
170
+ };
171
+
172
+ //#endregion
173
+ export { FileCacheDriver };
174
+ //# sourceMappingURL=file-cache-driver.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-cache-driver.mjs","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/file-cache-driver.ts"],"sourcesContent":["import {\r\n ensureDirectoryAsync,\r\n getJsonFileAsync,\r\n putJsonFileAsync,\r\n removeDirectoryAsync,\r\n} from \"@warlock.js/fs\";\r\nimport path from \"path\";\r\nimport type {\r\n CacheData,\r\n CacheDriver,\r\n CacheKey,\r\n CacheSetOptions,\r\n CacheSetResult,\r\n CacheTtl,\r\n FileCacheOptions,\r\n} from \"../types\";\r\nimport { CacheConfigurationError, CacheUnsupportedError } from \"../types\";\r\nimport { BaseCacheDriver } from \"./base-cache-driver\";\r\n\r\nexport class FileCacheDriver\r\n extends BaseCacheDriver<FileCacheDriver, FileCacheOptions>\r\n implements CacheDriver<FileCacheDriver, FileCacheOptions>\r\n{\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public name = \"file\";\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public setOptions(options: FileCacheOptions) {\r\n if (!options.directory) {\r\n throw new CacheConfigurationError(\r\n \"File driver requires 'directory' option to be configured.\",\r\n );\r\n }\r\n\r\n return super.setOptions(options);\r\n }\r\n\r\n /**\r\n * Get the cache directory\r\n */\r\n public get directory() {\r\n const directory = this.options.directory;\r\n\r\n if (typeof directory === \"function\") {\r\n return directory();\r\n }\r\n\r\n throw new CacheConfigurationError(\r\n \"Cache directory is not defined, please define it in the file driver options\",\r\n );\r\n }\r\n\r\n /**\r\n * Get file name\r\n */\r\n public get fileName() {\r\n const fileName = this.options.fileName;\r\n\r\n if (typeof fileName === \"function\") {\r\n return fileName();\r\n }\r\n\r\n return \"cache.json\";\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async removeNamespace(namespace: string) {\r\n this.log(\"clearing\", namespace);\r\n\r\n try {\r\n await removeDirectoryAsync(path.resolve(this.directory, namespace));\r\n\r\n this.log(\"cleared\", namespace);\r\n } catch (error) {\r\n //\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async set(\r\n key: CacheKey,\r\n value: any,\r\n ttlOrOptions?: CacheTtl | CacheSetOptions,\r\n ): Promise<any> {\r\n const parsedKey = this.parseKey(key);\r\n const { ttl, tags, onConflict, vector, staleAt } = this.resolveSetOptions(ttlOrOptions);\r\n\r\n if (vector) {\r\n throw new CacheUnsupportedError(\r\n \"'file' driver does not support similarity retrieval — use a memory driver, 'pg' (with pgvector), or 'redis' (with RediSearch).\",\r\n );\r\n }\r\n\r\n this.log(\"caching\", parsedKey);\r\n\r\n const existing = onConflict === \"upsert\" ? null : await this.get(key);\r\n const exists = existing !== null;\r\n\r\n if (onConflict === \"create\" && exists) {\r\n const result: CacheSetResult = { wasSet: false, existing };\r\n return result;\r\n }\r\n\r\n if (onConflict === \"update\" && !exists) {\r\n const result: CacheSetResult = { wasSet: false, existing: null };\r\n return result;\r\n }\r\n\r\n const data = this.prepareDataForStorage(value, ttl, staleAt);\r\n\r\n const fileDirectory = path.resolve(this.directory, parsedKey);\r\n\r\n await ensureDirectoryAsync(fileDirectory);\r\n\r\n await putJsonFileAsync(path.resolve(fileDirectory, this.fileName), data);\r\n\r\n if (tags && tags.length > 0) {\r\n await this.applyTags(parsedKey, tags);\r\n }\r\n\r\n this.log(\"cached\", parsedKey);\r\n\r\n await this.emit(\"set\", { key: parsedKey, value, ttl });\r\n\r\n if (onConflict === \"create\" || onConflict === \"update\") {\r\n const result: CacheSetResult = { wasSet: true, existing: null };\r\n return result;\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n *\r\n * File driver does not yet ship with a file-lock primitive, so concurrent\r\n * writers could clobber each other. Rather than ship an unsafe default, we\r\n * throw — consumers can fall back to memory/redis for `update` until a\r\n * proper file lock lands (tracked in `domains/cache/backlog.md`).\r\n */\r\n public async update(): Promise<never> {\r\n throw new CacheUnsupportedError(\r\n \"`update()` is not supported on the file driver. Use the memory or redis driver, or wait for the file-lock primitive (see domains/cache/backlog.md).\",\r\n );\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async merge(): Promise<never> {\r\n throw new CacheUnsupportedError(\r\n \"`merge()` is not supported on the file driver. Use the memory or redis driver.\",\r\n );\r\n }\r\n\r\n /**\r\n * Read the raw {@link CacheData} wrapper from disk, including `staleAt`\r\n * metadata. Returns `null` for missing or expired files — `swr()`\r\n * consumes this to branch on freshness.\r\n */\r\n protected async getEntry(key: CacheKey): Promise<CacheData | null> {\r\n const parsedKey = this.parseKey(key);\r\n const fileDirectory = path.resolve(this.directory, parsedKey);\r\n\r\n try {\r\n const entry = (await getJsonFileAsync(path.resolve(fileDirectory, this.fileName))) as\r\n | CacheData\r\n | undefined;\r\n\r\n if (!entry) {\r\n return null;\r\n }\r\n\r\n if (entry.expiresAt !== undefined && entry.expiresAt <= Date.now()) {\r\n return null;\r\n }\r\n\r\n return entry;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async get(key: CacheKey) {\r\n const parsedKey = this.parseKey(key);\r\n\r\n this.log(\"fetching\", parsedKey);\r\n\r\n const fileDirectory = path.resolve(this.directory, parsedKey);\r\n\r\n try {\r\n const value = await getJsonFileAsync(path.resolve(fileDirectory, this.fileName));\r\n\r\n const result = await this.parseCachedData(parsedKey, value as CacheData);\r\n\r\n if (result === null) {\r\n // Expired\r\n await this.emit(\"miss\", { key: parsedKey });\r\n } else {\r\n // Emit hit event\r\n await this.emit(\"hit\", { key: parsedKey, value: result });\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n this.log(\"notFound\", parsedKey);\r\n // Emit miss event\r\n await this.emit(\"miss\", { key: parsedKey });\r\n // Await the cleanup so it fully settles before returning. Leaving this\r\n // fire-and-forget let the async directory removal race a follow-up write\r\n // to the same key (e.g. the existence probe inside a `set({ onConflict })`\r\n // call), surfacing as an ENOENT mkdir/rm collision on Windows.\r\n await this.remove(key);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async remove(key: CacheKey) {\r\n const parsedKey = this.parseKey(key);\r\n this.log(\"removing\", parsedKey);\r\n\r\n const fileDirectory = path.resolve(this.directory, parsedKey);\r\n\r\n try {\r\n await removeDirectoryAsync(fileDirectory);\r\n\r\n this.log(\"removed\", parsedKey);\r\n // Emit removed event\r\n await this.emit(\"removed\", { key: parsedKey });\r\n } catch (error) {\r\n //\r\n }\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async flush() {\r\n this.log(\"flushing\");\r\n\r\n if (this.options.globalPrefix) {\r\n await this.removeNamespace(\"\");\r\n } else {\r\n await removeDirectoryAsync(this.directory);\r\n }\r\n\r\n this.log(\"flushed\");\r\n\r\n // Emit flushed event\r\n await this.emit(\"flushed\");\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async connect() {\r\n this.log(\"connecting\");\r\n await ensureDirectoryAsync(this.directory);\r\n this.log(\"connected\");\r\n await this.emit(\"connected\");\r\n }\r\n}\r\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { BaseCacheDriver, NormalizedSetOptions } from "./base-cache-driver.mjs";
2
+ import { FileCacheDriver } from "./file-cache-driver.mjs";
3
+ import { LRUMemoryCacheDriver } from "./lru-memory-cache-driver.mjs";
4
+ import { MemoryCacheDriver } from "./memory-cache-driver.mjs";
5
+ import { MemoryExtendedCacheDriver } from "./memory-extended-cache-driver.mjs";
6
+ import { MockCacheDriver } from "./mock-cache-driver.mjs";
7
+ import { NullCacheDriver } from "./null-cache-driver.mjs";
8
+ import { PgCacheDriver } from "./pg-cache-driver.mjs";
9
+ import { RedisCacheDriver } from "./redis-cache-driver.mjs";
@@ -0,0 +1,11 @@
1
+ import { BaseCacheDriver } from "./base-cache-driver.mjs";
2
+ import { FileCacheDriver } from "./file-cache-driver.mjs";
3
+ import { LRUMemoryCacheDriver } from "./lru-memory-cache-driver.mjs";
4
+ import { MemoryCacheDriver } from "./memory-cache-driver.mjs";
5
+ import { MemoryExtendedCacheDriver } from "./memory-extended-cache-driver.mjs";
6
+ import { MockCacheDriver } from "./mock-cache-driver.mjs";
7
+ import { NullCacheDriver } from "./null-cache-driver.mjs";
8
+ import { PgCacheDriver } from "./pg-cache-driver.mjs";
9
+ import { RedisCacheDriver } from "./redis-cache-driver.mjs";
10
+
11
+ export { };
@@ -0,0 +1,136 @@
1
+ import { BaseCacheDriver } from "./base-cache-driver.mjs";
2
+ import { CacheData, CacheDriver, CacheKey, CacheSetOptions, CacheSimilarHit, CacheSimilarOptions, CacheTtl, LRUMemoryCacheOptions } from "../types.mjs";
3
+
4
+ //#region ../../@warlock.js/cache/src/drivers/lru-memory-cache-driver.d.ts
5
+ declare class CacheNode {
6
+ key: string;
7
+ value: any;
8
+ next: CacheNode | null;
9
+ prev: CacheNode | null;
10
+ expiresAt?: number;
11
+ /**
12
+ * Freshness deadline (ms timestamp) — populated by `swr()`. Within
13
+ * `expiresAt > now > staleAt` the entry is "stale-but-revalidatable."
14
+ */
15
+ staleAt?: number;
16
+ /**
17
+ * Optional embedding vector — populated when the entry was written with
18
+ * `set({ vector })`. Scanned by `similar()`.
19
+ */
20
+ vector?: number[];
21
+ constructor(key: string, value: any, ttl?: number);
22
+ get isExpired(): boolean;
23
+ }
24
+ /**
25
+ * LRU Memory Cache Driver
26
+ * The concept of LRU is to remove the least recently used data
27
+ * whenever the cache is full
28
+ * The question that resides here is how to tell the cache is full?
29
+ */
30
+ declare class LRUMemoryCacheDriver extends BaseCacheDriver<LRUMemoryCacheDriver, LRUMemoryCacheOptions> implements CacheDriver<LRUMemoryCacheDriver, LRUMemoryCacheOptions> {
31
+ /**
32
+ * {@inheritdoc}
33
+ */
34
+ name: string;
35
+ /**
36
+ * Cache map
37
+ */
38
+ protected cache: Map<string, CacheNode>;
39
+ /**
40
+ * Head of the cache
41
+ */
42
+ protected head: CacheNode;
43
+ /**
44
+ * Tail of the cache
45
+ */
46
+ protected tail: CacheNode;
47
+ /**
48
+ * Cleanup interval reference
49
+ */
50
+ protected cleanupInterval?: NodeJS.Timeout;
51
+ /**
52
+ * {@inheritdoc}
53
+ */
54
+ constructor();
55
+ /**
56
+ * Initialize the cache
57
+ */
58
+ init(): void;
59
+ /**
60
+ * Start the cleanup process for expired items
61
+ */
62
+ startCleanup(): void;
63
+ /**
64
+ * {@inheritdoc}
65
+ *
66
+ * Clears every entry whose key starts with the parsed namespace (followed
67
+ * by a dot) or equals it exactly. Called with an empty namespace while a
68
+ * `globalPrefix` is configured, clears everything under the prefix — which
69
+ * is how `flush()` scopes cleanup per tenant.
70
+ */
71
+ removeNamespace(namespace: string): Promise<string[]>;
72
+ /**
73
+ * {@inheritdoc}
74
+ */
75
+ set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions): Promise<any>;
76
+ /**
77
+ * Move the node to the head
78
+ */
79
+ protected moveHead(node: CacheNode): void;
80
+ /**
81
+ * Remove the node from the cache
82
+ */
83
+ protected removeNode(node: CacheNode): void;
84
+ /**
85
+ * Add the node to the head
86
+ */
87
+ protected addNode(node: CacheNode): void;
88
+ /**
89
+ * Remove the tail node
90
+ */
91
+ protected removeTail(): void;
92
+ /**
93
+ * Read the raw {@link CacheData} wrapper, including `staleAt` metadata.
94
+ * Returns `null` for missing or expired nodes — `swr()` consumes this
95
+ * to branch on freshness without going through `get()`'s clone-and-emit
96
+ * path.
97
+ */
98
+ protected getEntry(key: CacheKey): Promise<CacheData | null>;
99
+ /**
100
+ * {@inheritdoc}
101
+ */
102
+ get(key: CacheKey): Promise<any>;
103
+ /**
104
+ * {@inheritdoc}
105
+ */
106
+ remove(key: CacheKey): Promise<void>;
107
+ /**
108
+ * {@inheritdoc}
109
+ *
110
+ * When a `globalPrefix` is configured, `flush` scopes itself to that prefix
111
+ * so multi-tenant caches don't accidentally wipe sibling tenants. Without
112
+ * a prefix, clears everything.
113
+ */
114
+ flush(): Promise<void>;
115
+ /**
116
+ * {@inheritdoc}
117
+ *
118
+ * Brute-force O(N) cosine similarity over every cached node that carries a
119
+ * vector. Suitable for development and small in-memory knowledge bases —
120
+ * not for production beyond ~10k entries.
121
+ *
122
+ * @warning Dev-only — O(N) per query.
123
+ */
124
+ similar<T = any>(vector: number[], options: CacheSimilarOptions): Promise<CacheSimilarHit<T>[]>;
125
+ /**
126
+ * Get lru capacity
127
+ */
128
+ get capacity(): number;
129
+ /**
130
+ * {@inheritdoc}
131
+ */
132
+ disconnect(): Promise<void>;
133
+ }
134
+ //#endregion
135
+ export { LRUMemoryCacheDriver };
136
+ //# sourceMappingURL=lru-memory-cache-driver.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru-memory-cache-driver.d.mts","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/lru-memory-cache-driver.ts"],"mappings":";;;;cAcM,SAAA;EAeK,GAAA;EACA,KAAA;EAfF,IAAA,EAAM,SAAA;EACN,IAAA,EAAM,SAAS;EACf,SAAA;EAYE;;;;EAPF,OAAA;EANM;;;;EAWN,MAAA;cAEE,GAAA,UACA,KAAA,OACP,GAAA;EAAA,IAOS,SAAA,CAAA;AAAA;;;AAAS;AAWtB;;;cAAa,oBAAA,SACH,eAAA,CAAgB,oBAAA,EAAsB,qBAAA,aACnC,WAAA,CAAY,oBAAA,EAAsB,qBAAA;EADC;;;EAMvC,IAAA;EAKU;;;EAAA,UAAP,KAAA,EAAO,GAAA,SAAY,SAAA;EA8EiB;;;EAAA,UAzEpC,IAAA,EAAM,SAAA;EAmHb;;;EAAA,UA9GO,IAAA,EAAM,SAAA;EAoOc;;;EAAA,UA/NpB,eAAA,GAAkB,MAAA,CAAO,OAAA;EAiPL;;;;EA6GnB;;;EA/UJ,IAAA,CAAA;EA+XgB;;;EAvXhB,YAAA,CAAA;EAhDe;;;;;;;;EAwFT,eAAA,CAAgB,SAAA,WAAiB,OAAA;EA9E7B;;;EAoHJ,GAAA,CACX,GAAA,EAAK,QAAA,EACL,KAAA,OACA,YAAA,GAAe,QAAA,GAAW,eAAA,GACzB,OAAA;EA9GO;;;EAAA,UA4LA,QAAA,CAAS,IAAA,EAAM,SAAA;EAvLU;;;EAAA,UA+LzB,UAAA,CAAW,IAAA,EAAM,SAAA;EAhId;;;EAAA,UAwIH,OAAA,CAAQ,IAAA,EAAM,SAAA;EAjGjB;;;EAAA,UA2GG,UAAA,CAAA;EAzGkB;;;;;;EAAA,UAuHZ,QAAA,CAAS,GAAA,EAAK,QAAA,GAAW,OAAA,CAAQ,SAAA;EAhCtB;;;EAkDd,GAAA,CAAI,GAAA,EAAK,QAAA,GAAQ,OAAA;EA1CZ;;;EAoGL,MAAA,CAAO,GAAA,EAAK,QAAA,GAAQ,OAAA;EA5ER;;;;;;;EAqGZ,KAAA,CAAA,GAAK,OAAA;EAzBO;;;;;;;;;EAiDZ,OAAA,SAAA,CACX,MAAA,YACA,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,eAAA,CAAgB,CAAA;EAAxB;;;EAAA,IAwCQ,QAAA,CAAA;EAOE;;;EAAA,UAAA,CAAA,GAAU,OAAA;AAAA"}
@@ -0,0 +1,317 @@
1
+ import { cosineSimilarity } from "../utils.mjs";
2
+ import { BaseCacheDriver } from "./base-cache-driver.mjs";
3
+
4
+ //#region ../../@warlock.js/cache/src/drivers/lru-memory-cache-driver.ts
5
+ var CacheNode = class {
6
+ constructor(key, value, ttl) {
7
+ this.key = key;
8
+ this.value = value;
9
+ this.next = null;
10
+ this.prev = null;
11
+ if (ttl && ttl !== Infinity) this.expiresAt = Date.now() + ttl * 1e3;
12
+ }
13
+ get isExpired() {
14
+ return this.expiresAt !== void 0 && this.expiresAt < Date.now();
15
+ }
16
+ };
17
+ /**
18
+ * LRU Memory Cache Driver
19
+ * The concept of LRU is to remove the least recently used data
20
+ * whenever the cache is full
21
+ * The question that resides here is how to tell the cache is full?
22
+ */
23
+ var LRUMemoryCacheDriver = class extends BaseCacheDriver {
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ constructor() {
28
+ super();
29
+ this.name = "lru";
30
+ this.cache = /* @__PURE__ */ new Map();
31
+ this.head = new CacheNode("", null);
32
+ this.tail = new CacheNode("", null);
33
+ this.init();
34
+ this.startCleanup();
35
+ }
36
+ /**
37
+ * Initialize the cache
38
+ */
39
+ init() {
40
+ this.head.next = this.tail;
41
+ this.tail.prev = this.head;
42
+ }
43
+ /**
44
+ * Start the cleanup process for expired items
45
+ */
46
+ startCleanup() {
47
+ if (this.cleanupInterval) clearInterval(this.cleanupInterval);
48
+ this.cleanupInterval = setInterval(async () => {
49
+ const now = Date.now();
50
+ const expiredKeys = [];
51
+ for (const [key, node] of this.cache) if (node.expiresAt && node.expiresAt <= now) expiredKeys.push(key);
52
+ for (const key of expiredKeys) {
53
+ const node = this.cache.get(key);
54
+ if (node) {
55
+ this.removeNode(node);
56
+ this.cache.delete(key);
57
+ this.log("expired", key);
58
+ await this.emit("expired", { key });
59
+ }
60
+ }
61
+ }, 1e3);
62
+ this.cleanupInterval.unref();
63
+ }
64
+ /**
65
+ * {@inheritdoc}
66
+ *
67
+ * Clears every entry whose key starts with the parsed namespace (followed
68
+ * by a dot) or equals it exactly. Called with an empty namespace while a
69
+ * `globalPrefix` is configured, clears everything under the prefix — which
70
+ * is how `flush()` scopes cleanup per tenant.
71
+ */
72
+ async removeNamespace(namespace) {
73
+ const parsedNamespace = this.parseKey(namespace);
74
+ this.log("clearing", parsedNamespace || "(all)");
75
+ const removed = [];
76
+ if (parsedNamespace === "") for (const key of this.cache.keys()) removed.push(key);
77
+ else {
78
+ const prefix = parsedNamespace + ".";
79
+ for (const key of this.cache.keys()) if (key === parsedNamespace || key.startsWith(prefix)) removed.push(key);
80
+ }
81
+ for (const key of removed) {
82
+ const node = this.cache.get(key);
83
+ if (node) {
84
+ this.removeNode(node);
85
+ this.cache.delete(key);
86
+ }
87
+ await this.emit("removed", { key });
88
+ }
89
+ this.log("cleared", parsedNamespace || "(all)");
90
+ return removed;
91
+ }
92
+ /**
93
+ * {@inheritdoc}
94
+ */
95
+ async set(key, value, ttlOrOptions) {
96
+ const parsedKey = this.parseKey(key);
97
+ const { ttl, tags, onConflict, vector, staleAt } = this.resolveSetOptions(ttlOrOptions);
98
+ this.log("caching", parsedKey);
99
+ let existingNode = this.cache.get(parsedKey);
100
+ if (existingNode && existingNode.isExpired) {
101
+ this.removeNode(existingNode);
102
+ this.cache.delete(parsedKey);
103
+ existingNode = void 0;
104
+ }
105
+ const exists = Boolean(existingNode);
106
+ if (onConflict === "create" && exists) return {
107
+ wasSet: false,
108
+ existing: existingNode.value
109
+ };
110
+ if (onConflict === "update" && !exists) return {
111
+ wasSet: false,
112
+ existing: null
113
+ };
114
+ if (existingNode) {
115
+ existingNode.value = value;
116
+ if (ttl && ttl !== Infinity) existingNode.expiresAt = Date.now() + ttl * 1e3;
117
+ else existingNode.expiresAt = void 0;
118
+ existingNode.staleAt = staleAt;
119
+ if (vector) existingNode.vector = vector.slice();
120
+ this.moveHead(existingNode);
121
+ } else {
122
+ const newNode = new CacheNode(parsedKey, value, ttl);
123
+ newNode.staleAt = staleAt;
124
+ if (vector) newNode.vector = vector.slice();
125
+ this.cache.set(parsedKey, newNode);
126
+ this.addNode(newNode);
127
+ if (this.cache.size > this.capacity) this.removeTail();
128
+ }
129
+ if (tags && tags.length > 0) await this.applyTags(parsedKey, tags);
130
+ this.log("cached", parsedKey);
131
+ await this.emit("set", {
132
+ key: parsedKey,
133
+ value,
134
+ ttl
135
+ });
136
+ if (onConflict === "create" || onConflict === "update") return {
137
+ wasSet: true,
138
+ existing: null
139
+ };
140
+ return this;
141
+ }
142
+ /**
143
+ * Move the node to the head
144
+ */
145
+ moveHead(node) {
146
+ this.removeNode(node);
147
+ this.addNode(node);
148
+ }
149
+ /**
150
+ * Remove the node from the cache
151
+ */
152
+ removeNode(node) {
153
+ node.prev.next = node.next;
154
+ node.next.prev = node.prev;
155
+ }
156
+ /**
157
+ * Add the node to the head
158
+ */
159
+ addNode(node) {
160
+ node.next = this.head.next;
161
+ node.prev = this.head;
162
+ this.head.next.prev = node;
163
+ this.head.next = node;
164
+ }
165
+ /**
166
+ * Remove the tail node
167
+ */
168
+ removeTail() {
169
+ const node = this.tail.prev;
170
+ this.removeNode(node);
171
+ this.cache.delete(node.key);
172
+ }
173
+ /**
174
+ * Read the raw {@link CacheData} wrapper, including `staleAt` metadata.
175
+ * Returns `null` for missing or expired nodes — `swr()` consumes this
176
+ * to branch on freshness without going through `get()`'s clone-and-emit
177
+ * path.
178
+ */
179
+ async getEntry(key) {
180
+ const parsedKey = this.parseKey(key);
181
+ const node = this.cache.get(parsedKey);
182
+ if (!node || node.isExpired) return null;
183
+ return {
184
+ data: node.value,
185
+ expiresAt: node.expiresAt,
186
+ staleAt: node.staleAt
187
+ };
188
+ }
189
+ /**
190
+ * {@inheritdoc}
191
+ */
192
+ async get(key) {
193
+ const parsedKey = this.parseKey(key);
194
+ this.log("fetching", parsedKey);
195
+ const node = this.cache.get(parsedKey);
196
+ if (!node) {
197
+ this.log("notFound", parsedKey);
198
+ await this.emit("miss", { key: parsedKey });
199
+ return null;
200
+ }
201
+ if (node.isExpired) {
202
+ this.removeNode(node);
203
+ this.cache.delete(parsedKey);
204
+ this.log("expired", parsedKey);
205
+ await this.emit("expired", { key: parsedKey });
206
+ await this.emit("miss", { key: parsedKey });
207
+ return null;
208
+ }
209
+ this.moveHead(node);
210
+ this.log("fetched", parsedKey);
211
+ const value = node.value;
212
+ if (value === null || value === void 0) return value;
213
+ const type = typeof value;
214
+ if (type === "string" || type === "number" || type === "boolean") {
215
+ await this.emit("hit", {
216
+ key: parsedKey,
217
+ value
218
+ });
219
+ return value;
220
+ }
221
+ try {
222
+ const clonedValue = structuredClone(value);
223
+ await this.emit("hit", {
224
+ key: parsedKey,
225
+ value: clonedValue
226
+ });
227
+ return clonedValue;
228
+ } catch (error) {
229
+ this.logError(`Failed to clone cached value for ${parsedKey}`, error);
230
+ throw error;
231
+ }
232
+ }
233
+ /**
234
+ * {@inheritdoc}
235
+ */
236
+ async remove(key) {
237
+ const parsedKey = this.parseKey(key);
238
+ this.log("removing", parsedKey);
239
+ const node = this.cache.get(parsedKey);
240
+ if (node) {
241
+ this.removeNode(node);
242
+ this.cache.delete(parsedKey);
243
+ }
244
+ this.log("removed", parsedKey);
245
+ await this.emit("removed", { key: parsedKey });
246
+ }
247
+ /**
248
+ * {@inheritdoc}
249
+ *
250
+ * When a `globalPrefix` is configured, `flush` scopes itself to that prefix
251
+ * so multi-tenant caches don't accidentally wipe sibling tenants. Without
252
+ * a prefix, clears everything.
253
+ */
254
+ async flush() {
255
+ this.log("flushing");
256
+ if (this.options.globalPrefix) await this.removeNamespace("");
257
+ else {
258
+ this.cache.clear();
259
+ this.init();
260
+ }
261
+ this.log("flushed");
262
+ await this.emit("flushed");
263
+ }
264
+ /**
265
+ * {@inheritdoc}
266
+ *
267
+ * Brute-force O(N) cosine similarity over every cached node that carries a
268
+ * vector. Suitable for development and small in-memory knowledge bases —
269
+ * not for production beyond ~10k entries.
270
+ *
271
+ * @warning Dev-only — O(N) per query.
272
+ */
273
+ async similar(vector, options) {
274
+ const tagFilter = await this.getKeysForTags(options.tags);
275
+ const hits = [];
276
+ for (const [parsedKey, node] of this.cache) {
277
+ if (!node.vector) continue;
278
+ if (node.isExpired) continue;
279
+ if (tagFilter && !tagFilter.has(parsedKey)) continue;
280
+ const score = cosineSimilarity(vector, node.vector);
281
+ if (options.threshold !== void 0 && score < options.threshold) continue;
282
+ let value = node.value;
283
+ if (value !== null && value !== void 0) {
284
+ const t = typeof value;
285
+ if (t !== "string" && t !== "number" && t !== "boolean") value = structuredClone(value);
286
+ }
287
+ hits.push({
288
+ key: parsedKey,
289
+ value,
290
+ score
291
+ });
292
+ }
293
+ hits.sort((a, b) => b.score - a.score);
294
+ if (options.topK >= 0 && hits.length > options.topK) hits.length = options.topK;
295
+ return hits;
296
+ }
297
+ /**
298
+ * Get lru capacity
299
+ */
300
+ get capacity() {
301
+ return this.options.capacity || 1e3;
302
+ }
303
+ /**
304
+ * {@inheritdoc}
305
+ */
306
+ async disconnect() {
307
+ if (this.cleanupInterval) {
308
+ clearInterval(this.cleanupInterval);
309
+ this.cleanupInterval = void 0;
310
+ }
311
+ await super.disconnect();
312
+ }
313
+ };
314
+
315
+ //#endregion
316
+ export { LRUMemoryCacheDriver };
317
+ //# sourceMappingURL=lru-memory-cache-driver.mjs.map