@c9up/echo 0.1.5 → 0.1.7

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 (56) hide show
  1. package/dist/CacheManager.d.ts +63 -28
  2. package/dist/CacheManager.d.ts.map +1 -1
  3. package/dist/CacheManager.js +348 -70
  4. package/dist/CacheManager.js.map +1 -1
  5. package/dist/EchoProvider.d.ts +15 -9
  6. package/dist/EchoProvider.d.ts.map +1 -1
  7. package/dist/EchoProvider.js +47 -13
  8. package/dist/EchoProvider.js.map +1 -1
  9. package/dist/StoreManager.d.ts +61 -0
  10. package/dist/StoreManager.d.ts.map +1 -0
  11. package/dist/StoreManager.js +70 -0
  12. package/dist/StoreManager.js.map +1 -0
  13. package/dist/drivers/MemoryDriver.d.ts +13 -6
  14. package/dist/drivers/MemoryDriver.d.ts.map +1 -1
  15. package/dist/drivers/MemoryDriver.js +67 -61
  16. package/dist/drivers/MemoryDriver.js.map +1 -1
  17. package/dist/drivers/RedisDriver.d.ts +17 -17
  18. package/dist/drivers/RedisDriver.d.ts.map +1 -1
  19. package/dist/drivers/RedisDriver.js +103 -55
  20. package/dist/drivers/RedisDriver.js.map +1 -1
  21. package/dist/drivers/TieredDriver.d.ts +41 -0
  22. package/dist/drivers/TieredDriver.d.ts.map +1 -0
  23. package/dist/drivers/TieredDriver.js +132 -0
  24. package/dist/drivers/TieredDriver.js.map +1 -0
  25. package/dist/duration.d.ts +32 -0
  26. package/dist/duration.d.ts.map +1 -0
  27. package/dist/duration.js +75 -0
  28. package/dist/duration.js.map +1 -0
  29. package/dist/errors.d.ts +21 -0
  30. package/dist/errors.d.ts.map +1 -0
  31. package/dist/errors.js +31 -0
  32. package/dist/errors.js.map +1 -0
  33. package/dist/index.d.ts +15 -3
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +10 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/testing/main.d.ts +41 -0
  38. package/dist/testing/main.d.ts.map +1 -0
  39. package/dist/testing/main.js +41 -0
  40. package/dist/testing/main.js.map +1 -0
  41. package/dist/types.d.ts +146 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +6 -0
  44. package/dist/types.js.map +1 -0
  45. package/package.json +6 -1
  46. package/src/CacheManager.ts +497 -99
  47. package/src/EchoProvider.ts +58 -15
  48. package/src/StoreManager.ts +104 -0
  49. package/src/drivers/MemoryDriver.ts +97 -66
  50. package/src/drivers/RedisDriver.ts +135 -58
  51. package/src/drivers/TieredDriver.ts +186 -0
  52. package/src/duration.ts +86 -0
  53. package/src/errors.ts +33 -0
  54. package/src/index.ts +43 -3
  55. package/src/testing/main.ts +69 -0
  56. package/src/types.ts +156 -0
@@ -6,7 +6,7 @@ import { type CacheConfig } from "./CacheManager.js";
6
6
  */
7
7
  interface EchoContainer {
8
8
  singleton(token: unknown, factory: () => unknown): void;
9
- resolve<T = unknown>(token: unknown): T;
9
+ resolve<T = unknown>(token: unknown): Promise<T>;
10
10
  }
