layercache 1.3.2 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -81
- package/dist/{chunk-GJBKCFE6.js → chunk-5RCAX2BQ.js} +9 -9
- package/dist/{chunk-BQLL6IM5.js → chunk-BORDQ3LA.js} +135 -0
- package/dist/cli.cjs +77 -5
- package/dist/cli.js +37 -7
- package/dist/{edge-CUHTP9Bc.d.cts → edge-DKkrQ_Ky.d.cts} +3 -14
- package/dist/{edge-CUHTP9Bc.d.ts → edge-DKkrQ_Ky.d.ts} +3 -14
- package/dist/edge.cjs +9 -9
- package/dist/edge.d.cts +1 -1
- package/dist/edge.d.ts +1 -1
- package/dist/edge.js +1 -1
- package/dist/index.cjs +511 -387
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +491 -480
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
RedisTagIndex
|
|
4
|
-
|
|
3
|
+
RedisTagIndex,
|
|
4
|
+
validateCacheKey,
|
|
5
|
+
validatePattern,
|
|
6
|
+
validateTag
|
|
7
|
+
} from "./chunk-BORDQ3LA.js";
|
|
5
8
|
import {
|
|
6
9
|
isStoredValueEnvelope,
|
|
7
10
|
resolveStoredValue
|
|
@@ -46,13 +49,17 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
46
49
|
throw new Error(`Failed to connect to Redis at ${maskRedisUrl(redisUrl)}: ${message}`);
|
|
47
50
|
});
|
|
48
51
|
if (args.command === "stats") {
|
|
49
|
-
const
|
|
50
|
-
|
|
52
|
+
const pattern = args.pattern ?? "*";
|
|
53
|
+
if (args.pattern && !validateCliInput(args.pattern, validatePattern)) return;
|
|
54
|
+
const keys = await scanKeys(redis, pattern);
|
|
55
|
+
process.stdout.write(`${JSON.stringify({ totalKeys: keys.length, pattern }, null, 2)}
|
|
51
56
|
`);
|
|
52
57
|
return;
|
|
53
58
|
}
|
|
54
59
|
if (args.command === "keys") {
|
|
55
|
-
const
|
|
60
|
+
const pattern = args.pattern ?? "*";
|
|
61
|
+
if (args.pattern && !validateCliInput(args.pattern, validatePattern)) return;
|
|
62
|
+
const keys = await scanKeys(redis, pattern);
|
|
56
63
|
if (keys.length > 0) {
|
|
57
64
|
process.stdout.write(`${keys.join("\n")}
|
|
58
65
|
`);
|
|
@@ -61,6 +68,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
61
68
|
}
|
|
62
69
|
if (args.command === "invalidate") {
|
|
63
70
|
if (args.tag) {
|
|
71
|
+
if (!validateCliInput(args.tag, validateTag)) return;
|
|
64
72
|
const tagIndex = new RedisTagIndex({ client: redis, prefix: args.tagIndexPrefix ?? "layercache:tag-index" });
|
|
65
73
|
const keys2 = await tagIndex.keysForTag(args.tag);
|
|
66
74
|
if (keys2.length > 0) {
|
|
@@ -70,11 +78,18 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
70
78
|
`);
|
|
71
79
|
return;
|
|
72
80
|
}
|
|
73
|
-
const
|
|
81
|
+
const effectivePattern = args.pattern ?? "*";
|
|
82
|
+
if (args.pattern && !validateCliInput(args.pattern, validatePattern)) return;
|
|
83
|
+
const keys = await scanKeys(redis, effectivePattern);
|
|
84
|
+
if (!args.pattern && !args.force && keys.length > 0) {
|
|
85
|
+
process.stderr.write(`Warning: this operation will invalidate ${keys.length} keys. Use --force to confirm.
|
|
86
|
+
`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
74
89
|
if (keys.length > 0) {
|
|
75
90
|
await batchDelete(redis, keys);
|
|
76
91
|
}
|
|
77
|
-
process.stdout.write(`${JSON.stringify({ deletedKeys: keys.length, pattern:
|
|
92
|
+
process.stdout.write(`${JSON.stringify({ deletedKeys: keys.length, pattern: effectivePattern }, null, 2)}
|
|
78
93
|
`);
|
|
79
94
|
return;
|
|
80
95
|
}
|
|
@@ -82,6 +97,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
82
97
|
if (!args.key) {
|
|
83
98
|
throw new Error("inspect requires --key <key>.");
|
|
84
99
|
}
|
|
100
|
+
if (!validateCliInput(args.key, validateCacheKey)) return;
|
|
85
101
|
const payload = await redis.getBuffer(args.key);
|
|
86
102
|
const ttl = await redis.ttl(args.key);
|
|
87
103
|
const decoded = decodeInspectablePayload(payload);
|
|
@@ -156,6 +172,8 @@ function parseArgs(argv) {
|
|
|
156
172
|
index += 1;
|
|
157
173
|
} else if (token === "--require-tls") {
|
|
158
174
|
parsed.requireTls = true;
|
|
175
|
+
} else if (token === "--force") {
|
|
176
|
+
parsed.force = true;
|
|
159
177
|
}
|
|
160
178
|
}
|
|
161
179
|
return parsed;
|
|
@@ -232,6 +250,18 @@ function maskRedisUrl(url) {
|
|
|
232
250
|
return url.replace(/:([^@/]+)@/, ":***@");
|
|
233
251
|
}
|
|
234
252
|
}
|
|
253
|
+
function validateCliInput(value, validator) {
|
|
254
|
+
try {
|
|
255
|
+
validator(value);
|
|
256
|
+
return true;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
259
|
+
process.stderr.write(`Error: ${message}
|
|
260
|
+
`);
|
|
261
|
+
process.exitCode = 1;
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
235
265
|
if (process.argv[1]?.endsWith("cli.cjs") || process.argv[1]?.endsWith("cli.js")) {
|
|
236
266
|
void main();
|
|
237
267
|
}
|
|
@@ -557,8 +557,6 @@ declare class CacheStack extends EventEmitter {
|
|
|
557
557
|
private readonly invalidation;
|
|
558
558
|
private readonly layerWriter;
|
|
559
559
|
private readonly snapshots;
|
|
560
|
-
private readonly backgroundRefreshes;
|
|
561
|
-
private readonly backgroundRefreshAbort;
|
|
562
560
|
private readonly layerDegradedUntil;
|
|
563
561
|
private readonly maintenance;
|
|
564
562
|
private readonly ttlResolver;
|
|
@@ -566,6 +564,7 @@ declare class CacheStack extends EventEmitter {
|
|
|
566
564
|
private nextOperationId;
|
|
567
565
|
private currentGeneration?;
|
|
568
566
|
private isDisconnecting;
|
|
567
|
+
private readonly reader;
|
|
569
568
|
private disconnectPromise?;
|
|
570
569
|
constructor(layers: CacheLayer[], options?: CacheStackOptions);
|
|
571
570
|
/**
|
|
@@ -575,7 +574,6 @@ declare class CacheStack extends EventEmitter {
|
|
|
575
574
|
* and no `fetcher` is provided.
|
|
576
575
|
*/
|
|
577
576
|
get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
578
|
-
private getPrepared;
|
|
579
577
|
/**
|
|
580
578
|
* Alias for `get(key, fetcher, options)` — explicit get-or-set pattern.
|
|
581
579
|
* Fetches and caches the value if not already present.
|
|
@@ -652,20 +650,10 @@ declare class CacheStack extends EventEmitter {
|
|
|
652
650
|
restoreFromFile(filePath: string): Promise<void>;
|
|
653
651
|
disconnect(): Promise<void>;
|
|
654
652
|
private initialize;
|
|
655
|
-
private fetchWithGuards;
|
|
656
|
-
private waitForFreshValue;
|
|
657
|
-
private fetchAndPopulate;
|
|
658
653
|
private storeEntry;
|
|
659
654
|
private writeBatch;
|
|
660
|
-
private readFromLayers;
|
|
661
|
-
private readLayerEntry;
|
|
662
|
-
private backfill;
|
|
663
655
|
private resolveFreshTtl;
|
|
664
656
|
private resolveLayerSeconds;
|
|
665
|
-
private shouldNegativeCache;
|
|
666
|
-
private scheduleBackgroundRefresh;
|
|
667
|
-
private runBackgroundRefresh;
|
|
668
|
-
private resolveSingleFlightOptions;
|
|
669
657
|
private deleteKeys;
|
|
670
658
|
private publishInvalidation;
|
|
671
659
|
private handleInvalidationMessage;
|
|
@@ -689,13 +677,14 @@ declare class CacheStack extends EventEmitter {
|
|
|
689
677
|
private validateWriteOptions;
|
|
690
678
|
private assertActive;
|
|
691
679
|
private awaitStartup;
|
|
680
|
+
private readLayerEntry;
|
|
681
|
+
private scheduleBackgroundRefresh;
|
|
692
682
|
private applyFreshReadPolicies;
|
|
693
683
|
private shouldSkipLayer;
|
|
694
684
|
private handleLayerFailure;
|
|
695
685
|
private reportRecoverableLayerFailure;
|
|
696
686
|
private isGracefulDegradationEnabled;
|
|
697
687
|
private recordCircuitFailure;
|
|
698
|
-
private isNegativeStoredValue;
|
|
699
688
|
private emitError;
|
|
700
689
|
private snapshotMaxBytes;
|
|
701
690
|
private snapshotMaxEntries;
|
|
@@ -557,8 +557,6 @@ declare class CacheStack extends EventEmitter {
|
|
|
557
557
|
private readonly invalidation;
|
|
558
558
|
private readonly layerWriter;
|
|
559
559
|
private readonly snapshots;
|
|
560
|
-
private readonly backgroundRefreshes;
|
|
561
|
-
private readonly backgroundRefreshAbort;
|
|
562
560
|
private readonly layerDegradedUntil;
|
|
563
561
|
private readonly maintenance;
|
|
564
562
|
private readonly ttlResolver;
|
|
@@ -566,6 +564,7 @@ declare class CacheStack extends EventEmitter {
|
|
|
566
564
|
private nextOperationId;
|
|
567
565
|
private currentGeneration?;
|
|
568
566
|
private isDisconnecting;
|
|
567
|
+
private readonly reader;
|
|
569
568
|
private disconnectPromise?;
|
|
570
569
|
constructor(layers: CacheLayer[], options?: CacheStackOptions);
|
|
571
570
|
/**
|
|
@@ -575,7 +574,6 @@ declare class CacheStack extends EventEmitter {
|
|
|
575
574
|
* and no `fetcher` is provided.
|
|
576
575
|
*/
|
|
577
576
|
get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
578
|
-
private getPrepared;
|
|
579
577
|
/**
|
|
580
578
|
* Alias for `get(key, fetcher, options)` — explicit get-or-set pattern.
|
|
581
579
|
* Fetches and caches the value if not already present.
|
|
@@ -652,20 +650,10 @@ declare class CacheStack extends EventEmitter {
|
|
|
652
650
|
restoreFromFile(filePath: string): Promise<void>;
|
|
653
651
|
disconnect(): Promise<void>;
|
|
654
652
|
private initialize;
|
|
655
|
-
private fetchWithGuards;
|
|
656
|
-
private waitForFreshValue;
|
|
657
|
-
private fetchAndPopulate;
|
|
658
653
|
private storeEntry;
|
|
659
654
|
private writeBatch;
|
|
660
|
-
private readFromLayers;
|
|
661
|
-
private readLayerEntry;
|
|
662
|
-
private backfill;
|
|
663
655
|
private resolveFreshTtl;
|
|
664
656
|
private resolveLayerSeconds;
|
|
665
|
-
private shouldNegativeCache;
|
|
666
|
-
private scheduleBackgroundRefresh;
|
|
667
|
-
private runBackgroundRefresh;
|
|
668
|
-
private resolveSingleFlightOptions;
|
|
669
657
|
private deleteKeys;
|
|
670
658
|
private publishInvalidation;
|
|
671
659
|
private handleInvalidationMessage;
|
|
@@ -689,13 +677,14 @@ declare class CacheStack extends EventEmitter {
|
|
|
689
677
|
private validateWriteOptions;
|
|
690
678
|
private assertActive;
|
|
691
679
|
private awaitStartup;
|
|
680
|
+
private readLayerEntry;
|
|
681
|
+
private scheduleBackgroundRefresh;
|
|
692
682
|
private applyFreshReadPolicies;
|
|
693
683
|
private shouldSkipLayer;
|
|
694
684
|
private handleLayerFailure;
|
|
695
685
|
private reportRecoverableLayerFailure;
|
|
696
686
|
private isGracefulDegradationEnabled;
|
|
697
687
|
private recordCircuitFailure;
|
|
698
|
-
private isNegativeStoredValue;
|
|
699
688
|
private emitError;
|
|
700
689
|
private snapshotMaxBytes;
|
|
701
690
|
private snapshotMaxEntries;
|
package/dist/edge.cjs
CHANGED
|
@@ -339,7 +339,7 @@ var MAX_PATTERN_RECURSION_DEPTH = 500;
|
|
|
339
339
|
var TagIndex = class {
|
|
340
340
|
tagToKeys = /* @__PURE__ */ new Map();
|
|
341
341
|
keyToTags = /* @__PURE__ */ new Map();
|
|
342
|
-
knownKeys = /* @__PURE__ */ new
|
|
342
|
+
knownKeys = /* @__PURE__ */ new Map();
|
|
343
343
|
maxKnownKeys;
|
|
344
344
|
nextNodeId = 1;
|
|
345
345
|
root = this.createTrieNode();
|
|
@@ -427,10 +427,11 @@ var TagIndex = class {
|
|
|
427
427
|
};
|
|
428
428
|
}
|
|
429
429
|
insertKnownKey(key) {
|
|
430
|
-
|
|
430
|
+
const isNew = !this.knownKeys.has(key);
|
|
431
|
+
this.knownKeys.set(key, Date.now());
|
|
432
|
+
if (!isNew) {
|
|
431
433
|
return;
|
|
432
434
|
}
|
|
433
|
-
this.knownKeys.add(key);
|
|
434
435
|
let node = this.root;
|
|
435
436
|
for (const character of key) {
|
|
436
437
|
let child = node.children.get(character);
|
|
@@ -525,14 +526,13 @@ var TagIndex = class {
|
|
|
525
526
|
if (this.maxKnownKeys === void 0 || this.knownKeys.size <= this.maxKnownKeys) {
|
|
526
527
|
return;
|
|
527
528
|
}
|
|
529
|
+
const sorted = [...this.knownKeys.entries()].sort((a, b) => a[1] - b[1]);
|
|
528
530
|
const toRemove = Math.ceil(this.maxKnownKeys * 0.1);
|
|
529
|
-
let
|
|
530
|
-
|
|
531
|
-
if (
|
|
532
|
-
|
|
531
|
+
for (let i = 0; i < toRemove && i < sorted.length; i += 1) {
|
|
532
|
+
const entry = sorted[i];
|
|
533
|
+
if (entry) {
|
|
534
|
+
this.removeKey(entry[0]);
|
|
533
535
|
}
|
|
534
|
-
this.removeKey(key);
|
|
535
|
-
removed += 1;
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
removeKey(key) {
|
package/dist/edge.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-
|
|
1
|
+
export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-DKkrQ_Ky.cjs';
|
|
2
2
|
import 'node:events';
|
package/dist/edge.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-
|
|
1
|
+
export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-DKkrQ_Ky.js';
|
|
2
2
|
import 'node:events';
|