layercache 1.3.4 → 2.0.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.
Files changed (40) hide show
  1. package/README.md +42 -41
  2. package/dist/{chunk-BORDQ3LA.js → chunk-7KMKQ6QZ.js} +15 -1
  3. package/dist/{chunk-5RCAX2BQ.js → chunk-FFZCC7EQ.js} +3 -3
  4. package/dist/{chunk-4PPBOOXT.js → chunk-KJDFYE5T.js} +38 -26
  5. package/dist/cli.cjs +9 -9
  6. package/dist/cli.js +4 -4
  7. package/dist/{edge-DKkrQ_Ky.d.cts → edge-D2FpRlyS.d.cts} +71 -22
  8. package/dist/{edge-DKkrQ_Ky.d.ts → edge-D2FpRlyS.d.ts} +71 -22
  9. package/dist/edge.cjs +9 -9
  10. package/dist/edge.d.cts +1 -1
  11. package/dist/edge.d.ts +1 -1
  12. package/dist/edge.js +2 -2
  13. package/dist/index.cjs +399 -164
  14. package/dist/index.d.cts +6 -6
  15. package/dist/index.d.ts +6 -6
  16. package/dist/index.js +294 -81
  17. package/package.json +5 -5
  18. package/benchmarks/direct.ts +0 -221
  19. package/benchmarks/edge-utils.ts +0 -28
  20. package/benchmarks/edge.ts +0 -491
  21. package/benchmarks/http.ts +0 -99
  22. package/benchmarks/latency.ts +0 -45
  23. package/benchmarks/memory-pressure.ts +0 -144
  24. package/benchmarks/multi-process-fanout.ts +0 -231
  25. package/benchmarks/multi-process-worker.ts +0 -151
  26. package/benchmarks/paths.ts +0 -25
  27. package/benchmarks/queue-amplification-utils.ts +0 -48
  28. package/benchmarks/queue-amplification.ts +0 -230
  29. package/benchmarks/redis-latency-proxy.ts +0 -100
  30. package/benchmarks/redis.ts +0 -107
  31. package/benchmarks/scenario-utils.ts +0 -38
  32. package/benchmarks/server.ts +0 -157
  33. package/benchmarks/slow-redis-latency.ts +0 -309
  34. package/benchmarks/slow-redis-utils.ts +0 -29
  35. package/benchmarks/slow-redis.ts +0 -47
  36. package/benchmarks/stampede.ts +0 -26
  37. package/benchmarks/stats.ts +0 -46
  38. package/benchmarks/workload.ts +0 -77
  39. package/examples/express-api/index.ts +0 -31
  40. package/examples/nextjs-api-routes/route.ts +0 -16
