@c9up/echo 0.1.13 → 0.1.15

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 (43) hide show
  1. package/dist/CacheManager.d.ts.map +1 -1
  2. package/dist/CacheManager.js +20 -3
  3. package/dist/CacheManager.js.map +1 -1
  4. package/dist/EchoProvider.d.ts +1 -0
  5. package/dist/EchoProvider.d.ts.map +1 -1
  6. package/dist/EchoProvider.js +9 -1
  7. package/dist/EchoProvider.js.map +1 -1
  8. package/dist/StoreManager.d.ts +18 -0
  9. package/dist/StoreManager.d.ts.map +1 -1
  10. package/dist/StoreManager.js +18 -2
  11. package/dist/StoreManager.js.map +1 -1
  12. package/dist/augmentations.d.ts +29 -0
  13. package/dist/augmentations.d.ts.map +1 -0
  14. package/dist/augmentations.js +18 -0
  15. package/dist/augmentations.js.map +1 -0
  16. package/dist/drivers/MemoryDriver.d.ts +1 -1
  17. package/dist/drivers/MemoryDriver.d.ts.map +1 -1
  18. package/dist/drivers/MemoryDriver.js +41 -1
  19. package/dist/drivers/MemoryDriver.js.map +1 -1
  20. package/dist/drivers/TieredDriver.d.ts +17 -0
  21. package/dist/drivers/TieredDriver.d.ts.map +1 -1
  22. package/dist/drivers/TieredDriver.js +88 -17
  23. package/dist/drivers/TieredDriver.js.map +1 -1
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/quasar.d.ts +17 -0
  29. package/dist/quasar.d.ts.map +1 -1
  30. package/dist/quasar.js +77 -0
  31. package/dist/quasar.js.map +1 -1
  32. package/dist/types.d.ts +12 -1
  33. package/dist/types.d.ts.map +1 -1
  34. package/package.json +5 -3
  35. package/src/CacheManager.ts +29 -4
  36. package/src/EchoProvider.ts +10 -3
  37. package/src/StoreManager.ts +22 -3
  38. package/src/augmentations.ts +33 -0
  39. package/src/drivers/MemoryDriver.ts +39 -1
  40. package/src/drivers/TieredDriver.ts +94 -17
  41. package/src/index.ts +2 -0
  42. package/src/quasar.ts +101 -0
  43. package/src/types.ts +12 -1
@@ -30,15 +30,40 @@ async function writeEntry(driver, key, value, options) {
30
30
  }
31
31
  await driver.set(key, value, options.ttlSeconds);
32
32
  }