11
11
  interface EchoConfigStore {
12
12
  get<T = unknown>(key: string): T | undefined;
@@ -20,28 +20,34 @@ export interface EchoProviderConfig extends CacheConfig {
20
20
  * Driver to bind by default. Only `"memory"` is created
21
21
  * automatically — other drivers (Redis etc.) need custom client
22
22
  * wiring, so apps build the `CacheManager` themselves and call
23
- * `setCache(...)` from `@c9up/echo/services/main`.
23
+ * `setCache(...)` from `@c9up/echo/services/main`, or use the
24
+ * multi-store `{ default, stores }` config with `drivers.*`.
24
25
  *
25
26
  * Default `"memory"`.
26
27
  */
27
28
  driver?: "memory";
28
29
  }
29
30
  /**
30
- * EchoProvider — registers a default in-memory `CacheManager` so apps
31
- * that don't need Redis can `import cache from '@c9up/echo/services/main'`
32
- * and `await cache.get(...)` straight away.
31
+ * EchoProvider — registers a `CacheManager` (single-store default, or the
32
+ * default store of a `{ default, stores }` config) so apps can
33
+ * `import cache from '@c9up/echo/services/main'` and use it straight away. If
34
+ * the host container exposes an `emitter`, cache events (`cache:hit` / `miss` /
35
+ * `written` / `deleted` / `cleared`) are wired through it.
33
36
  *
34
37
  * // reamrc.ts
35
38
  * providers: [() => import('@c9up/echo/provider')]
36
39
  *
37
- * // config/cache.ts
40
+ * // config/cache.ts (single store)
38
41
  * export default { driver: 'memory', prefix: 'myapp', ttl: 300 }
39
42
  *
40
- * // anywhere
41
- * import cache from '@c9up/echo/services/main'
42
- * await cache.set('k', v, 60)
43
+ * // config/cache.ts (multi-store)
44
+ * export default defineConfig({
45
+ * default: 'memory',
46
+ * stores: { memory: { driver: drivers.memory() } },
47
+ * })
43
48
  */
44
49
  export default class EchoProvider {
50
+ #private;
45
51
  protected app: EchoAppContext;
46
52
  constructor(app: EchoAppContext);
47
53
  register(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"EchoProvider.d.ts","sourceRoot":"","sources":["../src/EchoProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,mBAAmB,CAAC;AAInE;;;;GAIG;AACH,UAAU,aAAa;IACtB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IACxD,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC;CACxC;AACD,UAAU,eAAe;IACxB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AACD,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACtD;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;IACpB,SAAS,CAAC,GAAG,EAAE,cAAc;gBAAnB,GAAG,EAAE,cAAc;IAEzC,QAAQ,IAAI,IAAI;IAiBV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B"}
1
+ {"version":3,"file":"EchoProvider.d.ts","sourceRoot":"","sources":["../src/EchoProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,mBAAmB,CAAC;AAMnE;;;;GAIG;AACH,UAAU,aAAa;IACtB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IACxD,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACjD;AACD,UAAU,eAAe;IACxB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AACD,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACtD;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;CAClB;AAmBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;;IACpB,SAAS,CAAC,GAAG,EAAE,cAAc;gBAAnB,GAAG,EAAE,cAAc;IAYzC,QAAQ,IAAI,IAAI;IA0BV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B"}
@@ -1,40 +1,74 @@
1
1
  import { CacheManager } from "./CacheManager.js";
2
2
  import { MemoryDriver } from "./drivers/MemoryDriver.js";
3
+ import { CacheStoreManager } from "./StoreManager.js";
3
4
  import { setCache } from "./services/main.js";
5
+ function isEmitter(value) {
6
+ return (typeof value === "object" &&
7
+ value !== null &&
8
+ typeof Reflect.get(value, "emit") === "function");
9
+ }
10
+ function isMultiStoreConfig(value) {
11
+ return (typeof value === "object" &&
12
+ value !== null &&
13
+ "stores" in value &&
14
+ "default" in value);
15
+ }
4
16
  /**
5
- * EchoProvider — registers a default in-memory `CacheManager` so apps
6
- * that don't need Redis can `import cache from '@c9up/echo/services/main'`
7
- * and `await cache.get(...)` straight away.
17
+ * EchoProvider — registers a `CacheManager` (single-store default, or the
18
+ * default store of a `{ default, stores }` config) so apps can
19
+ * `import cache from '@c9up/echo/services/main'` and use it straight away. If
20
+ * the host container exposes an `emitter`, cache events (`cache:hit` / `miss` /
21
+ * `written` / `deleted` / `cleared`) are wired through it.
8
22
  *
9
23
  * // reamrc.ts
10
24
  * providers: [() => import('@c9up/echo/provider')]
11
25
  *
12
- * // config/cache.ts
26
+ * // config/cache.ts (single store)
13
27
  * export default { driver: 'memory', prefix: 'myapp', ttl: 300 }
14
28
  *
15
- * // anywhere
16
- * import cache from '@c9up/echo/services/main'
17
- * await cache.set('k', v, 60)
29
+ * // config/cache.ts (multi-store)
30
+ * export default defineConfig({
31
+ * default: 'memory',
32
+ * stores: { memory: { driver: drivers.memory() } },
33
+ * })
18
34
  */
19
35
  export default class EchoProvider {
20
36
  app;
21
37
  constructor(app) {
22
38
  this.app = app;
23
39
  }
40
+ async #resolveEmitter() {
41
+ try {
42
+ const candidate = await this.app.container.resolve("emitter");
43
+ if (isEmitter(candidate))
44
+ return candidate;
45
+ }
46
+ catch {
47
+ // No emitter bound — events are simply not emitted.
48
+ }
49
+ return undefined;
50
+ }
24
51
  register() {
25
- this.app.container.singleton(CacheManager, () => {
26
- const config = this.app.config.get("cache");
27
- const driver = config?.driver ?? "memory";
52
+ this.app.container.singleton(CacheManager, async () => {
53
+ const emitter = await this.#resolveEmitter();
54
+ const raw = this.app.config.get("cache");
55
+ if (isMultiStoreConfig(raw)) {
56
+ const manager = new CacheStoreManager({ ...raw, emitter });
57
+ return manager.use();
58
+ }
59
+ const config = (raw ?? {});
60
+ const driver = config.driver ?? "memory";
28
61
  if (driver !== "memory") {
29
62
  throw new Error(`[echo] Unsupported driver '${driver}' for default provider — ` +
30
- "wire CacheManager yourself for non-memory drivers.");
63
+ "wire CacheManager yourself for non-memory drivers, or use the " +
64
+ "multi-store `{ default, stores }` config.");
31
65
  }
32
- return new CacheManager(new MemoryDriver(), config);
66
+ return new CacheManager(new MemoryDriver(), { ...config, emitter });
33
67
  });
34
68
  this.app.container.singleton("cache", () => this.app.container.resolve(CacheManager));
35
69
  }
36
70
  async boot() {
37
- setCache(this.app.container.resolve(CacheManager));
71
+ setCache(await this.app.container.resolve(CacheManager));
38
72
  }
39
73
  async shutdown() { }
40
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EchoProvider.js","sourceRoot":"","sources":["../src/EchoProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AA+B9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;IACV;IAAtB,YAAsB,GAAmB;QAAnB,QAAG,GAAH,GAAG,CAAgB;IAAG,CAAC;IAE7C,QAAQ;QACP,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,EAAE,GAAG,EAAE;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAqB,OAAO,CAAC,CAAC;YAChE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,QAAQ,CAAC;YAC1C,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACd,8BAA8B,MAAM,2BAA2B;oBAC9D,oDAAoD,CACrD,CAAC;YACH,CAAC;YACD,OAAO,IAAI,YAAY,CAAC,IAAI,YAAY,EAAE,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,CAC1C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAe,YAAY,CAAC,CACtD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACT,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAe,YAAY,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,QAAQ,KAAmB,CAAC;CAClC"}
1
+ {"version":3,"file":"EchoProvider.js","sourceRoot":"","sources":["../src/EchoProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAyB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAiC9C,SAAS,SAAS,CAAC,KAAc;IAChC,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,UAAU,CAChD,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACzC,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,QAAQ,IAAI,KAAK;QACjB,SAAS,IAAI,KAAK,CAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;IACV;IAAtB,YAAsB,GAAmB;QAAnB,QAAG,GAAH,GAAG,CAAgB;IAAG,CAAC;IAE7C,KAAK,CAAC,eAAe;QACpB,IAAI,CAAC;YACJ,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAU,SAAS,CAAC,CAAC;YACvE,IAAI,SAAS,CAAC,SAAS,CAAC;gBAAE,OAAO,SAAS,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACR,oDAAoD;QACrD,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,QAAQ;QACP,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAU,OAAO,CAAC,CAAC;YAElD,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC3D,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;YACtB,CAAC;YAED,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,CAAuB,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC;YACzC,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACd,8BAA8B,MAAM,2BAA2B;oBAC9D,gEAAgE;oBAChE,2CAA2C,CAC5C,CAAC;YACH,CAAC;YACD,OAAO,IAAI,YAAY,CAAC,IAAI,YAAY,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,CAC1C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAe,YAAY,CAAC,CACtD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACT,QAAQ,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAe,YAAY,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,CAAC,QAAQ,KAAmB,CAAC;CAClC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Multi-store cache manager — `{ default, stores }` config + `cache.use(name)`
3
+ * (bentocache `BentoCache` / @adonisjs/cache parity), plus the `drivers.*`
4
+ * factory helpers.
5
+ *
6
+ * const cache = new CacheStoreManager(defineConfig({
7
+ * default: "memory",
8
+ * stores: {
9
+ * memory: { driver: drivers.memory() },
10
+ * redis: { driver: drivers.redis({ client }) },
11
+ * },
12
+ * }))
13
+ *
14
+ * await cache.use().set({ key: "k", value: 1 }) // default store
15
+ * await cache.use("redis").get({ key: "k" }) // named store
16
+ */
17
+ import { CacheManager } from "./CacheManager.js";
18
+ import { type RedisClient } from "./drivers/RedisDriver.js";
19
+ import { type CacheBus } from "./drivers/TieredDriver.js";
20
+ import type { Duration } from "./duration.js";
21
+ import type { CacheDriver, CacheEmitter } from "./types.js";
22
+ /** A lazily-instantiated driver (built once per store, on first `use`). */
23
+ export type DriverFactory = () => CacheDriver;
24
+ export interface StoreConfig {
25
+ driver: DriverFactory;
26
+ prefix?: string;
27
+ /** Default TTL in seconds. */
28
+ ttl?: number;
29
+ grace?: Duration;
30
+ timeout?: Duration;
31
+ hardTimeout?: Duration;
32
+ lockTimeout?: Duration;
33
+ }
34
+ export interface MultiStoreConfig {
35
+ default: string;
36
+ stores: Record<string, StoreConfig>;
37
+ /** Shared emitter for all stores' events. */
38
+ emitter?: CacheEmitter;
39
+ }
40
+ /** Driver factory helpers (bento `drivers.memory` / `drivers.redis`). */
41
+ export declare const drivers: {
42
+ memory(options?: {
43
+ sweepIntervalMs?: number;
44
+ }): DriverFactory;
45
+ redis(options: {
46
+ client: RedisClient;
47
+ prefix?: string;
48
+ }): DriverFactory;
49
+ tiered(options: {
50
+ l1: DriverFactory;
51
+ l2: DriverFactory;
52
+ bus?: CacheBus;
53
+ }): DriverFactory;
54
+ };
55
+ export declare class CacheStoreManager {
56
+ #private;
57
+ constructor(config: MultiStoreConfig);
58
+ /** Resolve a store by name (or the default). Instances are built once and cached. */
59
+ use(name?: string): CacheManager;
60
+ }
61
+ //# sourceMappingURL=StoreManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoreManager.d.ts","sourceRoot":"","sources":["../src/StoreManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,KAAK,WAAW,EAAe,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,WAAW,CAAC,EAAE,QAAQ,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,yEAAyE;AACzE,eAAO,MAAM,OAAO;qBACF;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa;mBAG9C;QAAE,MAAM,EAAE,WAAW,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa;oBAGvD;QACf,EAAE,EAAE,aAAa,CAAC;QAClB,EAAE,EAAE,aAAa,CAAC;QAClB,GAAG,CAAC,EAAE,QAAQ,CAAC;KACf,GAAG,aAAa;CAQjB,CAAC;AAEF,qBAAa,iBAAiB;;gBAIjB,MAAM,EAAE,gBAAgB;IASpC,qFAAqF;IACrF,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY;CAsBhC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Multi-store cache manager — `{ default, stores }` config + `cache.use(name)`
3
+ * (bentocache `BentoCache` / @adonisjs/cache parity), plus the `drivers.*`
4
+ * factory helpers.
5
+ *
6
+ * const cache = new CacheStoreManager(defineConfig({
7
+ * default: "memory",
8
+ * stores: {
9
+ * memory: { driver: drivers.memory() },
10
+ * redis: { driver: drivers.redis({ client }) },
11
+ * },
12
+ * }))
13
+ *
14
+ * await cache.use().set({ key: "k", value: 1 }) // default store
15
+ * await cache.use("redis").get({ key: "k" }) // named store
16
+ */
17
+ import { CacheManager } from "./CacheManager.js";
18
+ import { MemoryDriver } from "./drivers/MemoryDriver.js";
19
+ import { RedisDriver } from "./drivers/RedisDriver.js";
20
+ import { TieredDriver } from "./drivers/TieredDriver.js";
21
+ /** Driver factory helpers (bento `drivers.memory` / `drivers.redis`). */
22
+ export const drivers = {
23
+ memory(options) {
24
+ return () => new MemoryDriver(options?.sweepIntervalMs);
25
+ },
26
+ redis(options) {
27
+ return () => new RedisDriver(options.client, options.prefix);
28
+ },
29
+ tiered(options) {
30
+ return () => new TieredDriver({
31
+ l1: options.l1(),
32
+ l2: options.l2(),
33
+ bus: options.bus,
34
+ });
35
+ },
36
+ };
37
+ export class CacheStoreManager {
38
+ #config;
39
+ #built = new Map();
40
+ constructor(config) {
41
+ this.#config = config;
42
+ if (!config.stores[config.default]) {
43
+ throw new Error(`Echo: default store "${config.default}" is not defined in stores`);
44
+ }
45
+ }
46
+ /** Resolve a store by name (or the default). Instances are built once and cached. */
47
+ use(name) {
48
+ const store = name ?? this.#config.default;
49
+ const existing = this.#built.get(store);
50
+ if (existing)
51
+ return existing;
52
+ const cfg = this.#config.stores[store];
53
+ if (!cfg) {
54
+ throw new Error(`Echo: unknown cache store "${store}"`);
55
+ }
56
+ const manager = new CacheManager(cfg.driver(), {
57
+ prefix: cfg.prefix,
58
+ ttl: cfg.ttl,
59
+ grace: cfg.grace,
60
+ timeout: cfg.timeout,
61
+ hardTimeout: cfg.hardTimeout,
62
+ lockTimeout: cfg.lockTimeout,
63
+ name: store,
64
+ emitter: this.#config.emitter,
65
+ });
66
+ this.#built.set(store, manager);
67
+ return manager;
68
+ }
69
+ }
70
+ //# sourceMappingURL=StoreManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoreManager.js","sourceRoot":"","sources":["../src/StoreManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAoB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAiB,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAyBxE,yEAAyE;AACzE,MAAM,CAAC,MAAM,OAAO,GAAG;IACtB,MAAM,CAAC,OAAsC;QAC5C,OAAO,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACzD,CAAC;IACD,KAAK,CAAC,OAAiD;QACtD,OAAO,GAAG,EAAE,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,CAAC,OAIN;QACA,OAAO,GAAG,EAAE,CACX,IAAI,YAAY,CAAC;YAChB,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE;YAChB,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;CACD,CAAC;AAEF,MAAM,OAAO,iBAAiB;IAC7B,OAAO,CAAmB;IAC1B,MAAM,GAA8B,IAAI,GAAG,EAAE,CAAC;IAE9C,YAAY,MAAwB;QACnC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACd,wBAAwB,MAAM,CAAC,OAAO,4BAA4B,CAClE,CAAC;QACH,CAAC;IACF,CAAC;IAED,qFAAqF;IACrF,GAAG,CAAC,IAAa;QAChB,MAAM,KAAK,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,GAAG,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE;YAC9C,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;SAC7B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,OAAO,CAAC;IAChB,CAAC;CACD"}
@@ -1,20 +1,27 @@
1
1
  /**
2
- * Memory cache driver — in-process Map with TTL support.
3
- * Suitable for development and single-process deployments.
2
+ * Memory cache driver — in-process Map with TTL, grace (stale-while-revalidate)
3
+ * and tag support. Suitable for development and single-process deployments, and
4
+ * as the L1 tier of {@link TieredDriver}.
4
5
  */
5
- import type { CacheDriver } from "../CacheManager.js";
6
- export declare class MemoryDriver implements CacheDriver {
6
+ import type { CacheEntry, DriverSetOptions, TaggableDriver } from "../types.js";
7
+ export declare class MemoryDriver implements TaggableDriver {
7
8
  #private;
8
9
  constructor(sweepIntervalMs?: number);
9
10
  destroy(): void;
10
11
  get<T = unknown>(key: string): Promise<T | null>;
12
+ getEntry<T = unknown>(key: string): Promise<CacheEntry<T> | null>;
13
+ /** Synchronous read used by both `get` and `getEntry` (and by TieredDriver's L1 fast path). */
14
+ getEntrySync<T = unknown>(key: string): CacheEntry<T> | null;
11
15
  set(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
16
+ setEntry(key: string, value: unknown, options: DriverSetOptions): Promise<void>;
12
17
  delete(key: string): Promise<boolean>;
13
18
  flush(): Promise<void>;
14
19
  has(key: string): Promise<boolean>;
15
- /** Set with tags for group invalidation. */
20
+ /** Set with tags for group invalidation (bento parity; no grace). */
16
21
  setWithTags(key: string, value: unknown, tags: string[], ttlSeconds?: number): Promise<void>;
17
- /** Flush all entries tagged with any of the given tags. */
22
+ /** Invalidate all entries tagged with any of the given tags. */
23
+ deleteByTag(tags: string[]): Promise<void>;
24
+ /** @deprecated alias of {@link deleteByTag}. */
18
25
  flushTags(tags: string[]): Promise<void>;
19
26
  }
20
27
  //# sourceMappingURL=MemoryDriver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MemoryDriver.d.ts","sourceRoot":"","sources":["../../src/drivers/MemoryDriver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAQtD,qBAAa,YAAa,YAAW,WAAW;;gBAKnC,eAAe,SAAS;IAiBpC,OAAO,IAAI,IAAI;IAIT,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAqBhD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBpE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKxC,4CAA4C;IACtC,WAAW,CAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IA+BhB,2DAA2D;IACrD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAgC9C"}
1
+ {"version":3,"file":"MemoryDriver.d.ts","sourceRoot":"","sources":["../../src/drivers/MemoryDriver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAWhF,qBAAa,YAAa,YAAW,cAAc;;gBAKtC,eAAe,SAAS;IAiBpC,OAAO,IAAI,IAAI;IAIT,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAMhD,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAIvE,+FAA+F;IAC/F,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;IAqEtD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE,QAAQ,CACb,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,IAAI,CAAC;IAWV,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxC,qEAAqE;IAC/D,WAAW,CAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAIhB,gEAAgE;IAC1D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhD,gDAAgD;IAC1C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Memory cache driver — in-process Map with TTL support.
3
- * Suitable for development and single-process deployments.
2
+ * Memory cache driver — in-process Map with TTL, grace (stale-while-revalidate)
3
+ * and tag support. Suitable for development and single-process deployments, and
4
+ * as the L1 tier of {@link TieredDriver}.
4
5
  */
5
6
  export class MemoryDriver {
6
7
  #store = new Map();
@@ -10,7 +11,7 @@ export class MemoryDriver {
10
11
  this.#sweepInterval = setInterval(() => {
11
12
  const now = Date.now();
12
13
  for (const [key, entry] of this.#store) {
13
- if (entry.expiresAt > 0 && entry.expiresAt < now) {
14
+ if (entry.staleUntil > 0 && entry.staleUntil < now) {
14
15
  this.#evict(key, entry);
15
16
  }
16
17
  }
@@ -24,40 +25,79 @@ export class MemoryDriver {
24
25
  clearInterval(this.#sweepInterval);
25
26
  }
26
27
  async get(key) {
28
+ const entry = this.getEntrySync(key);
29
+ if (entry === null || entry.stale)
30
+ return null;
31
+ return entry.value;
32
+ }
33
+ async getEntry(key) {
34
+ return this.getEntrySync(key);
35
+ }
36
+ /** Synchronous read used by both `get` and `getEntry` (and by TieredDriver's L1 fast path). */
37
+ getEntrySync(key) {
27
38
  const entry = this.#store.get(key);
28
39
  if (!entry)
29
40
  return null;
30
- if (entry.expiresAt > 0 && entry.expiresAt < Date.now()) {
41
+ const now = Date.now();
42
+ if (entry.staleUntil > 0 && entry.staleUntil < now) {
31
43
  this.#evict(key, entry);
32
44
  return null;
33
45
  }
34
- return entry.value;
46
+ const stale = entry.expiresAt > 0 && entry.expiresAt < now;
47
+ return { value: entry.value, stale, expiresAt: entry.expiresAt };
35
48
  }
36
49
  /**
37
- * Delete an entry AND scrub its tag-index refs. TTL expiry (sweep + lazy
38
- * get) must go through this — a bare `#store.delete` left dangling refs in
39
- * `#tagIndex`, which a later `set(key, vNew)` reusing the key would turn into
40
- * a wrong-purge under flushTags (audit 2026-06-13).
50
+ * Delete an entry AND scrub its tag-index refs. TTL/grace expiry (sweep +
51
+ * lazy get) must go through this — a bare `#store.delete` left dangling refs
52
+ * in `#tagIndex`, which a later `set(key, vNew)` reusing the key would turn
53
+ * into a wrong-purge under deleteByTag (audit 2026-06-13).
41
54
  */
42
55
  #evict(key, entry) {
43
56
  for (const tag of entry.tags)
44
57
  this.#tagIndex.get(tag)?.delete(key);
45
58
  this.#store.delete(key);
46
59
  }
47
- async set(key, value, ttlSeconds) {
60
+ #write(key, value, ttlSeconds, graceSeconds, tags, expiresAtOverride) {
48
61
  if (value === null || value === undefined) {
49
62
  throw new TypeError("Echo: caching null/undefined values is not supported");
50
63
  }
51
- const expiresAt = ttlSeconds != null && ttlSeconds > 0 ? Date.now() + ttlSeconds * 1000 : 0;
52
- // Reconcile the tag index: overwriting a previously-tagged key with an
53
- // untagged value must drop its old tag-index refs, or a later flushTags
54
- // would purge this fresh value (the F3 fix only covered setWithTags).
64
+ const now = Date.now();
65
+ const hasTtl = ttlSeconds != null && ttlSeconds > 0;
66
+ // An absolute `expiresAtOverride` (e.g. `expire()` marking stale-now) wins
67
+ // over the ttl-derived expiry; a past value makes the entry immediately stale.
68
+ const expiresAt = expiresAtOverride !== undefined
69
+ ? expiresAtOverride
70
+ : hasTtl
71
+ ? now + ttlSeconds * 1000
72
+ : 0;
73
+ const graceMs = graceSeconds > 0 ? graceSeconds * 1000 : 0;
74
+ // A never-expiring entry never goes stale either; otherwise grace extends
75
+ // physical retention past the logical expiry. Measure grace from the LATER
76
+ // of the expiry and now, so an already-past expiry still survives its grace.
77
+ const staleUntil = expiresAt > 0 ? Math.max(expiresAt, now) + graceMs : 0;
78
+ // Reconcile the tag index: overwriting a previously-tagged key must drop
79
+ // its old tag-index refs, or a later deleteByTag could purge this fresh
80
+ // value (audit 2026-05-22 F3).
55
81
  const prev = this.#store.get(key);
56
82
  if (prev !== undefined) {
57
83
  for (const t of prev.tags)
58
84
  this.#tagIndex.get(t)?.delete(key);
59
85
  }
60
- this.#store.set(key, { value, expiresAt, tags: [] });
86
+ this.#store.set(key, { value, expiresAt, staleUntil, tags });
87
+ for (const tag of tags) {
88
+ let set = this.#tagIndex.get(tag);
89
+ if (!set) {
90
+ set = new Set();
91
+ this.#tagIndex.set(tag, set);
92
+ }
93
+ set.add(key);
94
+ }
95
+ }
96
+ async set(key, value, ttlSeconds) {
97
+ this.#write(key, value, ttlSeconds, 0, []);
98
+ }
99
+ async setEntry(key, value, options) {
100
+ this.#write(key, value, options.ttlSeconds, options.graceSeconds ?? 0, options.tags ?? [], options.expiresAt);
61
101
  }
62
102
  async delete(key) {
63
103
  const entry = this.#store.get(key);
@@ -73,52 +113,17 @@ export class MemoryDriver {
73
113
  this.#tagIndex.clear();
74
114
  }
75
115
  async has(key) {
76
- const val = await this.get(key);
77
- return val !== null;
116
+ return (await this.get(key)) !== null;
78
117
  }
79
- /** Set with tags for group invalidation. */
118
+ /** Set with tags for group invalidation (bento parity; no grace). */
80
119
  async setWithTags(key, value, tags, ttlSeconds) {
81
- // Audit 2026-05-22 F4: align with `set()` — both paths now treat any
82
- // `ttlSeconds <= 0` (and undefined) as "no expiration". Previously
83
- // `setWithTags` used a truthy check (`ttlSeconds ?`), which let a
84
- // negative value through and produced `Date.now() + (-N * 1000)` —
85
- // an already-past timestamp — so the entry was born already-expired.
86
- // `set()` correctly returned the immortal-entry branch on the same
87
- // input. The divergence made cache semantics depend on whether the
88
- // caller used tags or not, which is the worst kind of "very hard to
89
- // diagnose in prod" bug.
90
- const expiresAt = ttlSeconds != null && ttlSeconds > 0 ? Date.now() + ttlSeconds * 1000 : 0;
91
- // Audit 2026-05-22 F3 (overwrite leg): if `key` already exists with
92
- // a different tag set, the old #tagIndex entries become dangling
93
- // refs to the (now overwritten) key. Clean them up before re-tagging
94
- // so subsequent flushTags doesn't iterate stale references.
95
- const prev = this.#store.get(key);
96
- if (prev !== undefined) {
97
- for (const t of prev.tags)
98
- this.#tagIndex.get(t)?.delete(key);
99
- }
100
- this.#store.set(key, { value, expiresAt, tags });
101
- for (const tag of tags) {
102
- let set = this.#tagIndex.get(tag);
103
- if (!set) {
104
- set = new Set();
105
- this.#tagIndex.set(tag, set);
106
- }
107
- set.add(key);
108
- }
120
+ this.#write(key, value, ttlSeconds, 0, tags);
109
121
  }
110
- /** Flush all entries tagged with any of the given tags. */
111
- async flushTags(tags) {
112
- // Audit 2026-05-22 F3: when a key is multi-tagged (e.g. `[news, fr]`)
113
- // and we flush by `news`, the old code deleted the key from #store
114
- // and dropped the `news` Set, but `fr`'s Set kept a dangling
115
- // reference. A later flushTags(`fr`) would iterate over the
116
- // stale entry, attempt `#store.delete(key)` (no-op), and the entry
117
- // would silently linger in #tagIndex forever. Worse — if a new
118
- // entry was later written under the same key with different tags,
119
- // flushTags(`fr`) would WRONGLY purge it because of the residue.
120
- // Collect keys first, then scrub each one from EVERY tag set it
121
- // belonged to (including the tags we're not flushing this round).
122
+ /** Invalidate all entries tagged with any of the given tags. */
123
+ async deleteByTag(tags) {
124
+ // Audit 2026-05-22 F3: scrub each key from EVERY tag set it belongs to
125
+ // (including tags not being flushed this round), else a multi-tagged key
126
+ // leaves a dangling ref that later wrong-purges a reused key.
122
127
  const toDelete = new Set();
123
128
  for (const tag of tags) {
124
129
  const keys = this.#tagIndex.get(tag);
@@ -136,11 +141,12 @@ export class MemoryDriver {
136
141
  }
137
142
  this.#store.delete(key);
138
143
  }
139
- // Now drop the flushed tag sets themselves (any other keys still
140
- // referenced by them have been processed in the toDelete loop and
141
- // already removed via the inner scrub).
142
144
  for (const tag of tags)
143
145
  this.#tagIndex.delete(tag);
144
146
  }
147
+ /** @deprecated alias of {@link deleteByTag}. */
148
+ async flushTags(tags) {
149
+ return this.deleteByTag(tags);
150
+ }
145
151
  }
146
152
  //# sourceMappingURL=MemoryDriver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MemoryDriver.js","sourceRoot":"","sources":["../../src/drivers/MemoryDriver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MemoryDriver.js","sourceRoot":"","sources":["../../src/drivers/MemoryDriver.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,17 @@
1
1
  /**
2
- * Redis cache driver — production-grade cache with TTL and tags.
2
+ * Redis cache driver — production-grade cache with TTL, grace
3
+ * (stale-while-revalidate) and tags. Suitable as the L2 tier of
4
+ * {@link TieredDriver}.
3
5
  *
4
6
  * Requires a Redis client instance implementing the minimal interface below.
5
7
  * Compatible with ioredis and redis (node-redis) clients.
6
8
  *
7
- * @implements MISS-10
9
+ * STORAGE FORMAT (breaking vs echo <=0.1.5): values are stored as a JSON
10
+ * envelope `{ "v": <value>, "e": <logicalExpiryEpochMs> }`. The physical Redis
11
+ * TTL (`EX`) covers `ttl + grace` so a logically-expired value survives for the
12
+ * grace window; `e` records the logical expiry so reads can flag it stale.
8
13
  */
9
- import type { CacheDriver } from "../CacheManager.js";
14
+ import type { CacheEntry, DriverSetOptions, TaggableDriver } from "../types.js";
10
15
  /** Minimal Redis client interface — compatible with ioredis and node-redis. */
11
16
  export interface RedisClient {
12
17
  get(key: string): Promise<string | null>;
@@ -21,30 +26,25 @@ export interface RedisClient {
21
26
  ttl(key: string): Promise<number>;
22
27
  scan?(cursor: string, matchOption: "MATCH", pattern: string, countOption: "COUNT", count: number): Promise<[string, string[]]>;
23
28
  }
24
- export declare class RedisDriver implements CacheDriver {
29
+ export declare class RedisDriver implements TaggableDriver {
25
30
  #private;
26
31
  constructor(client: RedisClient, prefix?: string);
27
32
  delete(key: string): Promise<boolean>;
28
33
  get<T = unknown>(key: string): Promise<T | null>;
34
+ getEntry<T = unknown>(key: string): Promise<CacheEntry<T> | null>;
29
35
  set(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
36
+ setEntry(key: string, value: unknown, options: DriverSetOptions): Promise<void>;
30
37
  flush(): Promise<void>;
31
38
  has(key: string): Promise<boolean>;
32
- /**
33
- * Set a value with tag memberships for group invalidation.
34
- *
35
- * Re-tagging an existing key (e.g. `['news']` → `['homepage']`) cleans
36
- * the stale memberships via the per-key reverse-index — without this,
37
- * a later `flushTags(['news'])` would silently wipe the still-current
38
- * value because the abandoned `tag:news` set kept pointing at it.
39
- */
39
+ /** Set a value with tag memberships for group invalidation (no grace). */
40
40
  setWithTags(key: string, value: unknown, tags: string[], ttlSeconds?: number): Promise<void>;
41
41
  /**
42
- * Flush all entries tagged with any of the given tags. Cleans up the
43
- * per-key reverse-index AND cross-tag memberships so a multi-tag key
44
- * (e.g. `['news', 'homepage']`) flushed via `news` is also removed from
45
- * the `homepage` tag-set — otherwise the `homepage` set ends up with a
46
- * dangling reference to a now-deleted value.
42
+ * Invalidate all entries tagged with any of the given tags. Cleans the
43
+ * per-key reverse-index AND cross-tag memberships so a multi-tag key flushed
44
+ * via one tag is also removed from the others.
47
45
  */
46
+ deleteByTag(tags: string[]): Promise<void>;
47
+ /** @deprecated alias of {@link deleteByTag}. */
48
48
  flushTags(tags: string[]): Promise<void>;
49
49
  }
50
50
  //# sourceMappingURL=RedisDriver.d.ts.map