@warlock.js/cache 5.29.0 → 5.31.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 +31 -7
- package/README.md +12 -21
- package/cjs/index.cjs +134 -71
- package/cjs/index.cjs.map +1 -1
- package/esm/cache-manager.d.mts +4 -2
- package/esm/cache-manager.d.mts.map +1 -1
- package/esm/cache-manager.mjs +3 -3
- 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 +14 -6
- package/esm/drivers/base-cache-driver.d.mts.map +1 -1
- package/esm/drivers/base-cache-driver.mjs +32 -15
- 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 +4 -2
- package/esm/drivers/lru-memory-cache-driver.d.mts.map +1 -1
- package/esm/drivers/lru-memory-cache-driver.mjs +9 -6
- package/esm/drivers/lru-memory-cache-driver.mjs.map +1 -1
- package/esm/drivers/memory-cache-driver.d.mts +4 -2
- package/esm/drivers/memory-cache-driver.d.mts.map +1 -1
- package/esm/drivers/memory-cache-driver.mjs +12 -5
- 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 +4 -2
- package/esm/drivers/mock-cache-driver.d.mts.map +1 -1
- package/esm/drivers/mock-cache-driver.mjs +14 -6
- 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 +4 -2
- package/esm/drivers/pg-cache-driver.d.mts.map +1 -1
- package/esm/drivers/pg-cache-driver.mjs +9 -5
- package/esm/drivers/pg-cache-driver.mjs.map +1 -1
- package/esm/drivers/redis-cache-driver.d.mts +17 -3
- package/esm/drivers/redis-cache-driver.d.mts.map +1 -1
- package/esm/drivers/redis-cache-driver.mjs +26 -5
- 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 +4 -2
- package/esm/scoped-cache.d.mts.map +1 -1
- package/esm/scoped-cache.mjs +3 -3
- package/esm/scoped-cache.mjs.map +1 -1
- package/esm/tagged-cache.d.mts +4 -2
- package/esm/tagged-cache.d.mts.map +1 -1
- package/esm/tagged-cache.mjs +3 -3
- package/esm/tagged-cache.mjs.map +1 -1
- package/esm/tagged-scoped-cache.d.mts +4 -2
- package/esm/tagged-scoped-cache.d.mts.map +1 -1
- package/esm/tagged-scoped-cache.mjs +3 -3
- package/esm/tagged-scoped-cache.mjs.map +1 -1
- package/esm/types.d.mts +17 -6
- 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 +231 -224
- package/llms.txt +1 -1
- package/package.json +5 -4
- package/skills/apply-cache-patterns/SKILL.md +3 -2
- package/skills/cache-basics/SKILL.md +26 -24
- package/skills/configure-pg-cache/SKILL.md +2 -2
- package/skills/configure-set-options/SKILL.md +14 -14
- package/skills/handle-cache-errors/SKILL.md +8 -8
- package/skills/index.md +4 -1
- package/skills/observe-cache/SKILL.md +8 -8
- package/skills/pick-cache-driver/SKILL.md +24 -23
- package/skills/test-cache-code/SKILL.md +15 -10
- package/skills/use-cache-atomic/SKILL.md +17 -11
- package/skills/use-cache-bulk/SKILL.md +8 -5
- package/skills/use-cache-list/SKILL.md +13 -13
- package/skills/use-cache-lock/SKILL.md +11 -17
- package/skills/use-cache-namespace/SKILL.md +11 -13
- package/skills/use-cache-similarity/SKILL.md +9 -9
- package/skills/use-cache-tags/SKILL.md +13 -13
- package/skills/use-cache-update-merge/SKILL.md +10 -10
- package/skills/use-cache-utils/SKILL.md +17 -17
- package/skills/use-cached-hof/SKILL.md +8 -7
- package/skills/use-swr/SKILL.md +14 -18
package/cjs/index.cjs
CHANGED
|
@@ -37,7 +37,7 @@ let _warlock_js_fs = require("@warlock.js/fs");
|
|
|
37
37
|
let path = require("path");
|
|
38
38
|
path = __toESM(path, 1);
|
|
39
39
|
|
|
40
|
-
//#region
|
|
40
|
+
//#region ../../packages/cache/src/metrics.ts
|
|
41
41
|
/**
|
|
42
42
|
* Default size of the circular latency-sample buffer. 1000 samples covers
|
|
43
43
|
* "tell me the current p95" for every realistic workload while keeping the
|
|
@@ -232,7 +232,7 @@ var CacheMetricsCollector = class {
|
|
|
232
232
|
};
|
|
233
233
|
|
|
234
234
|
//#endregion
|
|
235
|
-
//#region
|
|
235
|
+
//#region ../../packages/cache/src/types.ts
|
|
236
236
|
/**
|
|
237
237
|
* Base error class for cache-related errors
|
|
238
238
|
*/
|
|
@@ -292,7 +292,7 @@ var CacheConcurrencyError = class extends CacheError {
|
|
|
292
292
|
};
|
|
293
293
|
|
|
294
294
|
//#endregion
|
|
295
|
-
//#region
|
|
295
|
+
//#region ../../packages/cache/src/utils.ts
|
|
296
296
|
/**
|
|
297
297
|
* Make a proper key for the cache
|
|
298
298
|
*/
|
|
@@ -549,7 +549,7 @@ let CACHE_FOR = /* @__PURE__ */ function(CACHE_FOR) {
|
|
|
549
549
|
}({});
|
|
550
550
|
|
|
551
551
|
//#endregion
|
|
552
|
-
//#region
|
|
552
|
+
//#region ../../packages/cache/src/tagged-scoped-cache.ts
|
|
553
553
|
/**
|
|
554
554
|
* One-shot tagged write handle on top of a {@link ScopedCache}.
|
|
555
555
|
*
|
|
@@ -666,8 +666,8 @@ var TaggedScopedCache = class {
|
|
|
666
666
|
* Atomic counter increment on the scoped key. Tags aren't applied to
|
|
667
667
|
* subsequent increments — they're attached at first-write time.
|
|
668
668
|
*/
|
|
669
|
-
increment(key, value) {
|
|
670
|
-
return this.scope.increment(key, value);
|
|
669
|
+
increment(key, value, options) {
|
|
670
|
+
return this.scope.increment(key, value, options);
|
|
671
671
|
}
|
|
672
672
|
/**
|
|
673
673
|
* Atomic counter decrement on the scoped key. See {@link increment}.
|
|
@@ -698,7 +698,7 @@ var TaggedScopedCache = class {
|
|
|
698
698
|
};
|
|
699
699
|
|
|
700
700
|
//#endregion
|
|
701
|
-
//#region
|
|
701
|
+
//#region ../../packages/cache/src/scoped-cache.ts
|
|
702
702
|
/**
|
|
703
703
|
* Scoped view over a cache source. Returned by `cache.namespace(prefix, options?)`.
|
|
704
704
|
*
|
|
@@ -860,8 +860,8 @@ var ScopedCache = class ScopedCache {
|
|
|
860
860
|
* Atomic counter increment on the scoped key. TTL is preserved by the
|
|
861
861
|
* underlying driver — scope ttl is only applied on first write via `set`.
|
|
862
862
|
*/
|
|
863
|
-
increment(key, value) {
|
|
864
|
-
return this.source.increment(this.scopedKey(key), value);
|
|
863
|
+
increment(key, value, options) {
|
|
864
|
+
return this.source.increment(this.scopedKey(key), value, { ttl: options?.ttl ?? this.defaults.ttl });
|
|
865
865
|
}
|
|
866
866
|
/**
|
|
867
867
|
* Atomic counter decrement on the scoped key. See {@link increment} for
|
|
@@ -979,7 +979,7 @@ var ScopedCache = class ScopedCache {
|
|
|
979
979
|
};
|
|
980
980
|
|
|
981
981
|
//#endregion
|
|
982
|
-
//#region
|
|
982
|
+
//#region ../../packages/cache/src/cache-manager.ts
|
|
983
983
|
var CacheManager = class {
|
|
984
984
|
constructor() {
|
|
985
985
|
this.loadedDrivers = {};
|
|
@@ -1321,9 +1321,9 @@ var CacheManager = class {
|
|
|
1321
1321
|
/**
|
|
1322
1322
|
* {@inheritdoc}
|
|
1323
1323
|
*/
|
|
1324
|
-
async increment(key, value) {
|
|
1324
|
+
async increment(key, value, options) {
|
|
1325
1325
|
this.ensureDriverInitialized();
|
|
1326
|
-
return this.currentDriver.increment(key, value);
|
|
1326
|
+
return this.currentDriver.increment(key, value, options);
|
|
1327
1327
|
}
|
|
1328
1328
|
/**
|
|
1329
1329
|
* {@inheritdoc}
|
|
@@ -1477,7 +1477,7 @@ var CacheManager = class {
|
|
|
1477
1477
|
const cache = new CacheManager();
|
|
1478
1478
|
|
|
1479
1479
|
//#endregion
|
|
1480
|
-
//#region
|
|
1480
|
+
//#region ../../packages/cache/src/cached/auto-key.ts
|
|
1481
1481
|
/**
|
|
1482
1482
|
* Derive a cache key from a prefix and a set of function arguments.
|
|
1483
1483
|
*
|
|
@@ -1543,7 +1543,7 @@ function normalize(value, prefix, seen) {
|
|
|
1543
1543
|
}
|
|
1544
1544
|
|
|
1545
1545
|
//#endregion
|
|
1546
|
-
//#region
|
|
1546
|
+
//#region ../../packages/cache/src/cached/normalize-args.ts
|
|
1547
1547
|
/**
|
|
1548
1548
|
* Resolve the positional-or-options arguments of `cached()` into a single
|
|
1549
1549
|
* normalized config. Keeps the wrapper body free of shape-checks.
|
|
@@ -1565,7 +1565,7 @@ function normalizeCachedArgs(prefixOrOptions, maybeTtl) {
|
|
|
1565
1565
|
}
|
|
1566
1566
|
|
|
1567
1567
|
//#endregion
|
|
1568
|
-
//#region
|
|
1568
|
+
//#region ../../packages/cache/src/cached/cached.ts
|
|
1569
1569
|
function cached(fn, prefixOrOptions, maybeTtl) {
|
|
1570
1570
|
const config = normalizeCachedArgs(prefixOrOptions, maybeTtl);
|
|
1571
1571
|
const buildRememberOptions = () => ({
|
|
@@ -1589,7 +1589,7 @@ function cached(fn, prefixOrOptions, maybeTtl) {
|
|
|
1589
1589
|
}
|
|
1590
1590
|
|
|
1591
1591
|
//#endregion
|
|
1592
|
-
//#region
|
|
1592
|
+
//#region ../../packages/cache/src/list/memory-cache-list.ts
|
|
1593
1593
|
/**
|
|
1594
1594
|
* Generic array-backed {@link CacheListAccessor}.
|
|
1595
1595
|
*
|
|
@@ -1708,7 +1708,7 @@ var MemoryCacheList = class {
|
|
|
1708
1708
|
};
|
|
1709
1709
|
|
|
1710
1710
|
//#endregion
|
|
1711
|
-
//#region
|
|
1711
|
+
//#region ../../packages/cache/src/tagged-cache.ts
|
|
1712
1712
|
/**
|
|
1713
1713
|
* Tagged Cache Wrapper
|
|
1714
1714
|
* Wraps a cache driver to automatically manage tag relationships
|
|
@@ -1902,8 +1902,8 @@ var TaggedCache = class TaggedCache {
|
|
|
1902
1902
|
/**
|
|
1903
1903
|
* {@inheritdoc}
|
|
1904
1904
|
*/
|
|
1905
|
-
async increment(key, value = 1) {
|
|
1906
|
-
const newValue = await this.driver.increment(key, value);
|
|
1905
|
+
async increment(key, value = 1, options) {
|
|
1906
|
+
const newValue = await this.driver.increment(key, value, options);
|
|
1907
1907
|
await this.storeTaggedKey(key);
|
|
1908
1908
|
return newValue;
|
|
1909
1909
|
}
|
|
@@ -1916,7 +1916,7 @@ var TaggedCache = class TaggedCache {
|
|
|
1916
1916
|
};
|
|
1917
1917
|
|
|
1918
1918
|
//#endregion
|
|
1919
|
-
//#region
|
|
1919
|
+
//#region ../../packages/cache/src/drivers/base-cache-driver.ts
|
|
1920
1920
|
const messages = {
|
|
1921
1921
|
clearing: "Clearing namespace",
|
|
1922
1922
|
cleared: "Namespace cleared",
|
|
@@ -2309,20 +2309,31 @@ var BaseCacheDriver = class {
|
|
|
2309
2309
|
* {@inheritdoc}
|
|
2310
2310
|
*
|
|
2311
2311
|
* Default implementation: read-add-write serialized per key in THIS process,
|
|
2312
|
-
* keeping the entry's
|
|
2313
|
-
*
|
|
2314
|
-
*
|
|
2315
|
-
|
|
2316
|
-
|
|
2312
|
+
* keeping the entry's deadline (a missing key starts from 0 with the driver
|
|
2313
|
+
* default TTL). Not atomic across servers: drivers with a native primitive
|
|
2314
|
+
* override it (redis `INCRBY`, pg single-statement upsert).
|
|
2315
|
+
*
|
|
2316
|
+
* The value and its deadline come from ONE read. Reading them separately
|
|
2317
|
+
* let a counter that expired in between be rewritten from its stale value
|
|
2318
|
+
* with no expiry at all (a login-throttle counter that then never resets).
|
|
2319
|
+
* The remaining TTL is rounded down, so repeated increments can never push
|
|
2320
|
+
* a window's deadline later.
|
|
2321
|
+
*/
|
|
2322
|
+
async increment(key, value = 1, options = {}) {
|
|
2323
|
+
const ttl = options.ttl === void 0 ? this.ttl : parseTtl(options.ttl);
|
|
2317
2324
|
const parsedKey = this.parseKey(key);
|
|
2318
2325
|
return this.runSerialized(parsedKey, async () => {
|
|
2319
|
-
const
|
|
2326
|
+
const entry = await this.getEntry(key);
|
|
2327
|
+
const now = Date.now();
|
|
2328
|
+
const expiresAt = entry?.expiresAt;
|
|
2329
|
+
const live = entry ? expiresAt == null || expiresAt > now : false;
|
|
2330
|
+
const current = entry && live ? entry.data : null;
|
|
2320
2331
|
const base = current === null || current === void 0 ? 0 : current;
|
|
2321
|
-
if (typeof base !== "number") throw new Error(`Cannot increment non-numeric value for key: ${parsedKey}`);
|
|
2332
|
+
if (typeof base !== "number") throw new Error(`Cannot increment non-numeric value for key: ${(0, _warlock_js_logger.maskEmailsInText)(parsedKey)}`);
|
|
2322
2333
|
const newValue = base + value;
|
|
2323
|
-
|
|
2324
|
-
if (
|
|
2325
|
-
else await this.set(key, newValue);
|
|
2334
|
+
if (!live) await this.set(key, newValue, { ttl });
|
|
2335
|
+
else if (expiresAt == null || expiresAt === Infinity) await this.set(key, newValue, { ttl: options.ttl === void 0 ? Infinity : ttl });
|
|
2336
|
+
else await this.set(key, newValue, { ttl: Math.max(1, Math.floor((expiresAt - now) / 1e3)) });
|
|
2326
2337
|
return newValue;
|
|
2327
2338
|
});
|
|
2328
2339
|
}
|
|
@@ -2349,7 +2360,7 @@ var BaseCacheDriver = class {
|
|
|
2349
2360
|
*/
|
|
2350
2361
|
log(operation, key) {
|
|
2351
2362
|
if (!this.shouldLog) return;
|
|
2352
|
-
if (typeof key === "string") key = key.replace(/\//g, ".");
|
|
2363
|
+
if (typeof key === "string") key = (0, _warlock_js_logger.maskEmailsInText)(key.replace(/\//g, "."));
|
|
2353
2364
|
if (operation === "connectionFailed") _warlock_js_logger.log.fatal(`cache.${this.name}`, operation, key);
|
|
2354
2365
|
if (operation == "notFound" || operation == "expired") return _warlock_js_logger.log.info("cache." + this.name, operation, (key ? key + " " : "") + messages[operation]);
|
|
2355
2366
|
if (operation.endsWith("ed")) return _warlock_js_logger.log.success("cache." + this.name, operation, (key ? key + " " : "") + messages[operation]);
|
|
@@ -2364,8 +2375,14 @@ var BaseCacheDriver = class {
|
|
|
2364
2375
|
* passed to the structured logger.
|
|
2365
2376
|
*/
|
|
2366
2377
|
logError(message, error) {
|
|
2367
|
-
|
|
2368
|
-
|
|
2378
|
+
const maskedMessage = (0, _warlock_js_logger.maskEmailsInText)(message);
|
|
2379
|
+
if (error) {
|
|
2380
|
+
const info = safeErrorInfo(error);
|
|
2381
|
+
_warlock_js_logger.log.error("cache." + this.name, "error", maskedMessage, {
|
|
2382
|
+
...info,
|
|
2383
|
+
message: (0, _warlock_js_logger.maskEmailsInText)(info.message)
|
|
2384
|
+
});
|
|
2385
|
+
} else _warlock_js_logger.log.error("cache." + this.name, "error", maskedMessage);
|
|
2369
2386
|
}
|
|
2370
2387
|
/**
|
|
2371
2388
|
* Get the default TTL in seconds. Parses human-readable strings (`"1h"`, `"30m"`)
|
|
@@ -2560,7 +2577,7 @@ var BaseCacheDriver = class {
|
|
|
2560
2577
|
};
|
|
2561
2578
|
|
|
2562
2579
|
//#endregion
|
|
2563
|
-
//#region
|
|
2580
|
+
//#region ../../packages/cache/src/drivers/file-cache-driver.ts
|
|
2564
2581
|
var FileCacheDriver = class extends BaseCacheDriver {
|
|
2565
2582
|
constructor(..._args) {
|
|
2566
2583
|
super(..._args);
|
|
@@ -2770,7 +2787,7 @@ var FileCacheDriver = class extends BaseCacheDriver {
|
|
|
2770
2787
|
try {
|
|
2771
2788
|
const entry = await (0, _warlock_js_fs.getJsonFileAsync)(path.default.resolve(fileDirectory, this.fileName));
|
|
2772
2789
|
if (!entry) return null;
|
|
2773
|
-
if (entry.expiresAt
|
|
2790
|
+
if (typeof entry.expiresAt === "number" && entry.expiresAt <= Date.now()) return null;
|
|
2774
2791
|
return entry;
|
|
2775
2792
|
} catch {
|
|
2776
2793
|
return null;
|
|
@@ -2837,7 +2854,7 @@ var FileCacheDriver = class extends BaseCacheDriver {
|
|
|
2837
2854
|
};
|
|
2838
2855
|
|
|
2839
2856
|
//#endregion
|
|
2840
|
-
//#region
|
|
2857
|
+
//#region ../../packages/cache/src/drivers/in-memory-tag-index.ts
|
|
2841
2858
|
/**
|
|
2842
2859
|
* Tag index for the in-process drivers (memory, memoryExtended, lru, mock).
|
|
2843
2860
|
*
|
|
@@ -2908,7 +2925,7 @@ var InMemoryTagIndex = class {
|
|
|
2908
2925
|
};
|
|
2909
2926
|
|
|
2910
2927
|
//#endregion
|
|
2911
|
-
//#region
|
|
2928
|
+
//#region ../../packages/cache/src/drivers/lru-memory-cache-driver.ts
|
|
2912
2929
|
var CacheNode = class {
|
|
2913
2930
|
constructor(key, value, ttl) {
|
|
2914
2931
|
this.key = key;
|
|
@@ -3116,17 +3133,19 @@ var LRUMemoryCacheDriver = class extends BaseCacheDriver {
|
|
|
3116
3133
|
* concurrent increments in this process never lose an update. An existing
|
|
3117
3134
|
* node keeps its expiry; a missing key starts from 0 with the default TTL.
|
|
3118
3135
|
*/
|
|
3119
|
-
async increment(key, value = 1) {
|
|
3136
|
+
async increment(key, value = 1, options = {}) {
|
|
3137
|
+
const ttl = options.ttl === void 0 ? this.ttl : parseTtl(options.ttl);
|
|
3120
3138
|
const parsedKey = this.parseKey(key);
|
|
3121
3139
|
const node = this.liveNode(parsedKey);
|
|
3122
3140
|
const current = node ? node.value : 0;
|
|
3123
|
-
if (typeof current !== "number") throw new Error(`Cannot increment non-numeric value for key: ${parsedKey}`);
|
|
3141
|
+
if (typeof current !== "number") throw new Error(`Cannot increment non-numeric value for key: ${(0, _warlock_js_logger.maskEmailsInText)(parsedKey)}`);
|
|
3124
3142
|
const newValue = current + value;
|
|
3125
3143
|
if (node) {
|
|
3126
3144
|
node.value = newValue;
|
|
3145
|
+
if (options.ttl !== void 0 && !Number.isFinite(node.expiresAt) && Number.isFinite(ttl) && ttl > 0) node.expiresAt = Date.now() + ttl * 1e3;
|
|
3127
3146
|
this.moveHead(node);
|
|
3128
3147
|
} else {
|
|
3129
|
-
const newNode = new CacheNode(parsedKey, newValue,
|
|
3148
|
+
const newNode = new CacheNode(parsedKey, newValue, ttl);
|
|
3130
3149
|
this.cache.set(parsedKey, newNode);
|
|
3131
3150
|
this.addNode(newNode);
|
|
3132
3151
|
if (this.cache.size > this.capacity) this.removeTail();
|
|
@@ -3134,7 +3153,7 @@ var LRUMemoryCacheDriver = class extends BaseCacheDriver {
|
|
|
3134
3153
|
await this.emit("set", {
|
|
3135
3154
|
key: parsedKey,
|
|
3136
3155
|
value: newValue,
|
|
3137
|
-
ttl
|
|
3156
|
+
ttl
|
|
3138
3157
|
});
|
|
3139
3158
|
return newValue;
|
|
3140
3159
|
}
|
|
@@ -3315,7 +3334,7 @@ var LRUMemoryCacheDriver = class extends BaseCacheDriver {
|
|
|
3315
3334
|
};
|
|
3316
3335
|
|
|
3317
3336
|
//#endregion
|
|
3318
|
-
//#region
|
|
3337
|
+
//#region ../../packages/cache/src/drivers/memory-cache-driver.ts
|
|
3319
3338
|
/**
|
|
3320
3339
|
* Clone non-primitive values so cached state can't be mutated through
|
|
3321
3340
|
* references held by callers. Primitives are immutable and returned as-is.
|
|
@@ -3487,17 +3506,23 @@ var MemoryCacheDriver = class extends BaseCacheDriver {
|
|
|
3487
3506
|
* concurrent increments in this process never lose an update. An existing
|
|
3488
3507
|
* entry keeps its expiry; a missing key starts from 0 with the default TTL.
|
|
3489
3508
|
*/
|
|
3490
|
-
async increment(key, value = 1) {
|
|
3509
|
+
async increment(key, value = 1, options = {}) {
|
|
3510
|
+
const ttl = options.ttl === void 0 ? this.ttl : parseTtl(options.ttl);
|
|
3491
3511
|
const parsedKey = this.parseKey(key);
|
|
3492
3512
|
const entry = this.readLive(parsedKey);
|
|
3493
3513
|
const current = entry ? entry.data : 0;
|
|
3494
|
-
if (typeof current !== "number") throw new Error(`Cannot increment non-numeric value for key: ${parsedKey}`);
|
|
3514
|
+
if (typeof current !== "number") throw new Error(`Cannot increment non-numeric value for key: ${(0, _warlock_js_logger.maskEmailsInText)(parsedKey)}`);
|
|
3495
3515
|
const newValue = current + value;
|
|
3496
3516
|
if (entry) {
|
|
3497
3517
|
entry.data = newValue;
|
|
3518
|
+
if (options.ttl !== void 0 && !Number.isFinite(entry.expiresAt) && Number.isFinite(ttl) && ttl > 0) {
|
|
3519
|
+
entry.ttl = ttl;
|
|
3520
|
+
entry.expiresAt = Date.now() + ttl * 1e3;
|
|
3521
|
+
this.expiry.set(parsedKey, entry.expiresAt);
|
|
3522
|
+
}
|
|
3498
3523
|
this.touch(parsedKey, entry);
|
|
3499
3524
|
} else {
|
|
3500
|
-
const data = this.prepareDataForStorage(newValue,
|
|
3525
|
+
const data = this.prepareDataForStorage(newValue, ttl);
|
|
3501
3526
|
this.entries.set(parsedKey, data);
|
|
3502
3527
|
if (data.expiresAt !== void 0 && Number.isFinite(data.expiresAt)) this.expiry.set(parsedKey, data.expiresAt);
|
|
3503
3528
|
this.enforceMaxSize(parsedKey);
|
|
@@ -3505,7 +3530,7 @@ var MemoryCacheDriver = class extends BaseCacheDriver {
|
|
|
3505
3530
|
await this.emit("set", {
|
|
3506
3531
|
key: parsedKey,
|
|
3507
3532
|
value: newValue,
|
|
3508
|
-
ttl: entry?.ttl ??
|
|
3533
|
+
ttl: entry?.ttl ?? ttl
|
|
3509
3534
|
});
|
|
3510
3535
|
return newValue;
|
|
3511
3536
|
}
|
|
@@ -3674,7 +3699,7 @@ var MemoryCacheDriver = class extends BaseCacheDriver {
|
|
|
3674
3699
|
};
|
|
3675
3700
|
|
|
3676
3701
|
//#endregion
|
|
3677
|
-
//#region
|
|
3702
|
+
//#region ../../packages/cache/src/drivers/memory-extended-cache-driver.ts
|
|
3678
3703
|
/**
|
|
3679
3704
|
* Memory driver with a sliding ttl: every live read pushes the entry's
|
|
3680
3705
|
* expiration forward by its ttl. The sliding itself lives in
|
|
@@ -3691,7 +3716,7 @@ var MemoryExtendedCacheDriver = class extends MemoryCacheDriver {
|
|
|
3691
3716
|
};
|
|
3692
3717
|
|
|
3693
3718
|
//#endregion
|
|
3694
|
-
//#region
|
|
3719
|
+
//#region ../../packages/cache/src/drivers/mock-cache-driver.ts
|
|
3695
3720
|
/**
|
|
3696
3721
|
* In-memory cache driver with introspection helpers, intended for use as a
|
|
3697
3722
|
* test double in downstream packages.
|
|
@@ -3857,19 +3882,25 @@ var MockCacheDriver = class extends BaseCacheDriver {
|
|
|
3857
3882
|
* Synchronous read-add-write (atomic within the process). Keeps an existing
|
|
3858
3883
|
* entry's expiry; a missing key starts from 0 with the default TTL.
|
|
3859
3884
|
*/
|
|
3860
|
-
async increment(key, value = 1) {
|
|
3885
|
+
async increment(key, value = 1, options = {}) {
|
|
3886
|
+
const ttl = options.ttl === void 0 ? this.ttl : parseTtl(options.ttl);
|
|
3861
3887
|
const parsedKey = this.parseKey(key);
|
|
3862
3888
|
this.recordCall("increment", parsedKey, [value]);
|
|
3863
3889
|
const entry = this.liveEntry(parsedKey);
|
|
3864
3890
|
const current = entry ? entry.data : 0;
|
|
3865
|
-
if (typeof current !== "number") throw new Error(`Cannot increment non-numeric value for key: ${parsedKey}`);
|
|
3891
|
+
if (typeof current !== "number") throw new Error(`Cannot increment non-numeric value for key: ${(0, _warlock_js_logger.maskEmailsInText)(parsedKey)}`);
|
|
3866
3892
|
const newValue = current + value;
|
|
3867
|
-
if (entry)
|
|
3868
|
-
|
|
3893
|
+
if (entry) {
|
|
3894
|
+
entry.data = newValue;
|
|
3895
|
+
if (options.ttl !== void 0 && !Number.isFinite(entry.expiresAt) && Number.isFinite(ttl) && ttl > 0) {
|
|
3896
|
+
entry.ttl = ttl;
|
|
3897
|
+
entry.expiresAt = Date.now() + ttl * 1e3;
|
|
3898
|
+
}
|
|
3899
|
+
} else this.storage.set(parsedKey, this.prepareDataForStorage(newValue, ttl));
|
|
3869
3900
|
await this.emit("set", {
|
|
3870
3901
|
key: parsedKey,
|
|
3871
3902
|
value: newValue,
|
|
3872
|
-
ttl
|
|
3903
|
+
ttl
|
|
3873
3904
|
});
|
|
3874
3905
|
return newValue;
|
|
3875
3906
|
}
|
|
@@ -4009,7 +4040,7 @@ var MockCacheDriver = class extends BaseCacheDriver {
|
|
|
4009
4040
|
};
|
|
4010
4041
|
|
|
4011
4042
|
//#endregion
|
|
4012
|
-
//#region
|
|
4043
|
+
//#region ../../packages/cache/src/drivers/null-cache-driver.ts
|
|
4013
4044
|
var NullCacheDriver = class extends BaseCacheDriver {
|
|
4014
4045
|
/**
|
|
4015
4046
|
* {@inheritdoc}
|
|
@@ -4052,32 +4083,39 @@ var NullCacheDriver = class extends BaseCacheDriver {
|
|
|
4052
4083
|
* {@inheritdoc}
|
|
4053
4084
|
*/
|
|
4054
4085
|
async removeNamespace(namespace) {
|
|
4055
|
-
|
|
4056
|
-
_warlock_js_logger.log.
|
|
4086
|
+
const loggableNamespace = (0, _warlock_js_logger.maskEmailsInText)(namespace);
|
|
4087
|
+
_warlock_js_logger.log.info("cache", "clearing namespace", loggableNamespace);
|
|
4088
|
+
_warlock_js_logger.log.success("cache", "namespace cleared", loggableNamespace);
|
|
4057
4089
|
return this;
|
|
4058
4090
|
}
|
|
4059
4091
|
/**
|
|
4092
|
+
* The key as it may appear in a log line: parsed, with email addresses masked
|
|
4093
|
+
*/
|
|
4094
|
+
loggableKey(key) {
|
|
4095
|
+
return (0, _warlock_js_logger.maskEmailsInText)(this.parseKey(key));
|
|
4096
|
+
}
|
|
4097
|
+
/**
|
|
4060
4098
|
* {@inheritdoc}
|
|
4061
4099
|
*/
|
|
4062
4100
|
async set(key, _value, _ttlOrOptions) {
|
|
4063
|
-
_warlock_js_logger.log.info("cache", "setting key", key);
|
|
4064
|
-
_warlock_js_logger.log.success("cache", "key set", key);
|
|
4101
|
+
_warlock_js_logger.log.info("cache", "setting key", this.loggableKey(key));
|
|
4102
|
+
_warlock_js_logger.log.success("cache", "key set", this.loggableKey(key));
|
|
4065
4103
|
return this;
|
|
4066
4104
|
}
|
|
4067
4105
|
/**
|
|
4068
4106
|
* {@inheritdoc}
|
|
4069
4107
|
*/
|
|
4070
4108
|
async get(key) {
|
|
4071
|
-
_warlock_js_logger.log.info("cache", "fetching", key);
|
|
4072
|
-
_warlock_js_logger.log.success("cache", "fetched", key);
|
|
4109
|
+
_warlock_js_logger.log.info("cache", "fetching", this.loggableKey(key));
|
|
4110
|
+
_warlock_js_logger.log.success("cache", "fetched", this.loggableKey(key));
|
|
4073
4111
|
return null;
|
|
4074
4112
|
}
|
|
4075
4113
|
/**
|
|
4076
4114
|
* {@inheritdoc}
|
|
4077
4115
|
*/
|
|
4078
4116
|
async remove(key) {
|
|
4079
|
-
_warlock_js_logger.log.info("cache", "removing", key);
|
|
4080
|
-
_warlock_js_logger.log.success("cache", "removed", key);
|
|
4117
|
+
_warlock_js_logger.log.info("cache", "removing", this.loggableKey(key));
|
|
4118
|
+
_warlock_js_logger.log.success("cache", "removed", this.loggableKey(key));
|
|
4081
4119
|
}
|
|
4082
4120
|
/**
|
|
4083
4121
|
* {@inheritdoc}
|
|
@@ -4104,7 +4142,7 @@ var NullCacheDriver = class extends BaseCacheDriver {
|
|
|
4104
4142
|
};
|
|
4105
4143
|
|
|
4106
4144
|
//#endregion
|
|
4107
|
-
//#region
|
|
4145
|
+
//#region ../../packages/cache/src/drivers/pg-cache-driver.ts
|
|
4108
4146
|
/** Compare-and-set attempts before `update()` gives up under contention. */
|
|
4109
4147
|
const PG_UPDATE_MAX_ATTEMPTS = 10;
|
|
4110
4148
|
/**
|
|
@@ -4539,7 +4577,7 @@ var PgCacheDriver = class extends BaseCacheDriver {
|
|
|
4539
4577
|
* keeps its `expires_at`; a missing or expired row restarts from `value`
|
|
4540
4578
|
* with the driver default TTL. A non-numeric live value is rejected.
|
|
4541
4579
|
*/
|
|
4542
|
-
async increment(key, value = 1) {
|
|
4580
|
+
async increment(key, value = 1, options = {}) {
|
|
4543
4581
|
const parsedKey = this.parseKey(key);
|
|
4544
4582
|
const t = this.table;
|
|
4545
4583
|
const expired = `${t}.expires_at IS NOT NULL AND ${t}.expires_at <= now()`;
|
|
@@ -4548,15 +4586,18 @@ var PgCacheDriver = class extends BaseCacheDriver {
|
|
|
4548
4586
|
ON CONFLICT (key) DO UPDATE
|
|
4549
4587
|
SET value = CASE WHEN ${expired} THEN EXCLUDED.value
|
|
4550
4588
|
ELSE to_jsonb((${t}.value #>> '{}')::numeric + $2::numeric) END,
|
|
4551
|
-
expires_at = CASE WHEN ${expired} THEN EXCLUDED.expires_at
|
|
4589
|
+
expires_at = CASE WHEN ${expired} THEN EXCLUDED.expires_at
|
|
4590
|
+
WHEN $4::boolean AND ${t}.expires_at IS NULL THEN EXCLUDED.expires_at
|
|
4591
|
+
ELSE ${t}.expires_at END,
|
|
4552
4592
|
stale_at = CASE WHEN ${expired} THEN NULL ELSE ${t}.stale_at END
|
|
4553
4593
|
WHERE (${expired}) OR jsonb_typeof(${t}.value) = 'number'
|
|
4554
4594
|
RETURNING value`, [
|
|
4555
4595
|
parsedKey,
|
|
4556
4596
|
value,
|
|
4557
|
-
this.ttlToSeconds(this.ttl)
|
|
4597
|
+
this.ttlToSeconds(options.ttl === void 0 ? this.ttl : parseTtl(options.ttl)),
|
|
4598
|
+
options.ttl !== void 0
|
|
4558
4599
|
]);
|
|
4559
|
-
if (rows.length === 0) throw new Error(`Cannot increment non-numeric value for key: ${parsedKey}`);
|
|
4600
|
+
if (rows.length === 0) throw new Error(`Cannot increment non-numeric value for key: ${(0, _warlock_js_logger.maskEmailsInText)(parsedKey)}`);
|
|
4560
4601
|
const newValue = Number(this.decodeJson(rows[0].value));
|
|
4561
4602
|
await this.emit("set", {
|
|
4562
4603
|
key: parsedKey,
|
|
@@ -4757,7 +4798,7 @@ var PgCacheDriver = class extends BaseCacheDriver {
|
|
|
4757
4798
|
};
|
|
4758
4799
|
|
|
4759
4800
|
//#endregion
|
|
4760
|
-
//#region
|
|
4801
|
+
//#region ../../packages/cache/src/drivers/redis-cache-driver.ts
|
|
4761
4802
|
/**
|
|
4762
4803
|
* Cached Redis module (loaded once, reused)
|
|
4763
4804
|
*/
|
|
@@ -4821,6 +4862,23 @@ return 1`;
|
|
|
4821
4862
|
const REDIS_GET_DEL_SCRIPT = `local v = redis.call('GET', KEYS[1])
|
|
4822
4863
|
if v then redis.call('DEL', KEYS[1]) end
|
|
4823
4864
|
return v`;
|
|
4865
|
+
/**
|
|
4866
|
+
* Increment that gives a counter without an expiry its per-call or default TTL,
|
|
4867
|
+
* in one round trip.
|
|
4868
|
+
*
|
|
4869
|
+
* KEYS[1]=key; ARGV[1]=amount; ARGV[2]=ttl seconds ('0' = none).
|
|
4870
|
+
*
|
|
4871
|
+
* Replaces `INCRBY` + `EXPIRE … NX`: the `NX` flag needs Redis >= 7.0, and on
|
|
4872
|
+
* Redis 6 the second command failed after the count had already gone up.
|
|
4873
|
+
* `TTL == -1` means "exists without an expiry", so a TTL set earlier (by
|
|
4874
|
+
* `set(..., { ttl })`) is never shortened or reset.
|
|
4875
|
+
*/
|
|
4876
|
+
const REDIS_INCREMENT_SCRIPT = `local v = redis.call('INCRBY', KEYS[1], ARGV[1])
|
|
4877
|
+
local ttl = tonumber(ARGV[2])
|
|
4878
|
+
if ttl > 0 and redis.call('TTL', KEYS[1]) == -1 then
|
|
4879
|
+
redis.call('EXPIRE', KEYS[1], ttl)
|
|
4880
|
+
end
|
|
4881
|
+
return v`;
|
|
4824
4882
|
/** Compare-and-set attempts before `update()` gives up under contention. */
|
|
4825
4883
|
const UPDATE_MAX_ATTEMPTS = 10;
|
|
4826
4884
|
/** Keys deleted per UNLINK/DEL while draining a namespace. */
|
|
@@ -5249,11 +5307,15 @@ var RedisCacheDriver = class extends BaseCacheDriver {
|
|
|
5249
5307
|
* Atomic increment using Redis native INCRBY command
|
|
5250
5308
|
* {@inheritdoc}
|
|
5251
5309
|
*/
|
|
5252
|
-
async increment(key, value = 1) {
|
|
5310
|
+
async increment(key, value = 1, options = {}) {
|
|
5253
5311
|
const parsedKey = this.parseKey(key);
|
|
5254
5312
|
this.log("caching", parsedKey);
|
|
5255
|
-
const
|
|
5256
|
-
|
|
5313
|
+
const ttl = options.ttl === void 0 ? this.ttl : parseTtl(options.ttl);
|
|
5314
|
+
const defaultTtl = Number.isFinite(ttl) && ttl > 0 ? Math.ceil(ttl) : 0;
|
|
5315
|
+
const result = defaultTtl > 0 ? Number(await this.client?.eval(REDIS_INCREMENT_SCRIPT, {
|
|
5316
|
+
keys: [parsedKey],
|
|
5317
|
+
arguments: [String(value), String(defaultTtl)]
|
|
5318
|
+
})) : await this.client?.incrBy(parsedKey, value);
|
|
5257
5319
|
this.log("cached", parsedKey);
|
|
5258
5320
|
await this.emit("set", {
|
|
5259
5321
|
key: parsedKey,
|
|
@@ -5327,6 +5389,7 @@ exports.PgCacheDriver = PgCacheDriver;
|
|
|
5327
5389
|
exports.REDIS_CAS_SET_SCRIPT = REDIS_CAS_SET_SCRIPT;
|
|
5328
5390
|
exports.REDIS_COMPARE_DELETE_SCRIPT = REDIS_COMPARE_DELETE_SCRIPT;
|
|
5329
5391
|
exports.REDIS_GET_DEL_SCRIPT = REDIS_GET_DEL_SCRIPT;
|
|
5392
|
+
exports.REDIS_INCREMENT_SCRIPT = REDIS_INCREMENT_SCRIPT;
|
|
5330
5393
|
exports.RedisCacheDriver = RedisCacheDriver;
|
|
5331
5394
|
exports.ScopedCache = ScopedCache;
|
|
5332
5395
|
exports.TaggedCache = TaggedCache;
|