layercache 1.0.2 → 1.1.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/benchmarks/latency.ts +1 -1
- package/benchmarks/stampede.ts +1 -4
- package/dist/{chunk-IILH5XTS.js → chunk-QUB5VZFZ.js} +33 -4
- package/dist/cli.cjs +75 -7
- package/dist/cli.js +43 -4
- package/dist/index.cjs +894 -240
- package/dist/index.d.cts +291 -11
- package/dist/index.d.ts +291 -11
- package/dist/index.js +858 -236
- package/examples/express-api/index.ts +12 -8
- package/examples/nestjs-module/app.module.ts +2 -5
- package/examples/nextjs-api-routes/route.ts +1 -4
- package/package.json +6 -1
- package/packages/nestjs/dist/index.cjs +552 -220
- package/packages/nestjs/dist/index.d.cts +151 -10
- package/packages/nestjs/dist/index.d.ts +151 -10
- package/packages/nestjs/dist/index.js +552 -220
|
@@ -31,6 +31,7 @@ interface CacheMSetEntry<T> {
|
|
|
31
31
|
value: T;
|
|
32
32
|
options?: CacheWriteOptions;
|
|
33
33
|
}
|
|
34
|
+
/** Interface that all cache backend implementations must satisfy. */
|
|
34
35
|
interface CacheLayer {
|
|
35
36
|
readonly name: string;
|
|
36
37
|
readonly defaultTtl?: number;
|
|
@@ -43,7 +44,24 @@ interface CacheLayer {
|
|
|
43
44
|
clear(): Promise<void>;
|
|
44
45
|
deleteMany?(keys: string[]): Promise<void>;
|
|
45
46
|
keys?(): Promise<string[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Returns true if the key exists and has not expired.
|
|
49
|
+
* Implementations may omit this; CacheStack will fall back to `get()`.
|
|
50
|
+
*/
|
|
51
|
+
has?(key: string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the remaining TTL in seconds for the key, or null if the key
|
|
54
|
+
* does not exist, has no TTL, or has already expired.
|
|
55
|
+
* Implementations may omit this.
|
|
56
|
+
*/
|
|
57
|
+
ttl?(key: string): Promise<number | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Returns the number of entries currently held by this layer.
|
|
60
|
+
* Implementations may omit this.
|
|
61
|
+
*/
|
|
62
|
+
size?(): Promise<number>;
|
|
46
63
|
}
|
|
64
|
+
/** Snapshot of cumulative cache counters. */
|
|
47
65
|
interface CacheMetricsSnapshot {
|
|
48
66
|
hits: number;
|
|
49
67
|
misses: number;
|
|
@@ -62,6 +80,15 @@ interface CacheMetricsSnapshot {
|
|
|
62
80
|
degradedOperations: number;
|
|
63
81
|
hitsByLayer: Record<string, number>;
|
|
64
82
|
missesByLayer: Record<string, number>;
|
|
83
|
+
/** Timestamp (ms since epoch) when metrics were last reset. */
|
|
84
|
+
resetAt: number;
|
|
85
|
+
}
|
|
86
|
+
/** Computed hit-rate statistics derived from CacheMetricsSnapshot. */
|
|
87
|
+
interface CacheHitRateSnapshot {
|
|
88
|
+
/** Overall hit rate across all layers (0–1). */
|
|
89
|
+
overall: number;
|
|
90
|
+
/** Per-layer hit rates (0–1 each). */
|
|
91
|
+
byLayer: Record<string, number>;
|
|
65
92
|
}
|
|
66
93
|
interface CacheLogger {
|
|
67
94
|
debug?(message: string, context?: Record<string, unknown>): void;
|
|
@@ -102,6 +129,9 @@ interface CacheStackOptions {
|
|
|
102
129
|
invalidationBus?: InvalidationBus;
|
|
103
130
|
tagIndex?: CacheTagIndex;
|
|
104
131
|
broadcastL1Invalidation?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* @deprecated Use `broadcastL1Invalidation` instead.
|
|
134
|
+
*/
|
|
105
135
|
publishSetInvalidation?: boolean;
|
|
106
136
|
negativeCaching?: boolean;
|
|
107
137
|
negativeTtl?: number | LayerTtlMap;
|
|
@@ -117,6 +147,12 @@ interface CacheStackOptions {
|
|
|
117
147
|
singleFlightLeaseMs?: number;
|
|
118
148
|
singleFlightTimeoutMs?: number;
|
|
119
149
|
singleFlightPollMs?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Maximum number of entries in `accessProfiles` and `circuitBreakers` maps
|
|
152
|
+
* before the oldest entries are pruned. Prevents unbounded memory growth.
|
|
153
|
+
* Defaults to 100 000.
|
|
154
|
+
*/
|
|
155
|
+
maxProfileEntries?: number;
|
|
120
156
|
}
|
|
121
157
|
interface CacheAdaptiveTtlOptions {
|
|
122
158
|
hotAfter?: number;
|
|
@@ -136,9 +172,19 @@ interface CacheWarmEntry<T = unknown> {
|
|
|
136
172
|
options?: CacheGetOptions;
|
|
137
173
|
priority?: number;
|
|
138
174
|
}
|
|
175
|
+
/** Options controlling the cache warm-up process. */
|
|
139
176
|
interface CacheWarmOptions {
|
|
140
177
|
concurrency?: number;
|
|
141
178
|
continueOnError?: boolean;
|
|
179
|
+
/** Called after each entry is processed (success or failure). */
|
|
180
|
+
onProgress?: (progress: CacheWarmProgress) => void;
|
|
181
|
+
}
|
|
182
|
+
/** Progress information delivered to `CacheWarmOptions.onProgress`. */
|
|
183
|
+
interface CacheWarmProgress {
|
|
184
|
+
completed: number;
|
|
185
|
+
total: number;
|
|
186
|
+
key: string;
|
|
187
|
+
success: boolean;
|
|
142
188
|
}
|
|
143
189
|
interface CacheWrapOptions<TArgs extends unknown[] = unknown[]> extends CacheGetOptions {
|
|
144
190
|
keyResolver?: (...args: TArgs) => string;
|
|
@@ -157,14 +203,66 @@ interface CacheStatsSnapshot {
|
|
|
157
203
|
}>;
|
|
158
204
|
backgroundRefreshes: number;
|
|
159
205
|
}
|
|
206
|
+
/** All events emitted by CacheStack and their payload shapes. */
|
|
207
|
+
interface CacheStackEvents {
|
|
208
|
+
/** Fired on every cache hit. */
|
|
209
|
+
hit: {
|
|
210
|
+
key: string;
|
|
211
|
+
layer: string;
|
|
212
|
+
state: 'fresh' | 'stale-while-revalidate' | 'stale-if-error';
|
|
213
|
+
};
|
|
214
|
+
/** Fired on every cache miss before the fetcher runs. */
|
|
215
|
+
miss: {
|
|
216
|
+
key: string;
|
|
217
|
+
mode: string;
|
|
218
|
+
};
|
|
219
|
+
/** Fired after a value is stored in the cache. */
|
|
220
|
+
set: {
|
|
221
|
+
key: string;
|
|
222
|
+
kind: string;
|
|
223
|
+
tags?: string[];
|
|
224
|
+
};
|
|
225
|
+
/** Fired after one or more keys are deleted. */
|
|
226
|
+
delete: {
|
|
227
|
+
keys: string[];
|
|
228
|
+
};
|
|
229
|
+
/** Fired when a value is backfilled into a faster layer. */
|
|
230
|
+
backfill: {
|
|
231
|
+
key: string;
|
|
232
|
+
layer: string;
|
|
233
|
+
};
|
|
234
|
+
/** Fired when a stale value is returned to the caller. */
|
|
235
|
+
'stale-serve': {
|
|
236
|
+
key: string;
|
|
237
|
+
state: string;
|
|
238
|
+
layer: string;
|
|
239
|
+
};
|
|
240
|
+
/** Fired when a duplicate request is deduplicated in stampede prevention. */
|
|
241
|
+
'stampede-dedupe': {
|
|
242
|
+
key: string;
|
|
243
|
+
};
|
|
244
|
+
/** Fired after a key is successfully warmed. */
|
|
245
|
+
warm: {
|
|
246
|
+
key: string;
|
|
247
|
+
};
|
|
248
|
+
/** Fired when an error occurs (layer failure, circuit breaker, etc.). */
|
|
249
|
+
error: {
|
|
250
|
+
operation: string;
|
|
251
|
+
[key: string]: unknown;
|
|
252
|
+
};
|
|
253
|
+
}
|
|
160
254
|
|
|
161
255
|
declare class CacheNamespace {
|
|
162
256
|
private readonly cache;
|
|
163
257
|
private readonly prefix;
|
|
164
258
|
constructor(cache: CacheStack, prefix: string);
|
|
165
259
|
get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
260
|
+
getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
261
|
+
has(key: string): Promise<boolean>;
|
|
262
|
+
ttl(key: string): Promise<number | null>;
|
|
166
263
|
set<T>(key: string, value: T, options?: CacheWriteOptions): Promise<void>;
|
|
167
264
|
delete(key: string): Promise<void>;
|
|
265
|
+
mdelete(keys: string[]): Promise<void>;
|
|
168
266
|
clear(): Promise<void>;
|
|
169
267
|
mget<T>(entries: CacheMGetEntry<T>[]): Promise<Array<T | null>>;
|
|
170
268
|
mset<T>(entries: CacheMSetEntry<T>[]): Promise<void>;
|
|
@@ -173,40 +271,90 @@ declare class CacheNamespace {
|
|
|
173
271
|
wrap<TArgs extends unknown[], TResult>(keyPrefix: string, fetcher: (...args: TArgs) => Promise<TResult>, options?: CacheWrapOptions<TArgs>): (...args: TArgs) => Promise<TResult | null>;
|
|
174
272
|
warm(entries: CacheWarmEntry[], options?: CacheWarmOptions): Promise<void>;
|
|
175
273
|
getMetrics(): CacheMetricsSnapshot;
|
|
274
|
+
getHitRate(): CacheHitRateSnapshot;
|
|
176
275
|
qualify(key: string): string;
|
|
177
276
|
}
|
|
178
277
|
|
|
278
|
+
/** Typed overloads for EventEmitter so callers get autocomplete on event names. */
|
|
279
|
+
interface CacheStack {
|
|
280
|
+
on<K extends keyof CacheStackEvents>(event: K, listener: (data: CacheStackEvents[K]) => void): this;
|
|
281
|
+
once<K extends keyof CacheStackEvents>(event: K, listener: (data: CacheStackEvents[K]) => void): this;
|
|
282
|
+
off<K extends keyof CacheStackEvents>(event: K, listener: (data: CacheStackEvents[K]) => void): this;
|
|
283
|
+
emit<K extends keyof CacheStackEvents>(event: K, data: CacheStackEvents[K]): boolean;
|
|
284
|
+
}
|
|
179
285
|
declare class CacheStack extends EventEmitter {
|
|
180
286
|
private readonly layers;
|
|
181
287
|
private readonly options;
|
|
182
288
|
private readonly stampedeGuard;
|
|
183
|
-
private readonly
|
|
289
|
+
private readonly metricsCollector;
|
|
184
290
|
private readonly instanceId;
|
|
185
291
|
private readonly startup;
|
|
186
292
|
private unsubscribeInvalidation?;
|
|
187
293
|
private readonly logger;
|
|
188
294
|
private readonly tagIndex;
|
|
189
295
|
private readonly backgroundRefreshes;
|
|
190
|
-
private readonly accessProfiles;
|
|
191
296
|
private readonly layerDegradedUntil;
|
|
192
|
-
private readonly
|
|
297
|
+
private readonly ttlResolver;
|
|
298
|
+
private readonly circuitBreakerManager;
|
|
193
299
|
private isDisconnecting;
|
|
194
300
|
private disconnectPromise?;
|
|
195
301
|
constructor(layers: CacheLayer[], options?: CacheStackOptions);
|
|
302
|
+
/**
|
|
303
|
+
* Read-through cache get.
|
|
304
|
+
* Returns the cached value if present and fresh, or invokes `fetcher` on a miss
|
|
305
|
+
* and stores the result across all layers. Returns `null` if the key is not found
|
|
306
|
+
* and no `fetcher` is provided.
|
|
307
|
+
*/
|
|
196
308
|
get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
309
|
+
/**
|
|
310
|
+
* Alias for `get(key, fetcher, options)` — explicit get-or-set pattern.
|
|
311
|
+
* Fetches and caches the value if not already present.
|
|
312
|
+
*/
|
|
313
|
+
getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
314
|
+
/**
|
|
315
|
+
* Returns true if the given key exists and is not expired in any layer.
|
|
316
|
+
*/
|
|
317
|
+
has(key: string): Promise<boolean>;
|
|
318
|
+
/**
|
|
319
|
+
* Returns the remaining TTL in seconds for the key in the fastest layer
|
|
320
|
+
* that has it, or null if the key is not found / has no TTL.
|
|
321
|
+
*/
|
|
322
|
+
ttl(key: string): Promise<number | null>;
|
|
323
|
+
/**
|
|
324
|
+
* Stores a value in all cache layers. Overwrites any existing value.
|
|
325
|
+
*/
|
|
197
326
|
set<T>(key: string, value: T, options?: CacheWriteOptions): Promise<void>;
|
|
327
|
+
/**
|
|
328
|
+
* Deletes the key from all layers and publishes an invalidation message.
|
|
329
|
+
*/
|
|
198
330
|
delete(key: string): Promise<void>;
|
|
199
331
|
clear(): Promise<void>;
|
|
332
|
+
/**
|
|
333
|
+
* Deletes multiple keys at once. More efficient than calling `delete()` in a loop.
|
|
334
|
+
*/
|
|
335
|
+
mdelete(keys: string[]): Promise<void>;
|
|
200
336
|
mget<T>(entries: CacheMGetEntry<T>[]): Promise<Array<T | null>>;
|
|
201
337
|
mset<T>(entries: CacheMSetEntry<T>[]): Promise<void>;
|
|
202
338
|
warm(entries: CacheWarmEntry[], options?: CacheWarmOptions): Promise<void>;
|
|
339
|
+
/**
|
|
340
|
+
* Returns a cached version of `fetcher`. The cache key is derived from
|
|
341
|
+
* `prefix` plus the serialized arguments unless a `keyResolver` is provided.
|
|
342
|
+
*/
|
|
203
343
|
wrap<TArgs extends unknown[], TResult>(prefix: string, fetcher: (...args: TArgs) => Promise<TResult>, options?: CacheWrapOptions<TArgs>): (...args: TArgs) => Promise<TResult | null>;
|
|
344
|
+
/**
|
|
345
|
+
* Creates a `CacheNamespace` that automatically prefixes all keys with
|
|
346
|
+
* `prefix:`. Useful for multi-tenant or module-level isolation.
|
|
347
|
+
*/
|
|
204
348
|
namespace(prefix: string): CacheNamespace;
|
|
205
349
|
invalidateByTag(tag: string): Promise<void>;
|
|
206
350
|
invalidateByPattern(pattern: string): Promise<void>;
|
|
207
351
|
getMetrics(): CacheMetricsSnapshot;
|
|
208
352
|
getStats(): CacheStatsSnapshot;
|
|
209
353
|
resetMetrics(): void;
|
|
354
|
+
/**
|
|
355
|
+
* Returns computed hit-rate statistics (overall and per-layer).
|
|
356
|
+
*/
|
|
357
|
+
getHitRate(): CacheHitRateSnapshot;
|
|
210
358
|
exportState(): Promise<CacheSnapshotEntry[]>;
|
|
211
359
|
importState(entries: CacheSnapshotEntry[]): Promise<void>;
|
|
212
360
|
persistToFile(filePath: string): Promise<void>;
|
|
@@ -224,8 +372,6 @@ declare class CacheStack extends EventEmitter {
|
|
|
224
372
|
private executeLayerOperations;
|
|
225
373
|
private resolveFreshTtl;
|
|
226
374
|
private resolveLayerSeconds;
|
|
227
|
-
private readLayerNumber;
|
|
228
|
-
private applyJitter;
|
|
229
375
|
private shouldNegativeCache;
|
|
230
376
|
private scheduleBackgroundRefresh;
|
|
231
377
|
private resolveSingleFlightOptions;
|
|
@@ -246,15 +392,10 @@ declare class CacheStack extends EventEmitter {
|
|
|
246
392
|
private validateAdaptiveTtlOptions;
|
|
247
393
|
private validateCircuitBreakerOptions;
|
|
248
394
|
private applyFreshReadPolicies;
|
|
249
|
-
private applyAdaptiveTtl;
|
|
250
|
-
private recordAccess;
|
|
251
|
-
private incrementMetricMap;
|
|
252
395
|
private shouldSkipLayer;
|
|
253
396
|
private handleLayerFailure;
|
|
254
397
|
private isGracefulDegradationEnabled;
|
|
255
|
-
private assertCircuitClosed;
|
|
256
398
|
private recordCircuitFailure;
|
|
257
|
-
private resetCircuitBreaker;
|
|
258
399
|
private isNegativeStoredValue;
|
|
259
400
|
private emitError;
|
|
260
401
|
private serializeKeyPart;
|
|
@@ -31,6 +31,7 @@ interface CacheMSetEntry<T> {
|
|
|
31
31
|
value: T;
|
|
32
32
|
options?: CacheWriteOptions;
|
|
33
33
|
}
|
|
34
|
+
/** Interface that all cache backend implementations must satisfy. */
|
|
34
35
|
interface CacheLayer {
|
|
35
36
|
readonly name: string;
|
|
36
37
|
readonly defaultTtl?: number;
|
|
@@ -43,7 +44,24 @@ interface CacheLayer {
|
|
|
43
44
|
clear(): Promise<void>;
|
|
44
45
|
deleteMany?(keys: string[]): Promise<void>;
|
|
45
46
|
keys?(): Promise<string[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Returns true if the key exists and has not expired.
|
|
49
|
+
* Implementations may omit this; CacheStack will fall back to `get()`.
|
|
50
|
+
*/
|
|
51
|
+
has?(key: string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the remaining TTL in seconds for the key, or null if the key
|
|
54
|
+
* does not exist, has no TTL, or has already expired.
|
|
55
|
+
* Implementations may omit this.
|
|
56
|
+
*/
|
|
57
|
+
ttl?(key: string): Promise<number | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Returns the number of entries currently held by this layer.
|
|
60
|
+
* Implementations may omit this.
|
|
61
|
+
*/
|
|
62
|
+
size?(): Promise<number>;
|
|
46
63
|
}
|
|
64
|
+
/** Snapshot of cumulative cache counters. */
|
|
47
65
|
interface CacheMetricsSnapshot {
|
|
48
66
|
hits: number;
|
|
49
67
|
misses: number;
|
|
@@ -62,6 +80,15 @@ interface CacheMetricsSnapshot {
|
|
|
62
80
|
degradedOperations: number;
|
|
63
81
|
hitsByLayer: Record<string, number>;
|
|
64
82
|
missesByLayer: Record<string, number>;
|
|
83
|
+
/** Timestamp (ms since epoch) when metrics were last reset. */
|
|
84
|
+
resetAt: number;
|
|
85
|
+
}
|
|
86
|
+
/** Computed hit-rate statistics derived from CacheMetricsSnapshot. */
|
|
87
|
+
interface CacheHitRateSnapshot {
|
|
88
|
+
/** Overall hit rate across all layers (0–1). */
|
|
89
|
+
overall: number;
|
|
90
|
+
/** Per-layer hit rates (0–1 each). */
|
|
91
|
+
byLayer: Record<string, number>;
|
|
65
92
|
}
|
|
66
93
|
interface CacheLogger {
|
|
67
94
|
debug?(message: string, context?: Record<string, unknown>): void;
|
|
@@ -102,6 +129,9 @@ interface CacheStackOptions {
|
|
|
102
129
|
invalidationBus?: InvalidationBus;
|
|
103
130
|
tagIndex?: CacheTagIndex;
|
|
104
131
|
broadcastL1Invalidation?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* @deprecated Use `broadcastL1Invalidation` instead.
|
|
134
|
+
*/
|
|
105
135
|
publishSetInvalidation?: boolean;
|
|
106
136
|
negativeCaching?: boolean;
|
|
107
137
|
negativeTtl?: number | LayerTtlMap;
|
|
@@ -117,6 +147,12 @@ interface CacheStackOptions {
|
|
|
117
147
|
singleFlightLeaseMs?: number;
|
|
118
148
|
singleFlightTimeoutMs?: number;
|
|
119
149
|
singleFlightPollMs?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Maximum number of entries in `accessProfiles` and `circuitBreakers` maps
|
|
152
|
+
* before the oldest entries are pruned. Prevents unbounded memory growth.
|
|
153
|
+
* Defaults to 100 000.
|
|
154
|
+
*/
|
|
155
|
+
maxProfileEntries?: number;
|
|
120
156
|
}
|
|
121
157
|
interface CacheAdaptiveTtlOptions {
|
|
122
158
|
hotAfter?: number;
|
|
@@ -136,9 +172,19 @@ interface CacheWarmEntry<T = unknown> {
|
|
|
136
172
|
options?: CacheGetOptions;
|
|
137
173
|
priority?: number;
|
|
138
174
|
}
|
|
175
|
+
/** Options controlling the cache warm-up process. */
|
|
139
176
|
interface CacheWarmOptions {
|
|
140
177
|
concurrency?: number;
|
|
141
178
|
continueOnError?: boolean;
|
|
179
|
+
/** Called after each entry is processed (success or failure). */
|
|
180
|
+
onProgress?: (progress: CacheWarmProgress) => void;
|
|
181
|
+
}
|
|
182
|
+
/** Progress information delivered to `CacheWarmOptions.onProgress`. */
|
|
183
|
+
interface CacheWarmProgress {
|
|
184
|
+
completed: number;
|
|
185
|
+
total: number;
|
|
186
|
+
key: string;
|
|
187
|
+
success: boolean;
|
|
142
188
|
}
|
|
143
189
|
interface CacheWrapOptions<TArgs extends unknown[] = unknown[]> extends CacheGetOptions {
|
|
144
190
|
keyResolver?: (...args: TArgs) => string;
|
|
@@ -157,14 +203,66 @@ interface CacheStatsSnapshot {
|
|
|
157
203
|
}>;
|
|
158
204
|
backgroundRefreshes: number;
|
|
159
205
|
}
|
|
206
|
+
/** All events emitted by CacheStack and their payload shapes. */
|
|
207
|
+
interface CacheStackEvents {
|
|
208
|
+
/** Fired on every cache hit. */
|
|
209
|
+
hit: {
|
|
210
|
+
key: string;
|
|
211
|
+
layer: string;
|
|
212
|
+
state: 'fresh' | 'stale-while-revalidate' | 'stale-if-error';
|
|
213
|
+
};
|
|
214
|
+
/** Fired on every cache miss before the fetcher runs. */
|
|
215
|
+
miss: {
|
|
216
|
+
key: string;
|
|
217
|
+
mode: string;
|
|
218
|
+
};
|
|
219
|
+
/** Fired after a value is stored in the cache. */
|
|
220
|
+
set: {
|
|
221
|
+
key: string;
|
|
222
|
+
kind: string;
|
|
223
|
+
tags?: string[];
|
|
224
|
+
};
|
|
225
|
+
/** Fired after one or more keys are deleted. */
|
|
226
|
+
delete: {
|
|
227
|
+
keys: string[];
|
|
228
|
+
};
|
|
229
|
+
/** Fired when a value is backfilled into a faster layer. */
|
|
230
|
+
backfill: {
|
|
231
|
+
key: string;
|
|
232
|
+
layer: string;
|
|
233
|
+
};
|
|
234
|
+
/** Fired when a stale value is returned to the caller. */
|
|
235
|
+
'stale-serve': {
|
|
236
|
+
key: string;
|
|
237
|
+
state: string;
|
|
238
|
+
layer: string;
|
|
239
|
+
};
|
|
240
|
+
/** Fired when a duplicate request is deduplicated in stampede prevention. */
|
|
241
|
+
'stampede-dedupe': {
|
|
242
|
+
key: string;
|
|
243
|
+
};
|
|
244
|
+
/** Fired after a key is successfully warmed. */
|
|
245
|
+
warm: {
|
|
246
|
+
key: string;
|
|
247
|
+
};
|
|
248
|
+
/** Fired when an error occurs (layer failure, circuit breaker, etc.). */
|
|
249
|
+
error: {
|
|
250
|
+
operation: string;
|
|
251
|
+
[key: string]: unknown;
|
|
252
|
+
};
|
|
253
|
+
}
|
|
160
254
|
|
|
161
255
|
declare class CacheNamespace {
|
|
162
256
|
private readonly cache;
|
|
163
257
|
private readonly prefix;
|
|
164
258
|
constructor(cache: CacheStack, prefix: string);
|
|
165
259
|
get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
260
|
+
getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
261
|
+
has(key: string): Promise<boolean>;
|
|
262
|
+
ttl(key: string): Promise<number | null>;
|
|
166
263
|
set<T>(key: string, value: T, options?: CacheWriteOptions): Promise<void>;
|
|
167
264
|
delete(key: string): Promise<void>;
|
|
265
|
+
mdelete(keys: string[]): Promise<void>;
|
|
168
266
|
clear(): Promise<void>;
|
|
169
267
|
mget<T>(entries: CacheMGetEntry<T>[]): Promise<Array<T | null>>;
|
|
170
268
|
mset<T>(entries: CacheMSetEntry<T>[]): Promise<void>;
|
|
@@ -173,40 +271,90 @@ declare class CacheNamespace {
|
|
|
173
271
|
wrap<TArgs extends unknown[], TResult>(keyPrefix: string, fetcher: (...args: TArgs) => Promise<TResult>, options?: CacheWrapOptions<TArgs>): (...args: TArgs) => Promise<TResult | null>;
|
|
174
272
|
warm(entries: CacheWarmEntry[], options?: CacheWarmOptions): Promise<void>;
|
|
175
273
|
getMetrics(): CacheMetricsSnapshot;
|
|
274
|
+
getHitRate(): CacheHitRateSnapshot;
|
|
176
275
|
qualify(key: string): string;
|
|
177
276
|
}
|
|
178
277
|
|
|
278
|
+
/** Typed overloads for EventEmitter so callers get autocomplete on event names. */
|
|
279
|
+
interface CacheStack {
|
|
280
|
+
on<K extends keyof CacheStackEvents>(event: K, listener: (data: CacheStackEvents[K]) => void): this;
|
|
281
|
+
once<K extends keyof CacheStackEvents>(event: K, listener: (data: CacheStackEvents[K]) => void): this;
|
|
282
|
+
off<K extends keyof CacheStackEvents>(event: K, listener: (data: CacheStackEvents[K]) => void): this;
|
|
283
|
+
emit<K extends keyof CacheStackEvents>(event: K, data: CacheStackEvents[K]): boolean;
|
|
284
|
+
}
|
|
179
285
|
declare class CacheStack extends EventEmitter {
|
|
180
286
|
private readonly layers;
|
|
181
287
|
private readonly options;
|
|
182
288
|
private readonly stampedeGuard;
|
|
183
|
-
private readonly
|
|
289
|
+
private readonly metricsCollector;
|
|
184
290
|
private readonly instanceId;
|
|
185
291
|
private readonly startup;
|
|
186
292
|
private unsubscribeInvalidation?;
|
|
187
293
|
private readonly logger;
|
|
188
294
|
private readonly tagIndex;
|
|
189
295
|
private readonly backgroundRefreshes;
|
|
190
|
-
private readonly accessProfiles;
|
|
191
296
|
private readonly layerDegradedUntil;
|
|
192
|
-
private readonly
|
|
297
|
+
private readonly ttlResolver;
|
|
298
|
+
private readonly circuitBreakerManager;
|
|
193
299
|
private isDisconnecting;
|
|
194
300
|
private disconnectPromise?;
|
|
195
301
|
constructor(layers: CacheLayer[], options?: CacheStackOptions);
|
|
302
|
+
/**
|
|
303
|
+
* Read-through cache get.
|
|
304
|
+
* Returns the cached value if present and fresh, or invokes `fetcher` on a miss
|
|
305
|
+
* and stores the result across all layers. Returns `null` if the key is not found
|
|
306
|
+
* and no `fetcher` is provided.
|
|
307
|
+
*/
|
|
196
308
|
get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
309
|
+
/**
|
|
310
|
+
* Alias for `get(key, fetcher, options)` — explicit get-or-set pattern.
|
|
311
|
+
* Fetches and caches the value if not already present.
|
|
312
|
+
*/
|
|
313
|
+
getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
|
|
314
|
+
/**
|
|
315
|
+
* Returns true if the given key exists and is not expired in any layer.
|
|
316
|
+
*/
|
|
317
|
+
has(key: string): Promise<boolean>;
|
|
318
|
+
/**
|
|
319
|
+
* Returns the remaining TTL in seconds for the key in the fastest layer
|
|
320
|
+
* that has it, or null if the key is not found / has no TTL.
|
|
321
|
+
*/
|
|
322
|
+
ttl(key: string): Promise<number | null>;
|
|
323
|
+
/**
|
|
324
|
+
* Stores a value in all cache layers. Overwrites any existing value.
|
|
325
|
+
*/
|
|
197
326
|
set<T>(key: string, value: T, options?: CacheWriteOptions): Promise<void>;
|
|
327
|
+
/**
|
|
328
|
+
* Deletes the key from all layers and publishes an invalidation message.
|
|
329
|
+
*/
|
|
198
330
|
delete(key: string): Promise<void>;
|
|
199
331
|
clear(): Promise<void>;
|
|
332
|
+
/**
|
|
333
|
+
* Deletes multiple keys at once. More efficient than calling `delete()` in a loop.
|
|
334
|
+
*/
|
|
335
|
+
mdelete(keys: string[]): Promise<void>;
|
|
200
336
|
mget<T>(entries: CacheMGetEntry<T>[]): Promise<Array<T | null>>;
|
|
201
337
|
mset<T>(entries: CacheMSetEntry<T>[]): Promise<void>;
|
|
202
338
|
warm(entries: CacheWarmEntry[], options?: CacheWarmOptions): Promise<void>;
|
|
339
|
+
/**
|
|
340
|
+
* Returns a cached version of `fetcher`. The cache key is derived from
|
|
341
|
+
* `prefix` plus the serialized arguments unless a `keyResolver` is provided.
|
|
342
|
+
*/
|
|
203
343
|
wrap<TArgs extends unknown[], TResult>(prefix: string, fetcher: (...args: TArgs) => Promise<TResult>, options?: CacheWrapOptions<TArgs>): (...args: TArgs) => Promise<TResult | null>;
|
|
344
|
+
/**
|
|
345
|
+
* Creates a `CacheNamespace` that automatically prefixes all keys with
|
|
346
|
+
* `prefix:`. Useful for multi-tenant or module-level isolation.
|
|
347
|
+
*/
|
|
204
348
|
namespace(prefix: string): CacheNamespace;
|
|
205
349
|
invalidateByTag(tag: string): Promise<void>;
|
|
206
350
|
invalidateByPattern(pattern: string): Promise<void>;
|
|
207
351
|
getMetrics(): CacheMetricsSnapshot;
|
|
208
352
|
getStats(): CacheStatsSnapshot;
|
|
209
353
|
resetMetrics(): void;
|
|
354
|
+
/**
|
|
355
|
+
* Returns computed hit-rate statistics (overall and per-layer).
|
|
356
|
+
*/
|
|
357
|
+
getHitRate(): CacheHitRateSnapshot;
|
|
210
358
|
exportState(): Promise<CacheSnapshotEntry[]>;
|
|
211
359
|
importState(entries: CacheSnapshotEntry[]): Promise<void>;
|
|
212
360
|
persistToFile(filePath: string): Promise<void>;
|
|
@@ -224,8 +372,6 @@ declare class CacheStack extends EventEmitter {
|
|
|
224
372
|
private executeLayerOperations;
|
|
225
373
|
private resolveFreshTtl;
|
|
226
374
|
private resolveLayerSeconds;
|
|
227
|
-
private readLayerNumber;
|
|
228
|
-
private applyJitter;
|
|
229
375
|
private shouldNegativeCache;
|
|
230
376
|
private scheduleBackgroundRefresh;
|
|
231
377
|
private resolveSingleFlightOptions;
|
|
@@ -246,15 +392,10 @@ declare class CacheStack extends EventEmitter {
|
|
|
246
392
|
private validateAdaptiveTtlOptions;
|
|
247
393
|
private validateCircuitBreakerOptions;
|
|
248
394
|
private applyFreshReadPolicies;
|
|
249
|
-
private applyAdaptiveTtl;
|
|
250
|
-
private recordAccess;
|
|
251
|
-
private incrementMetricMap;
|
|
252
395
|
private shouldSkipLayer;
|
|
253
396
|
private handleLayerFailure;
|
|
254
397
|
private isGracefulDegradationEnabled;
|
|
255
|
-
private assertCircuitClosed;
|
|
256
398
|
private recordCircuitFailure;
|
|
257
|
-
private resetCircuitBreaker;
|
|
258
399
|
private isNegativeStoredValue;
|
|
259
400
|
private emitError;
|
|
260
401
|
private serializeKeyPart;
|