@@ -11,18 +11,26 @@ declare class CacheMissError extends Error {
11
11
  interface LayerTtlMap {
12
12
  [layerName: string]: number | undefined;
13
13
  }
14
- interface CacheWriteOptions {
14
+ type CacheEntryWriteKind = 'value' | 'empty';
15
+ interface CacheEntryWriteOptions {
15
16
  tags?: string[];
16
17
  ttl?: number | LayerTtlMap;
17
18
  ttlPolicy?: CacheTtlPolicy;
18
- negativeCache?: boolean;
19
19
  negativeTtl?: number | LayerTtlMap;
20
20
  staleWhileRevalidate?: number | LayerTtlMap;
21
21
  staleIfError?: number | LayerTtlMap;
22
22
  ttlJitter?: number | LayerTtlMap;
23
+ adaptiveTtl?: boolean | CacheAdaptiveTtlOptions;
24
+ }
25
+ interface CacheContextOptionsContext {
26
+ key: string;
27
+ value: unknown;
28
+ kind: CacheEntryWriteKind;
29
+ }
30
+ interface CacheWriteOptions extends CacheEntryWriteOptions {
31
+ negativeCache?: boolean;
23
32
  slidingTtl?: boolean;
24
33
  refreshAhead?: number | LayerTtlMap;
25
- adaptiveTtl?: boolean | CacheAdaptiveTtlOptions;
26
34
  circuitBreaker?: CacheCircuitBreakerOptions;
27
35
  fetcherRateLimit?: CacheRateLimitOptions;
28
36
  /**
@@ -34,12 +42,37 @@ interface CacheWriteOptions {
34
42
  * cache.get('key', fetchData, { shouldCache: (v) => v.status === 200 })
35
43
  */
36
44
  shouldCache?: (value: unknown) => boolean;
45
+ /**
46
+ * Optional resolver that can override cache entry options using the current
47
+ * write context. This runs right before a value is stored, so callers can
48
+ * derive TTLs or tags from the fetched value instead of guessing upfront.
49
+ *
50
+ * Returned values override any static entry options already present on the
51
+ * same object. Fetch controls like `shouldCache`, `negativeCache`,
52
+ * `refreshAhead`, or `circuitBreaker` are not affected.
53
+ *
54
+ * @example
55
+ * cache.get('oauth:token', fetchToken, {
56
+ * ttl: 300_000,
57
+ * contextOptions: ({ value }) => ({
58
+ * ttl: Math.max(1, Math.floor(((value as { refreshExpiresIn: number }).refreshExpiresIn ?? 0) / 1_000))
59
+ * })
60
+ * })
61
+ */
62
+ contextOptions?: (context: CacheContextOptionsContext) => CacheEntryWriteOptions | undefined;
37
63
  }
38
64
  interface CacheGetOptions extends CacheWriteOptions {
39
65
  }
66
+ interface CacheFetcherContext<T = unknown> {
67
+ key: string;
68
+ currentValue: T | undefined;
69
+ state: 'miss' | 'fresh' | 'stale-while-revalidate' | 'stale-if-error';
70
+ layer?: string;
71
+ }
72
+ type CacheFetcher<T = unknown> = (context: CacheFetcherContext<T>) => Promise<T>;
40
73
  interface CacheMGetEntry<T> {
41
74
  key: string;
42
- fetch?: () => Promise<T>;
75
+ fetch?: CacheFetcher<T>;
43
76
  options?: CacheGetOptions;
44
77
  }
45
78
  interface CacheMSetEntry<T> {
@@ -75,7 +108,7 @@ interface CacheLayer {
75
108
  */
76
109
  has?(key: string): Promise<boolean>;
77
110
  /**
78
- * Returns the remaining TTL in seconds for the key, or null if the key
111
+ * Returns the remaining TTL in milliseconds for the key, or null if the key
79
112
  * does not exist, has no TTL, or has already expired.
80
113
  * Implementations may omit this.
81
114
  */
@@ -159,7 +192,7 @@ interface InvalidationMessage {
159
192
  scope: 'key' | 'keys' | 'clear';
160
193
  sourceId: string;
161
194
  keys?: string[];
162
- operation?: 'write' | 'delete' | 'invalidate' | 'clear';
195
+ operation?: 'write' | 'delete' | 'invalidate' | 'expire' | 'clear';
163
196
  }
164
197
  interface InvalidationBus {
165
198
  subscribe(handler: (message: InvalidationMessage) => Promise<void> | void): Promise<() => Promise<void> | void>;
@@ -255,7 +288,7 @@ interface CacheWriteBehindOptions {
255
288
  }
256
289
  interface CacheWarmEntry<T = unknown> {
257
290
  key: string;
258
- fetcher: () => Promise<T>;
291
+ fetcher: CacheFetcher<T>;
259
292
  options?: CacheGetOptions;
260
293
  priority?: number;
261
294
  }
@@ -301,12 +334,12 @@ interface CacheInspectResult {
301
334
  key: string;
302
335
  /** Layers in which the key is currently stored (not expired). */
303
336
  foundInLayers: string[];
304
- /** Remaining fresh TTL in seconds, or null if no expiry or not an envelope. */
305
- freshTtlSeconds: number | null;
306
- /** Remaining stale-while-revalidate window in seconds, or null. */
307
- staleTtlSeconds: number | null;
308
- /** Remaining stale-if-error window in seconds, or null. */
309
- errorTtlSeconds: number | null;
337
+ /** Remaining fresh TTL in milliseconds, or null if no expiry or not an envelope. */
338
+ freshTtlMs: number | null;
339
+ /** Remaining stale-while-revalidate window in milliseconds, or null. */
340
+ staleTtlMs: number | null;
341
+ /** Remaining stale-if-error window in milliseconds, or null. */
342
+ errorTtlMs: number | null;
310
343
  /** Whether the key is currently serving stale-while-revalidate. */
311
344
  isStale: boolean;
312
345
  /** Tags associated with this key (from the TagIndex). */
@@ -335,6 +368,10 @@ interface CacheStackEvents {
335
368
  delete: {
336
369
  keys: string[];
337
370
  };
371
+ /** Fired after one or more keys are marked expired but retained. */
372
+ expire: {
373
+ keys: string[];
374
+ };
338
375
  /** Fired when a value is backfilled into a faster layer. */
339
376
  backfill: {
340
377
  key: string;
@@ -486,12 +523,12 @@ declare class CacheNamespace {
486
523
  private static readonly metricsMutexes;
487
524
  private metrics;
488
525
  constructor(cache: CacheStack, prefix: string);
489
- get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
490
- getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
526
+ get<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
527
+ getOrSet<T>(key: string, fetcher: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
491
528
  /**
492
529
  * Like `get()`, but throws `CacheMissError` instead of returning `null`.
493
530
  */
494
- getOrThrow<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T>;
531
+ getOrThrow<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T>;
495
532
  has(key: string): Promise<boolean>;
496
533
  ttl(key: string): Promise<number | null>;
497
534
  set<T>(key: string, value: T, options?: CacheWriteOptions): Promise<void>;
@@ -501,9 +538,13 @@ declare class CacheNamespace {
501
538
  mget<T>(entries: CacheMGetEntry<T>[]): Promise<Array<T | null>>;
502
539
  mset<T>(entries: CacheMSetEntry<T>[]): Promise<void>;
503
540
  invalidateByTag(tag: string): Promise<void>;
541
+ expireByTag(tag: string): Promise<void>;
504
542
  invalidateByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
543
+ expireByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
505
544
  invalidateByPattern(pattern: string): Promise<void>;
545
+ expireByPattern(pattern: string): Promise<void>;
506
546
  invalidateByPrefix(prefix: string): Promise<void>;
547
+ expireByPrefix(prefix: string): Promise<void>;
507
548
  /**
508
549
  * Returns detailed metadata about a single cache key within this namespace.
509
550
  */
@@ -573,24 +614,24 @@ declare class CacheStack extends EventEmitter {
573
614
  * and stores the result across all layers. Returns `null` if the key is not found
574
615
  * and no `fetcher` is provided.
575
616
  */
576
- get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
617
+ get<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
577
618
  /**
578
619
  * Alias for `get(key, fetcher, options)` — explicit get-or-set pattern.
579
620
  * Fetches and caches the value if not already present.
580
621
  */
581
- getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
622
+ getOrSet<T>(key: string, fetcher: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
582
623
  /**
583
624
  * Like `get()`, but throws `CacheMissError` instead of returning `null`.
584
625
  * Useful when the value is expected to exist or the fetcher is expected to
585
626
  * return non-null.
586
627
  */
587
- getOrThrow<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T>;
628
+ getOrThrow<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T>;
588
629
  /**
589
630
  * Returns true if the given key exists and is not expired in any layer.
590
631
  */
591
632
  has(key: string): Promise<boolean>;
592
633
  /**
593
- * Returns the remaining TTL in seconds for the key in the fastest layer
634
+ * Returns the remaining TTL in milliseconds for the key in the fastest layer
594
635
  * that has it, or null if the key is not found / has no TTL.
595
636
  */
596
637
  ttl(key: string): Promise<number | null>;
@@ -621,9 +662,13 @@ declare class CacheStack extends EventEmitter {
621
662
  */
622
663
  namespace(prefix: string): CacheNamespace;
623
664
  invalidateByTag(tag: string): Promise<void>;
665
+ expireByTag(tag: string): Promise<void>;
624
666
  invalidateByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
667
+ expireByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
625
668
  invalidateByPattern(pattern: string): Promise<void>;
669
+ expireByPattern(pattern: string): Promise<void>;
626
670
  invalidateByPrefix(prefix: string): Promise<void>;
671
+ expireByPrefix(prefix: string): Promise<void>;
627
672
  getMetrics(): CacheMetricsSnapshot;
628
673
  getStats(): CacheStatsSnapshot;
629
674
  resetMetrics(): void;
@@ -653,8 +698,12 @@ declare class CacheStack extends EventEmitter {
653
698
  private storeEntry;
654
699
  private writeBatch;
655
700
  private resolveFreshTtl;
656
- private resolveLayerSeconds;
701
+ private resolveLayerMs;
702
+ private resolveContextOptions;
703
+ private isPlainObject;
657
704
  private deleteKeys;
705
+ private expireKeys;
706
+ private expireKeysInLayers;
658
707
  private publishInvalidation;
659
708
  private handleInvalidationMessage;
660
709
  private getTagsForKey;
@@ -711,4 +760,4 @@ interface HonoCacheMiddlewareOptions extends CacheGetOptions {
711
760
  }
712
761
  declare function createHonoCacheMiddleware(cache: CacheStack, options?: HonoCacheMiddlewareOptions): (context: HonoLikeContext, next: () => Promise<void>) => Promise<unknown>;
713
762
 
714
- export { type CacheStatsSnapshot as A, type CacheTtlPolicy as B, type CacheLogger as C, type CacheTtlPolicyContext as D, type CacheWarmEntry as E, type CacheWarmOptions as F, type CacheWarmProgress as G, type CacheWriteBehindOptions as H, type InvalidationBus as I, type CacheWriteOptions as J, type EvictionPolicy as K, type LayerTtlMap as L, MemoryLayer as M, type MemoryLayerOptions as N, type MemoryLayerSnapshotEntry as O, PatternMatcher as P, createHonoCacheMiddleware as Q, TagIndex as T, type InvalidationMessage as a, type CacheTagIndex as b, CacheStack as c, type CacheWrapOptions as d, type CacheGetOptions as e, type CacheLayer as f, type CacheSerializer as g, type CacheLayerSetManyEntry as h, type CacheSingleFlightCoordinator as i, type CacheSingleFlightExecutionOptions as j, type CacheAdaptiveTtlOptions as k, type CacheCircuitBreakerOptions as l, type CacheDegradationOptions as m, type CacheHealthCheckResult as n, type CacheHitRateSnapshot as o, type CacheInspectResult as p, type CacheLayerLatency as q, type CacheMGetEntry as r, type CacheMSetEntry as s, type CacheMetricsSnapshot as t, CacheMissError as u, CacheNamespace as v, type CacheRateLimitOptions as w, type CacheSnapshotEntry as x, type CacheStackEvents as y, type CacheStackOptions as z };
763
+ export { CacheNamespace as A, type CacheRateLimitOptions as B, type CacheLogger as C, type CacheSnapshotEntry as D, type CacheStackEvents as E, type CacheStackOptions as F, type CacheStatsSnapshot as G, type CacheTtlPolicy as H, type InvalidationBus as I, type CacheTtlPolicyContext as J, type CacheWarmEntry as K, type CacheWarmOptions as L, type CacheWarmProgress as M, type CacheWriteBehindOptions as N, type CacheWriteOptions as O, type EvictionPolicy as P, type LayerTtlMap as Q, MemoryLayer as R, type MemoryLayerOptions as S, type MemoryLayerSnapshotEntry as T, PatternMatcher as U, TagIndex as V, createHonoCacheMiddleware as W, type InvalidationMessage as a, type CacheTagIndex as b, CacheStack as c, type CacheWrapOptions as d, type CacheGetOptions as e, type CacheLayer as f, type CacheSerializer as g, type CacheLayerSetManyEntry as h, type CacheSingleFlightCoordinator as i, type CacheSingleFlightExecutionOptions as j, type CacheAdaptiveTtlOptions as k, type CacheCircuitBreakerOptions as l, type CacheContextOptionsContext as m, type CacheDegradationOptions as n, type CacheEntryWriteKind as o, type CacheEntryWriteOptions as p, type CacheFetcher as q, type CacheFetcherContext as r, type CacheHealthCheckResult as s, type CacheHitRateSnapshot as t, type CacheInspectResult as u, type CacheLayerLatency as v, type CacheMGetEntry as w, type CacheMSetEntry as x, type CacheMetricsSnapshot as y, CacheMissError as z };
@@ -11,18 +11,26 @@ declare class CacheMissError extends Error {
11
11
  interface LayerTtlMap {
12
12
  [layerName: string]: number | undefined;
13
13
  }
14
- interface CacheWriteOptions {
14
+ type CacheEntryWriteKind = 'value' | 'empty';
15
+ interface CacheEntryWriteOptions {
15
16
  tags?: string[];
16
17
  ttl?: number | LayerTtlMap;
17
18
  ttlPolicy?: CacheTtlPolicy;
18
- negativeCache?: boolean;
19
19
  negativeTtl?: number | LayerTtlMap;
20
20
  staleWhileRevalidate?: number | LayerTtlMap;
21
21
  staleIfError?: number | LayerTtlMap;
22
22
  ttlJitter?: number | LayerTtlMap;
23
+ adaptiveTtl?: boolean | CacheAdaptiveTtlOptions;
24
+ }
25
+ interface CacheContextOptionsContext {
26
+ key: string;
27
+ value: unknown;
28
+ kind: CacheEntryWriteKind;
29
+ }
30
+ interface CacheWriteOptions extends CacheEntryWriteOptions {
31
+ negativeCache?: boolean;
23
32
  slidingTtl?: boolean;
24
33
  refreshAhead?: number | LayerTtlMap;
25
- adaptiveTtl?: boolean | CacheAdaptiveTtlOptions;
26
34
  circuitBreaker?: CacheCircuitBreakerOptions;
27
35
  fetcherRateLimit?: CacheRateLimitOptions;
28
36
  /**
@@ -34,12 +42,37 @@ interface CacheWriteOptions {
34
42
  * cache.get('key', fetchData, { shouldCache: (v) => v.status === 200 })
35
43
  */
36
44
  shouldCache?: (value: unknown) => boolean;
45
+ /**
46
+ * Optional resolver that can override cache entry options using the current
47
+ * write context. This runs right before a value is stored, so callers can
48
+ * derive TTLs or tags from the fetched value instead of guessing upfront.
49
+ *
50
+ * Returned values override any static entry options already present on the
51
+ * same object. Fetch controls like `shouldCache`, `negativeCache`,
52
+ * `refreshAhead`, or `circuitBreaker` are not affected.
53
+ *
54
+ * @example
55
+ * cache.get('oauth:token', fetchToken, {
56
+ * ttl: 300_000,
57
+ * contextOptions: ({ value }) => ({
58
+ * ttl: Math.max(1, Math.floor(((value as { refreshExpiresIn: number }).refreshExpiresIn ?? 0) / 1_000))
59
+ * })
60
+ * })
61
+ */
62
+ contextOptions?: (context: CacheContextOptionsContext) => CacheEntryWriteOptions | undefined;
37
63
  }
38
64
  interface CacheGetOptions extends CacheWriteOptions {
39
65
  }
66
+ interface CacheFetcherContext<T = unknown> {
67
+ key: string;
68
+ currentValue: T | undefined;
69
+ state: 'miss' | 'fresh' | 'stale-while-revalidate' | 'stale-if-error';
70
+ layer?: string;
71
+ }
72
+ type CacheFetcher<T = unknown> = (context: CacheFetcherContext<T>) => Promise<T>;
40
73
  interface CacheMGetEntry<T> {
41
74
  key: string;
42
- fetch?: () => Promise<T>;
75
+ fetch?: CacheFetcher<T>;
43
76
  options?: CacheGetOptions;
44
77
  }
45
78
  interface CacheMSetEntry<T> {
@@ -75,7 +108,7 @@ interface CacheLayer {
75
108
  */
76
109
  has?(key: string): Promise<boolean>;
77
110
  /**
78
- * Returns the remaining TTL in seconds for the key, or null if the key
111
+ * Returns the remaining TTL in milliseconds for the key, or null if the key
79
112
  * does not exist, has no TTL, or has already expired.
80
113
  * Implementations may omit this.
81
114
  */
@@ -159,7 +192,7 @@ interface InvalidationMessage {
159
192
  scope: 'key' | 'keys' | 'clear';
160
193
  sourceId: string;
161
194
  keys?: string[];
162
- operation?: 'write' | 'delete' | 'invalidate' | 'clear';
195
+ operation?: 'write' | 'delete' | 'invalidate' | 'expire' | 'clear';
163
196
  }
164
197
  interface InvalidationBus {
165
198
  subscribe(handler: (message: InvalidationMessage) => Promise<void> | void): Promise<() => Promise<void> | void>;
@@ -255,7 +288,7 @@ interface CacheWriteBehindOptions {
255
288
  }
256
289
  interface CacheWarmEntry<T = unknown> {
257
290
  key: string;
258
- fetcher: () => Promise<T>;
291
+ fetcher: CacheFetcher<T>;
259
292
  options?: CacheGetOptions;
260
293
  priority?: number;
261
294
  }
@@ -301,12 +334,12 @@ interface CacheInspectResult {
301
334
  key: string;
302
335
  /** Layers in which the key is currently stored (not expired). */
303
336
  foundInLayers: string[];
304
- /** Remaining fresh TTL in seconds, or null if no expiry or not an envelope. */
305
- freshTtlSeconds: number | null;
306
- /** Remaining stale-while-revalidate window in seconds, or null. */
307
- staleTtlSeconds: number | null;
308
- /** Remaining stale-if-error window in seconds, or null. */
309
- errorTtlSeconds: number | null;
337
+ /** Remaining fresh TTL in milliseconds, or null if no expiry or not an envelope. */
338
+ freshTtlMs: number | null;
339
+ /** Remaining stale-while-revalidate window in milliseconds, or null. */
340
+ staleTtlMs: number | null;
341
+ /** Remaining stale-if-error window in milliseconds, or null. */
342
+ errorTtlMs: number | null;
310
343
  /** Whether the key is currently serving stale-while-revalidate. */
311
344
  isStale: boolean;
312
345
  /** Tags associated with this key (from the TagIndex). */
@@ -335,6 +368,10 @@ interface CacheStackEvents {
335
368
  delete: {
336
369
  keys: string[];
337
370
  };
371
+ /** Fired after one or more keys are marked expired but retained. */
372
+ expire: {
373
+ keys: string[];
374
+ };
338
375
  /** Fired when a value is backfilled into a faster layer. */
339
376
  backfill: {
340
377
  key: string;
@@ -486,12 +523,12 @@ declare class CacheNamespace {
486
523
  private static readonly metricsMutexes;
487
524
  private metrics;
488
525
  constructor(cache: CacheStack, prefix: string);
489
- get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
490
- getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
526
+ get<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
527
+ getOrSet<T>(key: string, fetcher: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
491
528
  /**
492
529
  * Like `get()`, but throws `CacheMissError` instead of returning `null`.
493
530
  */
494
- getOrThrow<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T>;
531
+ getOrThrow<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T>;
495
532
  has(key: string): Promise<boolean>;
496
533
  ttl(key: string): Promise<number | null>;
497
534
  set<T>(key: string, value: T, options?: CacheWriteOptions): Promise<void>;
@@ -501,9 +538,13 @@ declare class CacheNamespace {
501
538
  mget<T>(entries: CacheMGetEntry<T>[]): Promise<Array<T | null>>;
502
539
  mset<T>(entries: CacheMSetEntry<T>[]): Promise<void>;
503
540
  invalidateByTag(tag: string): Promise<void>;
541
+ expireByTag(tag: string): Promise<void>;
504
542
  invalidateByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
543
+ expireByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
505
544
  invalidateByPattern(pattern: string): Promise<void>;
545
+ expireByPattern(pattern: string): Promise<void>;
506
546
  invalidateByPrefix(prefix: string): Promise<void>;
547
+ expireByPrefix(prefix: string): Promise<void>;
507
548
  /**
508
549
  * Returns detailed metadata about a single cache key within this namespace.
509
550
  */
@@ -573,24 +614,24 @@ declare class CacheStack extends EventEmitter {
573
614
  * and stores the result across all layers. Returns `null` if the key is not found
574
615
  * and no `fetcher` is provided.
575
616
  */
576
- get<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
617
+ get<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
577
618
  /**
578
619
  * Alias for `get(key, fetcher, options)` — explicit get-or-set pattern.
579
620
  * Fetches and caches the value if not already present.
580
621
  */
581
- getOrSet<T>(key: string, fetcher: () => Promise<T>, options?: CacheGetOptions): Promise<T | null>;
622
+ getOrSet<T>(key: string, fetcher: CacheFetcher<T>, options?: CacheGetOptions): Promise<T | null>;
582
623
  /**
583
624
  * Like `get()`, but throws `CacheMissError` instead of returning `null`.
584
625
  * Useful when the value is expected to exist or the fetcher is expected to
585
626
  * return non-null.
586
627
  */
587
- getOrThrow<T>(key: string, fetcher?: () => Promise<T>, options?: CacheGetOptions): Promise<T>;
628
+ getOrThrow<T>(key: string, fetcher?: CacheFetcher<T>, options?: CacheGetOptions): Promise<T>;
588
629
  /**
589
630
  * Returns true if the given key exists and is not expired in any layer.
590
631
  */
591
632
  has(key: string): Promise<boolean>;
592
633
  /**
593
- * Returns the remaining TTL in seconds for the key in the fastest layer
634
+ * Returns the remaining TTL in milliseconds for the key in the fastest layer
594
635
  * that has it, or null if the key is not found / has no TTL.
595
636
  */
596
637
  ttl(key: string): Promise<number | null>;
@@ -621,9 +662,13 @@ declare class CacheStack extends EventEmitter {
621
662
  */
622
663
  namespace(prefix: string): CacheNamespace;
623
664
  invalidateByTag(tag: string): Promise<void>;
665
+ expireByTag(tag: string): Promise<void>;
624
666
  invalidateByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
667
+ expireByTags(tags: string[], mode?: 'any' | 'all'): Promise<void>;
625
668
  invalidateByPattern(pattern: string): Promise<void>;
669
+ expireByPattern(pattern: string): Promise<void>;
626
670
  invalidateByPrefix(prefix: string): Promise<void>;
671
+ expireByPrefix(prefix: string): Promise<void>;
627
672
  getMetrics(): CacheMetricsSnapshot;
628
673
  getStats(): CacheStatsSnapshot;
629
674
  resetMetrics(): void;
@@ -653,8 +698,12 @@ declare class CacheStack extends EventEmitter {
653
698
  private storeEntry;
654
699
  private writeBatch;
655
700
  private resolveFreshTtl;
656
- private resolveLayerSeconds;
701
+ private resolveLayerMs;
702
+ private resolveContextOptions;
703
+ private isPlainObject;
657
704
  private deleteKeys;
705
+ private expireKeys;
706
+ private expireKeysInLayers;
658
707
  private publishInvalidation;
659
708
  private handleInvalidationMessage;
660
709
  private getTagsForKey;
@@ -711,4 +760,4 @@ interface HonoCacheMiddlewareOptions extends CacheGetOptions {
711
760
  }
712
761
  declare function createHonoCacheMiddleware(cache: CacheStack, options?: HonoCacheMiddlewareOptions): (context: HonoLikeContext, next: () => Promise<void>) => Promise<unknown>;
713
762
 
714
- export { type CacheStatsSnapshot as A, type CacheTtlPolicy as B, type CacheLogger as C, type CacheTtlPolicyContext as D, type CacheWarmEntry as E, type CacheWarmOptions as F, type CacheWarmProgress as G, type CacheWriteBehindOptions as H, type InvalidationBus as I, type CacheWriteOptions as J, type EvictionPolicy as K, type LayerTtlMap as L, MemoryLayer as M, type MemoryLayerOptions as N, type MemoryLayerSnapshotEntry as O, PatternMatcher as P, createHonoCacheMiddleware as Q, TagIndex as T, type InvalidationMessage as a, type CacheTagIndex as b, CacheStack as c, type CacheWrapOptions as d, type CacheGetOptions as e, type CacheLayer as f, type CacheSerializer as g, type CacheLayerSetManyEntry as h, type CacheSingleFlightCoordinator as i, type CacheSingleFlightExecutionOptions as j, type CacheAdaptiveTtlOptions as k, type CacheCircuitBreakerOptions as l, type CacheDegradationOptions as m, type CacheHealthCheckResult as n, type CacheHitRateSnapshot as o, type CacheInspectResult as p, type CacheLayerLatency as q, type CacheMGetEntry as r, type CacheMSetEntry as s, type CacheMetricsSnapshot as t, CacheMissError as u, CacheNamespace as v, type CacheRateLimitOptions as w, type CacheSnapshotEntry as x, type CacheStackEvents as y, type CacheStackOptions as z };
763
+ export { CacheNamespace as A, type CacheRateLimitOptions as B, type CacheLogger as C, type CacheSnapshotEntry as D, type CacheStackEvents as E, type CacheStackOptions as F, type CacheStatsSnapshot as G, type CacheTtlPolicy as H, type InvalidationBus as I, type CacheTtlPolicyContext as J, type CacheWarmEntry as K, type CacheWarmOptions as L, type CacheWarmProgress as M, type CacheWriteBehindOptions as N, type CacheWriteOptions as O, type EvictionPolicy as P, type LayerTtlMap as Q, MemoryLayer as R, type MemoryLayerOptions as S, type MemoryLayerSnapshotEntry as T, PatternMatcher as U, TagIndex as V, createHonoCacheMiddleware as W, type InvalidationMessage as a, type CacheTagIndex as b, CacheStack as c, type CacheWrapOptions as d, type CacheGetOptions as e, type CacheLayer as f, type CacheSerializer as g, type CacheLayerSetManyEntry as h, type CacheSingleFlightCoordinator as i, type CacheSingleFlightExecutionOptions as j, type CacheAdaptiveTtlOptions as k, type CacheCircuitBreakerOptions as l, type CacheContextOptionsContext as m, type CacheDegradationOptions as n, type CacheEntryWriteKind as o, type CacheEntryWriteOptions as p, type CacheFetcher as q, type CacheFetcherContext as r, type CacheHealthCheckResult as s, type CacheHitRateSnapshot as t, type CacheInspectResult as u, type CacheLayerLatency as v, type CacheMGetEntry as w, type CacheMSetEntry as x, type CacheMetricsSnapshot as y, CacheMissError as z };
package/dist/edge.cjs CHANGED
@@ -67,17 +67,17 @@ function isStoredValueEnvelope(value) {
67
67
  if (typeof v.freshUntil === "number" && typeof v.errorUntil === "number" && v.errorUntil < v.freshUntil) {
68
68
  return false;
69
69
  }
70
- const maxTtlSeconds = 10 * 365 * 24 * 60 * 60;
71
- if (!isValidEnvelopeTtlSeconds(v.freshTtlSeconds, maxTtlSeconds)) {
70
+ const maxTtlMs = 10 * 365 * 24 * 60 * 60 * 1e3;
71
+ if (!isValidEnvelopeTtlMs(v.freshTtlMs, maxTtlMs)) {
72
72
  return false;
73
73
  }
74
- if (!isValidEnvelopeTtlSeconds(v.staleWhileRevalidateSeconds, maxTtlSeconds)) {
74
+ if (!isValidEnvelopeTtlMs(v.staleWhileRevalidateMs, maxTtlMs)) {
75
75
  return false;
76
76
  }
77
- if (!isValidEnvelopeTtlSeconds(v.staleIfErrorSeconds, maxTtlSeconds)) {
77
+ if (!isValidEnvelopeTtlMs(v.staleIfErrorMs, maxTtlMs)) {
78
78
  return false;
79
79
  }
80
- if (v.freshTtlSeconds == null && (v.staleWhileRevalidateSeconds != null || v.staleIfErrorSeconds != null)) {
80
+ if (v.freshTtlMs == null && (v.staleWhileRevalidateMs != null || v.staleIfErrorMs != null)) {
81
81
  return false;
82
82
  }
83
83
  return true;
@@ -91,11 +91,11 @@ function unwrapStoredValue(stored) {
91
91
  }
92
92
  return stored.value ?? null;
93
93
  }
94
- function isValidEnvelopeTtlSeconds(value, maxTtlSeconds) {
94
+ function isValidEnvelopeTtlMs(value, maxTtlMs) {
95
95
  if (value == null) {
96
96
  return true;
97
97
  }
98
- return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= maxTtlSeconds;
98
+ return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= maxTtlMs;
99
99
  }
100
100
 
101
101
  // src/layers/MemoryLayer.ts
@@ -153,7 +153,7 @@ var MemoryLayer = class {
153
153
  this.entries.delete(key);
154
154
  this.entries.set(key, {
155
155
  value,
156
- expiresAt: ttl && ttl > 0 ? Date.now() + ttl * 1e3 : null,
156
+ expiresAt: ttl && ttl > 0 ? Date.now() + ttl : null,
157
157
  accessCount: 0,
158
158
  insertedAt: Date.now()
159
159
  });
@@ -184,7 +184,7 @@ var MemoryLayer = class {
184
184
  if (entry.expiresAt === null) {
185
185
  return null;
186
186
  }
187
- return Math.max(0, Math.ceil((entry.expiresAt - Date.now()) / 1e3));
187
+ return Math.max(0, Math.ceil(entry.expiresAt - Date.now()));
188
188
  }
189
189
  async size() {
190
190
  this.pruneExpired();
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-DKkrQ_Ky.cjs';
1
+ export { m as CacheContextOptionsContext, o as CacheEntryWriteKind, p as CacheEntryWriteOptions, e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, y as CacheMetricsSnapshot, B as CacheRateLimitOptions, H as CacheTtlPolicy, J as CacheTtlPolicyContext, O as CacheWriteOptions, P as EvictionPolicy, R as MemoryLayer, S as MemoryLayerOptions, T as MemoryLayerSnapshotEntry, U as PatternMatcher, V as TagIndex, W as createHonoCacheMiddleware } from './edge-D2FpRlyS.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-DKkrQ_Ky.js';
1
+ export { m as CacheContextOptionsContext, o as CacheEntryWriteKind, p as CacheEntryWriteOptions, e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, y as CacheMetricsSnapshot, B as CacheRateLimitOptions, H as CacheTtlPolicy, J as CacheTtlPolicyContext, O as CacheWriteOptions, P as EvictionPolicy, R as MemoryLayer, S as MemoryLayerOptions, T as MemoryLayerSnapshotEntry, U as PatternMatcher, V as TagIndex, W as createHonoCacheMiddleware } from './edge-D2FpRlyS.js';
2
2
  import 'node:events';
package/dist/edge.js CHANGED
@@ -2,10 +2,10 @@ import {
2
2
  MemoryLayer,
3
3
  TagIndex,
4
4
  createHonoCacheMiddleware
5
- } from "./chunk-5RCAX2BQ.js";
5
+ } from "./chunk-FFZCC7EQ.js";
6
6
  import {
7
7
  PatternMatcher
8
- } from "./chunk-4PPBOOXT.js";
8
+ } from "./chunk-KJDFYE5T.js";
9
9
  export {
10
10
  MemoryLayer,
11
11
  PatternMatcher,