33
+ /**
34
+ * Run one tier's operation, capturing a rejection instead of letting it escape.
35
+ *
36
+ * The two tiers are attempted independently on purpose: awaiting L1 first meant
37
+ * a local driver that threw — a Redis L1 whose socket just dropped, one
38
+ * mid-shutdown — aborted the call before the SHARED tier was touched, so a
39
+ * `delete` left the copy every other instance reads. Upstream reaches the same
40
+ * end by never awaiting L1 at all (`this.l1?.set(...)` with no await, then
41
+ * `await this.l2?.set(...)`). The failure is still reported, after both tiers
42
+ * have had their turn.
43
+ */
44
+ async function settle(run) {
45
+ try {
46
+ return { ok: true, value: await run() };
47
+ }
48
+ catch (error) {
49
+ return { ok: false, error };
50
+ }
51
+ }
33
52
  export class TieredDriver {
34
53
  #l1;
35
54
  #l2;
36
55
  #bus;
56
+ /** This tier, as a bus sender. */
57
+ #id = crypto.randomUUID();
37
58
  constructor(options) {
38
59
  this.#l1 = options.l1;
39
60
  this.#l2 = options.l2;
40
61
  this.#bus = options.bus;
41
62
  this.#bus?.subscribe((message) => {
63
+ // Our own invalidation, come back round the bus. Acting on it would
64
+ // undo the write that sent it.
65
+ if (message.senderId === this.#id)
66
+ return;
42
67
  // Peer invalidation: only the local L1 needs clearing (L2 is shared).
43
68
  if (message.type === "clear") {
44
69
  this.#invalidate("flush", () => this.#l1.flush());
@@ -109,20 +134,50 @@ export class TieredDriver {
109
134
  await this.setEntry(key, value, { ttlSeconds });
110
135
  }
111
136
  async setEntry(key, value, options) {
112
- await writeEntry(this.#l1, key, value, options);
113
- await writeEntry(this.#l2, key, value, options);
114
- await this.#bus?.publish({ type: "delete", keys: [key] });
137
+ const l1 = await settle(() => writeEntry(this.#l1, key, value, options));
138
+ const l2 = await settle(() => writeEntry(this.#l2, key, value, options));
139
+ // Peers are told only when the shared write landed. Telling them to drop
140
+ // their L1 for a value that never reached L2 sends every one of them to a
141
+ // tier that does not have it. Upstream gates the same publish on the same
142
+ // thing (`if (this.l2 && l2Success || !this.l2)`).
143
+ if (l2.ok) {
144
+ await this.#bus?.publish({
145
+ type: "delete",
146
+ keys: [key],
147
+ senderId: this.#id,
148
+ });
149
+ }
150
+ if (!l1.ok)
151
+ throw l1.error;
152
+ if (!l2.ok)
153
+ throw l2.error;
115
154
  }
116
155
  async delete(key) {
117
- const l1 = await this.#l1.delete(key);
118
- const l2 = await this.#l2.delete(key);
119
- await this.#bus?.publish({ type: "delete", keys: [key] });
120
- return l1 || l2;
156
+ const l1 = await settle(() => this.#l1.delete(key));
157
+ const l2 = await settle(() => this.#l2.delete(key));
158
+ if (l2.ok) {
159
+ await this.#bus?.publish({
160
+ type: "delete",
161
+ keys: [key],
162
+ senderId: this.#id,
163
+ });
164
+ }
165
+ if (!l1.ok)
166
+ throw l1.error;
167
+ if (!l2.ok)
168
+ throw l2.error;
169
+ return l1.value || l2.value;
121
170
  }
122
171
  async flush() {
123
- await this.#l1.flush();
124
- await this.#l2.flush();
125
- await this.#bus?.publish({ type: "clear", keys: [] });
172
+ const l1 = await settle(() => this.#l1.flush());
173
+ const l2 = await settle(() => this.#l2.flush());
174
+ if (l2.ok) {
175
+ await this.#bus?.publish({ type: "clear", keys: [], senderId: this.#id });
176
+ }
177
+ if (!l1.ok)
178
+ throw l1.error;
179
+ if (!l2.ok)
180
+ throw l2.error;
126
181
  }
127
182
  async has(key) {
128
183
  return (await this.get(key)) !== null;
@@ -136,11 +191,17 @@ export class TieredDriver {
136
191
  if (!isTaggable(l1) || !isTaggable(l2)) {
137
192
  throw new Error("Echo: TieredDriver.deleteByTag requires both tiers to be taggable");
138
193
  }
139
- await l1.deleteByTag(tags);
140
- await l2.deleteByTag(tags);
194
+ const local = await settle(() => l1.deleteByTag(tags));
195
+ const shared = await settle(() => l2.deleteByTag(tags));
141
196
  // Peers can't map tags → keys locally; broadcast a clear so their L1 drops
142
197
  // any tagged copies (conservative but correct).
143
- await this.#bus?.publish({ type: "clear", keys: [] });
198
+ if (shared.ok) {
199
+ await this.#bus?.publish({ type: "clear", keys: [], senderId: this.#id });
200
+ }
201
+ if (!local.ok)
202
+ throw local.error;
203
+ if (!shared.ok)
204
+ throw shared.error;
144
205
  }
145
206
  /** @deprecated alias of {@link deleteByTag}. */
146
207
  async flushTags(tags) {
@@ -148,13 +209,23 @@ export class TieredDriver {
148
209
  }
149
210
  /** Prune both layers (bentocache `prune`). */
150
211
  async prune() {
151
- await this.#l1.prune?.();
152
- await this.#l2.prune?.();
212
+ const l1 = await settle(async () => this.#l1.prune?.());
213
+ const l2 = await settle(async () => this.#l2.prune?.());
214
+ if (!l1.ok)
215
+ throw l1.error;
216
+ if (!l2.ok)
217
+ throw l2.error;
153
218
  }
154
219
  /** Release both layers (bentocache `disconnect`). */
155
220
  async disconnect() {
156
- await this.#l1.disconnect?.();
157
- await this.#l2.disconnect?.();
221
+ // Both are released even when the first refuses: a tier left connected
222
+ // because its neighbour threw is a socket nobody closes.
223
+ const l1 = await settle(async () => this.#l1.disconnect?.());
224
+ const l2 = await settle(async () => this.#l2.disconnect?.());
225
+ if (!l1.ok)
226
+ throw l1.error;
227
+ if (!l2.ok)
228
+ throw l2.error;
158
229
  }
159
230
  }
160
231
  //# sourceMappingURL=TieredDriver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TieredDriver.js","sourceRoot":"","sources":["../../src/drivers/TieredDriver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TieredDriver.js","sourceRoot":"","sources":["../../src/drivers/TieredDriver.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  *
9
9
  * @implements MISS-10
10
10
  */
11
+ import "./augmentations.js";
11
12
  export type { CacheConfig, CacheDriver } from "./CacheManager.js";
12
13
  export { CacheManager } from "./CacheManager.js";
13
14
  export { MemoryDriver } from "./drivers/MemoryDriver.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EACX,UAAU,EACV,QAAQ,EACR,mBAAmB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACN,iBAAiB,EACjB,KAAK,aAAa,EAClB,OAAO,EACP,KAAK,gBAAgB,EACrB,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,GACL,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACX,YAAY,EACZ,UAAU,EACV,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,OAAO,EACP,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,UAAU,EACV,UAAU,EACV,cAAc,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,kBAAkB,GAAG,gBAAgB,EAC3E,MAAM,EAAE,CAAC,GACP,CAAC,CAEH"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EACX,UAAU,EACV,QAAQ,EACR,mBAAmB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACN,iBAAiB,EACjB,KAAK,aAAa,EAClB,OAAO,EACP,KAAK,gBAAgB,EACrB,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,GACL,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACX,YAAY,EACZ,UAAU,EACV,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,OAAO,EACP,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,UAAU,EACV,UAAU,EACV,cAAc,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,kBAAkB,GAAG,gBAAgB,EAC3E,MAAM,EAAE,CAAC,GACP,CAAC,CAEH"}
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@
8
8
  *
9
9
  * @implements MISS-10
10
10
  */
11
+ import "./augmentations.js";
11
12
  export { CacheManager } from "./CacheManager.js";
12
13
  export { MemoryDriver } from "./drivers/MemoryDriver.js";
13
14
  export { RedisDriver } from "./drivers/RedisDriver.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAMvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACN,iBAAiB,EAEjB,OAAO,EAEP,KAAK,EAEL,KAAK,GACL,MAAM,mBAAmB,CAAC;AAsB3B;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC3B,MAAS;IAET,OAAO,MAAM,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAMvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACN,iBAAiB,EAEjB,OAAO,EAEP,KAAK,EAEL,KAAK,GACL,MAAM,mBAAmB,CAAC;AAsB3B;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC3B,MAAS;IAET,OAAO,MAAM,CAAC;AACf,CAAC"}
package/dist/quasar.d.ts CHANGED
@@ -10,9 +10,26 @@
10
10
  * duck-types its host framework.
11
11
  */
12
12
  import type { RedisClient } from "./drivers/RedisDriver.js";
13
+ import type { CacheBus } from "./drivers/TieredDriver.js";
13
14
  /**
14
15
  * A resolver for `drivers.redis({ connection })` — quasar is loaded on the
15
16
  * first cache command, not at config time.
16
17
  */
17
18
  export declare function quasarConnection(name?: string): () => Promise<RedisClient>;
19
+ /**
20
+ * Redis pub/sub as a cache bus, for keeping each instance's L1 in step.
21
+ *
22
+ * A two-layer store without one is wrong the moment a second instance exists:
23
+ * each process keeps serving its own L1 copy of a key another process has
24
+ * already deleted, and nothing ever tells it. That is what the bus is for, and
25
+ * it is why `useBus` sits next to `useL2Layer` in the generated config.
26
+ *
27
+ * Quasar opens the subscriber socket lazily and on its own connection — Redis
28
+ * puts a subscribed client into a mode where it accepts nothing else, so a
29
+ * connection that both publishes and listens needs two.
30
+ */
31
+ export declare function quasarBus(options?: {
32
+ connection?: string;
33
+ channel?: string;
34
+ }): CacheBus;
18
35
  //# sourceMappingURL=quasar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quasar.d.ts","sourceRoot":"","sources":["../src/quasar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAyC5D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CA+B1E"}
1
+ {"version":3,"file":"quasar.d.ts","sourceRoot":"","sources":["../src/quasar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAc,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAyCtE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CA+B1E;AAuCD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,QAAQ,CA8CX"}
package/dist/quasar.js CHANGED
@@ -66,4 +66,81 @@ export function quasarConnection(name) {
66
66
  return connection;
67
67
  };
68
68
  }
69
+ function isPubSubSource(value) {
70
+ return (typeof value === "object" &&
71
+ value !== null &&
72
+ typeof Reflect.get(value, "publish") === "function" &&
73
+ typeof Reflect.get(value, "subscribe") === "function");
74
+ }
75
+ /**
76
+ * Resolve quasar's manager, loading it on first use.
77
+ *
78
+ * Shared by the connection resolver and the bus: echo declares quasar an
79
+ * optional peer and never imports it statically, so an application that caches
80
+ * in memory neither installs it nor pays for it.
81
+ */
82
+ async function loadQuasar(context) {
83
+ const specifier = "@c9up/quasar/services/main";
84
+ try {
85
+ const loaded = await import(/* @vite-ignore */ specifier);
86
+ return isConnectionSource(loaded) || isPubSubSource(loaded)
87
+ ? loaded
88
+ : Reflect.get(Object(loaded), "default");
89
+ }
90
+ catch (cause) {
91
+ throw new Error(`Echo: ${context}, but @c9up/quasar is not installed.\n pnpm add @c9up/quasar`, { cause });
92
+ }
93
+ }
94
+ /**
95
+ * Redis pub/sub as a cache bus, for keeping each instance's L1 in step.
96
+ *
97
+ * A two-layer store without one is wrong the moment a second instance exists:
98
+ * each process keeps serving its own L1 copy of a key another process has
99
+ * already deleted, and nothing ever tells it. That is what the bus is for, and
100
+ * it is why `useBus` sits next to `useL2Layer` in the generated config.
101
+ *
102
+ * Quasar opens the subscriber socket lazily and on its own connection — Redis
103
+ * puts a subscribed client into a mode where it accepts nothing else, so a
104
+ * connection that both publishes and listens needs two.
105
+ */
106
+ export function quasarBus(options) {
107
+ const channel = options?.channel ?? "echo::invalidate";
108
+ let ready;
109
+ const manager = () => {
110
+ ready ??= loadQuasar(`the cache bus asks for the "${options?.connection ?? "default"}" quasar connection`).then((loaded) => {
111
+ const source = isConnectionSource(loaded)
112
+ ? loaded.connection(options?.connection)
113
+ : loaded;
114
+ if (!isPubSubSource(source)) {
115
+ throw new Error("Echo: the quasar connection does not expose publish()/subscribe()");
116
+ }
117
+ return source;
118
+ });
119
+ return ready;
120
+ };
121
+ return {
122
+ async publish(message) {
123
+ const source = await manager();
124
+ await source.publish(channel, JSON.stringify(message));
125
+ },
126
+ subscribe(handler) {
127
+ // Not awaited: `subscribe` is synchronous in the bus contract, and the
128
+ // socket opens on quasar's own schedule. A failure to reach Redis must
129
+ // not take down the store — a bus that is down costs staleness, and
130
+ // throwing here would cost every cache read.
131
+ void manager()
132
+ .then((source) => source.subscribe(channel, (raw) => {
133
+ try {
134
+ handler(JSON.parse(raw));
135
+ }
136
+ catch {
137
+ /* a malformed frame is not a reason to stop listening */
138
+ }
139
+ }))
140
+ .catch(() => {
141
+ /* reported by the first publish, which does surface its error */
142
+ });
143
+ },
144
+ };
145
+ }
69
146
  //# sourceMappingURL=quasar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"quasar.js","sourceRoot":"","sources":["../src/quasar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,SAAS,kBAAkB,CAAC,KAAc;IACzC,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,CAAC,KAAK,UAAU,CACtD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,2EAA2E;IAC3E,qDAAqD;IACrD,EAAE;IACF,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,uEAAuE;IACvE,yEAAyE;IACzE,qCAAqC;IACrC,MAAM,QAAQ,GAAG;QAChB,KAAK;QACL,KAAK;QACL,KAAK;QACL,MAAM;QACN,MAAM;QACN,UAAU;QACV,QAAQ;QACR,KAAK;KACL,CAAC;IACF,OAAO,QAAQ,CAAC,KAAK,CACpB,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,UAAU,CACxD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC7C,OAAO,KAAK,IAAI,EAAE;QACjB,MAAM,SAAS,GAAG,4BAA4B,CAAC;QAC/C,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACd,cAAc,IAAI,IAAI,SAAS,kFAAkF;gBAChH,yBAAyB,EAC1B,EAAE,KAAK,EAAE,CACT,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC;YACzC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CACd,wEAAwE,CACxE,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACd,4BAA4B,IAAI,IAAI,SAAS,gDAAgD,CAC7F,CAAC;QACH,CAAC;QACD,OAAO,UAAU,CAAC;IACnB,CAAC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"quasar.js","sourceRoot":"","sources":["../src/quasar.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -152,6 +152,17 @@ export interface CacheEventMap {
152
152
  * (ream's emitter, Node's EventEmitter, mitt, …). echo never imports one.
153
153
  */
154
154
  export interface CacheEmitter {
155
- emit(event: string, payload: unknown): void;
155
+ /**
156
+ * NAMED DEVIATION from `@adonisjs/events`, which declares
157
+ * `emit(): Promise<void>` on its own class. This is a DUCK-TYPE of an
158
+ * emitter echo does not own, so it must also accept a synchronous one — a
159
+ * Node `EventEmitter` returns `boolean`, for instance.
160
+ *
161
+ * `unknown` rather than `void`, because `void` ACCEPTS a
162
+ * promise-returning function and then reads as if there were nothing to
163
+ * handle: that is what hid an Adonis emitter's rejection here. Same choice
164
+ * warden's `AuthManager` already made.
165
+ */
166
+ emit(event: string, payload: unknown): unknown;
156
167
  }
157
168
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c9up/echo",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Cache — pluggable cache contract with memory + Redis drivers for the Ream framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,8 +36,10 @@
36
36
  "@biomejs/biome": "^2.4.10",
37
37
  "@c9up/quasar": "^0.1.0",
38
38
  "@types/node": "^22.19.15",
39
+ "@vitest/coverage-v8": "^4.1.2",
39
40
  "typescript": "^6.0.2",
40
- "vitest": "^4.1.2"
41
+ "vitest": "^4.1.2",
42
+ "@c9up/ream": "^0.2.0"
41
43
  },
42
44
  "engines": {
43
45
  "node": ">=22.0.0"
@@ -66,7 +68,7 @@
66
68
  "scripts": {
67
69
  "build": "tsc -p tsconfig.build.json",
68
70
  "test": "vitest run",
69
- "lint": "biome check src/",
71
+ "lint": "biome check src/ tests/",
70
72
  "test:coverage": "vitest run --coverage",
71
73
  "typecheck": "tsc --noEmit"
72
74
  }
@@ -52,15 +52,25 @@ function resolveMs(duration: Duration | undefined): number | undefined {
52
52
 
53
53
  const TIMEOUT: unique symbol = Symbol("echo.timeout");
54
54
 
55
+ /** A timer handle that can be unreferenced — Node's, not the browser's. */
56
+ function hasUnref(timer: unknown): timer is { unref(): void } {
57
+ return (
58
+ typeof timer === "object" &&
59
+ timer !== null &&
60
+ typeof Reflect.get(timer, "unref") === "function"
61
+ );
62
+ }
63
+
55
64
  function withTimeout<T>(
56
65
  promise: Promise<T>,
57
66
  ms: number,
58
67
  ): Promise<T | typeof TIMEOUT> {
59
68
  return new Promise((resolve, reject) => {
60
69
  const timer = setTimeout(() => resolve(TIMEOUT), ms);
61
- if (typeof timer === "object" && "unref" in timer) {
62
- (timer as { unref(): void }).unref();
63
- }
70
+ // A soft timeout is for the request in flight, not a reason for the
71
+ // process to stay up. Checked rather than asserted: the browser's
72
+ // `setTimeout` answers a number, which has no `unref`.
73
+ if (hasUnref(timer)) timer.unref();
64
74
  promise.then(
65
75
  (value) => {
66
76
  clearTimeout(timer);
@@ -156,7 +166,22 @@ export class CacheManager {
156
166
  event: E,
157
167
  payload: CacheEventMap[E],
158
168
  ): void {
159
- this.#emitter?.emit(event, payload);
169
+ // Not just called: an Adonis emitter's `emit` is `async` and REJECTS when
170
+ // a listener throws and the application registered no error handler
171
+ // (`@adonisjs/events`: `if (this.#errorHandler) … else throw error`).
172
+ // Nobody awaits a cache event, so that rejection had nowhere to go and
173
+ // ended the process over a metrics listener. The interface said `void`,
174
+ // which is why nothing looked wrong — TypeScript accepts a
175
+ // promise-returning function for a `void` return.
176
+ void (async () => this.#emitter?.emit(event, payload))().catch(
177
+ (error: unknown) => {
178
+ process.stderr.write(
179
+ `[echo] '${String(event)}' listener failed: ${
180
+ error instanceof Error ? error.message : String(error)
181
+ }\n`,
182
+ );
183
+ },
184
+ );
160
185
  for (const listener of this.#listeners[event]) {
161
186
  try {
162
187
  listener(payload);
@@ -1,3 +1,4 @@
1
+ import "./augmentations.js";
1
2
  import { type CacheConfig, CacheManager } from "./CacheManager.js";
2
3
  import { MemoryDriver } from "./drivers/MemoryDriver.js";
3
4
  import { CacheStoreManager, type MultiStoreConfig } from "./StoreManager.js";
@@ -104,9 +105,15 @@ export default class EchoProvider {
104
105
  }
105
106
  return new CacheManager(new MemoryDriver(), { ...config, emitter });
106
107
  });
107
- this.app.container.singleton("cache", () =>
108
- this.app.container.resolve<CacheManager>(CacheManager),
109
- );
108
+ // Namespaced by the package that owns it, the way upstream namespaces
109
+ // `lucid.db`, `auth.manager` and `drive.manager` by theirs. The bare
110
+ // token stays bound beside it: it is what every existing
111
+ // `container.make(...)` asks for, and a token is not worth breaking an
112
+ // application over.
113
+ const cache = (): Promise<CacheManager> =>
114
+ this.app.container.resolve<CacheManager>(CacheManager);
115
+ this.app.container.singleton("echo.cache", cache);
116
+ this.app.container.singleton("cache", cache);
110
117
  }
111
118
 
112
119
  /** The cache THIS provider booted — not whatever the module singleton holds. */
@@ -20,7 +20,7 @@ import { MemoryDriver } from "./drivers/MemoryDriver.js";
20
20
  import { type RedisClient, RedisDriver } from "./drivers/RedisDriver.js";
21
21
  import { type CacheBus, TieredDriver } from "./drivers/TieredDriver.js";
22
22
  import type { Duration } from "./duration.js";
23
- import { quasarConnection } from "./quasar.js";
23
+ import { quasarBus, quasarConnection } from "./quasar.js";
24
24
  import type { CacheDriver, CacheEmitter, CacheEventMap } from "./types.js";
25
25
 
26
26
  /** A lazily-instantiated driver (built once per store, on first `use`). */
@@ -127,8 +127,16 @@ function entryOf(config: StoreConfig | Store): StoreConfig {
127
127
 
128
128
  /** Driver factory helpers (bento `drivers.memory` / `drivers.redis`). */
129
129
  export const drivers = {
130
- memory(options?: { sweepIntervalMs?: number }): DriverFactory {
131
- return () => new MemoryDriver(options?.sweepIntervalMs);
130
+ /**
131
+ * `maxItems` bounds the store by COUNT, which a TTL cannot: a cache keyed by
132
+ * a user id or a search term grows until the process runs out of memory,
133
+ * however short each entry's life. Omit it for no ceiling.
134
+ */
135
+ memory(options?: {
136
+ sweepIntervalMs?: number;
137
+ maxItems?: number;
138
+ }): DriverFactory {
139
+ return () => new MemoryDriver(options?.sweepIntervalMs, options?.maxItems);
132
140
  },
133
141
  /**
134
142
  * Either hand it a client, or name a quasar connection — the AdonisJS shape,
@@ -147,6 +155,17 @@ export const drivers = {
147
155
  return () =>
148
156
  new RedisDriver(quasarConnection(options.connection), options.prefix);
149
157
  },
158
+ /**
159
+ * Redis pub/sub as the bus that keeps each instance's L1 in step.
160
+ *
161
+ * Named alongside `redis` and taking the same `connection`, because it is
162
+ * the same deployment decision: a two-layer store without a bus is wrong as
163
+ * soon as a second instance exists, each process serving its own L1 copy of
164
+ * a key another has already deleted.
165
+ */
166
+ redisBus(options?: { connection?: string; channel?: string }): CacheBus {
167
+ return quasarBus(options);
168
+ },
150
169
  tiered(options: {
151
170
  l1: DriverFactory;
152
171
  l2: DriverFactory;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Teach ream's `ContainerBindings` what `container.make(...)` returns for the
3
+ * tokens echo binds.
4
+ *
5
+ * ream declares that interface open on purpose: it registers its own entries
6
+ * and expects each package to contribute the ones it owns. Nothing filled
7
+ * these in, so resolving by the string token answered `unknown` and every call
8
+ * site had to assert a type it could not prove.
9
+ *
10
+ * Loaded from the package barrel, so importing Echo anywhere in the
11
+ * application is enough — nobody writes a `declare module` of their own.
12
+ *
13
+ * Type-only, and ream stays an OPTIONAL peer: nothing here reaches a runtime
14
+ * import, and a `declare module` for a specifier that does not resolve is
15
+ * simply inert.
16
+ */
17
+
18
+ // Referenced so the augmentation below resolves the module it augments.
19
+ import type {} from "@c9up/ream/types";
20
+
21
+ import type { CacheManager } from "./CacheManager.js";
22
+
23
+ declare module "@c9up/ream/types" {
24
+ interface ContainerBindings {
25
+ /** The cache manager, bound by `EchoProvider`. */
26
+ "echo.cache": CacheManager;
27
+ /**
28
+ * The same binding under the name it had before the token carried its
29
+ * package. Kept bound so an existing `container.make(...)` resolves.
30
+ */
31
+ cache: CacheManager;
32
+ }
33
+ }
@@ -19,8 +19,19 @@ export class MemoryDriver implements TaggableDriver {
19
19
  #store: Map<string, StoredEntry> = new Map();
20
20
  #tagIndex: Map<string, Set<string>> = new Map();
21
21
  #sweepInterval: ReturnType<typeof setInterval>;
22
+ /**
23
+ * How many entries this driver holds before it starts dropping the oldest.
24
+ *
25
+ * Eviction was by TTL alone, which bounds how long an entry lives and not
26
+ * how many there are: a cache keyed by anything unbounded — a user id, a
27
+ * search term — grew until the process ran out of memory, and only a key
28
+ * that was written ever left. `0` keeps the old behaviour for a caller that
29
+ * genuinely wants no ceiling.
30
+ */
31
+ readonly #maxItems: number;
22
32
 
23
- constructor(sweepIntervalMs = 60_000) {
33
+ constructor(sweepIntervalMs = 60_000, maxItems = 0) {
34
+ this.#maxItems = maxItems > 0 ? maxItems : 0;
24
35
  this.#sweepInterval = setInterval(() => this.#sweep(), sweepIntervalMs);
25
36
  if (
26
37
  typeof this.#sweepInterval === "object" &&
@@ -30,6 +41,28 @@ export class MemoryDriver implements TaggableDriver {
30
41
  }
31
42
  }
32
43
 
44
+ /**
45
+ * Drop the oldest entries until the store fits under its ceiling.
46
+ *
47
+ * Expired ones go first — evicting a live entry while a dead one sits in
48
+ * the map would throw away a value someone still wants. Only if that is not
49
+ * enough does it take the least recently written.
50
+ */
51
+ #enforceCeiling(): void {
52
+ if (this.#maxItems === 0 || this.#store.size <= this.#maxItems) return;
53
+ const now = Date.now();
54
+ for (const [key, entry] of this.#store) {
55
+ if (this.#store.size <= this.#maxItems) return;
56
+ if (entry.staleUntil > 0 && entry.staleUntil < now) {
57
+ this.#evict(key, entry);
58
+ }
59
+ }
60
+ for (const [key, entry] of this.#store) {
61
+ if (this.#store.size <= this.#maxItems) return;
62
+ this.#evict(key, entry);
63
+ }
64
+ }
65
+
33
66
  /** Evict every entry past its grace window. */
34
67
  #sweep(): void {
35
68
  const now = Date.now();
@@ -130,7 +163,12 @@ export class MemoryDriver implements TaggableDriver {
130
163
  if (prev !== undefined) {
131
164
  for (const t of prev.tags) this.#tagIndex.get(t)?.delete(key);
132
165
  }
166
+ // Re-inserting moves the key to the end of the Map's iteration order, so
167
+ // the first entry is always the least recently WRITTEN — which is the
168
+ // order this evicts in.
169
+ this.#store.delete(key);
133
170
  this.#store.set(key, { value, expiresAt, staleUntil, tags });
171
+ this.#enforceCeiling();
134
172
  for (const tag of tags) {
135
173
  let set = this.#tagIndex.get(tag);
136
174
  if (!set) {