@warlock.js/cache 5.29.0 → 5.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/cjs/index.cjs +91 -47
- package/cjs/index.cjs.map +1 -1
- package/esm/cache-manager.d.mts +1 -1
- package/esm/cache-manager.d.mts.map +1 -1
- package/esm/cache-manager.mjs +1 -1
- package/esm/cache-manager.mjs.map +1 -1
- package/esm/cached/auto-key.d.mts +1 -1
- package/esm/cached/auto-key.d.mts.map +1 -1
- package/esm/cached/auto-key.mjs +1 -1
- package/esm/cached/auto-key.mjs.map +1 -1
- package/esm/cached/cached.d.mts +1 -1
- package/esm/cached/cached.d.mts.map +1 -1
- package/esm/cached/cached.mjs +1 -1
- package/esm/cached/cached.mjs.map +1 -1
- package/esm/cached/normalize-args.d.mts +1 -1
- package/esm/cached/normalize-args.d.mts.map +1 -1
- package/esm/cached/normalize-args.mjs +1 -1
- package/esm/cached/normalize-args.mjs.map +1 -1
- package/esm/drivers/base-cache-driver.d.mts +11 -5
- package/esm/drivers/base-cache-driver.d.mts.map +1 -1
- package/esm/drivers/base-cache-driver.mjs +29 -13
- package/esm/drivers/base-cache-driver.mjs.map +1 -1
- package/esm/drivers/file-cache-driver.d.mts +1 -1
- package/esm/drivers/file-cache-driver.d.mts.map +1 -1
- package/esm/drivers/file-cache-driver.mjs +2 -2
- package/esm/drivers/file-cache-driver.mjs.map +1 -1
- package/esm/drivers/in-memory-tag-index.d.mts +1 -1
- package/esm/drivers/in-memory-tag-index.d.mts.map +1 -1
- package/esm/drivers/in-memory-tag-index.mjs +1 -1
- package/esm/drivers/in-memory-tag-index.mjs.map +1 -1
- package/esm/drivers/index.d.mts +1 -1
- package/esm/drivers/index.mjs +1 -1
- package/esm/drivers/lru-memory-cache-driver.d.mts +1 -1
- package/esm/drivers/lru-memory-cache-driver.d.mts.map +1 -1
- package/esm/drivers/lru-memory-cache-driver.mjs +3 -2
- package/esm/drivers/lru-memory-cache-driver.mjs.map +1 -1
- package/esm/drivers/memory-cache-driver.d.mts +1 -1
- package/esm/drivers/memory-cache-driver.d.mts.map +1 -1
- package/esm/drivers/memory-cache-driver.mjs +3 -2
- package/esm/drivers/memory-cache-driver.mjs.map +1 -1
- package/esm/drivers/memory-extended-cache-driver.d.mts +1 -1
- package/esm/drivers/memory-extended-cache-driver.d.mts.map +1 -1
- package/esm/drivers/memory-extended-cache-driver.mjs +1 -1
- package/esm/drivers/memory-extended-cache-driver.mjs.map +1 -1
- package/esm/drivers/mock-cache-driver.d.mts +1 -1
- package/esm/drivers/mock-cache-driver.d.mts.map +1 -1
- package/esm/drivers/mock-cache-driver.mjs +3 -2
- package/esm/drivers/mock-cache-driver.mjs.map +1 -1
- package/esm/drivers/null-cache-driver.d.mts +5 -1
- package/esm/drivers/null-cache-driver.d.mts.map +1 -1
- package/esm/drivers/null-cache-driver.mjs +17 -10
- package/esm/drivers/null-cache-driver.mjs.map +1 -1
- package/esm/drivers/pg-cache-driver.d.mts +1 -1
- package/esm/drivers/pg-cache-driver.d.mts.map +1 -1
- package/esm/drivers/pg-cache-driver.mjs +3 -2
- package/esm/drivers/pg-cache-driver.mjs.map +1 -1
- package/esm/drivers/redis-cache-driver.d.mts +14 -2
- package/esm/drivers/redis-cache-driver.d.mts.map +1 -1
- package/esm/drivers/redis-cache-driver.mjs +24 -4
- package/esm/drivers/redis-cache-driver.mjs.map +1 -1
- package/esm/index.d.mts +2 -2
- package/esm/index.mjs +2 -2
- package/esm/list/memory-cache-list.d.mts +1 -1
- package/esm/list/memory-cache-list.d.mts.map +1 -1
- package/esm/list/memory-cache-list.mjs +1 -1
- package/esm/list/memory-cache-list.mjs.map +1 -1
- package/esm/metrics.d.mts +1 -1
- package/esm/metrics.d.mts.map +1 -1
- package/esm/metrics.mjs +1 -1
- package/esm/metrics.mjs.map +1 -1
- package/esm/scoped-cache.d.mts +1 -1
- package/esm/scoped-cache.d.mts.map +1 -1
- package/esm/scoped-cache.mjs +1 -1
- package/esm/scoped-cache.mjs.map +1 -1
- package/esm/tagged-cache.d.mts +1 -1
- package/esm/tagged-cache.d.mts.map +1 -1
- package/esm/tagged-cache.mjs +1 -1
- package/esm/tagged-cache.mjs.map +1 -1
- package/esm/tagged-scoped-cache.d.mts +1 -1
- package/esm/tagged-scoped-cache.d.mts.map +1 -1
- package/esm/tagged-scoped-cache.mjs +1 -1
- package/esm/tagged-scoped-cache.mjs.map +1 -1
- package/esm/types.d.mts +1 -1
- package/esm/types.d.mts.map +1 -1
- package/esm/types.mjs +1 -1
- package/esm/types.mjs.map +1 -1
- package/esm/utils.d.mts +1 -1
- package/esm/utils.d.mts.map +1 -1
- package/esm/utils.mjs +1 -1
- package/esm/utils.mjs.map +1 -1
- package/llms-full.txt +2 -0
- package/package.json +5 -4
- package/skills/cache-basics/SKILL.md +2 -0
package/esm/cache-manager.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CacheConfigurations, CacheDriver, CacheEventHandler, CacheEventType, CacheKey, CacheListAccessor, CacheMetricsSnapshot, CacheNamespaceOptions, CacheSetOptions, CacheSimilarHit, CacheSimilarOptions, CacheSwrOptions, CacheTtl, DriverClass, LockOptions, LockOutcome, RememberOptions, ScopedCacheContract, TaggedCacheDriver } from "./types.mjs";
|
|
2
2
|
import { CacheMetricsCollector } from "./metrics.mjs";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/cache/src/cache-manager.d.ts
|
|
5
5
|
declare class CacheManager implements CacheDriver<any, any> {
|
|
6
6
|
/**
|
|
7
7
|
* Cache Driver
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-manager.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"cache-manager.d.mts","names":[],"sources":["../../../../../../../packages/cache/src/cache-manager.ts"],"mappings":"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"}
|
package/esm/cache-manager.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { CacheMetricsCollector } from "./metrics.mjs";
|
|
|
2
2
|
import { CacheConfigurationError, CacheDriverNotInitializedError } from "./types.mjs";
|
|
3
3
|
import { ScopedCache } from "./scoped-cache.mjs";
|
|
4
4
|
|
|
5
|
-
//#region
|
|
5
|
+
//#region ../../packages/cache/src/cache-manager.ts
|
|
6
6
|
var CacheManager = class {
|
|
7
7
|
constructor() {
|
|
8
8
|
this.loadedDrivers = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-manager.mjs","names":[],"sources":["../../../../../../cache/src/cache-manager.ts"],"sourcesContent":["import { CacheMetricsCollector } from \"./metrics\";\nimport { ScopedCache } from \"./scoped-cache\";\nimport type {\n CacheConfigurations,\n CacheDriver,\n CacheEventHandler,\n CacheEventType,\n CacheKey,\n CacheListAccessor,\n CacheMetricsSnapshot,\n CacheNamespaceOptions,\n CacheSetOptions,\n CacheSimilarHit,\n CacheSimilarOptions,\n CacheSwrOptions,\n CacheTtl,\n DriverClass,\n LockOptions,\n LockOutcome,\n RememberOptions,\n ScopedCacheContract,\n TaggedCacheDriver,\n} from \"./types\";\nimport { CacheConfigurationError, CacheDriverNotInitializedError } from \"./types\";\n\nexport class CacheManager implements CacheDriver<any, any> {\n /**\n * Cache Driver\n */\n public currentDriver?: CacheDriver<any, any>;\n\n /**\n * Loaded drivers\n */\n public loadedDrivers: Record<string, CacheDriver<any, any>> = {};\n\n /**\n * In-flight `load()` promises, so concurrent callers share one `connect()`.\n */\n protected loadingDrivers = new Map<string, Promise<CacheDriver<any, any>>>();\n\n /**\n * Configurations list\n */\n protected configurations: CacheConfigurations = {\n drivers: {},\n options: {},\n };\n\n /**\n * Global event listeners\n */\n protected globalEventListeners: Map<CacheEventType, Set<CacheEventHandler>> = new Map();\n\n /**\n * Metrics collector — lazy on first {@link metrics} call so apps that\n * never read metrics pay zero cost. Once instantiated, it stays\n * subscribed to events for the manager's lifetime.\n */\n protected metricsCollector?: CacheMetricsCollector;\n\n /**\n * {@inheritdoc}\n */\n public name = \"cacheManager\";\n\n /**\n * {@inheritdoc}\n */\n public get client() {\n return this.currentDriver?.client;\n }\n\n /**\n * Set the cache configurations\n */\n public setCacheConfigurations(configurations: CacheConfigurations) {\n this.configurations.default = configurations.default;\n this.configurations.drivers = configurations.drivers;\n this.configurations.options = configurations.options;\n this.configurations.logging = configurations.logging;\n }\n\n /**\n * Set logging state\n */\n public setLoggingState(loggingState: boolean) {\n this.ensureDriverInitialized();\n\n this.currentDriver!.setLoggingState(loggingState);\n }\n\n /**\n * Switch the manager to a registered driver, optionally injecting runtime\n * options that merge over the static config.\n *\n * The string form looks the driver up in `setCacheConfigurations({ drivers })`,\n * loads it (or returns the cached instance), and sets it as `currentDriver`.\n * The instance form takes a pre-built driver and bypasses the registry; the\n * `runtimeOptions` argument is silently ignored in that case because the\n * instance was constructed externally.\n *\n * Runtime options merge over `config.options[name]` per-key — runtime wins.\n * Use this for constructor-only knobs that can't live in static config\n * (e.g. `pg`'s `client: pg.Pool`).\n *\n * @example\n * const pool = new Pool({ connectionString });\n * await cache.use(\"pg\", { client: pool });\n */\n public async use(\n driver: string | CacheDriver<any, any>,\n runtimeOptions?: Record<string, any>,\n ) {\n if (typeof driver === \"string\") {\n const driverInstance = await this.load(driver, runtimeOptions);\n\n if (!driverInstance) {\n throw new CacheConfigurationError(\n `Cache driver ${driver} is not found, please declare it in the cache drivers in the configurations list.`,\n );\n }\n\n driver = driverInstance;\n }\n\n this.attachGlobalListeners(driver);\n\n if (this.configurations.logging !== undefined) {\n driver.setLoggingState(this.configurations.logging);\n }\n\n this.currentDriver = driver;\n\n return this;\n }\n\n /**\n * Ensure driver is initialized before operations\n */\n protected ensureDriverInitialized(): void {\n if (!this.currentDriver) {\n throw new CacheDriverNotInitializedError();\n }\n }\n\n /**\n * Return the running metrics snapshot — counters, hit-rate, latency\n * percentiles, per-driver breakdowns. Lazy-attaches the collector on\n * first call so apps that never read metrics pay zero cost.\n *\n * @example\n * const m = cache.metrics();\n * console.log(`hit rate: ${(m.hitRate * 100).toFixed(1)}%`);\n * console.log(`p95: ${m.latencyMs.p95.toFixed(2)}ms`);\n */\n public metrics(): CacheMetricsSnapshot {\n return this.ensureMetricsCollector().snapshot();\n }\n\n /**\n * Wipe every counter + latency sample and reset `startedAt` to now.\n * The collector itself stays subscribed to events.\n */\n public resetMetrics(): void {\n this.ensureMetricsCollector().reset();\n }\n\n /**\n * Lazy-construct the metrics collector and wire it to the global event\n * bus. Subsequent calls return the same instance — survives `cache.use()`\n * driver switches because handlers attach via `on()` and re-bind to every\n * loaded driver.\n */\n protected ensureMetricsCollector(): CacheMetricsCollector {\n if (this.metricsCollector) {\n return this.metricsCollector;\n }\n\n const collector = new CacheMetricsCollector();\n\n this.on(\"hit\", (data) => collector.recordEvent(\"hit\", data));\n this.on(\"miss\", (data) => collector.recordEvent(\"miss\", data));\n this.on(\"set\", (data) => collector.recordEvent(\"set\", data));\n this.on(\"removed\", (data) => collector.recordEvent(\"removed\", data));\n this.on(\"error\", (data) => collector.recordEvent(\"error\", data));\n\n this.metricsCollector = collector;\n\n return collector;\n }\n\n /**\n * Time the body, record the elapsed milliseconds against the metrics\n * collector for the given driver (defaults to the current driver's name).\n * Pass-through if the collector hasn't been instantiated yet — apps that\n * don't read metrics never pay for sample collection.\n */\n protected async timed<T>(\n body: () => Promise<T>,\n driverName?: string,\n ): Promise<T> {\n if (!this.metricsCollector) {\n return body();\n }\n\n const start = performance.now();\n\n try {\n return await body();\n } finally {\n const elapsed = performance.now() - start;\n const name = driverName ?? this.currentDriver?.name ?? \"unknown\";\n this.metricsCollector.recordLatency(name, elapsed);\n }\n }\n\n /**\n * {@inheritdoc}\n */\n public async get<T = any>(key: CacheKey): Promise<T | null> {\n this.ensureDriverInitialized();\n return this.timed(() => this.currentDriver!.get<T>(key));\n }\n\n /**\n * Set a value in the cache.\n *\n * Accepts a positional TTL (number of seconds or duration string like `\"1h\"`)\n * or a rich {@link CacheSetOptions} object supporting `ttl`, `expiresAt`,\n * `tags`, `onConflict`, `namespace`, and per-call `driver` overrides.\n */\n public async set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions) {\n this.ensureDriverInitialized();\n\n const driverOverride =\n ttlOrOptions && typeof ttlOrOptions === \"object\" && \"driver\" in ttlOrOptions\n ? ttlOrOptions.driver\n : undefined;\n\n if (driverOverride) {\n const driver = await this.load(driverOverride);\n return this.timed(() => driver.set(key, value, ttlOrOptions), driver.name);\n }\n\n return this.timed(() => this.currentDriver!.set(key, value, ttlOrOptions));\n }\n\n /**\n * {@inheritdoc}\n */\n public async remove(key: CacheKey) {\n this.ensureDriverInitialized();\n return this.timed(() => this.currentDriver!.remove(key));\n }\n\n /**\n * {@inheritdoc}\n */\n public async removeNamespace(namespace: string) {\n this.ensureDriverInitialized();\n return this.currentDriver!.removeNamespace(namespace);\n }\n\n /**\n * {@inheritdoc}\n */\n public async flush() {\n this.ensureDriverInitialized();\n return this.currentDriver!.flush();\n }\n\n /**\n * {@inheritdoc}\n */\n public async connect() {\n this.ensureDriverInitialized();\n return this.currentDriver!.connect();\n }\n\n /**\n * {@inheritdoc}\n */\n public parseKey(key: CacheKey) {\n this.ensureDriverInitialized();\n return this.currentDriver!.parseKey(key);\n }\n\n /**\n * {@inheritdoc}\n */\n public get options() {\n this.ensureDriverInitialized();\n return this.currentDriver!.options;\n }\n\n /**\n * {@inheritdoc}\n */\n public setOptions(options: Record<string, any>) {\n this.ensureDriverInitialized();\n return this.currentDriver!.setOptions(options || {});\n }\n\n /**\n * Return the loaded driver instance for `driverName`, loading it on first\n * call. Optional `runtimeOptions` follow the same merge-over-config rules\n * as {@link load}; passing options after the driver has already been\n * loaded throws to avoid silent swallowing.\n */\n public async driver(driverName: string, runtimeOptions?: Record<string, any>) {\n if (this.loadedDrivers[driverName]) {\n this.assertNoConflictingReload(driverName, runtimeOptions);\n\n return this.loadedDrivers[driverName];\n }\n\n return this.load(driverName, runtimeOptions);\n }\n\n /**\n * Initialize the cache manager and pick the default driver\n */\n public async init() {\n const defaultCacheDriverName = this.configurations.default;\n\n if (!defaultCacheDriverName) {\n return;\n }\n\n const driver = await this.driver(defaultCacheDriverName);\n\n await this.use(driver);\n }\n\n /**\n * Load and connect the registered driver named `driver`. First-call wins —\n * subsequent calls without `runtimeOptions` return the cached instance, and\n * subsequent calls *with* `runtimeOptions` throw {@link CacheConfigurationError}\n * to avoid silently dropping the new options.\n *\n * `runtimeOptions` merge over `config.options[driver]` per-key (runtime wins),\n * letting consumers split static knobs (table, ttl, globalPrefix) from\n * constructor-only ones (pg's `client`, custom adapters, etc.).\n *\n * @example\n * const pool = new Pool({ connectionString });\n * const pg = await cache.load(\"pg\", { client: pool });\n */\n public async load(driver: string, runtimeOptions?: Record<string, any>) {\n if (this.loadedDrivers[driver]) {\n this.assertNoConflictingReload(driver, runtimeOptions);\n\n return this.loadedDrivers[driver];\n }\n\n const inFlight = this.loadingDrivers.get(driver);\n\n if (inFlight) {\n this.assertNoConflictingReload(driver, runtimeOptions);\n\n return inFlight;\n }\n\n const Driver = this.configurations.drivers[\n driver as keyof typeof this.configurations.drivers\n ] as DriverClass | undefined;\n\n if (!Driver) {\n throw new CacheConfigurationError(\n `Cache driver ${driver} is not found, please declare it in the cache drivers in the configurations list.`,\n );\n }\n\n const driverInstance = new Driver();\n const configOptions =\n this.configurations.options[driver as keyof typeof this.configurations.options] || {};\n\n driverInstance.setOptions({ ...configOptions, ...(runtimeOptions ?? {}) });\n\n const promise = (async () => {\n try {\n await driverInstance.connect();\n\n this.attachGlobalListeners(driverInstance);\n\n this.loadedDrivers[driver] = driverInstance;\n\n return driverInstance as CacheDriver<any, any>;\n } finally {\n this.loadingDrivers.delete(driver);\n }\n })();\n\n this.loadingDrivers.set(driver, promise);\n\n return promise;\n }\n\n /**\n * Guard against silently dropping runtime options on a re-load. Once a\n * driver has been instantiated, its options are frozen — calling `load` /\n * `driver` / `use` again with a non-empty `runtimeOptions` would otherwise\n * appear to work but actually use the original options. We throw instead\n * so the misuse surfaces at the call site.\n */\n protected assertNoConflictingReload(\n driverName: string,\n runtimeOptions: Record<string, any> | undefined,\n ): void {\n if (runtimeOptions === undefined) {\n return;\n }\n\n if (Object.keys(runtimeOptions).length === 0) {\n return;\n }\n\n throw new CacheConfigurationError(\n `Cache driver '${driverName}' is already loaded; runtime options on subsequent calls are ignored — register a second driver name if you need a different configuration.`,\n );\n }\n\n /**\n * Register and bind a driver\n */\n public registerDriver(driverName: string, driverClass: DriverClass) {\n (this.configurations.drivers as Record<string, DriverClass>)[driverName] = driverClass;\n }\n\n /**\n * Disconnect the cache manager\n */\n public async disconnect() {\n const drivers = new Set<any>(Object.values(this.loadedDrivers));\n\n if (this.currentDriver) {\n drivers.add(this.currentDriver);\n }\n\n await Promise.allSettled([...drivers].map(driver => driver.disconnect()));\n\n for (const name of Object.keys(this.loadedDrivers)) {\n delete this.loadedDrivers[name];\n }\n\n this.loadingDrivers.clear();\n }\n\n /**\n * {@inheritdoc}\n */\n public async has(key: CacheKey): Promise<boolean> {\n this.ensureDriverInitialized();\n return this.currentDriver!.has(key);\n }\n\n /**\n * {@inheritdoc}\n */\n public async remember<T = any>(\n key: CacheKey,\n ttlOrOptions: CacheTtl | RememberOptions,\n callback: () => Promise<T>,\n ): Promise<T> {\n this.ensureDriverInitialized();\n\n const driverOverride =\n ttlOrOptions && typeof ttlOrOptions === \"object\" && \"driver\" in ttlOrOptions\n ? ttlOrOptions.driver\n : undefined;\n\n if (driverOverride) {\n const driver = await this.load(driverOverride);\n return driver.remember(key, ttlOrOptions, callback);\n }\n\n return this.currentDriver!.remember(key, ttlOrOptions, callback);\n }\n\n /**\n * Stale-while-revalidate. Returns cached when fresh, returns the stale\n * value plus a background refresh when within `freshTtl..staleTtl`,\n * blocks like a normal miss past `staleTtl`. Honors per-call `driver`\n * override the same way `remember()` does.\n *\n * @example\n * const product = await cache.swr(\n * \"product.42\",\n * { freshTtl: \"1m\", staleTtl: \"1h\" },\n * () => db.products.find(42),\n * );\n */\n public async swr<T = any>(\n key: CacheKey,\n options: CacheSwrOptions,\n callback: () => Promise<T>,\n ): Promise<T> {\n this.ensureDriverInitialized();\n\n const driverOverride = options.driver;\n\n if (driverOverride) {\n const driver = await this.load(driverOverride);\n\n return driver.swr<T>(key, options, callback);\n }\n\n return this.currentDriver!.swr<T>(key, options, callback);\n }\n\n /**\n * {@inheritdoc}\n */\n public async pull(key: CacheKey): Promise<any | null> {\n this.ensureDriverInitialized();\n return this.currentDriver!.pull(key);\n }\n\n /**\n * {@inheritdoc}\n */\n public async forever(key: CacheKey, value: any): Promise<any> {\n this.ensureDriverInitialized();\n return this.currentDriver!.forever(key, value);\n }\n\n /**\n * {@inheritdoc}\n */\n public async increment(key: CacheKey, value?: number): Promise<number> {\n this.ensureDriverInitialized();\n return this.currentDriver!.increment(key, value);\n }\n\n /**\n * {@inheritdoc}\n */\n public async decrement(key: CacheKey, value?: number): Promise<number> {\n this.ensureDriverInitialized();\n return this.currentDriver!.decrement(key, value);\n }\n\n /**\n * {@inheritdoc}\n */\n public async many(keys: CacheKey[]): Promise<any[]> {\n this.ensureDriverInitialized();\n return this.currentDriver!.many(keys);\n }\n\n /**\n * {@inheritdoc}\n */\n public async setMany(items: Record<string, any>, ttl?: number): Promise<void> {\n this.ensureDriverInitialized();\n return this.currentDriver!.setMany(items, ttl);\n }\n\n /**\n * Register a global event listener (applies to all drivers)\n */\n public on(event: CacheEventType, handler: CacheEventHandler): this {\n if (!this.globalEventListeners.has(event)) {\n this.globalEventListeners.set(event, new Set());\n }\n this.globalEventListeners.get(event)!.add(handler);\n\n // Also attach to current driver if exists\n if (this.currentDriver) {\n this.currentDriver.on(event, handler);\n }\n\n // Attach to all loaded drivers\n for (const driver of Object.values(this.loadedDrivers)) {\n driver.on(event, handler);\n }\n\n return this;\n }\n\n /**\n * Remove a global event listener\n */\n public off(event: CacheEventType, handler: CacheEventHandler): this {\n const handlers = this.globalEventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n\n // Also remove from current driver\n if (this.currentDriver) {\n this.currentDriver.off(event, handler);\n }\n\n // Remove from all loaded drivers\n for (const driver of Object.values(this.loadedDrivers)) {\n driver.off(event, handler);\n }\n\n return this;\n }\n\n /**\n * Register a one-time global event listener\n */\n public once(event: CacheEventType, handler: CacheEventHandler): this {\n const onceHandler: CacheEventHandler = async (data) => {\n await handler(data);\n this.off(event, onceHandler);\n };\n return this.on(event, onceHandler);\n }\n\n /**\n * Attach global listeners to a driver\n */\n protected attachGlobalListeners(driver: CacheDriver<any, any>) {\n for (const [event, handlers] of this.globalEventListeners) {\n for (const handler of handlers) {\n driver.on(event, handler);\n }\n }\n }\n\n /**\n * Set if not exists (atomic operation)\n * Returns true if key was set, false if key already existed\n * Note: Only supported by drivers that implement setNX (e.g., Redis)\n */\n public async setNX(key: CacheKey, value: any, ttl?: number): Promise<boolean> {\n this.ensureDriverInitialized();\n\n if (!this.currentDriver!.setNX) {\n throw new Error(\n `setNX is not supported by the current cache driver: ${this.currentDriver!.name}`,\n );\n }\n\n return this.currentDriver!.setNX(key, value, ttl);\n }\n\n /**\n * Create a tagged cache instance for the given tags\n */\n public tags(tags: string[]): TaggedCacheDriver {\n this.ensureDriverInitialized();\n return this.currentDriver!.tags(tags);\n }\n\n /**\n * Atomically read, transform, and write a cached value. Delegates to the current driver.\n */\n public async update<T = any>(\n key: CacheKey,\n fn: (current: T | null) => T | null | Promise<T | null>,\n options?: { ttl?: CacheTtl },\n ): Promise<T | null> {\n this.ensureDriverInitialized();\n return this.currentDriver!.update<T>(key, fn, options);\n }\n\n /**\n * Shallow-merge a partial object into a cached value.\n */\n public async merge<T extends Record<string, any> = Record<string, any>>(\n key: CacheKey,\n partial: Partial<T>,\n options?: { ttl?: CacheTtl },\n ): Promise<T> {\n this.ensureDriverInitialized();\n return this.currentDriver!.merge<T>(key, partial, options);\n }\n\n /**\n * Obtain a list accessor bound to the current driver.\n */\n public list<T = any>(key: CacheKey): CacheListAccessor<T> {\n this.ensureDriverInitialized();\n return this.currentDriver!.list<T>(key);\n }\n\n /**\n * Acquire a distributed lock, run `fn`, and auto-release. Returns a\n * {@link LockOutcome} discriminated union so callers can distinguish\n * \"ran and got this value\" from \"skipped because someone else holds it\".\n *\n * Honors the `driver` option for per-call driver override, same as `set`\n * and `remember`.\n *\n * @example\n * const outcome = await cache.lock(\"lock.import\", \"5m\", async () => {\n * await runImport();\n * return \"done\";\n * });\n * if (!outcome.acquired) {\n * console.log(\"another worker is already importing\");\n * }\n */\n public async lock<T>(\n key: CacheKey,\n ttlOrOptions: CacheTtl | LockOptions,\n fn: () => Promise<T>,\n ): Promise<LockOutcome<T>> {\n this.ensureDriverInitialized();\n\n const driverOverride =\n ttlOrOptions && typeof ttlOrOptions === \"object\" && \"driver\" in ttlOrOptions\n ? ttlOrOptions.driver\n : undefined;\n\n const driver = driverOverride\n ? await this.load(driverOverride)\n : this.currentDriver!;\n\n return driver.lock<T>(key, ttlOrOptions as CacheTtl | Omit<LockOptions, \"driver\">, fn);\n }\n\n /**\n * Similarity retrieval. Delegates to the current driver's `similar()` impl.\n *\n * Drivers that lack a similarity index throw {@link CacheUnsupportedError}.\n *\n * @example\n * const hits = await cache.similar(await embed(query), { topK: 5, threshold: 0.7 });\n */\n /**\n * Create a scoped view over the cache. Every key written through the\n * returned scope is automatically prefixed with `prefix`; optional defaults\n * (`ttl`, `tags`) flow through every write inside the scope.\n *\n * Per-call options always win over scope defaults. Scope tags merge\n * additively with per-call tags. Nested scopes inherit from the parent.\n *\n * @example\n * const chat = cache.namespace(\"chats.10\", { ttl: \"30d\" });\n * await chat.set(\"messages.1\", msg); // → \"chats.10.messages.1\", 30d\n * await chat.set(\"draft\", d, { ttl: \"1h\" }); // per-call ttl wins\n * await chat.namespace(\"typing\", { ttl: \"5s\" }).set(\"user.42\", true);\n * await chat.clear(); // wipe the whole scope\n */\n public namespace(prefix: string, options?: CacheNamespaceOptions): ScopedCacheContract {\n this.ensureDriverInitialized();\n return new ScopedCache(this, prefix, options);\n }\n\n public async similar<T = any>(\n vector: number[],\n options: CacheSimilarOptions,\n ): Promise<CacheSimilarHit<T>[]> {\n this.ensureDriverInitialized();\n return this.currentDriver!.similar<T>(vector, options);\n }\n}\n\nexport const cache = new CacheManager();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cache-manager.mjs","names":[],"sources":["../../../../../../../packages/cache/src/cache-manager.ts"],"sourcesContent":["import { CacheMetricsCollector } from \"./metrics\";\nimport { ScopedCache } from \"./scoped-cache\";\nimport type {\n CacheConfigurations,\n CacheDriver,\n CacheEventHandler,\n CacheEventType,\n CacheKey,\n CacheListAccessor,\n CacheMetricsSnapshot,\n CacheNamespaceOptions,\n CacheSetOptions,\n CacheSimilarHit,\n CacheSimilarOptions,\n CacheSwrOptions,\n CacheTtl,\n DriverClass,\n LockOptions,\n LockOutcome,\n RememberOptions,\n ScopedCacheContract,\n TaggedCacheDriver,\n} from \"./types\";\nimport { CacheConfigurationError, CacheDriverNotInitializedError } from \"./types\";\n\nexport class CacheManager implements CacheDriver<any, any> {\n /**\n * Cache Driver\n */\n public currentDriver?: CacheDriver<any, any>;\n\n /**\n * Loaded drivers\n */\n public loadedDrivers: Record<string, CacheDriver<any, any>> = {};\n\n /**\n * In-flight `load()` promises, so concurrent callers share one `connect()`.\n */\n protected loadingDrivers = new Map<string, Promise<CacheDriver<any, any>>>();\n\n /**\n * Configurations list\n */\n protected configurations: CacheConfigurations = {\n drivers: {},\n options: {},\n };\n\n /**\n * Global event listeners\n */\n protected globalEventListeners: Map<CacheEventType, Set<CacheEventHandler>> = new Map();\n\n /**\n * Metrics collector — lazy on first {@link metrics} call so apps that\n * never read metrics pay zero cost. Once instantiated, it stays\n * subscribed to events for the manager's lifetime.\n */\n protected metricsCollector?: CacheMetricsCollector;\n\n /**\n * {@inheritdoc}\n */\n public name = \"cacheManager\";\n\n /**\n * {@inheritdoc}\n */\n public get client() {\n return this.currentDriver?.client;\n }\n\n /**\n * Set the cache configurations\n */\n public setCacheConfigurations(configurations: CacheConfigurations) {\n this.configurations.default = configurations.default;\n this.configurations.drivers = configurations.drivers;\n this.configurations.options = configurations.options;\n this.configurations.logging = configurations.logging;\n }\n\n /**\n * Set logging state\n */\n public setLoggingState(loggingState: boolean) {\n this.ensureDriverInitialized();\n\n this.currentDriver!.setLoggingState(loggingState);\n }\n\n /**\n * Switch the manager to a registered driver, optionally injecting runtime\n * options that merge over the static config.\n *\n * The string form looks the driver up in `setCacheConfigurations({ drivers })`,\n * loads it (or returns the cached instance), and sets it as `currentDriver`.\n * The instance form takes a pre-built driver and bypasses the registry; the\n * `runtimeOptions` argument is silently ignored in that case because the\n * instance was constructed externally.\n *\n * Runtime options merge over `config.options[name]` per-key — runtime wins.\n * Use this for constructor-only knobs that can't live in static config\n * (e.g. `pg`'s `client: pg.Pool`).\n *\n * @example\n * const pool = new Pool({ connectionString });\n * await cache.use(\"pg\", { client: pool });\n */\n public async use(\n driver: string | CacheDriver<any, any>,\n runtimeOptions?: Record<string, any>,\n ) {\n if (typeof driver === \"string\") {\n const driverInstance = await this.load(driver, runtimeOptions);\n\n if (!driverInstance) {\n throw new CacheConfigurationError(\n `Cache driver ${driver} is not found, please declare it in the cache drivers in the configurations list.`,\n );\n }\n\n driver = driverInstance;\n }\n\n this.attachGlobalListeners(driver);\n\n if (this.configurations.logging !== undefined) {\n driver.setLoggingState(this.configurations.logging);\n }\n\n this.currentDriver = driver;\n\n return this;\n }\n\n /**\n * Ensure driver is initialized before operations\n */\n protected ensureDriverInitialized(): void {\n if (!this.currentDriver) {\n throw new CacheDriverNotInitializedError();\n }\n }\n\n /**\n * Return the running metrics snapshot — counters, hit-rate, latency\n * percentiles, per-driver breakdowns. Lazy-attaches the collector on\n * first call so apps that never read metrics pay zero cost.\n *\n * @example\n * const m = cache.metrics();\n * console.log(`hit rate: ${(m.hitRate * 100).toFixed(1)}%`);\n * console.log(`p95: ${m.latencyMs.p95.toFixed(2)}ms`);\n */\n public metrics(): CacheMetricsSnapshot {\n return this.ensureMetricsCollector().snapshot();\n }\n\n /**\n * Wipe every counter + latency sample and reset `startedAt` to now.\n * The collector itself stays subscribed to events.\n */\n public resetMetrics(): void {\n this.ensureMetricsCollector().reset();\n }\n\n /**\n * Lazy-construct the metrics collector and wire it to the global event\n * bus. Subsequent calls return the same instance — survives `cache.use()`\n * driver switches because handlers attach via `on()` and re-bind to every\n * loaded driver.\n */\n protected ensureMetricsCollector(): CacheMetricsCollector {\n if (this.metricsCollector) {\n return this.metricsCollector;\n }\n\n const collector = new CacheMetricsCollector();\n\n this.on(\"hit\", (data) => collector.recordEvent(\"hit\", data));\n this.on(\"miss\", (data) => collector.recordEvent(\"miss\", data));\n this.on(\"set\", (data) => collector.recordEvent(\"set\", data));\n this.on(\"removed\", (data) => collector.recordEvent(\"removed\", data));\n this.on(\"error\", (data) => collector.recordEvent(\"error\", data));\n\n this.metricsCollector = collector;\n\n return collector;\n }\n\n /**\n * Time the body, record the elapsed milliseconds against the metrics\n * collector for the given driver (defaults to the current driver's name).\n * Pass-through if the collector hasn't been instantiated yet — apps that\n * don't read metrics never pay for sample collection.\n */\n protected async timed<T>(\n body: () => Promise<T>,\n driverName?: string,\n ): Promise<T> {\n if (!this.metricsCollector) {\n return body();\n }\n\n const start = performance.now();\n\n try {\n return await body();\n } finally {\n const elapsed = performance.now() - start;\n const name = driverName ?? this.currentDriver?.name ?? \"unknown\";\n this.metricsCollector.recordLatency(name, elapsed);\n }\n }\n\n /**\n * {@inheritdoc}\n */\n public async get<T = any>(key: CacheKey): Promise<T | null> {\n this.ensureDriverInitialized();\n return this.timed(() => this.currentDriver!.get<T>(key));\n }\n\n /**\n * Set a value in the cache.\n *\n * Accepts a positional TTL (number of seconds or duration string like `\"1h\"`)\n * or a rich {@link CacheSetOptions} object supporting `ttl`, `expiresAt`,\n * `tags`, `onConflict`, `namespace`, and per-call `driver` overrides.\n */\n public async set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions) {\n this.ensureDriverInitialized();\n\n const driverOverride =\n ttlOrOptions && typeof ttlOrOptions === \"object\" && \"driver\" in ttlOrOptions\n ? ttlOrOptions.driver\n : undefined;\n\n if (driverOverride) {\n const driver = await this.load(driverOverride);\n return this.timed(() => driver.set(key, value, ttlOrOptions), driver.name);\n }\n\n return this.timed(() => this.currentDriver!.set(key, value, ttlOrOptions));\n }\n\n /**\n * {@inheritdoc}\n */\n public async remove(key: CacheKey) {\n this.ensureDriverInitialized();\n return this.timed(() => this.currentDriver!.remove(key));\n }\n\n /**\n * {@inheritdoc}\n */\n public async removeNamespace(namespace: string) {\n this.ensureDriverInitialized();\n return this.currentDriver!.removeNamespace(namespace);\n }\n\n /**\n * {@inheritdoc}\n */\n public async flush() {\n this.ensureDriverInitialized();\n return this.currentDriver!.flush();\n }\n\n /**\n * {@inheritdoc}\n */\n public async connect() {\n this.ensureDriverInitialized();\n return this.currentDriver!.connect();\n }\n\n /**\n * {@inheritdoc}\n */\n public parseKey(key: CacheKey) {\n this.ensureDriverInitialized();\n return this.currentDriver!.parseKey(key);\n }\n\n /**\n * {@inheritdoc}\n */\n public get options() {\n this.ensureDriverInitialized();\n return this.currentDriver!.options;\n }\n\n /**\n * {@inheritdoc}\n */\n public setOptions(options: Record<string, any>) {\n this.ensureDriverInitialized();\n return this.currentDriver!.setOptions(options || {});\n }\n\n /**\n * Return the loaded driver instance for `driverName`, loading it on first\n * call. Optional `runtimeOptions` follow the same merge-over-config rules\n * as {@link load}; passing options after the driver has already been\n * loaded throws to avoid silent swallowing.\n */\n public async driver(driverName: string, runtimeOptions?: Record<string, any>) {\n if (this.loadedDrivers[driverName]) {\n this.assertNoConflictingReload(driverName, runtimeOptions);\n\n return this.loadedDrivers[driverName];\n }\n\n return this.load(driverName, runtimeOptions);\n }\n\n /**\n * Initialize the cache manager and pick the default driver\n */\n public async init() {\n const defaultCacheDriverName = this.configurations.default;\n\n if (!defaultCacheDriverName) {\n return;\n }\n\n const driver = await this.driver(defaultCacheDriverName);\n\n await this.use(driver);\n }\n\n /**\n * Load and connect the registered driver named `driver`. First-call wins —\n * subsequent calls without `runtimeOptions` return the cached instance, and\n * subsequent calls *with* `runtimeOptions` throw {@link CacheConfigurationError}\n * to avoid silently dropping the new options.\n *\n * `runtimeOptions` merge over `config.options[driver]` per-key (runtime wins),\n * letting consumers split static knobs (table, ttl, globalPrefix) from\n * constructor-only ones (pg's `client`, custom adapters, etc.).\n *\n * @example\n * const pool = new Pool({ connectionString });\n * const pg = await cache.load(\"pg\", { client: pool });\n */\n public async load(driver: string, runtimeOptions?: Record<string, any>) {\n if (this.loadedDrivers[driver]) {\n this.assertNoConflictingReload(driver, runtimeOptions);\n\n return this.loadedDrivers[driver];\n }\n\n const inFlight = this.loadingDrivers.get(driver);\n\n if (inFlight) {\n this.assertNoConflictingReload(driver, runtimeOptions);\n\n return inFlight;\n }\n\n const Driver = this.configurations.drivers[\n driver as keyof typeof this.configurations.drivers\n ] as DriverClass | undefined;\n\n if (!Driver) {\n throw new CacheConfigurationError(\n `Cache driver ${driver} is not found, please declare it in the cache drivers in the configurations list.`,\n );\n }\n\n const driverInstance = new Driver();\n const configOptions =\n this.configurations.options[driver as keyof typeof this.configurations.options] || {};\n\n driverInstance.setOptions({ ...configOptions, ...(runtimeOptions ?? {}) });\n\n const promise = (async () => {\n try {\n await driverInstance.connect();\n\n this.attachGlobalListeners(driverInstance);\n\n this.loadedDrivers[driver] = driverInstance;\n\n return driverInstance as CacheDriver<any, any>;\n } finally {\n this.loadingDrivers.delete(driver);\n }\n })();\n\n this.loadingDrivers.set(driver, promise);\n\n return promise;\n }\n\n /**\n * Guard against silently dropping runtime options on a re-load. Once a\n * driver has been instantiated, its options are frozen — calling `load` /\n * `driver` / `use` again with a non-empty `runtimeOptions` would otherwise\n * appear to work but actually use the original options. We throw instead\n * so the misuse surfaces at the call site.\n */\n protected assertNoConflictingReload(\n driverName: string,\n runtimeOptions: Record<string, any> | undefined,\n ): void {\n if (runtimeOptions === undefined) {\n return;\n }\n\n if (Object.keys(runtimeOptions).length === 0) {\n return;\n }\n\n throw new CacheConfigurationError(\n `Cache driver '${driverName}' is already loaded; runtime options on subsequent calls are ignored — register a second driver name if you need a different configuration.`,\n );\n }\n\n /**\n * Register and bind a driver\n */\n public registerDriver(driverName: string, driverClass: DriverClass) {\n (this.configurations.drivers as Record<string, DriverClass>)[driverName] = driverClass;\n }\n\n /**\n * Disconnect the cache manager\n */\n public async disconnect() {\n const drivers = new Set<any>(Object.values(this.loadedDrivers));\n\n if (this.currentDriver) {\n drivers.add(this.currentDriver);\n }\n\n await Promise.allSettled([...drivers].map(driver => driver.disconnect()));\n\n for (const name of Object.keys(this.loadedDrivers)) {\n delete this.loadedDrivers[name];\n }\n\n this.loadingDrivers.clear();\n }\n\n /**\n * {@inheritdoc}\n */\n public async has(key: CacheKey): Promise<boolean> {\n this.ensureDriverInitialized();\n return this.currentDriver!.has(key);\n }\n\n /**\n * {@inheritdoc}\n */\n public async remember<T = any>(\n key: CacheKey,\n ttlOrOptions: CacheTtl | RememberOptions,\n callback: () => Promise<T>,\n ): Promise<T> {\n this.ensureDriverInitialized();\n\n const driverOverride =\n ttlOrOptions && typeof ttlOrOptions === \"object\" && \"driver\" in ttlOrOptions\n ? ttlOrOptions.driver\n : undefined;\n\n if (driverOverride) {\n const driver = await this.load(driverOverride);\n return driver.remember(key, ttlOrOptions, callback);\n }\n\n return this.currentDriver!.remember(key, ttlOrOptions, callback);\n }\n\n /**\n * Stale-while-revalidate. Returns cached when fresh, returns the stale\n * value plus a background refresh when within `freshTtl..staleTtl`,\n * blocks like a normal miss past `staleTtl`. Honors per-call `driver`\n * override the same way `remember()` does.\n *\n * @example\n * const product = await cache.swr(\n * \"product.42\",\n * { freshTtl: \"1m\", staleTtl: \"1h\" },\n * () => db.products.find(42),\n * );\n */\n public async swr<T = any>(\n key: CacheKey,\n options: CacheSwrOptions,\n callback: () => Promise<T>,\n ): Promise<T> {\n this.ensureDriverInitialized();\n\n const driverOverride = options.driver;\n\n if (driverOverride) {\n const driver = await this.load(driverOverride);\n\n return driver.swr<T>(key, options, callback);\n }\n\n return this.currentDriver!.swr<T>(key, options, callback);\n }\n\n /**\n * {@inheritdoc}\n */\n public async pull(key: CacheKey): Promise<any | null> {\n this.ensureDriverInitialized();\n return this.currentDriver!.pull(key);\n }\n\n /**\n * {@inheritdoc}\n */\n public async forever(key: CacheKey, value: any): Promise<any> {\n this.ensureDriverInitialized();\n return this.currentDriver!.forever(key, value);\n }\n\n /**\n * {@inheritdoc}\n */\n public async increment(key: CacheKey, value?: number): Promise<number> {\n this.ensureDriverInitialized();\n return this.currentDriver!.increment(key, value);\n }\n\n /**\n * {@inheritdoc}\n */\n public async decrement(key: CacheKey, value?: number): Promise<number> {\n this.ensureDriverInitialized();\n return this.currentDriver!.decrement(key, value);\n }\n\n /**\n * {@inheritdoc}\n */\n public async many(keys: CacheKey[]): Promise<any[]> {\n this.ensureDriverInitialized();\n return this.currentDriver!.many(keys);\n }\n\n /**\n * {@inheritdoc}\n */\n public async setMany(items: Record<string, any>, ttl?: number): Promise<void> {\n this.ensureDriverInitialized();\n return this.currentDriver!.setMany(items, ttl);\n }\n\n /**\n * Register a global event listener (applies to all drivers)\n */\n public on(event: CacheEventType, handler: CacheEventHandler): this {\n if (!this.globalEventListeners.has(event)) {\n this.globalEventListeners.set(event, new Set());\n }\n this.globalEventListeners.get(event)!.add(handler);\n\n // Also attach to current driver if exists\n if (this.currentDriver) {\n this.currentDriver.on(event, handler);\n }\n\n // Attach to all loaded drivers\n for (const driver of Object.values(this.loadedDrivers)) {\n driver.on(event, handler);\n }\n\n return this;\n }\n\n /**\n * Remove a global event listener\n */\n public off(event: CacheEventType, handler: CacheEventHandler): this {\n const handlers = this.globalEventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n\n // Also remove from current driver\n if (this.currentDriver) {\n this.currentDriver.off(event, handler);\n }\n\n // Remove from all loaded drivers\n for (const driver of Object.values(this.loadedDrivers)) {\n driver.off(event, handler);\n }\n\n return this;\n }\n\n /**\n * Register a one-time global event listener\n */\n public once(event: CacheEventType, handler: CacheEventHandler): this {\n const onceHandler: CacheEventHandler = async (data) => {\n await handler(data);\n this.off(event, onceHandler);\n };\n return this.on(event, onceHandler);\n }\n\n /**\n * Attach global listeners to a driver\n */\n protected attachGlobalListeners(driver: CacheDriver<any, any>) {\n for (const [event, handlers] of this.globalEventListeners) {\n for (const handler of handlers) {\n driver.on(event, handler);\n }\n }\n }\n\n /**\n * Set if not exists (atomic operation)\n * Returns true if key was set, false if key already existed\n * Note: Only supported by drivers that implement setNX (e.g., Redis)\n */\n public async setNX(key: CacheKey, value: any, ttl?: number): Promise<boolean> {\n this.ensureDriverInitialized();\n\n if (!this.currentDriver!.setNX) {\n throw new Error(\n `setNX is not supported by the current cache driver: ${this.currentDriver!.name}`,\n );\n }\n\n return this.currentDriver!.setNX(key, value, ttl);\n }\n\n /**\n * Create a tagged cache instance for the given tags\n */\n public tags(tags: string[]): TaggedCacheDriver {\n this.ensureDriverInitialized();\n return this.currentDriver!.tags(tags);\n }\n\n /**\n * Atomically read, transform, and write a cached value. Delegates to the current driver.\n */\n public async update<T = any>(\n key: CacheKey,\n fn: (current: T | null) => T | null | Promise<T | null>,\n options?: { ttl?: CacheTtl },\n ): Promise<T | null> {\n this.ensureDriverInitialized();\n return this.currentDriver!.update<T>(key, fn, options);\n }\n\n /**\n * Shallow-merge a partial object into a cached value.\n */\n public async merge<T extends Record<string, any> = Record<string, any>>(\n key: CacheKey,\n partial: Partial<T>,\n options?: { ttl?: CacheTtl },\n ): Promise<T> {\n this.ensureDriverInitialized();\n return this.currentDriver!.merge<T>(key, partial, options);\n }\n\n /**\n * Obtain a list accessor bound to the current driver.\n */\n public list<T = any>(key: CacheKey): CacheListAccessor<T> {\n this.ensureDriverInitialized();\n return this.currentDriver!.list<T>(key);\n }\n\n /**\n * Acquire a distributed lock, run `fn`, and auto-release. Returns a\n * {@link LockOutcome} discriminated union so callers can distinguish\n * \"ran and got this value\" from \"skipped because someone else holds it\".\n *\n * Honors the `driver` option for per-call driver override, same as `set`\n * and `remember`.\n *\n * @example\n * const outcome = await cache.lock(\"lock.import\", \"5m\", async () => {\n * await runImport();\n * return \"done\";\n * });\n * if (!outcome.acquired) {\n * console.log(\"another worker is already importing\");\n * }\n */\n public async lock<T>(\n key: CacheKey,\n ttlOrOptions: CacheTtl | LockOptions,\n fn: () => Promise<T>,\n ): Promise<LockOutcome<T>> {\n this.ensureDriverInitialized();\n\n const driverOverride =\n ttlOrOptions && typeof ttlOrOptions === \"object\" && \"driver\" in ttlOrOptions\n ? ttlOrOptions.driver\n : undefined;\n\n const driver = driverOverride\n ? await this.load(driverOverride)\n : this.currentDriver!;\n\n return driver.lock<T>(key, ttlOrOptions as CacheTtl | Omit<LockOptions, \"driver\">, fn);\n }\n\n /**\n * Similarity retrieval. Delegates to the current driver's `similar()` impl.\n *\n * Drivers that lack a similarity index throw {@link CacheUnsupportedError}.\n *\n * @example\n * const hits = await cache.similar(await embed(query), { topK: 5, threshold: 0.7 });\n */\n /**\n * Create a scoped view over the cache. Every key written through the\n * returned scope is automatically prefixed with `prefix`; optional defaults\n * (`ttl`, `tags`) flow through every write inside the scope.\n *\n * Per-call options always win over scope defaults. Scope tags merge\n * additively with per-call tags. Nested scopes inherit from the parent.\n *\n * @example\n * const chat = cache.namespace(\"chats.10\", { ttl: \"30d\" });\n * await chat.set(\"messages.1\", msg); // → \"chats.10.messages.1\", 30d\n * await chat.set(\"draft\", d, { ttl: \"1h\" }); // per-call ttl wins\n * await chat.namespace(\"typing\", { ttl: \"5s\" }).set(\"user.42\", true);\n * await chat.clear(); // wipe the whole scope\n */\n public namespace(prefix: string, options?: CacheNamespaceOptions): ScopedCacheContract {\n this.ensureDriverInitialized();\n return new ScopedCache(this, prefix, options);\n }\n\n public async similar<T = any>(\n vector: number[],\n options: CacheSimilarOptions,\n ): Promise<CacheSimilarHit<T>[]> {\n this.ensureDriverInitialized();\n return this.currentDriver!.similar<T>(vector, options);\n }\n}\n\nexport const cache = new CacheManager();\n"],"mappings":";;;;;AAyBA,IAAa,eAAb,MAA2D;;uBASK,CAAC;wCAKpC,IAAI,IAA4C;wBAK3B;GAC9C,SAAS,CAAC;GACV,SAAS,CAAC;EACZ;8CAK8E,IAAI,IAAI;cAYxE;;;;;CAKd,IAAW,SAAS;EAClB,OAAO,KAAK,eAAe;CAC7B;;;;CAKA,AAAO,uBAAuB,gBAAqC;EACjE,KAAK,eAAe,UAAU,eAAe;EAC7C,KAAK,eAAe,UAAU,eAAe;EAC7C,KAAK,eAAe,UAAU,eAAe;EAC7C,KAAK,eAAe,UAAU,eAAe;CAC/C;;;;CAKA,AAAO,gBAAgB,cAAuB;EAC5C,KAAK,wBAAwB;EAE7B,KAAK,cAAe,gBAAgB,YAAY;CAClD;;;;;;;;;;;;;;;;;;;CAoBA,MAAa,IACX,QACA,gBACA;EACA,IAAI,OAAO,WAAW,UAAU;GAC9B,MAAM,iBAAiB,MAAM,KAAK,KAAK,QAAQ,cAAc;GAE7D,IAAI,CAAC,gBACH,MAAM,IAAI,wBACR,gBAAgB,OAAO,kFACzB;GAGF,SAAS;EACX;EAEA,KAAK,sBAAsB,MAAM;EAEjC,IAAI,KAAK,eAAe,YAAY,QAClC,OAAO,gBAAgB,KAAK,eAAe,OAAO;EAGpD,KAAK,gBAAgB;EAErB,OAAO;CACT;;;;CAKA,AAAU,0BAAgC;EACxC,IAAI,CAAC,KAAK,eACR,MAAM,IAAI,+BAA+B;CAE7C;;;;;;;;;;;CAYA,AAAO,UAAgC;EACrC,OAAO,KAAK,uBAAuB,CAAC,CAAC,SAAS;CAChD;;;;;CAMA,AAAO,eAAqB;EAC1B,KAAK,uBAAuB,CAAC,CAAC,MAAM;CACtC;;;;;;;CAQA,AAAU,yBAAgD;EACxD,IAAI,KAAK,kBACP,OAAO,KAAK;EAGd,MAAM,YAAY,IAAI,sBAAsB;EAE5C,KAAK,GAAG,QAAQ,SAAS,UAAU,YAAY,OAAO,IAAI,CAAC;EAC3D,KAAK,GAAG,SAAS,SAAS,UAAU,YAAY,QAAQ,IAAI,CAAC;EAC7D,KAAK,GAAG,QAAQ,SAAS,UAAU,YAAY,OAAO,IAAI,CAAC;EAC3D,KAAK,GAAG,YAAY,SAAS,UAAU,YAAY,WAAW,IAAI,CAAC;EACnE,KAAK,GAAG,UAAU,SAAS,UAAU,YAAY,SAAS,IAAI,CAAC;EAE/D,KAAK,mBAAmB;EAExB,OAAO;CACT;;;;;;;CAQA,MAAgB,MACd,MACA,YACY;EACZ,IAAI,CAAC,KAAK,kBACR,OAAO,KAAK;EAGd,MAAM,QAAQ,YAAY,IAAI;EAE9B,IAAI;GACF,OAAO,MAAM,KAAK;EACpB,UAAU;GACR,MAAM,UAAU,YAAY,IAAI,IAAI;GACpC,MAAM,OAAO,cAAc,KAAK,eAAe,QAAQ;GACvD,KAAK,iBAAiB,cAAc,MAAM,OAAO;EACnD;CACF;;;;CAKA,MAAa,IAAa,KAAkC;EAC1D,KAAK,wBAAwB;EAC7B,OAAO,KAAK,YAAY,KAAK,cAAe,IAAO,GAAG,CAAC;CACzD;;;;;;;;CASA,MAAa,IAAI,KAAe,OAAY,cAA2C;EACrF,KAAK,wBAAwB;EAE7B,MAAM,iBACJ,gBAAgB,OAAO,iBAAiB,YAAY,YAAY,eAC5D,aAAa,SACb;EAEN,IAAI,gBAAgB;GAClB,MAAM,SAAS,MAAM,KAAK,KAAK,cAAc;GAC7C,OAAO,KAAK,YAAY,OAAO,IAAI,KAAK,OAAO,YAAY,GAAG,OAAO,IAAI;EAC3E;EAEA,OAAO,KAAK,YAAY,KAAK,cAAe,IAAI,KAAK,OAAO,YAAY,CAAC;CAC3E;;;;CAKA,MAAa,OAAO,KAAe;EACjC,KAAK,wBAAwB;EAC7B,OAAO,KAAK,YAAY,KAAK,cAAe,OAAO,GAAG,CAAC;CACzD;;;;CAKA,MAAa,gBAAgB,WAAmB;EAC9C,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,gBAAgB,SAAS;CACtD;;;;CAKA,MAAa,QAAQ;EACnB,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,MAAM;CACnC;;;;CAKA,MAAa,UAAU;EACrB,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,QAAQ;CACrC;;;;CAKA,AAAO,SAAS,KAAe;EAC7B,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,SAAS,GAAG;CACzC;;;;CAKA,IAAW,UAAU;EACnB,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe;CAC7B;;;;CAKA,AAAO,WAAW,SAA8B;EAC9C,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,WAAW,WAAW,CAAC,CAAC;CACrD;;;;;;;CAQA,MAAa,OAAO,YAAoB,gBAAsC;EAC5E,IAAI,KAAK,cAAc,aAAa;GAClC,KAAK,0BAA0B,YAAY,cAAc;GAEzD,OAAO,KAAK,cAAc;EAC5B;EAEA,OAAO,KAAK,KAAK,YAAY,cAAc;CAC7C;;;;CAKA,MAAa,OAAO;EAClB,MAAM,yBAAyB,KAAK,eAAe;EAEnD,IAAI,CAAC,wBACH;EAGF,MAAM,SAAS,MAAM,KAAK,OAAO,sBAAsB;EAEvD,MAAM,KAAK,IAAI,MAAM;CACvB;;;;;;;;;;;;;;;CAgBA,MAAa,KAAK,QAAgB,gBAAsC;EACtE,IAAI,KAAK,cAAc,SAAS;GAC9B,KAAK,0BAA0B,QAAQ,cAAc;GAErD,OAAO,KAAK,cAAc;EAC5B;EAEA,MAAM,WAAW,KAAK,eAAe,IAAI,MAAM;EAE/C,IAAI,UAAU;GACZ,KAAK,0BAA0B,QAAQ,cAAc;GAErD,OAAO;EACT;EAEA,MAAM,SAAS,KAAK,eAAe,QACjC;EAGF,IAAI,CAAC,QACH,MAAM,IAAI,wBACR,gBAAgB,OAAO,kFACzB;EAGF,MAAM,iBAAiB,IAAI,OAAO;EAClC,MAAM,gBACJ,KAAK,eAAe,QAAQ,WAAuD,CAAC;EAEtF,eAAe,WAAW;GAAE,GAAG;GAAe,GAAI,kBAAkB,CAAC;EAAG,CAAC;EAEzE,MAAM,WAAW,YAAY;GAC3B,IAAI;IACF,MAAM,eAAe,QAAQ;IAE7B,KAAK,sBAAsB,cAAc;IAEzC,KAAK,cAAc,UAAU;IAE7B,OAAO;GACT,UAAU;IACR,KAAK,eAAe,OAAO,MAAM;GACnC;EACF,EAAC,CAAE;EAEH,KAAK,eAAe,IAAI,QAAQ,OAAO;EAEvC,OAAO;CACT;;;;;;;;CASA,AAAU,0BACR,YACA,gBACM;EACN,IAAI,mBAAmB,QACrB;EAGF,IAAI,OAAO,KAAK,cAAc,CAAC,CAAC,WAAW,GACzC;EAGF,MAAM,IAAI,wBACR,iBAAiB,WAAW,4IAC9B;CACF;;;;CAKA,AAAO,eAAe,YAAoB,aAA0B;EAClE,AAAC,KAAK,eAAe,QAAwC,cAAc;CAC7E;;;;CAKA,MAAa,aAAa;EACxB,MAAM,UAAU,IAAI,IAAS,OAAO,OAAO,KAAK,aAAa,CAAC;EAE9D,IAAI,KAAK,eACP,QAAQ,IAAI,KAAK,aAAa;EAGhC,MAAM,QAAQ,WAAW,CAAC,GAAG,OAAO,CAAC,CAAC,KAAI,WAAU,OAAO,WAAW,CAAC,CAAC;EAExE,KAAK,MAAM,QAAQ,OAAO,KAAK,KAAK,aAAa,GAC/C,OAAO,KAAK,cAAc;EAG5B,KAAK,eAAe,MAAM;CAC5B;;;;CAKA,MAAa,IAAI,KAAiC;EAChD,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,IAAI,GAAG;CACpC;;;;CAKA,MAAa,SACX,KACA,cACA,UACY;EACZ,KAAK,wBAAwB;EAE7B,MAAM,iBACJ,gBAAgB,OAAO,iBAAiB,YAAY,YAAY,eAC5D,aAAa,SACb;EAEN,IAAI,gBAEF,QAAO,MADc,KAAK,KAAK,cAAc,EAChC,CAAC,SAAS,KAAK,cAAc,QAAQ;EAGpD,OAAO,KAAK,cAAe,SAAS,KAAK,cAAc,QAAQ;CACjE;;;;;;;;;;;;;;CAeA,MAAa,IACX,KACA,SACA,UACY;EACZ,KAAK,wBAAwB;EAE7B,MAAM,iBAAiB,QAAQ;EAE/B,IAAI,gBAGF,QAAO,MAFc,KAAK,KAAK,cAAc,EAEhC,CAAC,IAAO,KAAK,SAAS,QAAQ;EAG7C,OAAO,KAAK,cAAe,IAAO,KAAK,SAAS,QAAQ;CAC1D;;;;CAKA,MAAa,KAAK,KAAoC;EACpD,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,KAAK,GAAG;CACrC;;;;CAKA,MAAa,QAAQ,KAAe,OAA0B;EAC5D,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,QAAQ,KAAK,KAAK;CAC/C;;;;CAKA,MAAa,UAAU,KAAe,OAAiC;EACrE,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,UAAU,KAAK,KAAK;CACjD;;;;CAKA,MAAa,UAAU,KAAe,OAAiC;EACrE,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,UAAU,KAAK,KAAK;CACjD;;;;CAKA,MAAa,KAAK,MAAkC;EAClD,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,KAAK,IAAI;CACtC;;;;CAKA,MAAa,QAAQ,OAA4B,KAA6B;EAC5E,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,QAAQ,OAAO,GAAG;CAC/C;;;;CAKA,AAAO,GAAG,OAAuB,SAAkC;EACjE,IAAI,CAAC,KAAK,qBAAqB,IAAI,KAAK,GACtC,KAAK,qBAAqB,IAAI,uBAAO,IAAI,IAAI,CAAC;EAEhD,KAAK,qBAAqB,IAAI,KAAK,CAAC,CAAE,IAAI,OAAO;EAGjD,IAAI,KAAK,eACP,KAAK,cAAc,GAAG,OAAO,OAAO;EAItC,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,aAAa,GACnD,OAAO,GAAG,OAAO,OAAO;EAG1B,OAAO;CACT;;;;CAKA,AAAO,IAAI,OAAuB,SAAkC;EAClE,MAAM,WAAW,KAAK,qBAAqB,IAAI,KAAK;EACpD,IAAI,UACF,SAAS,OAAO,OAAO;EAIzB,IAAI,KAAK,eACP,KAAK,cAAc,IAAI,OAAO,OAAO;EAIvC,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,aAAa,GACnD,OAAO,IAAI,OAAO,OAAO;EAG3B,OAAO;CACT;;;;CAKA,AAAO,KAAK,OAAuB,SAAkC;EACnE,MAAM,cAAiC,OAAO,SAAS;GACrD,MAAM,QAAQ,IAAI;GAClB,KAAK,IAAI,OAAO,WAAW;EAC7B;EACA,OAAO,KAAK,GAAG,OAAO,WAAW;CACnC;;;;CAKA,AAAU,sBAAsB,QAA+B;EAC7D,KAAK,MAAM,CAAC,OAAO,aAAa,KAAK,sBACnC,KAAK,MAAM,WAAW,UACpB,OAAO,GAAG,OAAO,OAAO;CAG9B;;;;;;CAOA,MAAa,MAAM,KAAe,OAAY,KAAgC;EAC5E,KAAK,wBAAwB;EAE7B,IAAI,CAAC,KAAK,cAAe,OACvB,MAAM,IAAI,MACR,uDAAuD,KAAK,cAAe,MAC7E;EAGF,OAAO,KAAK,cAAe,MAAM,KAAK,OAAO,GAAG;CAClD;;;;CAKA,AAAO,KAAK,MAAmC;EAC7C,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,KAAK,IAAI;CACtC;;;;CAKA,MAAa,OACX,KACA,IACA,SACmB;EACnB,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,OAAU,KAAK,IAAI,OAAO;CACvD;;;;CAKA,MAAa,MACX,KACA,SACA,SACY;EACZ,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,MAAS,KAAK,SAAS,OAAO;CAC3D;;;;CAKA,AAAO,KAAc,KAAqC;EACxD,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,KAAQ,GAAG;CACxC;;;;;;;;;;;;;;;;;;CAmBA,MAAa,KACX,KACA,cACA,IACyB;EACzB,KAAK,wBAAwB;EAE7B,MAAM,iBACJ,gBAAgB,OAAO,iBAAiB,YAAY,YAAY,eAC5D,aAAa,SACb;EAMN,QAJe,iBACX,MAAM,KAAK,KAAK,cAAc,IAC9B,KAAK,cAEI,CAAC,KAAQ,KAAK,cAAwD,EAAE;CACvF;;;;;;;;;;;;;;;;;;;;;;;;CAyBA,AAAO,UAAU,QAAgB,SAAsD;EACrF,KAAK,wBAAwB;EAC7B,OAAO,IAAI,YAAY,MAAM,QAAQ,OAAO;CAC9C;CAEA,MAAa,QACX,QACA,SAC+B;EAC/B,KAAK,wBAAwB;EAC7B,OAAO,KAAK,cAAe,QAAW,QAAQ,OAAO;CACvD;AACF;AAEA,MAAa,QAAQ,IAAI,aAAa"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-key.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"auto-key.d.mts","names":[],"sources":["../../../../../../../../packages/cache/src/cached/auto-key.ts"],"mappings":";;AAuBA;;;;AAAsE;;;;;;;;;;;;;;;iBAAtD,aAAA,CAAc,MAAA,UAAgB,IAAwB"}
|
package/esm/cached/auto-key.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CacheConfigurationError } from "../types.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/cache/src/cached/auto-key.ts
|
|
5
5
|
/**
|
|
6
6
|
* Derive a cache key from a prefix and a set of function arguments.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-key.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"auto-key.mjs","names":[],"sources":["../../../../../../../../packages/cache/src/cached/auto-key.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { CacheConfigurationError } from \"../types\";\n\n/**\n * Derive a cache key from a prefix and a set of function arguments.\n *\n * The key is `<prefix>.<hash>` where `hash` is the first 16 hex chars of the\n * sha1 of a stable JSON encoding of the args. Hashing keeps the mapping\n * injective — raw punctuation-joined segments can be folded together by\n * `parseCacheKey` (e.g. `(\"1.private\", \"\")` vs `(\"1\", \"private\")`).\n *\n * Encoding rules: object keys are sorted, `Date` → ISO string, `undefined` →\n * `{\"$u\":1}`, `bigint` → decimal string with an `n` suffix.\n *\n * No args → the prefix alone.\n *\n * Map, Set, functions, symbols and class instances cannot be encoded stably\n * and throw `CacheConfigurationError`; supply a custom `key` function instead.\n *\n * @example\n * deriveAutoKey(\"featured\", []); // \"featured\"\n * deriveAutoKey(\"user\", [42]); // \"user.<16 hex chars>\"\n */\nexport function deriveAutoKey(prefix: string, args: readonly unknown[]): string {\n if (args.length === 0) {\n return prefix;\n }\n\n let encoded: string;\n\n try {\n encoded = JSON.stringify(args.map((arg) => normalize(arg, prefix, new Set())));\n } catch (error) {\n if (error instanceof CacheConfigurationError) {\n throw error;\n }\n\n throw new CacheConfigurationError(\n `cached(): could not derive an auto-key from args for prefix \"${prefix}\". ` +\n `The args are not serializable. Use the options form with a custom key function. ` +\n `Original error: ${(error as Error).message}`,\n );\n }\n\n const hash = createHash(\"sha1\").update(encoded).digest(\"hex\").slice(0, 16);\n\n return `${prefix}.${hash}`;\n}\n\nfunction unsupported(prefix: string, what: string): never {\n throw new CacheConfigurationError(\n `cached(): cannot derive an auto-key for prefix \"${prefix}\" from ${what}. ` +\n `Use the options form with a custom key function.`,\n );\n}\n\nfunction normalize(value: unknown, prefix: string, seen: Set<object>): unknown {\n if (value === undefined) return { $u: 1 };\n if (value === null) return null;\n\n switch (typeof value) {\n case \"string\":\n case \"boolean\":\n return value;\n case \"number\":\n // NaN / Infinity would collapse to null in JSON\n return Number.isFinite(value) ? value : { $n: String(value) };\n case \"bigint\":\n return `${value.toString()}n`;\n case \"function\":\n return unsupported(prefix, \"a function argument\");\n case \"symbol\":\n return unsupported(prefix, \"a symbol argument\");\n }\n\n const obj = value as object;\n\n if (obj instanceof Date) {\n return Number.isNaN(obj.getTime()) ? { $d: \"invalid\" } : obj.toISOString();\n }\n\n if (obj instanceof Map) return unsupported(prefix, \"a Map argument\");\n if (obj instanceof Set) return unsupported(prefix, \"a Set argument\");\n\n if (seen.has(obj)) {\n throw new CacheConfigurationError(\n `cached(): could not derive an auto-key for prefix \"${prefix}\": circular reference in args. ` +\n `Use the options form with a custom key function.`,\n );\n }\n\n seen.add(obj);\n\n let result: unknown;\n\n if (Array.isArray(obj)) {\n result = obj.map((item) => normalize(item, prefix, seen));\n } else {\n const proto = Object.getPrototypeOf(obj);\n\n if (proto !== Object.prototype && proto !== null) {\n unsupported(prefix, \"a class instance argument\");\n }\n\n const out: Record<string, unknown> = {};\n\n for (const key of Object.keys(obj).sort()) {\n out[key] = normalize((obj as Record<string, unknown>)[key], prefix, seen);\n }\n\n result = out;\n }\n\n seen.delete(obj);\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,cAAc,QAAgB,MAAkC;CAC9E,IAAI,KAAK,WAAW,GAClB,OAAO;CAGT,IAAI;CAEJ,IAAI;EACF,UAAU,KAAK,UAAU,KAAK,KAAK,QAAQ,UAAU,KAAK,wBAAQ,IAAI,IAAI,CAAC,CAAC,CAAC;CAC/E,SAAS,OAAO;EACd,IAAI,iBAAiB,yBACnB,MAAM;EAGR,MAAM,IAAI,wBACR,gEAAgE,OAAO,qGAEjD,MAAgB,SACxC;CACF;CAIA,OAAO,GAAG,OAAO,GAFJ,WAAW,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAEhD;AACzB;AAEA,SAAS,YAAY,QAAgB,MAAqB;CACxD,MAAM,IAAI,wBACR,mDAAmD,OAAO,SAAS,KAAK,mDAE1E;AACF;AAEA,SAAS,UAAU,OAAgB,QAAgB,MAA4B;CAC7E,IAAI,UAAU,QAAW,OAAO,EAAE,IAAI,EAAE;CACxC,IAAI,UAAU,MAAM,OAAO;CAE3B,QAAQ,OAAO,OAAf;EACE,KAAK;EACL,KAAK,WACH,OAAO;EACT,KAAK,UAEH,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ,EAAE,IAAI,OAAO,KAAK,EAAE;EAC9D,KAAK,UACH,OAAO,GAAG,MAAM,SAAS,EAAE;EAC7B,KAAK,YACH,OAAO,YAAY,QAAQ,qBAAqB;EAClD,KAAK,UACH,OAAO,YAAY,QAAQ,mBAAmB;CAClD;CAEA,MAAM,MAAM;CAEZ,IAAI,eAAe,MACjB,OAAO,OAAO,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,UAAU,IAAI,IAAI,YAAY;CAG3E,IAAI,eAAe,KAAK,OAAO,YAAY,QAAQ,gBAAgB;CACnE,IAAI,eAAe,KAAK,OAAO,YAAY,QAAQ,gBAAgB;CAEnE,IAAI,KAAK,IAAI,GAAG,GACd,MAAM,IAAI,wBACR,sDAAsD,OAAO,gFAE/D;CAGF,KAAK,IAAI,GAAG;CAEZ,IAAI;CAEJ,IAAI,MAAM,QAAQ,GAAG,GACnB,SAAS,IAAI,KAAK,SAAS,UAAU,MAAM,QAAQ,IAAI,CAAC;MACnD;EACL,MAAM,QAAQ,OAAO,eAAe,GAAG;EAEvC,IAAI,UAAU,OAAO,aAAa,UAAU,MAC1C,YAAY,QAAQ,2BAA2B;EAGjD,MAAM,MAA+B,CAAC;EAEtC,KAAK,MAAM,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,KAAK,GACtC,IAAI,OAAO,UAAW,IAAgC,MAAM,QAAQ,IAAI;EAG1E,SAAS;CACX;CAEA,KAAK,OAAO,GAAG;CAEf,OAAO;AACT"}
|
package/esm/cached/cached.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CacheTtl } from "../types.mjs";
|
|
2
2
|
import { CachedOptions } from "./normalize-args.mjs";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/cache/src/cached/cached.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* The shape returned by `cached()`. Callable like the wrapped function, plus
|
|
7
7
|
* helpers for manual invalidation.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cached.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"cached.d.mts","names":[],"sources":["../../../../../../../../packages/cache/src/cached/cached.ts"],"mappings":";;;;;;AASA;;KAAY,QAAA,mCAA2C,IAAA,EAAM,IAAA,KAAS,OAAA,CAAQ,CAAA;EAAjB;;;;;;;EAQ3D,UAAA,IAAc,IAAA,EAAM,IAAA,GAAO,OAAA;AAAA;;;;;;;;;;AAAO;AAiCpC;;;;;;;;;;;;;;;;;;;;iBAAgB,MAAA,4BACd,EAAA,MAAQ,IAAA,EAAM,IAAA,KAAS,OAAA,CAAQ,CAAA,GAC/B,MAAA,WACC,QAAA,CAAS,IAAA,EAAM,CAAA;AAAA,iBACF,MAAA,4BACd,EAAA,MAAQ,IAAA,EAAM,IAAA,KAAS,OAAA,CAAQ,CAAA,GAC/B,MAAA,UACA,GAAA,EAAK,QAAA,GACJ,QAAA,CAAS,IAAA,EAAM,CAAA;AAAA,iBACF,MAAA,4BACd,EAAA,MAAQ,IAAA,EAAM,IAAA,KAAS,OAAA,CAAQ,CAAA,GAC/B,OAAA,EAAS,aAAA,CAAc,IAAA,IACtB,QAAA,CAAS,IAAA,EAAM,CAAA"}
|
package/esm/cached/cached.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cache } from "../cache-manager.mjs";
|
|
2
2
|
import { normalizeCachedArgs } from "./normalize-args.mjs";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/cache/src/cached/cached.ts
|
|
5
5
|
function cached(fn, prefixOrOptions, maybeTtl) {
|
|
6
6
|
const config = normalizeCachedArgs(prefixOrOptions, maybeTtl);
|
|
7
7
|
const buildRememberOptions = () => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cached.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"cached.mjs","names":[],"sources":["../../../../../../../../packages/cache/src/cached/cached.ts"],"sourcesContent":["import { cache } from \"../cache-manager\";\nimport type { CacheTtl, RememberOptions } from \"../types\";\nimport type { CachedOptions } from \"./normalize-args\";\nimport { normalizeCachedArgs } from \"./normalize-args\";\n\n/**\n * The shape returned by `cached()`. Callable like the wrapped function, plus\n * helpers for manual invalidation.\n */\nexport type CachedFn<Args extends unknown[], R> = ((...args: Args) => Promise<R>) & {\n /**\n * Drop the cache entry for a specific argument combination.\n *\n * @example\n * const getUser = cached((id: number) => db.users.find(id), \"user\", \"1h\");\n * await getUser.invalidate(42); // drops \"user.42\"\n */\n invalidate(...args: Args): Promise<void>;\n};\n\n/**\n * Wrap an async function so every invocation runs through the cache.\n *\n * Uses `cache.remember()` internally — inherits its stampede-protection\n * guarantees. Three calling shapes, `fn` always first.\n *\n * @example\n * // Shorthand — prefix auto-expands with the function's arguments.\n * // getUser(42) caches under \"user.42\".\n * const getUser = cached(\n * (id: number) => db.users.find(id),\n * \"user\",\n * \"1h\",\n * );\n *\n * @example\n * // Options form — custom key function, tags, per-call driver override.\n * const searchProducts = cached(\n * (filters: ProductFilters) => db.products.search(filters),\n * {\n * key: (filters) => `products.search.${filters.category}.${filters.sort}`,\n * ttl: \"15m\",\n * tags: [\"products\"],\n * },\n * );\n *\n * @example\n * // Manual invalidation — uses the same key scheme the wrapper uses internally.\n * await getUser.invalidate(42);\n */\nexport function cached<Args extends unknown[], R>(\n fn: (...args: Args) => Promise<R>,\n prefix: string,\n): CachedFn<Args, R>;\nexport function cached<Args extends unknown[], R>(\n fn: (...args: Args) => Promise<R>,\n prefix: string,\n ttl: CacheTtl,\n): CachedFn<Args, R>;\nexport function cached<Args extends unknown[], R>(\n fn: (...args: Args) => Promise<R>,\n options: CachedOptions<Args>,\n): CachedFn<Args, R>;\nexport function cached<Args extends unknown[], R>(\n fn: (...args: Args) => Promise<R>,\n prefixOrOptions: string | CachedOptions<Args>,\n maybeTtl?: CacheTtl,\n): CachedFn<Args, R> {\n const config = normalizeCachedArgs<Args>(prefixOrOptions, maybeTtl);\n\n // Build the RememberOptions payload once per call. `ttl` may still be undefined\n // here — that's fine, `remember` falls back to the driver's default TTL.\n const buildRememberOptions = (): RememberOptions => ({\n ttl: config.ttl,\n tags: config.tags,\n driver: config.driver,\n });\n\n const wrapper = (async (...args: Args): Promise<R> => {\n const key = config.key(...args);\n return cache.remember<R>(key, buildRememberOptions(), () => fn(...args));\n }) as CachedFn<Args, R>;\n\n wrapper.invalidate = async (...args: Args): Promise<void> => {\n const key = config.key(...args);\n if (config.driver) {\n await (await cache.driver(config.driver)).remove(key);\n return;\n }\n\n await cache.remove(key);\n };\n\n return wrapper;\n}\n"],"mappings":";;;;AA+DA,SAAgB,OACd,IACA,iBACA,UACmB;CACnB,MAAM,SAAS,oBAA0B,iBAAiB,QAAQ;CAIlE,MAAM,8BAA+C;EACnD,KAAK,OAAO;EACZ,MAAM,OAAO;EACb,QAAQ,OAAO;CACjB;CAEA,MAAM,WAAW,OAAO,GAAG,SAA2B;EACpD,MAAM,MAAM,OAAO,IAAI,GAAG,IAAI;EAC9B,OAAO,MAAM,SAAY,KAAK,qBAAqB,SAAS,GAAG,GAAG,IAAI,CAAC;CACzE;CAEA,QAAQ,aAAa,OAAO,GAAG,SAA8B;EAC3D,MAAM,MAAM,OAAO,IAAI,GAAG,IAAI;EAC9B,IAAI,OAAO,QAAQ;GACjB,OAAO,MAAM,MAAM,OAAO,OAAO,MAAM,EAAC,CAAE,OAAO,GAAG;GACpD;EACF;EAEA,MAAM,MAAM,OAAO,GAAG;CACxB;CAEA,OAAO;AACT"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CacheTtl } from "../types.mjs";
|
|
2
2
|
|
|
3
|
-
//#region
|
|
3
|
+
//#region ../../packages/cache/src/cached/normalize-args.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Options accepted by the `cached()` factory in its verbose form. `key` is the
|
|
6
6
|
* decisive escape hatch when the shorthand's auto-key rules don't fit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-args.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"normalize-args.d.mts","names":[],"sources":["../../../../../../../../packages/cache/src/cached/normalize-args.ts"],"mappings":";;;;;AASA;;;;KAAY,aAAA;EAMV;;;;;EAAA,GAAA,MAAS,IAAA,EAAM,IAAA;EAcf;;AAAM;EAVN,GAAA,GAAM,QAAQ;EAmBkB;;;;EAdhC,IAAA;EAeS;;;;EAVT,MAAA;AAAA;;AAaM;AAOR;;;;KAXY,sBAAA;EACV,GAAA,MAAS,IAAA,EAAM,IAAA;EACf,GAAA,GAAM,QAAQ;EACd,IAAA;EACA,MAAA;AAAA;;;;;iBAOc,mBAAA,yBACd,eAAA,WAA0B,aAAA,CAAc,IAAA,GACxC,QAAA,GAAW,QAAA,GACV,sBAAA,CAAuB,IAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { deriveAutoKey } from "./auto-key.mjs";
|
|
2
2
|
|
|
3
|
-
//#region
|
|
3
|
+
//#region ../../packages/cache/src/cached/normalize-args.ts
|
|
4
4
|
/**
|
|
5
5
|
* Resolve the positional-or-options arguments of `cached()` into a single
|
|
6
6
|
* normalized config. Keeps the wrapper body free of shape-checks.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-args.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"normalize-args.mjs","names":[],"sources":["../../../../../../../../packages/cache/src/cached/normalize-args.ts"],"sourcesContent":["import type { CacheTtl } from \"../types\";\nimport { deriveAutoKey } from \"./auto-key\";\n\n/**\n * Options accepted by the `cached()` factory in its verbose form. `key` is the\n * decisive escape hatch when the shorthand's auto-key rules don't fit.\n *\n * @see cached\n */\nexport type CachedOptions<Args extends unknown[]> = {\n /**\n * Derive a cache key from the wrapped function's arguments. Must be pure and\n * deterministic — every call with equivalent inputs should produce the same\n * key.\n */\n key: (...args: Args) => string;\n /**\n * Optional TTL on cache miss. Falls back to the driver's default TTL when omitted.\n */\n ttl?: CacheTtl;\n /**\n * Optional tags attached to every cache-miss write this wrapper produces.\n * Invalidate them the usual way via `cache.tags([...]).invalidate()`.\n */\n tags?: string[];\n /**\n * Per-call driver override. Routes every call produced by this wrapper to\n * the named driver without mutating `currentDriver`.\n */\n driver?: string;\n};\n\n/**\n * Normalized form of the factory arguments — a single shape every call path\n * in `cached()` operates on. Users never see this type.\n *\n * @internal\n */\nexport type NormalizedCachedConfig<Args extends unknown[]> = {\n key: (...args: Args) => string;\n ttl?: CacheTtl;\n tags?: string[];\n driver?: string;\n};\n\n/**\n * Resolve the positional-or-options arguments of `cached()` into a single\n * normalized config. Keeps the wrapper body free of shape-checks.\n */\nexport function normalizeCachedArgs<Args extends unknown[]>(\n prefixOrOptions: string | CachedOptions<Args>,\n maybeTtl?: CacheTtl,\n): NormalizedCachedConfig<Args> {\n if (typeof prefixOrOptions === \"string\") {\n const prefix = prefixOrOptions;\n return {\n key: (...args: Args) => deriveAutoKey(prefix, args),\n ttl: maybeTtl,\n };\n }\n\n return {\n key: prefixOrOptions.key,\n ttl: prefixOrOptions.ttl,\n tags: prefixOrOptions.tags,\n driver: prefixOrOptions.driver,\n };\n}\n"],"mappings":";;;;;;;AAiDA,SAAgB,oBACd,iBACA,UAC8B;CAC9B,IAAI,OAAO,oBAAoB,UAAU;EACvC,MAAM,SAAS;EACf,OAAO;GACL,MAAM,GAAG,SAAe,cAAc,QAAQ,IAAI;GAClD,KAAK;EACP;CACF;CAEA,OAAO;EACL,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,MAAM,gBAAgB;EACtB,QAAQ,gBAAgB;CAC1B;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CacheConflictPolicy, CacheData, CacheDriver, CacheEventData, CacheEventHandler, CacheEventType, CacheKey, CacheListAccessor, CacheOperationType, CacheSetOptions, CacheSimilarHit, CacheSimilarOptions, CacheSwrOptions, CacheTtl, LockOptions, LockOutcome, RememberOptions } from "../types.mjs";
|
|
2
2
|
|
|
3
|
-
//#region
|
|
3
|
+
//#region ../../packages/cache/src/drivers/base-cache-driver.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Normalized form of the 3rd `set` argument.
|
|
6
6
|
*
|
|
@@ -282,9 +282,15 @@ declare abstract class BaseCacheDriver<ClientType, Options extends Record<string
|
|
|
282
282
|
* {@inheritdoc}
|
|
283
283
|
*
|
|
284
284
|
* Default implementation: read-add-write serialized per key in THIS process,
|
|
285
|
-
* keeping the entry's
|
|
286
|
-
*
|
|
287
|
-
*
|
|
285
|
+
* keeping the entry's deadline (a missing key starts from 0 with the driver
|
|
286
|
+
* default TTL). Not atomic across servers: drivers with a native primitive
|
|
287
|
+
* override it (redis `INCRBY`, pg single-statement upsert).
|
|
288
|
+
*
|
|
289
|
+
* The value and its deadline come from ONE read. Reading them separately
|
|
290
|
+
* let a counter that expired in between be rewritten from its stale value
|
|
291
|
+
* with no expiry at all (a login-throttle counter that then never resets).
|
|
292
|
+
* The remaining TTL is rounded down, so repeated increments can never push
|
|
293
|
+
* a window's deadline later.
|
|
288
294
|
*/
|
|
289
295
|
increment(key: CacheKey, value?: number): Promise<number>;
|
|
290
296
|
/**
|
|
@@ -302,7 +308,7 @@ declare abstract class BaseCacheDriver<ClientType, Options extends Record<string
|
|
|
302
308
|
/**
|
|
303
309
|
* Log the operation
|
|
304
310
|
*/
|
|
305
|
-
protected log(operation: CacheOperationType, key?: string | any):
|
|
311
|
+
protected log(operation: CacheOperationType, key?: string | any): import("@warlock.js/logger").Logger | undefined;
|
|
306
312
|
/**
|
|
307
313
|
* Log error message
|
|
308
314
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-cache-driver.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"base-cache-driver.d.mts","names":[],"sources":["../../../../../../../../packages/cache/src/drivers/base-cache-driver.ts"],"mappings":"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"}
|
|
@@ -3,9 +3,9 @@ import { normalizeToOptions, parseCacheKey, parseTtl, resolveTtl, safeErrorInfo
|
|
|
3
3
|
import { MemoryCacheList } from "../list/memory-cache-list.mjs";
|
|
4
4
|
import { TaggedCache } from "../tagged-cache.mjs";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
|
-
import { log } from "@warlock.js/logger";
|
|
6
|
+
import { log, maskEmailsInText } from "@warlock.js/logger";
|
|
7
7
|
|
|
8
|
-
//#region
|
|
8
|
+
//#region ../../packages/cache/src/drivers/base-cache-driver.ts
|
|
9
9
|
const messages = {
|
|
10
10
|
clearing: "Clearing namespace",
|
|
11
11
|
cleared: "Namespace cleared",
|
|
@@ -398,20 +398,30 @@ var BaseCacheDriver = class {
|
|
|
398
398
|
* {@inheritdoc}
|
|
399
399
|
*
|
|
400
400
|
* Default implementation: read-add-write serialized per key in THIS process,
|
|
401
|
-
* keeping the entry's
|
|
402
|
-
*
|
|
403
|
-
*
|
|
401
|
+
* keeping the entry's deadline (a missing key starts from 0 with the driver
|
|
402
|
+
* default TTL). Not atomic across servers: drivers with a native primitive
|
|
403
|
+
* override it (redis `INCRBY`, pg single-statement upsert).
|
|
404
|
+
*
|
|
405
|
+
* The value and its deadline come from ONE read. Reading them separately
|
|
406
|
+
* let a counter that expired in between be rewritten from its stale value
|
|
407
|
+
* with no expiry at all (a login-throttle counter that then never resets).
|
|
408
|
+
* The remaining TTL is rounded down, so repeated increments can never push
|
|
409
|
+
* a window's deadline later.
|
|
404
410
|
*/
|
|
405
411
|
async increment(key, value = 1) {
|
|
406
412
|
const parsedKey = this.parseKey(key);
|
|
407
413
|
return this.runSerialized(parsedKey, async () => {
|
|
408
|
-
const
|
|
414
|
+
const entry = await this.getEntry(key);
|
|
415
|
+
const now = Date.now();
|
|
416
|
+
const expiresAt = entry?.expiresAt;
|
|
417
|
+
const live = entry ? expiresAt == null || expiresAt > now : false;
|
|
418
|
+
const current = entry && live ? entry.data : null;
|
|
409
419
|
const base = current === null || current === void 0 ? 0 : current;
|
|
410
|
-
if (typeof base !== "number") throw new Error(`Cannot increment non-numeric value for key: ${parsedKey}`);
|
|
420
|
+
if (typeof base !== "number") throw new Error(`Cannot increment non-numeric value for key: ${maskEmailsInText(parsedKey)}`);
|
|
411
421
|
const newValue = base + value;
|
|
412
|
-
|
|
413
|
-
if (
|
|
414
|
-
else await this.set(key, newValue);
|
|
422
|
+
if (!live) await this.set(key, newValue);
|
|
423
|
+
else if (expiresAt == null || expiresAt === Infinity) await this.set(key, newValue, { ttl: Infinity });
|
|
424
|
+
else await this.set(key, newValue, { ttl: Math.max(1, Math.floor((expiresAt - now) / 1e3)) });
|
|
415
425
|
return newValue;
|
|
416
426
|
});
|
|
417
427
|
}
|
|
@@ -438,7 +448,7 @@ var BaseCacheDriver = class {
|
|
|
438
448
|
*/
|
|
439
449
|
log(operation, key) {
|
|
440
450
|
if (!this.shouldLog) return;
|
|
441
|
-
if (typeof key === "string") key = key.replace(/\//g, ".");
|
|
451
|
+
if (typeof key === "string") key = maskEmailsInText(key.replace(/\//g, "."));
|
|
442
452
|
if (operation === "connectionFailed") log.fatal(`cache.${this.name}`, operation, key);
|
|
443
453
|
if (operation == "notFound" || operation == "expired") return log.info("cache." + this.name, operation, (key ? key + " " : "") + messages[operation]);
|
|
444
454
|
if (operation.endsWith("ed")) return log.success("cache." + this.name, operation, (key ? key + " " : "") + messages[operation]);
|
|
@@ -453,8 +463,14 @@ var BaseCacheDriver = class {
|
|
|
453
463
|
* passed to the structured logger.
|
|
454
464
|
*/
|
|
455
465
|
logError(message, error) {
|
|
456
|
-
|
|
457
|
-
|
|
466
|
+
const maskedMessage = maskEmailsInText(message);
|
|
467
|
+
if (error) {
|
|
468
|
+
const info = safeErrorInfo(error);
|
|
469
|
+
log.error("cache." + this.name, "error", maskedMessage, {
|
|
470
|
+
...info,
|
|
471
|
+
message: maskEmailsInText(info.message)
|
|
472
|
+
});
|
|
473
|
+
} else log.error("cache." + this.name, "error", maskedMessage);
|
|
458
474
|
}
|
|
459
475
|
/**
|
|
460
476
|
* Get the default TTL in seconds. Parses human-readable strings (`"1h"`, `"30m"`)
|