@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.
- package/README.md +85 -0
- package/cjs/index.cjs +4088 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/cache-manager.d.mts +314 -0
- package/esm/cache-manager.d.mts.map +1 -0
- package/esm/cache-manager.mjs +486 -0
- package/esm/cache-manager.mjs.map +1 -0
- package/esm/cached/auto-key.d.mts +25 -0
- package/esm/cached/auto-key.d.mts.map +1 -0
- package/esm/cached/auto-key.mjs +55 -0
- package/esm/cached/auto-key.mjs.map +1 -0
- package/esm/cached/cached.d.mts +54 -0
- package/esm/cached/cached.d.mts.map +1 -0
- package/esm/cached/cached.mjs +25 -0
- package/esm/cached/cached.mjs.map +1 -0
- package/esm/cached/index.d.mts +3 -0
- package/esm/cached/index.mjs +5 -0
- package/esm/cached/normalize-args.d.mts +51 -0
- package/esm/cached/normalize-args.d.mts.map +1 -0
- package/esm/cached/normalize-args.mjs +26 -0
- package/esm/cached/normalize-args.mjs.map +1 -0
- package/esm/drivers/base-cache-driver.d.mts +322 -0
- package/esm/drivers/base-cache-driver.d.mts.map +1 -0
- package/esm/drivers/base-cache-driver.mjs +522 -0
- package/esm/drivers/base-cache-driver.mjs.map +1 -0
- package/esm/drivers/file-cache-driver.d.mts +68 -0
- package/esm/drivers/file-cache-driver.d.mts.map +1 -0
- package/esm/drivers/file-cache-driver.mjs +174 -0
- package/esm/drivers/file-cache-driver.mjs.map +1 -0
- package/esm/drivers/index.d.mts +9 -0
- package/esm/drivers/index.mjs +11 -0
- package/esm/drivers/lru-memory-cache-driver.d.mts +136 -0
- package/esm/drivers/lru-memory-cache-driver.d.mts.map +1 -0
- package/esm/drivers/lru-memory-cache-driver.mjs +317 -0
- package/esm/drivers/lru-memory-cache-driver.mjs.map +1 -0
- package/esm/drivers/memory-cache-driver.d.mts +112 -0
- package/esm/drivers/memory-cache-driver.d.mts.map +1 -0
- package/esm/drivers/memory-cache-driver.mjs +241 -0
- package/esm/drivers/memory-cache-driver.mjs.map +1 -0
- package/esm/drivers/memory-extended-cache-driver.d.mts +17 -0
- package/esm/drivers/memory-extended-cache-driver.d.mts.map +1 -0
- package/esm/drivers/memory-extended-cache-driver.mjs +34 -0
- package/esm/drivers/memory-extended-cache-driver.mjs.map +1 -0
- package/esm/drivers/mock-cache-driver.d.mts +137 -0
- package/esm/drivers/mock-cache-driver.d.mts.map +1 -0
- package/esm/drivers/mock-cache-driver.mjs +226 -0
- package/esm/drivers/mock-cache-driver.mjs.map +1 -0
- package/esm/drivers/null-cache-driver.d.mts +69 -0
- package/esm/drivers/null-cache-driver.d.mts.map +1 -0
- package/esm/drivers/null-cache-driver.mjs +92 -0
- package/esm/drivers/null-cache-driver.mjs.map +1 -0
- package/esm/drivers/pg-cache-driver.d.mts +148 -0
- package/esm/drivers/pg-cache-driver.d.mts.map +1 -0
- package/esm/drivers/pg-cache-driver.mjs +437 -0
- package/esm/drivers/pg-cache-driver.mjs.map +1 -0
- package/esm/drivers/redis-cache-driver.d.mts +86 -0
- package/esm/drivers/redis-cache-driver.d.mts.map +1 -0
- package/esm/drivers/redis-cache-driver.mjs +312 -0
- package/esm/drivers/redis-cache-driver.mjs.map +1 -0
- package/esm/index.d.mts +21 -0
- package/esm/index.mjs +24 -0
- package/esm/list/index.d.mts +1 -0
- package/esm/list/memory-cache-list.d.mts +77 -0
- package/esm/list/memory-cache-list.d.mts.map +1 -0
- package/esm/list/memory-cache-list.mjs +119 -0
- package/esm/list/memory-cache-list.mjs.map +1 -0
- package/esm/metrics.d.mts +118 -0
- package/esm/metrics.d.mts.map +1 -0
- package/esm/metrics.mjs +197 -0
- package/esm/metrics.mjs.map +1 -0
- package/esm/scoped-cache.d.mts +205 -0
- package/esm/scoped-cache.d.mts.map +1 -0
- package/esm/scoped-cache.mjs +274 -0
- package/esm/scoped-cache.mjs.map +1 -0
- package/esm/tagged-cache.d.mts +89 -0
- package/esm/tagged-cache.d.mts.map +1 -0
- package/esm/tagged-cache.mjs +147 -0
- package/esm/tagged-cache.mjs.map +1 -0
- package/esm/tagged-scoped-cache.d.mts +111 -0
- package/esm/tagged-scoped-cache.d.mts.map +1 -0
- package/esm/tagged-scoped-cache.mjs +142 -0
- package/esm/tagged-scoped-cache.mjs.map +1 -0
- package/esm/types.d.mts +1067 -0
- package/esm/types.d.mts.map +1 -0
- package/esm/types.mjs +62 -0
- package/esm/types.mjs.map +1 -0
- package/esm/utils.d.mts +161 -0
- package/esm/utils.d.mts.map +1 -0
- package/esm/utils.mjs +222 -0
- package/esm/utils.mjs.map +1 -0
- package/llms-full.txt +2071 -0
- package/llms.txt +28 -0
- package/package.json +53 -39
- package/skills/apply-cache-patterns/SKILL.md +97 -0
- package/skills/cache-basics/SKILL.md +121 -0
- package/skills/configure-pg-cache/SKILL.md +115 -0
- package/skills/configure-set-options/SKILL.md +96 -0
- package/skills/handle-cache-errors/SKILL.md +91 -0
- package/skills/observe-cache/SKILL.md +103 -0
- package/skills/overview/SKILL.md +69 -0
- package/skills/pick-cache-driver/SKILL.md +115 -0
- package/skills/test-cache-code/SKILL.md +219 -0
- package/skills/use-cache-atomic/SKILL.md +67 -0
- package/skills/use-cache-bulk/SKILL.md +57 -0
- package/skills/use-cache-list/SKILL.md +85 -0
- package/skills/use-cache-lock/SKILL.md +104 -0
- package/skills/use-cache-namespace/SKILL.md +88 -0
- package/skills/use-cache-similarity/SKILL.md +94 -0
- package/skills/use-cache-tags/SKILL.md +85 -0
- package/skills/use-cache-update-merge/SKILL.md +84 -0
- package/skills/use-cache-utils/SKILL.md +89 -0
- package/skills/use-cached-hof/SKILL.md +102 -0
- package/skills/use-swr/SKILL.md +104 -0
- package/cjs/cache-manager.d.ts +0 -163
- package/cjs/cache-manager.d.ts.map +0 -1
- package/cjs/cache-manager.js +0 -322
- package/cjs/cache-manager.js.map +0 -1
- package/cjs/drivers/base-cache-driver.d.ts +0 -152
- package/cjs/drivers/base-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/base-cache-driver.js +0 -321
- package/cjs/drivers/base-cache-driver.js.map +0 -1
- package/cjs/drivers/file-cache-driver.d.ts +0 -45
- package/cjs/drivers/file-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/file-cache-driver.js +0 -133
- package/cjs/drivers/file-cache-driver.js.map +0 -1
- package/cjs/drivers/index.d.ts +0 -8
- package/cjs/drivers/index.d.ts.map +0 -1
- package/cjs/drivers/lru-memory-cache-driver.d.ts +0 -98
- package/cjs/drivers/lru-memory-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/lru-memory-cache-driver.js +0 -252
- package/cjs/drivers/lru-memory-cache-driver.js.map +0 -1
- package/cjs/drivers/memory-cache-driver.d.ts +0 -82
- package/cjs/drivers/memory-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/memory-cache-driver.js +0 -218
- package/cjs/drivers/memory-cache-driver.js.map +0 -1
- package/cjs/drivers/memory-extended-cache-driver.d.ts +0 -13
- package/cjs/drivers/memory-extended-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/memory-extended-cache-driver.js +0 -25
- package/cjs/drivers/memory-extended-cache-driver.js.map +0 -1
- package/cjs/drivers/null-cache-driver.d.ts +0 -58
- package/cjs/drivers/null-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/null-cache-driver.js +0 -84
- package/cjs/drivers/null-cache-driver.js.map +0 -1
- package/cjs/drivers/redis-cache-driver.d.ts +0 -57
- package/cjs/drivers/redis-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/redis-cache-driver.js +0 -263
- package/cjs/drivers/redis-cache-driver.js.map +0 -1
- package/cjs/index.d.ts +0 -6
- package/cjs/index.d.ts.map +0 -1
- package/cjs/index.js +0 -1
- package/cjs/index.js.map +0 -1
- package/cjs/tagged-cache.d.ts +0 -77
- package/cjs/tagged-cache.d.ts.map +0 -1
- package/cjs/tagged-cache.js +0 -160
- package/cjs/tagged-cache.js.map +0 -1
- package/cjs/types.d.ts +0 -391
- package/cjs/types.d.ts.map +0 -1
- package/cjs/types.js +0 -36
- package/cjs/types.js.map +0 -1
- package/cjs/utils.d.ts +0 -50
- package/cjs/utils.d.ts.map +0 -1
- package/cjs/utils.js +0 -55
- package/cjs/utils.js.map +0 -1
- package/esm/cache-manager.d.ts +0 -163
- package/esm/cache-manager.d.ts.map +0 -1
- package/esm/cache-manager.js +0 -322
- package/esm/cache-manager.js.map +0 -1
- package/esm/drivers/base-cache-driver.d.ts +0 -152
- package/esm/drivers/base-cache-driver.d.ts.map +0 -1
- package/esm/drivers/base-cache-driver.js +0 -321
- package/esm/drivers/base-cache-driver.js.map +0 -1
- package/esm/drivers/file-cache-driver.d.ts +0 -45
- package/esm/drivers/file-cache-driver.d.ts.map +0 -1
- package/esm/drivers/file-cache-driver.js +0 -133
- package/esm/drivers/file-cache-driver.js.map +0 -1
- package/esm/drivers/index.d.ts +0 -8
- package/esm/drivers/index.d.ts.map +0 -1
- package/esm/drivers/lru-memory-cache-driver.d.ts +0 -98
- package/esm/drivers/lru-memory-cache-driver.d.ts.map +0 -1
- package/esm/drivers/lru-memory-cache-driver.js +0 -252
- package/esm/drivers/lru-memory-cache-driver.js.map +0 -1
- package/esm/drivers/memory-cache-driver.d.ts +0 -82
- package/esm/drivers/memory-cache-driver.d.ts.map +0 -1
- package/esm/drivers/memory-cache-driver.js +0 -218
- package/esm/drivers/memory-cache-driver.js.map +0 -1
- package/esm/drivers/memory-extended-cache-driver.d.ts +0 -13
- package/esm/drivers/memory-extended-cache-driver.d.ts.map +0 -1
- package/esm/drivers/memory-extended-cache-driver.js +0 -25
- package/esm/drivers/memory-extended-cache-driver.js.map +0 -1
- package/esm/drivers/null-cache-driver.d.ts +0 -58
- package/esm/drivers/null-cache-driver.d.ts.map +0 -1
- package/esm/drivers/null-cache-driver.js +0 -84
- package/esm/drivers/null-cache-driver.js.map +0 -1
- package/esm/drivers/redis-cache-driver.d.ts +0 -57
- package/esm/drivers/redis-cache-driver.d.ts.map +0 -1
- package/esm/drivers/redis-cache-driver.js +0 -263
- package/esm/drivers/redis-cache-driver.js.map +0 -1
- package/esm/index.d.ts +0 -6
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -1
- package/esm/index.js.map +0 -1
- package/esm/tagged-cache.d.ts +0 -77
- package/esm/tagged-cache.d.ts.map +0 -1
- package/esm/tagged-cache.js +0 -160
- package/esm/tagged-cache.js.map +0 -1
- package/esm/types.d.ts +0 -391
- package/esm/types.d.ts.map +0 -1
- package/esm/types.js +0 -36
- package/esm/types.js.map +0 -1
- package/esm/utils.d.ts +0 -50
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -55
- package/esm/utils.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lru-memory-cache-driver.mjs","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/lru-memory-cache-driver.ts"],"sourcesContent":["import type {\r\n CacheData,\r\n CacheDriver,\r\n CacheKey,\r\n CacheSetOptions,\r\n CacheSetResult,\r\n CacheSimilarHit,\r\n CacheSimilarOptions,\r\n CacheTtl,\r\n LRUMemoryCacheOptions,\r\n} from \"../types\";\r\nimport { cosineSimilarity } from \"../utils\";\r\nimport { BaseCacheDriver } from \"./base-cache-driver\";\r\n\r\nclass CacheNode {\r\n public next: CacheNode | null = null;\r\n public prev: CacheNode | null = null;\r\n public expiresAt?: number;\r\n /**\r\n * Freshness deadline (ms timestamp) — populated by `swr()`. Within\r\n * `expiresAt > now > staleAt` the entry is \"stale-but-revalidatable.\"\r\n */\r\n public staleAt?: number;\r\n /**\r\n * Optional embedding vector — populated when the entry was written with\r\n * `set({ vector })`. Scanned by `similar()`.\r\n */\r\n public vector?: number[];\r\n public constructor(\r\n public key: string,\r\n public value: any,\r\n ttl?: number,\r\n ) {\r\n if (ttl && ttl !== Infinity) {\r\n this.expiresAt = Date.now() + ttl * 1000;\r\n }\r\n }\r\n\r\n public get isExpired(): boolean {\r\n return this.expiresAt !== undefined && this.expiresAt < Date.now();\r\n }\r\n}\r\n\r\n/**\r\n * LRU Memory Cache Driver\r\n * The concept of LRU is to remove the least recently used data\r\n * whenever the cache is full\r\n * The question that resides here is how to tell the cache is full?\r\n */\r\nexport class LRUMemoryCacheDriver\r\n extends BaseCacheDriver<LRUMemoryCacheDriver, LRUMemoryCacheOptions>\r\n implements CacheDriver<LRUMemoryCacheDriver, LRUMemoryCacheOptions>\r\n{\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public name = \"lru\";\r\n\r\n /**\r\n * Cache map\r\n */\r\n protected cache: Map<string, CacheNode> = new Map();\r\n\r\n /**\r\n * Head of the cache\r\n */\r\n protected head: CacheNode = new CacheNode(\"\", null);\r\n\r\n /**\r\n * Tail of the cache\r\n */\r\n protected tail: CacheNode = new CacheNode(\"\", null);\r\n\r\n /**\r\n * Cleanup interval reference\r\n */\r\n protected cleanupInterval?: NodeJS.Timeout;\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public constructor() {\r\n super();\r\n\r\n this.init();\r\n this.startCleanup();\r\n }\r\n\r\n /**\r\n * Initialize the cache\r\n */\r\n public init() {\r\n this.head.next = this.tail;\r\n this.tail.prev = this.head;\r\n }\r\n\r\n /**\r\n * Start the cleanup process for expired items\r\n */\r\n public startCleanup() {\r\n // Clear existing interval if any\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n }\r\n\r\n this.cleanupInterval = setInterval(async () => {\r\n const now = Date.now();\r\n const expiredKeys: string[] = [];\r\n\r\n for (const [key, node] of this.cache) {\r\n if (node.expiresAt && node.expiresAt <= now) {\r\n expiredKeys.push(key);\r\n }\r\n }\r\n\r\n for (const key of expiredKeys) {\r\n const node = this.cache.get(key);\r\n if (node) {\r\n this.removeNode(node);\r\n this.cache.delete(key);\r\n this.log(\"expired\", key);\r\n // Emit expired event\r\n await this.emit(\"expired\", { key });\r\n }\r\n }\r\n }, 1000);\r\n\r\n // do not block the process from exiting\r\n this.cleanupInterval.unref();\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n *\r\n * Clears every entry whose key starts with the parsed namespace (followed\r\n * by a dot) or equals it exactly. Called with an empty namespace while a\r\n * `globalPrefix` is configured, clears everything under the prefix — which\r\n * is how `flush()` scopes cleanup per tenant.\r\n */\r\n public async removeNamespace(namespace: string) {\r\n const parsedNamespace = this.parseKey(namespace);\r\n\r\n this.log(\"clearing\", parsedNamespace || \"(all)\");\r\n\r\n const removed: string[] = [];\r\n\r\n if (parsedNamespace === \"\") {\r\n for (const key of this.cache.keys()) {\r\n removed.push(key);\r\n }\r\n } else {\r\n const prefix = parsedNamespace + \".\";\r\n\r\n for (const key of this.cache.keys()) {\r\n if (key === parsedNamespace || key.startsWith(prefix)) {\r\n removed.push(key);\r\n }\r\n }\r\n }\r\n\r\n for (const key of removed) {\r\n const node = this.cache.get(key);\r\n if (node) {\r\n this.removeNode(node);\r\n this.cache.delete(key);\r\n }\r\n await this.emit(\"removed\", { key });\r\n }\r\n\r\n this.log(\"cleared\", parsedNamespace || \"(all)\");\r\n\r\n return removed;\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 this.log(\"caching\", parsedKey);\r\n\r\n // For conditional writes, check existence via get() so expired entries\r\n // are treated as missing (get() handles expiry cleanup). The raw `cache.get`\r\n // node lookup would let stale entries block onConflict: \"create\".\r\n let existingNode = this.cache.get(parsedKey);\r\n if (existingNode && existingNode.isExpired) {\r\n this.removeNode(existingNode);\r\n this.cache.delete(parsedKey);\r\n existingNode = undefined;\r\n }\r\n\r\n const exists = Boolean(existingNode);\r\n\r\n if (onConflict === \"create\" && exists) {\r\n const result: CacheSetResult = {\r\n wasSet: false,\r\n existing: existingNode!.value,\r\n };\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 if (existingNode) {\r\n existingNode.value = value;\r\n if (ttl && ttl !== Infinity) {\r\n existingNode.expiresAt = Date.now() + ttl * 1000;\r\n } else {\r\n existingNode.expiresAt = undefined;\r\n }\r\n existingNode.staleAt = staleAt;\r\n if (vector) {\r\n existingNode.vector = vector.slice();\r\n }\r\n\r\n this.moveHead(existingNode);\r\n } else {\r\n const newNode = new CacheNode(parsedKey, value, ttl);\r\n newNode.staleAt = staleAt;\r\n if (vector) {\r\n newNode.vector = vector.slice();\r\n }\r\n\r\n this.cache.set(parsedKey, newNode);\r\n\r\n this.addNode(newNode);\r\n if (this.cache.size > this.capacity) {\r\n this.removeTail();\r\n }\r\n }\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 * Move the node to the head\r\n */\r\n protected moveHead(node: CacheNode) {\r\n this.removeNode(node);\r\n this.addNode(node);\r\n }\r\n\r\n /**\r\n * Remove the node from the cache\r\n */\r\n protected removeNode(node: CacheNode) {\r\n node.prev!.next = node.next;\r\n node.next!.prev = node.prev;\r\n }\r\n\r\n /**\r\n * Add the node to the head\r\n */\r\n protected addNode(node: CacheNode) {\r\n node.next = this.head.next;\r\n node.prev = this.head;\r\n this.head.next!.prev = node;\r\n this.head.next = node;\r\n }\r\n\r\n /**\r\n * Remove the tail node\r\n */\r\n protected removeTail() {\r\n const node = this.tail.prev!;\r\n\r\n this.removeNode(node);\r\n\r\n this.cache.delete(node.key);\r\n }\r\n\r\n /**\r\n * Read the raw {@link CacheData} wrapper, including `staleAt` metadata.\r\n * Returns `null` for missing or expired nodes — `swr()` consumes this\r\n * to branch on freshness without going through `get()`'s clone-and-emit\r\n * path.\r\n */\r\n protected async getEntry(key: CacheKey): Promise<CacheData | null> {\r\n const parsedKey = this.parseKey(key);\r\n const node = this.cache.get(parsedKey);\r\n\r\n if (!node || node.isExpired) {\r\n return null;\r\n }\r\n\r\n return {\r\n data: node.value,\r\n expiresAt: node.expiresAt,\r\n staleAt: node.staleAt,\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 node = this.cache.get(parsedKey);\r\n\r\n if (!node) {\r\n this.log(\"notFound\", parsedKey);\r\n // Emit miss event\r\n await this.emit(\"miss\", { key: parsedKey });\r\n return null;\r\n }\r\n\r\n // Check if expired\r\n if (node.isExpired) {\r\n this.removeNode(node);\r\n this.cache.delete(parsedKey);\r\n this.log(\"expired\", parsedKey);\r\n // Emit expired event\r\n await this.emit(\"expired\", { key: parsedKey });\r\n // Also emit miss since we're returning null\r\n await this.emit(\"miss\", { key: parsedKey });\r\n return null;\r\n }\r\n\r\n this.moveHead(node);\r\n\r\n this.log(\"fetched\", parsedKey);\r\n\r\n const value = node.value;\r\n\r\n // Apply cloning for immutability protection\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n const type = typeof value;\r\n if (type === \"string\" || type === \"number\" || type === \"boolean\") {\r\n // Emit hit event\r\n await this.emit(\"hit\", { key: parsedKey, value });\r\n return value;\r\n }\r\n\r\n try {\r\n const clonedValue = structuredClone(value);\r\n // Emit hit event\r\n await this.emit(\"hit\", { key: parsedKey, value: clonedValue });\r\n return clonedValue;\r\n } catch (error) {\r\n this.logError(`Failed to clone cached value for ${parsedKey}`, error);\r\n throw error;\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\r\n this.log(\"removing\", parsedKey);\r\n\r\n const node = this.cache.get(parsedKey);\r\n\r\n if (node) {\r\n this.removeNode(node);\r\n this.cache.delete(parsedKey);\r\n }\r\n\r\n this.log(\"removed\", parsedKey);\r\n\r\n // Emit removed event\r\n await this.emit(\"removed\", { key: parsedKey });\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n *\r\n * When a `globalPrefix` is configured, `flush` scopes itself to that prefix\r\n * so multi-tenant caches don't accidentally wipe sibling tenants. Without\r\n * a prefix, clears everything.\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 this.cache.clear();\r\n this.init();\r\n }\r\n\r\n this.log(\"flushed\");\r\n\r\n await this.emit(\"flushed\");\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n *\r\n * Brute-force O(N) cosine similarity over every cached node that carries a\r\n * vector. Suitable for development and small in-memory knowledge bases —\r\n * not for production beyond ~10k entries.\r\n *\r\n * @warning Dev-only — O(N) per query.\r\n */\r\n public async similar<T = any>(\r\n vector: number[],\r\n options: CacheSimilarOptions,\r\n ): Promise<CacheSimilarHit<T>[]> {\r\n const tagFilter = await this.getKeysForTags(options.tags);\r\n\r\n const hits: CacheSimilarHit<T>[] = [];\r\n\r\n for (const [parsedKey, node] of this.cache) {\r\n if (!node.vector) continue;\r\n if (node.isExpired) continue;\r\n if (tagFilter && !tagFilter.has(parsedKey)) continue;\r\n\r\n const score = cosineSimilarity(vector, node.vector);\r\n\r\n if (options.threshold !== undefined && score < options.threshold) {\r\n continue;\r\n }\r\n\r\n // Clone object values to match get() semantics.\r\n let value: any = node.value;\r\n if (value !== null && value !== undefined) {\r\n const t = typeof value;\r\n if (t !== \"string\" && t !== \"number\" && t !== \"boolean\") {\r\n value = structuredClone(value);\r\n }\r\n }\r\n\r\n hits.push({ key: parsedKey, value, score });\r\n }\r\n\r\n hits.sort((a, b) => b.score - a.score);\r\n\r\n if (options.topK >= 0 && hits.length > options.topK) {\r\n hits.length = options.topK;\r\n }\r\n\r\n return hits;\r\n }\r\n\r\n /**\r\n * Get lru capacity\r\n */\r\n public get capacity() {\r\n return this.options.capacity || 1000;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async disconnect() {\r\n // Clear the cleanup interval to prevent memory leaks\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = undefined;\r\n }\r\n\r\n await super.disconnect();\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
2
|
+
import { CacheData, CacheDriver, CacheKey, CacheSetOptions, CacheSimilarHit, CacheSimilarOptions, CacheTtl, MemoryCacheOptions } from "../types.mjs";
|
|
3
|
+
import { GenericObject } from "@mongez/reinforcements";
|
|
4
|
+
|
|
5
|
+
//#region ../../@warlock.js/cache/src/drivers/memory-cache-driver.d.ts
|
|
6
|
+
declare class MemoryCacheDriver extends BaseCacheDriver<MemoryCacheDriver, MemoryCacheOptions> implements CacheDriver<MemoryCacheDriver, MemoryCacheOptions> {
|
|
7
|
+
/**
|
|
8
|
+
* {@inheritdoc}
|
|
9
|
+
*/
|
|
10
|
+
name: string;
|
|
11
|
+
/**
|
|
12
|
+
* Cached data
|
|
13
|
+
*/
|
|
14
|
+
data: GenericObject;
|
|
15
|
+
/**
|
|
16
|
+
* List of data that will be cleared from cache
|
|
17
|
+
*/
|
|
18
|
+
protected temporaryData: Record<string, {
|
|
19
|
+
key: string;
|
|
20
|
+
expiresAt: number;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Cleanup interval reference
|
|
24
|
+
*/
|
|
25
|
+
protected cleanupInterval?: NodeJS.Timeout;
|
|
26
|
+
/**
|
|
27
|
+
* Access order tracking for LRU eviction (when maxSize is set)
|
|
28
|
+
*/
|
|
29
|
+
protected accessOrder: string[];
|
|
30
|
+
/**
|
|
31
|
+
* Parallel vector index keyed by parsedKey. Populated by `set({ vector })`,
|
|
32
|
+
* scanned by `similar()`. Lifetime mirrors the main entry — cleared on
|
|
33
|
+
* `remove`, `flush`, expiry, namespace clear, and LRU eviction.
|
|
34
|
+
*/
|
|
35
|
+
protected vectorIndex: Map<string, number[]>;
|
|
36
|
+
/**
|
|
37
|
+
* {@inheritdoc}
|
|
38
|
+
*/
|
|
39
|
+
constructor();
|
|
40
|
+
/**
|
|
41
|
+
* Start the cleanup process whenever a data that has a cache key is set
|
|
42
|
+
*/
|
|
43
|
+
startCleanup(): void;
|
|
44
|
+
/**
|
|
45
|
+
* {@inheritdoc}
|
|
46
|
+
*/
|
|
47
|
+
removeNamespace(namespace: string): Promise<this>;
|
|
48
|
+
/**
|
|
49
|
+
* {@inheritdoc}
|
|
50
|
+
*/
|
|
51
|
+
set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* {@inheritdoc}
|
|
54
|
+
*/
|
|
55
|
+
get(key: CacheKey): Promise<any>;
|
|
56
|
+
/**
|
|
57
|
+
* Read the raw {@link CacheData} wrapper, including `staleAt` metadata.
|
|
58
|
+
* Returns `null` for missing or expired entries so the SWR flow can branch
|
|
59
|
+
* cleanly. Does not emit `hit`/`miss` events — that's `get()`'s job.
|
|
60
|
+
*/
|
|
61
|
+
protected getEntry(key: CacheKey): Promise<CacheData | null>;
|
|
62
|
+
/**
|
|
63
|
+
* {@inheritdoc}
|
|
64
|
+
*/
|
|
65
|
+
remove(key: CacheKey): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* {@inheritdoc}
|
|
68
|
+
*/
|
|
69
|
+
flush(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Set the temporary data
|
|
72
|
+
*/
|
|
73
|
+
protected setTemporaryData(key: CacheKey, parsedKey: string, ttl: number): void;
|
|
74
|
+
/**
|
|
75
|
+
* Track access for LRU eviction
|
|
76
|
+
*/
|
|
77
|
+
protected trackAccess(key: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Remove key from access order tracking
|
|
80
|
+
*/
|
|
81
|
+
protected removeFromAccessOrder(key: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Enforce max size by evicting least recently used items.
|
|
84
|
+
*
|
|
85
|
+
* Recomputes the live cache size on every iteration — a single snapshot at
|
|
86
|
+
* the top of the loop would go stale and cause this routine to evict every
|
|
87
|
+
* entry in `accessOrder` (including the just-inserted key).
|
|
88
|
+
*/
|
|
89
|
+
protected enforceMaxSize(): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Get current cache size (number of cached items)
|
|
92
|
+
*/
|
|
93
|
+
protected getCacheSize(): number;
|
|
94
|
+
/**
|
|
95
|
+
* {@inheritdoc}
|
|
96
|
+
*
|
|
97
|
+
* Brute-force O(N) cosine similarity over every entry that was written with
|
|
98
|
+
* `set({ vector })`. Suitable for development and small in-memory knowledge
|
|
99
|
+
* bases — not for production beyond ~10k entries. Use the `pg` driver
|
|
100
|
+
* (with pgvector) or `redis` (with RediSearch) at scale.
|
|
101
|
+
*
|
|
102
|
+
* @warning Dev-only — O(N) per query.
|
|
103
|
+
*/
|
|
104
|
+
similar<T = any>(vector: number[], options: CacheSimilarOptions): Promise<CacheSimilarHit<T>[]>;
|
|
105
|
+
/**
|
|
106
|
+
* {@inheritdoc}
|
|
107
|
+
*/
|
|
108
|
+
disconnect(): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { MemoryCacheDriver };
|
|
112
|
+
//# sourceMappingURL=memory-cache-driver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-cache-driver.d.mts","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/memory-cache-driver.ts"],"mappings":";;;;;cAgBa,iBAAA,SACH,eAAA,CAAgB,iBAAA,EAAmB,kBAAA,aAChC,WAAA,CAAY,iBAAA,EAAmB,kBAAA;;AAF5C;;EAOS,IAAA;EANiB;;;EAWjB,IAAA,EAAM,aAAA;EAAA;;;EAAA,UAKH,aAAA,EAAe,MAAA;IAGrB,GAAA;IACA,SAAA;EAAA;EA2FwB;;;EAAA,UApFlB,eAAA,GAAkB,MAAA,CAAO,OAAA;EAkLL;;;EAAA,UA7KpB,WAAA;EA+LuB;;;;;EAAA,UAxLvB,WAAA,EAAa,GAAA;EAuTZ;;;;EA7VA;;;EAoDJ,YAAA,CAAA;EArDiB;;;EAiFX,eAAA,CAAgB,SAAA,WAAiB,OAAA;EAhFJ;;;EA2G7B,GAAA,CACX,GAAA,EAAK,QAAA,EACL,KAAA,OACA,YAAA,GAAe,QAAA,GAAW,eAAA,GACzB,OAAA;EAhGO;;;EA2JG,GAAA,CAAI,GAAA,EAAK,QAAA,GAAQ,OAAA;EAhJpB;;;;;EAAA,UAkLM,QAAA,CAAS,GAAA,EAAK,QAAA,GAAW,OAAA,CAAQ,SAAA;;;;EAkBpC,MAAA,CAAO,GAAA,EAAK,QAAA,GAAQ,OAAA;EA9Ia;;;EAuKjC,KAAA,CAAA,GAAK,OAAA;EA1IhB;;;EAAA,UA6JQ,gBAAA,CAAiB,GAAA,EAAK,QAAA,EAAU,SAAA,UAAmB,GAAA;EA3J1D;;;EAAA,UAqKO,WAAA,CAAY,GAAA;EA1GQ;;;EAAA,UA0HpB,qBAAA,CAAsB,GAAA;EAxFS;;;;;;;EAAA,UAsGzB,cAAA,CAAA,GAAc,OAAA;EAxCpB;;;EAAA,UAiEA,YAAA,CAAA;EAjEmD;;;;;;;;;;EAgFhD,OAAA,SAAA,CACX,MAAA,YACA,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,eAAA,CAAgB,CAAA;EADhB;;;EAuCE,UAAA,CAAA,GAAU,OAAA;AAAA"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { cosineSimilarity } from "../utils.mjs";
|
|
2
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
3
|
+
import { get, set, unset } from "@mongez/reinforcements";
|
|
4
|
+
|
|
5
|
+
//#region ../../@warlock.js/cache/src/drivers/memory-cache-driver.ts
|
|
6
|
+
var MemoryCacheDriver = class extends BaseCacheDriver {
|
|
7
|
+
/**
|
|
8
|
+
* {@inheritdoc}
|
|
9
|
+
*/
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.name = "memory";
|
|
13
|
+
this.data = {};
|
|
14
|
+
this.temporaryData = {};
|
|
15
|
+
this.accessOrder = [];
|
|
16
|
+
this.vectorIndex = /* @__PURE__ */ new Map();
|
|
17
|
+
this.startCleanup();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start the cleanup process whenever a data that has a cache key is set
|
|
21
|
+
*/
|
|
22
|
+
startCleanup() {
|
|
23
|
+
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
24
|
+
this.cleanupInterval = setInterval(async () => {
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
for (const key in this.temporaryData) if (this.temporaryData[key].expiresAt <= now) {
|
|
27
|
+
await this.remove(this.temporaryData[key].key);
|
|
28
|
+
delete this.temporaryData[key];
|
|
29
|
+
this.log("expired", key);
|
|
30
|
+
await this.emit("expired", { key });
|
|
31
|
+
}
|
|
32
|
+
}, 1e3);
|
|
33
|
+
this.cleanupInterval.unref();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* {@inheritdoc}
|
|
37
|
+
*/
|
|
38
|
+
async removeNamespace(namespace) {
|
|
39
|
+
this.log("clearing", namespace);
|
|
40
|
+
namespace = this.parseKey(namespace);
|
|
41
|
+
unset(this.data, [namespace]);
|
|
42
|
+
if (namespace === "") this.vectorIndex.clear();
|
|
43
|
+
else {
|
|
44
|
+
const prefix = namespace + ".";
|
|
45
|
+
for (const k of [...this.vectorIndex.keys()]) if (k === namespace || k.startsWith(prefix)) this.vectorIndex.delete(k);
|
|
46
|
+
}
|
|
47
|
+
this.log("cleared", namespace);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* {@inheritdoc}
|
|
52
|
+
*/
|
|
53
|
+
async set(key, value, ttlOrOptions) {
|
|
54
|
+
const parsedKey = this.parseKey(key);
|
|
55
|
+
const { ttl, tags, onConflict, vector, staleAt } = this.resolveSetOptions(ttlOrOptions);
|
|
56
|
+
this.log("caching", parsedKey);
|
|
57
|
+
const existingValue = onConflict === "upsert" ? null : await this.get(key);
|
|
58
|
+
const exists = existingValue !== null;
|
|
59
|
+
if (onConflict === "create" && exists) return {
|
|
60
|
+
wasSet: false,
|
|
61
|
+
existing: existingValue
|
|
62
|
+
};
|
|
63
|
+
if (onConflict === "update" && !exists) return {
|
|
64
|
+
wasSet: false,
|
|
65
|
+
existing: null
|
|
66
|
+
};
|
|
67
|
+
const data = this.prepareDataForStorage(value, ttl, staleAt);
|
|
68
|
+
if (ttl) this.setTemporaryData(key, parsedKey, ttl);
|
|
69
|
+
set(this.data, parsedKey, data);
|
|
70
|
+
this.trackAccess(parsedKey);
|
|
71
|
+
if (!exists && this.options.maxSize) await this.enforceMaxSize();
|
|
72
|
+
if (tags && tags.length > 0) await this.applyTags(parsedKey, tags);
|
|
73
|
+
if (vector) this.vectorIndex.set(parsedKey, vector.slice());
|
|
74
|
+
this.log("cached", parsedKey);
|
|
75
|
+
await this.emit("set", {
|
|
76
|
+
key: parsedKey,
|
|
77
|
+
value,
|
|
78
|
+
ttl
|
|
79
|
+
});
|
|
80
|
+
if (onConflict === "create" || onConflict === "update") return {
|
|
81
|
+
wasSet: true,
|
|
82
|
+
existing: null
|
|
83
|
+
};
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* {@inheritdoc}
|
|
88
|
+
*/
|
|
89
|
+
async get(key) {
|
|
90
|
+
const parsedKey = this.parseKey(key);
|
|
91
|
+
this.log("fetching", parsedKey);
|
|
92
|
+
const value = get(this.data, parsedKey);
|
|
93
|
+
if (!value) {
|
|
94
|
+
this.log("notFound", parsedKey);
|
|
95
|
+
await this.emit("miss", { key: parsedKey });
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const result = await this.parseCachedData(parsedKey, value);
|
|
99
|
+
if (result === null) await this.emit("miss", { key: parsedKey });
|
|
100
|
+
else {
|
|
101
|
+
this.trackAccess(parsedKey);
|
|
102
|
+
await this.emit("hit", {
|
|
103
|
+
key: parsedKey,
|
|
104
|
+
value: result
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Read the raw {@link CacheData} wrapper, including `staleAt` metadata.
|
|
111
|
+
* Returns `null` for missing or expired entries so the SWR flow can branch
|
|
112
|
+
* cleanly. Does not emit `hit`/`miss` events — that's `get()`'s job.
|
|
113
|
+
*/
|
|
114
|
+
async getEntry(key) {
|
|
115
|
+
const parsedKey = this.parseKey(key);
|
|
116
|
+
const entry = get(this.data, parsedKey);
|
|
117
|
+
if (!entry) return null;
|
|
118
|
+
if (entry.expiresAt !== void 0 && entry.expiresAt <= Date.now()) return null;
|
|
119
|
+
return entry;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* {@inheritdoc}
|
|
123
|
+
*/
|
|
124
|
+
async remove(key) {
|
|
125
|
+
const parsedKey = this.parseKey(key);
|
|
126
|
+
this.log("removing", parsedKey);
|
|
127
|
+
unset(this.data, [parsedKey]);
|
|
128
|
+
delete this.temporaryData[parsedKey];
|
|
129
|
+
this.removeFromAccessOrder(parsedKey);
|
|
130
|
+
this.vectorIndex.delete(parsedKey);
|
|
131
|
+
this.log("removed", parsedKey);
|
|
132
|
+
await this.emit("removed", { key: parsedKey });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* {@inheritdoc}
|
|
136
|
+
*/
|
|
137
|
+
async flush() {
|
|
138
|
+
this.log("flushing");
|
|
139
|
+
if (this.options.globalPrefix) this.removeNamespace("");
|
|
140
|
+
else {
|
|
141
|
+
this.data = {};
|
|
142
|
+
this.accessOrder = [];
|
|
143
|
+
this.vectorIndex.clear();
|
|
144
|
+
}
|
|
145
|
+
this.log("flushed");
|
|
146
|
+
await this.emit("flushed");
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Set the temporary data
|
|
150
|
+
*/
|
|
151
|
+
setTemporaryData(key, parsedKey, ttl) {
|
|
152
|
+
this.temporaryData[parsedKey] = {
|
|
153
|
+
key: JSON.stringify(key),
|
|
154
|
+
expiresAt: Date.now() + ttl * 1e3
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Track access for LRU eviction
|
|
159
|
+
*/
|
|
160
|
+
trackAccess(key) {
|
|
161
|
+
if (!this.options.maxSize) return;
|
|
162
|
+
const index = this.accessOrder.indexOf(key);
|
|
163
|
+
if (index > -1) this.accessOrder.splice(index, 1);
|
|
164
|
+
this.accessOrder.push(key);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Remove key from access order tracking
|
|
168
|
+
*/
|
|
169
|
+
removeFromAccessOrder(key) {
|
|
170
|
+
const index = this.accessOrder.indexOf(key);
|
|
171
|
+
if (index > -1) this.accessOrder.splice(index, 1);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Enforce max size by evicting least recently used items.
|
|
175
|
+
*
|
|
176
|
+
* Recomputes the live cache size on every iteration — a single snapshot at
|
|
177
|
+
* the top of the loop would go stale and cause this routine to evict every
|
|
178
|
+
* entry in `accessOrder` (including the just-inserted key).
|
|
179
|
+
*/
|
|
180
|
+
async enforceMaxSize() {
|
|
181
|
+
if (!this.options.maxSize) return;
|
|
182
|
+
while (this.getCacheSize() > this.options.maxSize && this.accessOrder.length > 0) {
|
|
183
|
+
const lruKey = this.accessOrder.shift();
|
|
184
|
+
if (!lruKey) break;
|
|
185
|
+
this.log("removing", lruKey);
|
|
186
|
+
unset(this.data, [lruKey]);
|
|
187
|
+
delete this.temporaryData[lruKey];
|
|
188
|
+
this.vectorIndex.delete(lruKey);
|
|
189
|
+
this.log("removed", lruKey);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get current cache size (number of cached items)
|
|
194
|
+
*/
|
|
195
|
+
getCacheSize() {
|
|
196
|
+
return Object.keys(this.data).length;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* {@inheritdoc}
|
|
200
|
+
*
|
|
201
|
+
* Brute-force O(N) cosine similarity over every entry that was written with
|
|
202
|
+
* `set({ vector })`. Suitable for development and small in-memory knowledge
|
|
203
|
+
* bases — not for production beyond ~10k entries. Use the `pg` driver
|
|
204
|
+
* (with pgvector) or `redis` (with RediSearch) at scale.
|
|
205
|
+
*
|
|
206
|
+
* @warning Dev-only — O(N) per query.
|
|
207
|
+
*/
|
|
208
|
+
async similar(vector, options) {
|
|
209
|
+
const tagFilter = await this.getKeysForTags(options.tags);
|
|
210
|
+
const hits = [];
|
|
211
|
+
for (const [parsedKey, stored] of this.vectorIndex) {
|
|
212
|
+
if (tagFilter && !tagFilter.has(parsedKey)) continue;
|
|
213
|
+
const value = await this.get(parsedKey);
|
|
214
|
+
if (value === null) continue;
|
|
215
|
+
const score = cosineSimilarity(vector, stored);
|
|
216
|
+
if (options.threshold !== void 0 && score < options.threshold) continue;
|
|
217
|
+
hits.push({
|
|
218
|
+
key: parsedKey,
|
|
219
|
+
value,
|
|
220
|
+
score
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
hits.sort((a, b) => b.score - a.score);
|
|
224
|
+
if (options.topK >= 0 && hits.length > options.topK) hits.length = options.topK;
|
|
225
|
+
return hits;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* {@inheritdoc}
|
|
229
|
+
*/
|
|
230
|
+
async disconnect() {
|
|
231
|
+
if (this.cleanupInterval) {
|
|
232
|
+
clearInterval(this.cleanupInterval);
|
|
233
|
+
this.cleanupInterval = void 0;
|
|
234
|
+
}
|
|
235
|
+
await super.disconnect();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
//#endregion
|
|
240
|
+
export { MemoryCacheDriver };
|
|
241
|
+
//# sourceMappingURL=memory-cache-driver.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-cache-driver.mjs","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/memory-cache-driver.ts"],"sourcesContent":["import type { GenericObject } from \"@mongez/reinforcements\";\r\nimport { get, set, unset } from \"@mongez/reinforcements\";\r\nimport type {\r\n CacheData,\r\n CacheDriver,\r\n CacheKey,\r\n CacheSetOptions,\r\n CacheSetResult,\r\n CacheSimilarHit,\r\n CacheSimilarOptions,\r\n CacheTtl,\r\n MemoryCacheOptions,\r\n} from \"../types\";\r\nimport { cosineSimilarity } from \"../utils\";\r\nimport { BaseCacheDriver } from \"./base-cache-driver\";\r\n\r\nexport class MemoryCacheDriver\r\n extends BaseCacheDriver<MemoryCacheDriver, MemoryCacheOptions>\r\n implements CacheDriver<MemoryCacheDriver, MemoryCacheOptions>\r\n{\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public name = \"memory\";\r\n\r\n /**\r\n * Cached data\r\n */\r\n public data: GenericObject = {};\r\n\r\n /**\r\n * List of data that will be cleared from cache\r\n */\r\n protected temporaryData: Record<\r\n string,\r\n {\r\n key: string;\r\n expiresAt: number;\r\n }\r\n > = {};\r\n\r\n /**\r\n * Cleanup interval reference\r\n */\r\n protected cleanupInterval?: NodeJS.Timeout;\r\n\r\n /**\r\n * Access order tracking for LRU eviction (when maxSize is set)\r\n */\r\n protected accessOrder: string[] = [];\r\n\r\n /**\r\n * Parallel vector index keyed by parsedKey. Populated by `set({ vector })`,\r\n * scanned by `similar()`. Lifetime mirrors the main entry — cleared on\r\n * `remove`, `flush`, expiry, namespace clear, and LRU eviction.\r\n */\r\n protected vectorIndex: Map<string, number[]> = new Map();\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public constructor() {\r\n super();\r\n\r\n this.startCleanup();\r\n }\r\n\r\n /**\r\n * Start the cleanup process whenever a data that has a cache key is set\r\n */\r\n public startCleanup() {\r\n // Clear existing interval if any\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n }\r\n\r\n this.cleanupInterval = setInterval(async () => {\r\n const now = Date.now();\r\n\r\n for (const key in this.temporaryData) {\r\n if (this.temporaryData[key].expiresAt <= now) {\r\n await this.remove(this.temporaryData[key].key);\r\n delete this.temporaryData[key];\r\n\r\n this.log(\"expired\", key);\r\n // Emit expired event\r\n await this.emit(\"expired\", { key });\r\n }\r\n }\r\n }, 1000);\r\n\r\n // do not block the process from exiting\r\n this.cleanupInterval.unref();\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 namespace = this.parseKey(namespace);\r\n\r\n unset(this.data, [namespace]);\r\n\r\n // Drop vector entries that fall under this namespace.\r\n if (namespace === \"\") {\r\n this.vectorIndex.clear();\r\n } else {\r\n const prefix = namespace + \".\";\r\n for (const k of [...this.vectorIndex.keys()]) {\r\n if (k === namespace || k.startsWith(prefix)) {\r\n this.vectorIndex.delete(k);\r\n }\r\n }\r\n }\r\n\r\n this.log(\"cleared\", namespace);\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 this.log(\"caching\", parsedKey);\r\n\r\n // Use get() for the existence check so expired entries are treated as\r\n // missing (and cleaned up as a side effect). A raw map lookup would let\r\n // stale entries block onConflict: \"create\" even after their TTL elapsed.\r\n const existingValue = onConflict === \"upsert\" ? null : await this.get(key);\r\n const exists = existingValue !== null;\r\n\r\n if (onConflict === \"create\" && exists) {\r\n const result: CacheSetResult = { wasSet: false, existing: existingValue };\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 if (ttl) {\r\n this.setTemporaryData(key, parsedKey, ttl);\r\n }\r\n\r\n set(this.data, parsedKey, data);\r\n\r\n this.trackAccess(parsedKey);\r\n\r\n if (!exists && this.options.maxSize) {\r\n await this.enforceMaxSize();\r\n }\r\n\r\n if (tags && tags.length > 0) {\r\n await this.applyTags(parsedKey, tags);\r\n }\r\n\r\n if (vector) {\r\n this.vectorIndex.set(parsedKey, vector.slice());\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 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 value: CacheData = get(this.data, parsedKey);\r\n\r\n if (!value) {\r\n this.log(\"notFound\", parsedKey);\r\n // Emit miss event\r\n await this.emit(\"miss\", { key: parsedKey });\r\n return null;\r\n }\r\n\r\n const result = await this.parseCachedData(parsedKey, value);\r\n\r\n if (result === null) {\r\n // Expired\r\n await this.emit(\"miss\", { key: parsedKey });\r\n } else {\r\n // Track access for LRU\r\n this.trackAccess(parsedKey);\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 }\r\n\r\n /**\r\n * Read the raw {@link CacheData} wrapper, including `staleAt` metadata.\r\n * Returns `null` for missing or expired entries so the SWR flow can branch\r\n * cleanly. Does not emit `hit`/`miss` events — that's `get()`'s job.\r\n */\r\n protected async getEntry(key: CacheKey): Promise<CacheData | null> {\r\n const parsedKey = this.parseKey(key);\r\n const entry: CacheData | undefined = get(this.data, parsedKey);\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 }\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\r\n this.log(\"removing\", parsedKey);\r\n\r\n unset(this.data, [parsedKey]);\r\n\r\n // Clean up from temporaryData as well\r\n delete this.temporaryData[parsedKey];\r\n\r\n // Remove from access order\r\n this.removeFromAccessOrder(parsedKey);\r\n\r\n // Drop the vector index entry if any\r\n this.vectorIndex.delete(parsedKey);\r\n\r\n this.log(\"removed\", parsedKey);\r\n\r\n // Emit removed event\r\n await this.emit(\"removed\", { key: parsedKey });\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async flush() {\r\n this.log(\"flushing\");\r\n if (this.options.globalPrefix) {\r\n this.removeNamespace(\"\");\r\n } else {\r\n this.data = {};\r\n this.accessOrder = [];\r\n this.vectorIndex.clear();\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 * Set the temporary data\r\n */\r\n protected setTemporaryData(key: CacheKey, parsedKey: string, ttl: number) {\r\n this.temporaryData[parsedKey] = {\r\n key: JSON.stringify(key),\r\n expiresAt: Date.now() + ttl * 1000,\r\n };\r\n }\r\n\r\n /**\r\n * Track access for LRU eviction\r\n */\r\n protected trackAccess(key: string) {\r\n if (!this.options.maxSize) return;\r\n\r\n // Remove key from current position\r\n const index = this.accessOrder.indexOf(key);\r\n if (index > -1) {\r\n this.accessOrder.splice(index, 1);\r\n }\r\n\r\n // Add to end (most recently used)\r\n this.accessOrder.push(key);\r\n }\r\n\r\n /**\r\n * Remove key from access order tracking\r\n */\r\n protected removeFromAccessOrder(key: string) {\r\n const index = this.accessOrder.indexOf(key);\r\n if (index > -1) {\r\n this.accessOrder.splice(index, 1);\r\n }\r\n }\r\n\r\n /**\r\n * Enforce max size by evicting least recently used items.\r\n *\r\n * Recomputes the live cache size on every iteration — a single snapshot at\r\n * the top of the loop would go stale and cause this routine to evict every\r\n * entry in `accessOrder` (including the just-inserted key).\r\n */\r\n protected async enforceMaxSize() {\r\n if (!this.options.maxSize) {\r\n return;\r\n }\r\n\r\n while (\r\n this.getCacheSize() > this.options.maxSize &&\r\n this.accessOrder.length > 0\r\n ) {\r\n const lruKey = this.accessOrder.shift();\r\n if (!lruKey) {\r\n break;\r\n }\r\n\r\n this.log(\"removing\", lruKey);\r\n unset(this.data, [lruKey]);\r\n delete this.temporaryData[lruKey];\r\n this.vectorIndex.delete(lruKey);\r\n this.log(\"removed\", lruKey);\r\n }\r\n }\r\n\r\n /**\r\n * Get current cache size (number of cached items)\r\n */\r\n protected getCacheSize(): number {\r\n // Count top-level keys in data object\r\n return Object.keys(this.data).length;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n *\r\n * Brute-force O(N) cosine similarity over every entry that was written with\r\n * `set({ vector })`. Suitable for development and small in-memory knowledge\r\n * bases — not for production beyond ~10k entries. Use the `pg` driver\r\n * (with pgvector) or `redis` (with RediSearch) at scale.\r\n *\r\n * @warning Dev-only — O(N) per query.\r\n */\r\n public async similar<T = any>(\r\n vector: number[],\r\n options: CacheSimilarOptions,\r\n ): Promise<CacheSimilarHit<T>[]> {\r\n const tagFilter = await this.getKeysForTags(options.tags);\r\n\r\n const hits: CacheSimilarHit<T>[] = [];\r\n\r\n for (const [parsedKey, stored] of this.vectorIndex) {\r\n if (tagFilter && !tagFilter.has(parsedKey)) {\r\n continue;\r\n }\r\n\r\n const value = (await this.get(parsedKey)) as T | null;\r\n // get() returns null for expired entries — and remove() drops the vector\r\n // index, so the next pass won't see it. Skip in case of timing.\r\n if (value === null) {\r\n continue;\r\n }\r\n\r\n const score = cosineSimilarity(vector, stored);\r\n\r\n if (options.threshold !== undefined && score < options.threshold) {\r\n continue;\r\n }\r\n\r\n hits.push({ key: parsedKey, value, score });\r\n }\r\n\r\n hits.sort((a, b) => b.score - a.score);\r\n\r\n if (options.topK >= 0 && hits.length > options.topK) {\r\n hits.length = options.topK;\r\n }\r\n\r\n return hits;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async disconnect() {\r\n // Clear the cleanup interval to prevent memory leaks\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = undefined;\r\n }\r\n\r\n await super.disconnect();\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MemoryCacheDriver } from "./memory-cache-driver.mjs";
|
|
2
|
+
import { CacheDriver, CacheKey, MemoryExtendedCacheOptions } from "../types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../../@warlock.js/cache/src/drivers/memory-extended-cache-driver.d.ts
|
|
5
|
+
declare class MemoryExtendedCacheDriver extends MemoryCacheDriver implements CacheDriver<MemoryExtendedCacheDriver, MemoryExtendedCacheOptions> {
|
|
6
|
+
/**
|
|
7
|
+
* {@inheritdoc}
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/**
|
|
11
|
+
* {@inheritdoc}
|
|
12
|
+
*/
|
|
13
|
+
get(key: CacheKey): Promise<any>;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { MemoryExtendedCacheDriver };
|
|
17
|
+
//# sourceMappingURL=memory-extended-cache-driver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-extended-cache-driver.d.mts","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/memory-extended-cache-driver.ts"],"mappings":";;;;cAKa,yBAAA,SACH,iBAAA,YACG,WAAA,CAAY,yBAAA,EAA2B,0BAAA;;AAFpD;;EAOS,IAAA;EALgB;;;EAUV,GAAA,CAAI,GAAA,EAAK,QAAA,GAAQ,OAAA;AAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { parseTtl } from "../utils.mjs";
|
|
2
|
+
import { MemoryCacheDriver } from "./memory-cache-driver.mjs";
|
|
3
|
+
import { get } from "@mongez/reinforcements";
|
|
4
|
+
|
|
5
|
+
//#region ../../@warlock.js/cache/src/drivers/memory-extended-cache-driver.ts
|
|
6
|
+
var MemoryExtendedCacheDriver = class extends MemoryCacheDriver {
|
|
7
|
+
constructor(..._args) {
|
|
8
|
+
super(..._args);
|
|
9
|
+
this.name = "memoryExtended";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* {@inheritdoc}
|
|
13
|
+
*/
|
|
14
|
+
async get(key) {
|
|
15
|
+
const parsedKey = this.parseKey(key);
|
|
16
|
+
this.log("fetching", parsedKey);
|
|
17
|
+
const value = get(this.data, parsedKey);
|
|
18
|
+
if (!value) {
|
|
19
|
+
this.log("notFound", parsedKey);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const rawTtl = value.ttl ?? this.options.ttl;
|
|
23
|
+
const ttl = rawTtl !== void 0 ? parseTtl(rawTtl) : void 0;
|
|
24
|
+
if (ttl) {
|
|
25
|
+
this.setTemporaryData(key, parsedKey, ttl);
|
|
26
|
+
value.expiresAt = this.getExpiresAt(ttl);
|
|
27
|
+
}
|
|
28
|
+
return this.parseCachedData(parsedKey, value);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { MemoryExtendedCacheDriver };
|
|
34
|
+
//# sourceMappingURL=memory-extended-cache-driver.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-extended-cache-driver.mjs","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/memory-extended-cache-driver.ts"],"sourcesContent":["import { get } from \"@mongez/reinforcements\";\r\nimport type { CacheData, CacheDriver, CacheKey, MemoryExtendedCacheOptions } from \"../types\";\r\nimport { parseTtl } from \"../utils\";\r\nimport { MemoryCacheDriver } from \"./memory-cache-driver\";\r\n\r\nexport class MemoryExtendedCacheDriver\r\n extends MemoryCacheDriver\r\n implements CacheDriver<MemoryExtendedCacheDriver, MemoryExtendedCacheOptions>\r\n{\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public name = \"memoryExtended\";\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 value: CacheData = get(this.data, parsedKey);\r\n\r\n if (!value) {\r\n this.log(\"notFound\", parsedKey);\r\n return null;\r\n }\r\n\r\n const rawTtl = value.ttl ?? this.options.ttl;\r\n const ttl = rawTtl !== undefined ? parseTtl(rawTtl) : undefined;\r\n\r\n if (ttl) {\r\n // reset the expiration time\r\n this.setTemporaryData(key, parsedKey, ttl);\r\n value.expiresAt = this.getExpiresAt(ttl);\r\n }\r\n\r\n return this.parseCachedData(parsedKey, value);\r\n }\r\n}\r\n"],"mappings":";;;;;AAKA,IAAa,4BAAb,cACU,kBAEV;;;cAIgB;;;;;CAKd,MAAa,IAAI,KAAe;EAC9B,MAAM,YAAY,KAAK,SAAS,GAAG;EAEnC,KAAK,IAAI,YAAY,SAAS;EAE9B,MAAM,QAAmB,IAAI,KAAK,MAAM,SAAS;EAEjD,IAAI,CAAC,OAAO;GACV,KAAK,IAAI,YAAY,SAAS;GAC9B,OAAO;EACT;EAEA,MAAM,SAAS,MAAM,OAAO,KAAK,QAAQ;EACzC,MAAM,MAAM,WAAW,SAAY,SAAS,MAAM,IAAI;EAEtD,IAAI,KAAK;GAEP,KAAK,iBAAiB,KAAK,WAAW,GAAG;GACzC,MAAM,YAAY,KAAK,aAAa,GAAG;EACzC;EAEA,OAAO,KAAK,gBAAgB,WAAW,KAAK;CAC9C;AACF"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
2
|
+
import { CacheCall, CacheData, CacheDriver, CacheKey, CacheSetOptions, CacheTtl, MockCacheOptions } from "../types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../../@warlock.js/cache/src/drivers/mock-cache-driver.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* In-memory cache driver with introspection helpers, intended for use as a
|
|
7
|
+
* test double in downstream packages.
|
|
8
|
+
*
|
|
9
|
+
* **Role.** Drop-in replacement for any real driver in test setups, with
|
|
10
|
+
* extra surface that makes behavioral assertions easy: every public op gets
|
|
11
|
+
* recorded into {@link MockCacheDriver.callLog}, and {@link wasCalled} /
|
|
12
|
+
* {@link getStored} / {@link reset} let tests verify side effects without
|
|
13
|
+
* pulling in a real Redis / Postgres / file system.
|
|
14
|
+
*
|
|
15
|
+
* **Responsibility.**
|
|
16
|
+
* - Owns: in-memory storage backed by a `Map`, the `callLog`, TTL handling
|
|
17
|
+
* via `parseCachedData`, `onConflict` policies, and tag-index storage.
|
|
18
|
+
* - Does NOT own: similarity retrieval (vectors are recorded into the
|
|
19
|
+
* `callLog` but `similar()` throws — use `MemoryCacheDriver` for tests
|
|
20
|
+
* that need real nearest-neighbor scoring), connection lifecycle
|
|
21
|
+
* (no-op `connect`/`disconnect`), or eviction (no `maxSize`).
|
|
22
|
+
*
|
|
23
|
+
* Register it like any other driver — sub-paths are not part of the
|
|
24
|
+
* package's export convention; the same single barrel ships it next to
|
|
25
|
+
* the production drivers.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* import { cache, MockCacheDriver } from "@warlock.js/cache";
|
|
29
|
+
*
|
|
30
|
+
* beforeEach(async () => {
|
|
31
|
+
* cache.setCacheConfigurations({
|
|
32
|
+
* default: "mock",
|
|
33
|
+
* drivers: { mock: MockCacheDriver },
|
|
34
|
+
* options: { mock: {} },
|
|
35
|
+
* });
|
|
36
|
+
* await cache.init();
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* it("invalidates the user cache after update", async () => {
|
|
40
|
+
* await userService.update(42, { name: "Jane" });
|
|
41
|
+
*
|
|
42
|
+
* const driver = cache.currentDriver as MockCacheDriver;
|
|
43
|
+
* expect(driver.wasCalled("remove", "users.42")).toBe(true);
|
|
44
|
+
* });
|
|
45
|
+
*/
|
|
46
|
+
declare class MockCacheDriver extends BaseCacheDriver<MockCacheDriver, MockCacheOptions> implements CacheDriver<MockCacheDriver, MockCacheOptions> {
|
|
47
|
+
/**
|
|
48
|
+
* {@inheritdoc}
|
|
49
|
+
*/
|
|
50
|
+
name: string;
|
|
51
|
+
/**
|
|
52
|
+
* {@inheritdoc}
|
|
53
|
+
*/
|
|
54
|
+
options: MockCacheOptions;
|
|
55
|
+
/**
|
|
56
|
+
* Storage backing the mock — keyed by post-`parseKey` string. Public-readonly
|
|
57
|
+
* so tests can introspect raw entries when {@link getStored} isn't enough.
|
|
58
|
+
*/
|
|
59
|
+
readonly storage: Map<string, CacheData>;
|
|
60
|
+
/**
|
|
61
|
+
* Ordered record of every public operation routed through this driver.
|
|
62
|
+
* Pushed to before each op runs; tests assert via {@link wasCalled} or by
|
|
63
|
+
* inspecting the array directly.
|
|
64
|
+
*/
|
|
65
|
+
readonly callLog: CacheCall[];
|
|
66
|
+
/**
|
|
67
|
+
* Standard driver setup. Mirrors the null driver — no connection, no
|
|
68
|
+
* resources to release.
|
|
69
|
+
*/
|
|
70
|
+
connect(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Standard driver teardown.
|
|
73
|
+
*/
|
|
74
|
+
disconnect(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Wipe everything under `namespace`. Matches `MemoryCacheDriver` semantics
|
|
77
|
+
* — the namespace itself and any key with the namespace prefix is removed.
|
|
78
|
+
*/
|
|
79
|
+
removeNamespace(namespace: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Standard `set` with full `onConflict` support. Honors scope-default TTL
|
|
82
|
+
* via {@link BaseCacheDriver.resolveSetOptions}.
|
|
83
|
+
*/
|
|
84
|
+
set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions): Promise<any>;
|
|
85
|
+
/**
|
|
86
|
+
* Standard `get` with TTL handling. Emits `hit` / `miss` events to keep
|
|
87
|
+
* downstream metrics tests realistic.
|
|
88
|
+
*/
|
|
89
|
+
get<T = any>(key: CacheKey): Promise<T | null>;
|
|
90
|
+
/**
|
|
91
|
+
* Read the raw {@link CacheData} wrapper from the in-memory `Map`,
|
|
92
|
+
* including `staleAt` metadata. Returns `null` for missing or expired
|
|
93
|
+
* entries — `swr()` consumes this to branch on freshness.
|
|
94
|
+
*/
|
|
95
|
+
protected getEntry(key: CacheKey): Promise<CacheData | null>;
|
|
96
|
+
/**
|
|
97
|
+
* Standard `remove` — drops the entry and emits the `removed` event.
|
|
98
|
+
*/
|
|
99
|
+
remove(key: CacheKey): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Standard `flush` — wipes the entire mock store + tag index. Does NOT
|
|
102
|
+
* touch the call log; use {@link reset} to clear that as well.
|
|
103
|
+
*/
|
|
104
|
+
flush(): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Was a given operation invoked? When `key` is provided, the match is
|
|
107
|
+
* post-`parseKey` so callers pass the same key shape they used at the
|
|
108
|
+
* call site — strings or objects, both resolve to the same parsed key.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* driver.wasCalled("set"); // any set
|
|
112
|
+
* driver.wasCalled("set", "users.42"); // set on this specific key
|
|
113
|
+
* driver.wasCalled("set", { id: 42 }); // same — object key normalized
|
|
114
|
+
*/
|
|
115
|
+
wasCalled(operation: string, key?: CacheKey): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Return the raw stored value for `key`, bypassing TTL handling and clone
|
|
118
|
+
* protection. Useful when a test wants to assert on the persisted shape
|
|
119
|
+
* (or assert that an entry expired without going through `get`).
|
|
120
|
+
*
|
|
121
|
+
* Returns `undefined` when the key isn't present.
|
|
122
|
+
*/
|
|
123
|
+
getStored<T = any>(key: CacheKey): T | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Wipe everything — storage, tag index, and the call log. Pair with
|
|
126
|
+
* Vitest's `beforeEach` to get clean isolation between tests.
|
|
127
|
+
*/
|
|
128
|
+
reset(): void;
|
|
129
|
+
/**
|
|
130
|
+
* Append a row to {@link callLog}. Internal helper called by every
|
|
131
|
+
* recorded op before the actual work runs.
|
|
132
|
+
*/
|
|
133
|
+
protected recordCall(operation: string, key: string | undefined, args?: unknown[]): void;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { MockCacheDriver };
|
|
137
|
+
//# sourceMappingURL=mock-cache-driver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-cache-driver.d.mts","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/mock-cache-driver.ts"],"mappings":";;;;;;AAqDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,eAAA,SACH,eAAA,CAAgB,eAAA,EAAiB,gBAAA,aAC9B,WAAA,CAAY,eAAA,EAAiB,gBAAA;EAKjC;;;EAAA,IAAA;EAWkB;;;EANlB,OAAA,EAAS,gBAAA;EAmBH;;;;EAAA,SAbG,OAAA,EAAS,GAAA,SAAY,SAAA;EA8BR;;;;;EAAA,SAvBb,OAAA,EAAS,SAAA;EA+CR;;;;EAzCJ,OAAA,CAAA,GAAW,OAAA;EAuFP;;;EA/EJ,UAAA,CAAA,GAAc,OAAA;EA+EuB;;;;EAtErC,eAAA,CAAgB,SAAA,WAAoB,OAAA;EAyGA;;;;EApFpC,GAAA,CACX,GAAA,EAAK,QAAA,EACL,KAAA,OACA,YAAA,GAAe,QAAA,GAAW,eAAA,GACzB,OAAA;EAkHU;;;;EArEA,GAAA,SAAA,CAAa,GAAA,EAAK,QAAA,GAAW,OAAA,CAAQ,CAAA;EAyFd;;;;;EAAA,UAtDpB,QAAA,CAAS,GAAA,EAAK,QAAA,GAAW,OAAA,CAAQ,SAAA;EAwF1C;;;EAtEM,MAAA,CAAO,GAAA,EAAK,QAAA,GAAW,OAAA;EAkFlC;;AAAoB;;EAlET,KAAA,CAAA,GAAS,OAAA;;;;;;;;;;;EAoBf,SAAA,CAAU,SAAA,UAAmB,GAAA,GAAM,QAAA;;;;;;;;EAmBnC,SAAA,SAAA,CAAmB,GAAA,EAAK,QAAA,GAAW,CAAA;;;;;EAenC,KAAA,CAAA;;;;;YASG,UAAA,CACR,SAAA,UACA,GAAA,sBACA,IAAA;AAAA"}
|