layercache 1.2.9 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { I as InvalidationBus, C as CacheLogger, a as InvalidationMessage, b as CacheTagIndex, c as CacheStack, d as CacheWrapOptions, e as CacheGetOptions, f as CacheLayer, g as CacheSerializer, h as CacheLayerSetManyEntry, i as CacheSingleFlightCoordinator, j as CacheSingleFlightExecutionOptions } from './edge-BXWTKlI1.cjs';
2
- export { k as CacheAdaptiveTtlOptions, l as CacheCircuitBreakerOptions, m as CacheDegradationOptions, n as CacheHealthCheckResult, o as CacheHitRateSnapshot, p as CacheInspectResult, q as CacheLayerLatency, r as CacheMGetEntry, s as CacheMSetEntry, t as CacheMetricsSnapshot, u as CacheMissError, v as CacheNamespace, w as CacheRateLimitOptions, x as CacheSnapshotEntry, y as CacheStackEvents, z as CacheStackOptions, A as CacheStatsSnapshot, B as CacheTtlPolicy, D as CacheTtlPolicyContext, E as CacheWarmEntry, F as CacheWarmOptions, G as CacheWarmProgress, H as CacheWriteBehindOptions, J as CacheWriteOptions, K as EvictionPolicy, L as LayerTtlMap, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-BXWTKlI1.cjs';
1
+ import { I as InvalidationBus, C as CacheLogger, a as InvalidationMessage, b as CacheTagIndex, c as CacheStack, d as CacheWrapOptions, e as CacheGetOptions, f as CacheLayer, g as CacheSerializer, h as CacheLayerSetManyEntry, i as CacheSingleFlightCoordinator, j as CacheSingleFlightExecutionOptions } from './edge-CUHTP9Bc.cjs';
2
+ export { k as CacheAdaptiveTtlOptions, l as CacheCircuitBreakerOptions, m as CacheDegradationOptions, n as CacheHealthCheckResult, o as CacheHitRateSnapshot, p as CacheInspectResult, q as CacheLayerLatency, r as CacheMGetEntry, s as CacheMSetEntry, t as CacheMetricsSnapshot, u as CacheMissError, v as CacheNamespace, w as CacheRateLimitOptions, x as CacheSnapshotEntry, y as CacheStackEvents, z as CacheStackOptions, A as CacheStatsSnapshot, B as CacheTtlPolicy, D as CacheTtlPolicyContext, E as CacheWarmEntry, F as CacheWarmOptions, G as CacheWarmProgress, H as CacheWriteBehindOptions, J as CacheWriteOptions, K as EvictionPolicy, L as LayerTtlMap, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-CUHTP9Bc.cjs';
3
3
  import Redis from 'ioredis';
4
4
  import 'node:events';
5
5
 
@@ -63,6 +63,11 @@ declare class RedisTagIndex implements CacheTagIndex {
63
63
  }
64
64
 
65
65
  interface CacheStatsHandlerOptions {
66
+ /**
67
+ * @deprecated Exposing cache stats without authentication is a security risk.
68
+ * Provide an `authorize` callback instead. This option will be removed in a
69
+ * future release.
70
+ */
66
71
  allowPublicAccess?: boolean;
67
72
  authorize?: (request: unknown) => boolean | Promise<boolean>;
68
73
  unauthorizedStatusCode?: number;
@@ -91,6 +96,11 @@ interface FastifyLikeReply {
91
96
  interface FastifyLayercachePluginOptions {
92
97
  exposeStatsRoute?: boolean;
93
98
  statsPath?: string;
99
+ /**
100
+ * @deprecated Exposing cache stats without authentication is a security risk.
101
+ * Provide an `authorizeStatsRoute` callback instead. This option will be
102
+ * removed in a future release.
103
+ */
94
104
  allowPublicStatsRoute?: boolean;
95
105
  authorizeStatsRoute?: (request: unknown) => boolean | Promise<boolean>;
96
106
  unauthorizedStatusCode?: number;
@@ -203,6 +213,11 @@ interface RedisLayerOptions {
203
213
  * Prevents decompression bomb attacks. Defaults to 64 MiB.
204
214
  */
205
215
  decompressionMaxBytes?: number;
216
+ /**
217
+ * Per-command timeout in milliseconds for Redis round-trips.
218
+ * Slow commands reject so CacheStack can treat the layer as degraded.
219
+ */
220
+ commandTimeoutMs?: number;
206
221
  disconnectOnDispose?: boolean;
207
222
  }
208
223
  declare class RedisLayer implements CacheLayer {
@@ -217,6 +232,7 @@ declare class RedisLayer implements CacheLayer {
217
232
  private readonly compression?;
218
233
  private readonly compressionThreshold;
219
234
  private readonly decompressionMaxBytes;
235
+ private readonly commandTimeoutMs;
220
236
  private readonly disconnectOnDispose;
221
237
  constructor(options: RedisLayerOptions);
222
238
  get<T>(key: string): Promise<T | null>;
@@ -240,6 +256,8 @@ declare class RedisLayer implements CacheLayer {
240
256
  forEachKey(visitor: (key: string) => void | Promise<void>): Promise<void>;
241
257
  private scanKeys;
242
258
  private withPrefix;
259
+ private validateKey;
260
+ private displayKey;
243
261
  private deserializeOrDelete;
244
262
  private deleteCorruptedKey;
245
263
  private rewriteWithPrimarySerializer;
@@ -256,6 +274,8 @@ declare class RedisLayer implements CacheLayer {
256
274
  */
257
275
  private decodePayload;
258
276
  private decompressWithLimit;
277
+ private normalizeCommandTimeoutMs;
278
+ private runCommand;
259
279
  }
260
280
 
261
281
  interface DiskLayerOptions {
@@ -266,7 +286,8 @@ interface DiskLayerOptions {
266
286
  /**
267
287
  * Maximum number of cache files to store on disk. When exceeded, the oldest
268
288
  * entries (by file mtime) are evicted to keep the directory bounded.
269
- * Defaults to unlimited.
289
+ * Defaults to 50 000. Set to `Infinity` to disable the limit (not recommended
290
+ * in production — unbounded growth will eventually exhaust disk space).
270
291
  */
271
292
  maxFiles?: number;
272
293
  /**
@@ -275,6 +296,19 @@ interface DiskLayerOptions {
275
296
  * Set to `false` to disable the limit.
276
297
  */
277
298
  maxEntryBytes?: number | false;
299
+ /**
300
+ * Encrypt cached data at rest using AES-256-GCM. Accepts a string or Buffer.
301
+ * The key material is hashed with SHA-256 to derive the actual cipher key.
302
+ * Encryption also provides authenticated integrity — a separate signingKey
303
+ * is unnecessary when encryption is enabled.
304
+ */
305
+ encryptionKey?: string | Buffer;
306
+ /**
307
+ * Sign cached data at rest using HMAC-SHA256 for integrity verification.
308
+ * Accepts a string or Buffer. Ignored when `encryptionKey` is also provided
309
+ * (AES-GCM already provides integrity).
310
+ */
311
+ signingKey?: string | Buffer;
278
312
  }
279
313
  /**
280
314
  * A file-system backed cache layer.
@@ -295,6 +329,7 @@ declare class DiskLayer implements CacheLayer {
295
329
  private readonly serializer;
296
330
  private readonly maxFiles;
297
331
  private readonly maxEntryBytes;
332
+ private readonly protection;
298
333
  private writeQueue;
299
334
  constructor(options: DiskLayerOptions);
300
335
  get<T>(key: string): Promise<T | null>;
@@ -408,19 +443,41 @@ declare class MsgpackSerializer implements CacheSerializer {
408
443
  interface RedisSingleFlightCoordinatorOptions {
409
444
  client: Redis;
410
445
  prefix?: string;
446
+ commandTimeoutMs?: number;
411
447
  }
412
448
  declare class RedisSingleFlightCoordinator implements CacheSingleFlightCoordinator {
413
449
  private readonly client;
414
450
  private readonly prefix;
451
+ private readonly commandTimeoutMs;
415
452
  constructor(options: RedisSingleFlightCoordinatorOptions);
416
453
  execute<T>(key: string, options: CacheSingleFlightExecutionOptions, worker: () => Promise<T>, waiter: () => Promise<T>): Promise<T>;
417
454
  private startLeaseRenewal;
455
+ private normalizeCommandTimeoutMs;
456
+ private runCommand;
418
457
  }
419
458
 
459
+ interface StampedeGuardOptions {
460
+ /**
461
+ * Maximum number of concurrent in-flight keys. When exceeded, new `execute`
462
+ * calls for keys that are not already in-flight will throw immediately.
463
+ * Defaults to 10 000.
464
+ */
465
+ maxInFlight?: number;
466
+ /**
467
+ * Maximum milliseconds to wait for a single in-flight task before rejecting
468
+ * with a timeout error. When a timeout fires the entry is released so
469
+ * subsequent callers can retry. Defaults to no timeout.
470
+ */
471
+ entryTimeoutMs?: number;
472
+ }
420
473
  declare class StampedeGuard {
421
- private readonly mutexes;
474
+ private readonly inFlight;
475
+ private readonly maxInFlight;
476
+ private readonly entryTimeoutMs;
477
+ constructor(options?: StampedeGuardOptions);
422
478
  execute<T>(key: string, task: () => Promise<T>): Promise<T>;
423
- private getMutexEntry;
479
+ private withTimeout;
480
+ private releaseEntry;
424
481
  }
425
482
 
426
483
  /**
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { I as InvalidationBus, C as CacheLogger, a as InvalidationMessage, b as CacheTagIndex, c as CacheStack, d as CacheWrapOptions, e as CacheGetOptions, f as CacheLayer, g as CacheSerializer, h as CacheLayerSetManyEntry, i as CacheSingleFlightCoordinator, j as CacheSingleFlightExecutionOptions } from './edge-BXWTKlI1.js';
2
- export { k as CacheAdaptiveTtlOptions, l as CacheCircuitBreakerOptions, m as CacheDegradationOptions, n as CacheHealthCheckResult, o as CacheHitRateSnapshot, p as CacheInspectResult, q as CacheLayerLatency, r as CacheMGetEntry, s as CacheMSetEntry, t as CacheMetricsSnapshot, u as CacheMissError, v as CacheNamespace, w as CacheRateLimitOptions, x as CacheSnapshotEntry, y as CacheStackEvents, z as CacheStackOptions, A as CacheStatsSnapshot, B as CacheTtlPolicy, D as CacheTtlPolicyContext, E as CacheWarmEntry, F as CacheWarmOptions, G as CacheWarmProgress, H as CacheWriteBehindOptions, J as CacheWriteOptions, K as EvictionPolicy, L as LayerTtlMap, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-BXWTKlI1.js';
1
+ import { I as InvalidationBus, C as CacheLogger, a as InvalidationMessage, b as CacheTagIndex, c as CacheStack, d as CacheWrapOptions, e as CacheGetOptions, f as CacheLayer, g as CacheSerializer, h as CacheLayerSetManyEntry, i as CacheSingleFlightCoordinator, j as CacheSingleFlightExecutionOptions } from './edge-CUHTP9Bc.js';
2
+ export { k as CacheAdaptiveTtlOptions, l as CacheCircuitBreakerOptions, m as CacheDegradationOptions, n as CacheHealthCheckResult, o as CacheHitRateSnapshot, p as CacheInspectResult, q as CacheLayerLatency, r as CacheMGetEntry, s as CacheMSetEntry, t as CacheMetricsSnapshot, u as CacheMissError, v as CacheNamespace, w as CacheRateLimitOptions, x as CacheSnapshotEntry, y as CacheStackEvents, z as CacheStackOptions, A as CacheStatsSnapshot, B as CacheTtlPolicy, D as CacheTtlPolicyContext, E as CacheWarmEntry, F as CacheWarmOptions, G as CacheWarmProgress, H as CacheWriteBehindOptions, J as CacheWriteOptions, K as EvictionPolicy, L as LayerTtlMap, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-CUHTP9Bc.js';
3
3
  import Redis from 'ioredis';
4
4
  import 'node:events';
5
5
 
@@ -63,6 +63,11 @@ declare class RedisTagIndex implements CacheTagIndex {
63
63
  }
64
64
 
65
65
  interface CacheStatsHandlerOptions {
66
+ /**
67
+ * @deprecated Exposing cache stats without authentication is a security risk.
68
+ * Provide an `authorize` callback instead. This option will be removed in a
69
+ * future release.
70
+ */
66
71
  allowPublicAccess?: boolean;
67
72
  authorize?: (request: unknown) => boolean | Promise<boolean>;
68
73
  unauthorizedStatusCode?: number;
@@ -91,6 +96,11 @@ interface FastifyLikeReply {
91
96
  interface FastifyLayercachePluginOptions {
92
97
  exposeStatsRoute?: boolean;
93
98
  statsPath?: string;
99
+ /**
100
+ * @deprecated Exposing cache stats without authentication is a security risk.
101
+ * Provide an `authorizeStatsRoute` callback instead. This option will be
102
+ * removed in a future release.
103
+ */
94
104
  allowPublicStatsRoute?: boolean;
95
105
  authorizeStatsRoute?: (request: unknown) => boolean | Promise<boolean>;
96
106
  unauthorizedStatusCode?: number;
@@ -203,6 +213,11 @@ interface RedisLayerOptions {
203
213
  * Prevents decompression bomb attacks. Defaults to 64 MiB.
204
214
  */
205
215
  decompressionMaxBytes?: number;
216
+ /**
217
+ * Per-command timeout in milliseconds for Redis round-trips.
218
+ * Slow commands reject so CacheStack can treat the layer as degraded.
219
+ */
220
+ commandTimeoutMs?: number;
206
221
  disconnectOnDispose?: boolean;
207
222
  }
208
223
  declare class RedisLayer implements CacheLayer {
@@ -217,6 +232,7 @@ declare class RedisLayer implements CacheLayer {
217
232
  private readonly compression?;
218
233
  private readonly compressionThreshold;
219
234
  private readonly decompressionMaxBytes;
235
+ private readonly commandTimeoutMs;
220
236
  private readonly disconnectOnDispose;
221
237
  constructor(options: RedisLayerOptions);
222
238
  get<T>(key: string): Promise<T | null>;
@@ -240,6 +256,8 @@ declare class RedisLayer implements CacheLayer {
240
256
  forEachKey(visitor: (key: string) => void | Promise<void>): Promise<void>;
241
257
  private scanKeys;
242
258
  private withPrefix;
259
+ private validateKey;
260
+ private displayKey;
243
261
  private deserializeOrDelete;
244
262
  private deleteCorruptedKey;
245
263
  private rewriteWithPrimarySerializer;
@@ -256,6 +274,8 @@ declare class RedisLayer implements CacheLayer {
256
274
  */
257
275
  private decodePayload;
258
276
  private decompressWithLimit;
277
+ private normalizeCommandTimeoutMs;
278
+ private runCommand;
259
279
  }
260
280
 
261
281
  interface DiskLayerOptions {
@@ -266,7 +286,8 @@ interface DiskLayerOptions {
266
286
  /**
267
287
  * Maximum number of cache files to store on disk. When exceeded, the oldest
268
288
  * entries (by file mtime) are evicted to keep the directory bounded.
269
- * Defaults to unlimited.
289
+ * Defaults to 50 000. Set to `Infinity` to disable the limit (not recommended
290
+ * in production — unbounded growth will eventually exhaust disk space).
270
291
  */
271
292
  maxFiles?: number;
272
293
  /**
@@ -275,6 +296,19 @@ interface DiskLayerOptions {
275
296
  * Set to `false` to disable the limit.
276
297
  */
277
298
  maxEntryBytes?: number | false;
299
+ /**
300
+ * Encrypt cached data at rest using AES-256-GCM. Accepts a string or Buffer.
301
+ * The key material is hashed with SHA-256 to derive the actual cipher key.
302
+ * Encryption also provides authenticated integrity — a separate signingKey
303
+ * is unnecessary when encryption is enabled.
304
+ */
305
+ encryptionKey?: string | Buffer;
306
+ /**
307
+ * Sign cached data at rest using HMAC-SHA256 for integrity verification.
308
+ * Accepts a string or Buffer. Ignored when `encryptionKey` is also provided
309
+ * (AES-GCM already provides integrity).
310
+ */
311
+ signingKey?: string | Buffer;
278
312
  }
279
313
  /**
280
314
  * A file-system backed cache layer.
@@ -295,6 +329,7 @@ declare class DiskLayer implements CacheLayer {
295
329
  private readonly serializer;
296
330
  private readonly maxFiles;
297
331
  private readonly maxEntryBytes;
332
+ private readonly protection;
298
333
  private writeQueue;
299
334
  constructor(options: DiskLayerOptions);
300
335
  get<T>(key: string): Promise<T | null>;
@@ -408,19 +443,41 @@ declare class MsgpackSerializer implements CacheSerializer {
408
443
  interface RedisSingleFlightCoordinatorOptions {
409
444
  client: Redis;
410
445
  prefix?: string;
446
+ commandTimeoutMs?: number;
411
447
  }
412
448
  declare class RedisSingleFlightCoordinator implements CacheSingleFlightCoordinator {
413
449
  private readonly client;
414
450
  private readonly prefix;
451
+ private readonly commandTimeoutMs;
415
452
  constructor(options: RedisSingleFlightCoordinatorOptions);
416
453
  execute<T>(key: string, options: CacheSingleFlightExecutionOptions, worker: () => Promise<T>, waiter: () => Promise<T>): Promise<T>;
417
454
  private startLeaseRenewal;
455
+ private normalizeCommandTimeoutMs;
456
+ private runCommand;
418
457
  }
419
458
 
459
+ interface StampedeGuardOptions {
460
+ /**
461
+ * Maximum number of concurrent in-flight keys. When exceeded, new `execute`
462
+ * calls for keys that are not already in-flight will throw immediately.
463
+ * Defaults to 10 000.
464
+ */
465
+ maxInFlight?: number;
466
+ /**
467
+ * Maximum milliseconds to wait for a single in-flight task before rejecting
468
+ * with a timeout error. When a timeout fires the entry is released so
469
+ * subsequent callers can retry. Defaults to no timeout.
470
+ */
471
+ entryTimeoutMs?: number;
472
+ }
420
473
  declare class StampedeGuard {
421
- private readonly mutexes;
474
+ private readonly inFlight;
475
+ private readonly maxInFlight;
476
+ private readonly entryTimeoutMs;
477
+ constructor(options?: StampedeGuardOptions);
422
478
  execute<T>(key: string, task: () => Promise<T>): Promise<T>;
423
- private getMutexEntry;
479
+ private withTimeout;
480
+ private releaseEntry;
424
481
  }
425
482
 
426
483
  /**