@warlock.js/cache 4.0.171 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +85 -0
  2. package/cjs/index.cjs +4088 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/cache-manager.d.mts +314 -0
  5. package/esm/cache-manager.d.mts.map +1 -0
  6. package/esm/cache-manager.mjs +486 -0
  7. package/esm/cache-manager.mjs.map +1 -0
  8. package/esm/cached/auto-key.d.mts +25 -0
  9. package/esm/cached/auto-key.d.mts.map +1 -0
  10. package/esm/cached/auto-key.mjs +55 -0
  11. package/esm/cached/auto-key.mjs.map +1 -0
  12. package/esm/cached/cached.d.mts +54 -0
  13. package/esm/cached/cached.d.mts.map +1 -0
  14. package/esm/cached/cached.mjs +25 -0
  15. package/esm/cached/cached.mjs.map +1 -0
  16. package/esm/cached/index.d.mts +3 -0
  17. package/esm/cached/index.mjs +5 -0
  18. package/esm/cached/normalize-args.d.mts +51 -0
  19. package/esm/cached/normalize-args.d.mts.map +1 -0
  20. package/esm/cached/normalize-args.mjs +26 -0
  21. package/esm/cached/normalize-args.mjs.map +1 -0
  22. package/esm/drivers/base-cache-driver.d.mts +322 -0
  23. package/esm/drivers/base-cache-driver.d.mts.map +1 -0
  24. package/esm/drivers/base-cache-driver.mjs +522 -0
  25. package/esm/drivers/base-cache-driver.mjs.map +1 -0
  26. package/esm/drivers/file-cache-driver.d.mts +68 -0
  27. package/esm/drivers/file-cache-driver.d.mts.map +1 -0
  28. package/esm/drivers/file-cache-driver.mjs +174 -0
  29. package/esm/drivers/file-cache-driver.mjs.map +1 -0
  30. package/esm/drivers/index.d.mts +9 -0
  31. package/esm/drivers/index.mjs +11 -0
  32. package/esm/drivers/lru-memory-cache-driver.d.mts +136 -0
  33. package/esm/drivers/lru-memory-cache-driver.d.mts.map +1 -0
  34. package/esm/drivers/lru-memory-cache-driver.mjs +317 -0
  35. package/esm/drivers/lru-memory-cache-driver.mjs.map +1 -0
  36. package/esm/drivers/memory-cache-driver.d.mts +112 -0
  37. package/esm/drivers/memory-cache-driver.d.mts.map +1 -0
  38. package/esm/drivers/memory-cache-driver.mjs +241 -0
  39. package/esm/drivers/memory-cache-driver.mjs.map +1 -0
  40. package/esm/drivers/memory-extended-cache-driver.d.mts +17 -0
  41. package/esm/drivers/memory-extended-cache-driver.d.mts.map +1 -0
  42. package/esm/drivers/memory-extended-cache-driver.mjs +34 -0
  43. package/esm/drivers/memory-extended-cache-driver.mjs.map +1 -0
  44. package/esm/drivers/mock-cache-driver.d.mts +137 -0
  45. package/esm/drivers/mock-cache-driver.d.mts.map +1 -0
  46. package/esm/drivers/mock-cache-driver.mjs +226 -0
  47. package/esm/drivers/mock-cache-driver.mjs.map +1 -0
  48. package/esm/drivers/null-cache-driver.d.mts +69 -0
  49. package/esm/drivers/null-cache-driver.d.mts.map +1 -0
  50. package/esm/drivers/null-cache-driver.mjs +92 -0
  51. package/esm/drivers/null-cache-driver.mjs.map +1 -0
  52. package/esm/drivers/pg-cache-driver.d.mts +148 -0
  53. package/esm/drivers/pg-cache-driver.d.mts.map +1 -0
  54. package/esm/drivers/pg-cache-driver.mjs +437 -0
  55. package/esm/drivers/pg-cache-driver.mjs.map +1 -0
  56. package/esm/drivers/redis-cache-driver.d.mts +86 -0
  57. package/esm/drivers/redis-cache-driver.d.mts.map +1 -0
  58. package/esm/drivers/redis-cache-driver.mjs +312 -0
  59. package/esm/drivers/redis-cache-driver.mjs.map +1 -0
  60. package/esm/index.d.mts +21 -0
  61. package/esm/index.mjs +24 -0
  62. package/esm/list/index.d.mts +1 -0
  63. package/esm/list/memory-cache-list.d.mts +77 -0
  64. package/esm/list/memory-cache-list.d.mts.map +1 -0
  65. package/esm/list/memory-cache-list.mjs +119 -0
  66. package/esm/list/memory-cache-list.mjs.map +1 -0
  67. package/esm/metrics.d.mts +118 -0
  68. package/esm/metrics.d.mts.map +1 -0
  69. package/esm/metrics.mjs +197 -0
  70. package/esm/metrics.mjs.map +1 -0
  71. package/esm/scoped-cache.d.mts +205 -0
  72. package/esm/scoped-cache.d.mts.map +1 -0
  73. package/esm/scoped-cache.mjs +274 -0
  74. package/esm/scoped-cache.mjs.map +1 -0
  75. package/esm/tagged-cache.d.mts +89 -0
  76. package/esm/tagged-cache.d.mts.map +1 -0
  77. package/esm/tagged-cache.mjs +147 -0
  78. package/esm/tagged-cache.mjs.map +1 -0
  79. package/esm/tagged-scoped-cache.d.mts +111 -0
  80. package/esm/tagged-scoped-cache.d.mts.map +1 -0
  81. package/esm/tagged-scoped-cache.mjs +142 -0
  82. package/esm/tagged-scoped-cache.mjs.map +1 -0
  83. package/esm/types.d.mts +1067 -0
  84. package/esm/types.d.mts.map +1 -0
  85. package/esm/types.mjs +62 -0
  86. package/esm/types.mjs.map +1 -0
  87. package/esm/utils.d.mts +161 -0
  88. package/esm/utils.d.mts.map +1 -0
  89. package/esm/utils.mjs +222 -0
  90. package/esm/utils.mjs.map +1 -0
  91. package/llms-full.txt +2071 -0
  92. package/llms.txt +28 -0
  93. package/package.json +53 -39
  94. package/skills/apply-cache-patterns/SKILL.md +97 -0
  95. package/skills/cache-basics/SKILL.md +121 -0
  96. package/skills/configure-pg-cache/SKILL.md +115 -0
  97. package/skills/configure-set-options/SKILL.md +96 -0
  98. package/skills/handle-cache-errors/SKILL.md +91 -0
  99. package/skills/observe-cache/SKILL.md +103 -0
  100. package/skills/overview/SKILL.md +69 -0
  101. package/skills/pick-cache-driver/SKILL.md +115 -0
  102. package/skills/test-cache-code/SKILL.md +219 -0
  103. package/skills/use-cache-atomic/SKILL.md +67 -0
  104. package/skills/use-cache-bulk/SKILL.md +57 -0
  105. package/skills/use-cache-list/SKILL.md +85 -0
  106. package/skills/use-cache-lock/SKILL.md +104 -0
  107. package/skills/use-cache-namespace/SKILL.md +88 -0
  108. package/skills/use-cache-similarity/SKILL.md +94 -0
  109. package/skills/use-cache-tags/SKILL.md +85 -0
  110. package/skills/use-cache-update-merge/SKILL.md +84 -0
  111. package/skills/use-cache-utils/SKILL.md +89 -0
  112. package/skills/use-cached-hof/SKILL.md +102 -0
  113. package/skills/use-swr/SKILL.md +104 -0
  114. package/cjs/cache-manager.d.ts +0 -163
  115. package/cjs/cache-manager.d.ts.map +0 -1
  116. package/cjs/cache-manager.js +0 -322
  117. package/cjs/cache-manager.js.map +0 -1
  118. package/cjs/drivers/base-cache-driver.d.ts +0 -152
  119. package/cjs/drivers/base-cache-driver.d.ts.map +0 -1
  120. package/cjs/drivers/base-cache-driver.js +0 -321
  121. package/cjs/drivers/base-cache-driver.js.map +0 -1
  122. package/cjs/drivers/file-cache-driver.d.ts +0 -45
  123. package/cjs/drivers/file-cache-driver.d.ts.map +0 -1
  124. package/cjs/drivers/file-cache-driver.js +0 -133
  125. package/cjs/drivers/file-cache-driver.js.map +0 -1
  126. package/cjs/drivers/index.d.ts +0 -8
  127. package/cjs/drivers/index.d.ts.map +0 -1
  128. package/cjs/drivers/lru-memory-cache-driver.d.ts +0 -98
  129. package/cjs/drivers/lru-memory-cache-driver.d.ts.map +0 -1
  130. package/cjs/drivers/lru-memory-cache-driver.js +0 -252
  131. package/cjs/drivers/lru-memory-cache-driver.js.map +0 -1
  132. package/cjs/drivers/memory-cache-driver.d.ts +0 -82
  133. package/cjs/drivers/memory-cache-driver.d.ts.map +0 -1
  134. package/cjs/drivers/memory-cache-driver.js +0 -218
  135. package/cjs/drivers/memory-cache-driver.js.map +0 -1
  136. package/cjs/drivers/memory-extended-cache-driver.d.ts +0 -13
  137. package/cjs/drivers/memory-extended-cache-driver.d.ts.map +0 -1
  138. package/cjs/drivers/memory-extended-cache-driver.js +0 -25
  139. package/cjs/drivers/memory-extended-cache-driver.js.map +0 -1
  140. package/cjs/drivers/null-cache-driver.d.ts +0 -58
  141. package/cjs/drivers/null-cache-driver.d.ts.map +0 -1
  142. package/cjs/drivers/null-cache-driver.js +0 -84
  143. package/cjs/drivers/null-cache-driver.js.map +0 -1
  144. package/cjs/drivers/redis-cache-driver.d.ts +0 -57
  145. package/cjs/drivers/redis-cache-driver.d.ts.map +0 -1
  146. package/cjs/drivers/redis-cache-driver.js +0 -263
  147. package/cjs/drivers/redis-cache-driver.js.map +0 -1
  148. package/cjs/index.d.ts +0 -6
  149. package/cjs/index.d.ts.map +0 -1
  150. package/cjs/index.js +0 -1
  151. package/cjs/index.js.map +0 -1
  152. package/cjs/tagged-cache.d.ts +0 -77
  153. package/cjs/tagged-cache.d.ts.map +0 -1
  154. package/cjs/tagged-cache.js +0 -160
  155. package/cjs/tagged-cache.js.map +0 -1
  156. package/cjs/types.d.ts +0 -391
  157. package/cjs/types.d.ts.map +0 -1
  158. package/cjs/types.js +0 -36
  159. package/cjs/types.js.map +0 -1
  160. package/cjs/utils.d.ts +0 -50
  161. package/cjs/utils.d.ts.map +0 -1
  162. package/cjs/utils.js +0 -55
  163. package/cjs/utils.js.map +0 -1
  164. package/esm/cache-manager.d.ts +0 -163
  165. package/esm/cache-manager.d.ts.map +0 -1
  166. package/esm/cache-manager.js +0 -322
  167. package/esm/cache-manager.js.map +0 -1
  168. package/esm/drivers/base-cache-driver.d.ts +0 -152
  169. package/esm/drivers/base-cache-driver.d.ts.map +0 -1
  170. package/esm/drivers/base-cache-driver.js +0 -321
  171. package/esm/drivers/base-cache-driver.js.map +0 -1
  172. package/esm/drivers/file-cache-driver.d.ts +0 -45
  173. package/esm/drivers/file-cache-driver.d.ts.map +0 -1
  174. package/esm/drivers/file-cache-driver.js +0 -133
  175. package/esm/drivers/file-cache-driver.js.map +0 -1
  176. package/esm/drivers/index.d.ts +0 -8
  177. package/esm/drivers/index.d.ts.map +0 -1
  178. package/esm/drivers/lru-memory-cache-driver.d.ts +0 -98
  179. package/esm/drivers/lru-memory-cache-driver.d.ts.map +0 -1
  180. package/esm/drivers/lru-memory-cache-driver.js +0 -252
  181. package/esm/drivers/lru-memory-cache-driver.js.map +0 -1
  182. package/esm/drivers/memory-cache-driver.d.ts +0 -82
  183. package/esm/drivers/memory-cache-driver.d.ts.map +0 -1
  184. package/esm/drivers/memory-cache-driver.js +0 -218
  185. package/esm/drivers/memory-cache-driver.js.map +0 -1
  186. package/esm/drivers/memory-extended-cache-driver.d.ts +0 -13
  187. package/esm/drivers/memory-extended-cache-driver.d.ts.map +0 -1
  188. package/esm/drivers/memory-extended-cache-driver.js +0 -25
  189. package/esm/drivers/memory-extended-cache-driver.js.map +0 -1
  190. package/esm/drivers/null-cache-driver.d.ts +0 -58
  191. package/esm/drivers/null-cache-driver.d.ts.map +0 -1
  192. package/esm/drivers/null-cache-driver.js +0 -84
  193. package/esm/drivers/null-cache-driver.js.map +0 -1
  194. package/esm/drivers/redis-cache-driver.d.ts +0 -57
  195. package/esm/drivers/redis-cache-driver.d.ts.map +0 -1
  196. package/esm/drivers/redis-cache-driver.js +0 -263
  197. package/esm/drivers/redis-cache-driver.js.map +0 -1
  198. package/esm/index.d.ts +0 -6
  199. package/esm/index.d.ts.map +0 -1
  200. package/esm/index.js +0 -1
  201. package/esm/index.js.map +0 -1
  202. package/esm/tagged-cache.d.ts +0 -77
  203. package/esm/tagged-cache.d.ts.map +0 -1
  204. package/esm/tagged-cache.js +0 -160
  205. package/esm/tagged-cache.js.map +0 -1
  206. package/esm/types.d.ts +0 -391
  207. package/esm/types.d.ts.map +0 -1
  208. package/esm/types.js +0 -36
  209. package/esm/types.js.map +0 -1
  210. package/esm/utils.d.ts +0 -50
  211. package/esm/utils.d.ts.map +0 -1
  212. package/esm/utils.js +0 -55
  213. package/esm/utils.js.map +0 -1
@@ -0,0 +1,118 @@
1
+ import { CacheEventData, CacheMetricsSnapshot } from "./types.mjs";
2
+
3
+ //#region ../../@warlock.js/cache/src/metrics.d.ts
4
+ /**
5
+ * Per-driver counter row tracked inside {@link CacheMetricsCollector}.
6
+ *
7
+ * Same shape as the public {@link CacheMetricsSnapshot} except for the lack
8
+ * of `byDriver` (which is the breakdown itself) and the `latencySamples`
9
+ * array — the buffer that p50/p95/p99 are computed from at snapshot time.
10
+ */
11
+ type DriverCounters = {
12
+ hits: number;
13
+ misses: number;
14
+ sets: number;
15
+ removed: number;
16
+ errors: number;
17
+ latencySamples: number[]; /** Pointer into `latencySamples` for the next write — circular buffer. */
18
+ latencyCursor: number;
19
+ };
20
+ /**
21
+ * Listens to `CacheManager` events and accumulates running counters + a
22
+ * circular latency buffer per driver. Returned to consumers via
23
+ * `cache.metrics()` as a {@link CacheMetricsSnapshot}.
24
+ *
25
+ * **Role.** Single-instance observability layer attached to the manager.
26
+ * Subscribes once at construction; survives `cache.use()` driver switches
27
+ * because the global event registry on the manager re-attaches handlers to
28
+ * every loaded driver.
29
+ *
30
+ * **Responsibility.**
31
+ * - Owns: per-driver and aggregate counters (`hits`, `misses`, `sets`,
32
+ * `removed`, `errors`), the latency circular buffer, and snapshot
33
+ * computation including hit-rate + percentile calculation.
34
+ * - Does NOT own: event emission (driven by drivers via `BaseCacheDriver.emit`),
35
+ * timing instrumentation (done at the manager level via `recordLatency`),
36
+ * or persistence — every metric resets on `resetMetrics()` and on process
37
+ * restart.
38
+ *
39
+ * @example
40
+ * cache.metrics();
41
+ * // {
42
+ * // hits: 9821, misses: 173, hitRate: 0.983,
43
+ * // latencyMs: { p50: 0.4, p95: 2.1, p99: 8.2, samples: 1000 },
44
+ * // byDriver: { memory: { ... }, redis: { ... } },
45
+ * // startedAt: 1714185600000,
46
+ * // }
47
+ */
48
+ declare class CacheMetricsCollector {
49
+ /**
50
+ * Maximum number of latency samples retained per driver. Older samples
51
+ * are overwritten in arrival order — quantile calc operates on whatever
52
+ * window is currently in the buffer.
53
+ */
54
+ protected readonly bufferSize: number;
55
+ /**
56
+ * Aggregate counters across every driver. Mirrors what one driver bucket
57
+ * holds — the snapshot reports both totals and per-driver breakdowns.
58
+ */
59
+ protected readonly aggregate: DriverCounters;
60
+ /**
61
+ * Per-driver buckets keyed by driver name (`"memory"`, `"redis"`, …).
62
+ * Lazy-allocated on first event.
63
+ */
64
+ protected readonly byDriver: Map<string, DriverCounters>;
65
+ /** Millisecond timestamp the collector last reset. */
66
+ protected startedAt: number;
67
+ constructor(bufferSize?: number);
68
+ /**
69
+ * Increment the appropriate counters for a cache event. Called from the
70
+ * manager's global listeners (one per event type).
71
+ */
72
+ recordEvent(event: "hit" | "miss" | "set" | "removed" | "error", data: CacheEventData): void;
73
+ /**
74
+ * Append a latency sample for `driver`. Called by the manager from its
75
+ * timed wrappers around `get` / `set` / `remove`. Uses circular-buffer
76
+ * semantics: oldest samples are overwritten once the buffer is full.
77
+ */
78
+ recordLatency(driver: string, durationMs: number): void;
79
+ /**
80
+ * Compute and return the current snapshot. Latency percentiles are
81
+ * derived from a sorted copy of the buffer at call time — O(N log N)
82
+ * on N=1000 is cheap enough that we don't bother caching.
83
+ */
84
+ snapshot(): CacheMetricsSnapshot;
85
+ /**
86
+ * Wipe every counter, drop every latency sample, and reset `startedAt`.
87
+ * The collector itself stays subscribed to events.
88
+ */
89
+ reset(): void;
90
+ /**
91
+ * Locate the per-driver bucket, creating it on first reference. Driver
92
+ * names are taken verbatim from `CacheEventData.driver`.
93
+ */
94
+ protected bucketFor(driverName: string): DriverCounters;
95
+ /**
96
+ * Convert raw counters into the public snapshot row shape. Computes
97
+ * `hitRate` and the latency percentiles on the fly.
98
+ */
99
+ protected toRow(bucket: DriverCounters): Omit<CacheMetricsSnapshot, "byDriver">;
100
+ /**
101
+ * Sort a copy of the buffer and pick the percentile entries directly.
102
+ * Empty buffers return zeroed percentiles so consumers can render
103
+ * dashboards without null-checking.
104
+ */
105
+ protected computeLatency(samples: number[]): CacheMetricsSnapshot["latencyMs"];
106
+ /**
107
+ * Append a latency sample using circular-buffer semantics — overwrite the
108
+ * oldest entry once the buffer is full instead of growing unbounded.
109
+ */
110
+ protected appendLatency(bucket: DriverCounters, durationMs: number): void;
111
+ /** Build a fresh counter row with zeroed totals and an empty buffer. */
112
+ protected createCounters(): DriverCounters;
113
+ /** Reset an existing counter row in place. Used by `reset()` for the aggregate. */
114
+ protected resetCounters(bucket: DriverCounters): void;
115
+ }
116
+ //#endregion
117
+ export { CacheMetricsCollector };
118
+ //# sourceMappingURL=metrics.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.mts","names":[],"sources":["../../../../../@warlock.js/cache/src/metrics.ts"],"mappings":";;;;;AAGiB;;;;;KAgBZ,cAAA;EACH,IAAA;EACA,MAAA;EACA,IAAA;EACA,OAAA;EACA,MAAA;EACA,cAAA,YAEa;EAAb,aAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+BW,qBAAA;EAoEJ;;;;;EAAA,mBA9DY,UAAA;EAoGT;;;;EAAA,mBA9FS,SAAA,EAAW,cAAA;EA6Gd;;;;EAAA,mBAvGG,QAAA,EAAU,GAAA,SAAY,cAAA;EA6HI;EAAA,UA1HnC,SAAA;cAES,UAAA;EAgJK;;;;EAvIjB,WAAA,CACL,KAAA,gDACA,IAAA,EAAM,cAAA;EA8JwB;;;AAAc;;EA5HvC,aAAA,CAAc,MAAA,UAAgB,UAAA;;;;;;EAU9B,QAAA,CAAA,GAAY,oBAAA;;;;;EAkBZ,KAAA,CAAA;;;;;YAUG,SAAA,CAAU,UAAA,WAAqB,cAAA;;;;;YAe/B,KAAA,CAAM,MAAA,EAAQ,cAAA,GAAiB,IAAA,CAAK,oBAAA;;;;;;YAsBpC,cAAA,CAAe,OAAA,aAAoB,oBAAA;;;;;YAwBnC,aAAA,CAAc,MAAA,EAAQ,cAAA,EAAgB,UAAA;;YAYtC,cAAA,CAAA,GAAkB,cAAA;;YAalB,aAAA,CAAc,MAAA,EAAQ,cAAA;AAAA"}
@@ -0,0 +1,197 @@
1
+ //#region ../../@warlock.js/cache/src/metrics.ts
2
+ /**
3
+ * Default size of the circular latency-sample buffer. 1000 samples covers
4
+ * "tell me the current p95" for every realistic workload while keeping the
5
+ * memory cost negligible (8KB at 8 bytes per number).
6
+ */
7
+ const DEFAULT_LATENCY_BUFFER_SIZE = 1e3;
8
+ /**
9
+ * Listens to `CacheManager` events and accumulates running counters + a
10
+ * circular latency buffer per driver. Returned to consumers via
11
+ * `cache.metrics()` as a {@link CacheMetricsSnapshot}.
12
+ *
13
+ * **Role.** Single-instance observability layer attached to the manager.
14
+ * Subscribes once at construction; survives `cache.use()` driver switches
15
+ * because the global event registry on the manager re-attaches handlers to
16
+ * every loaded driver.
17
+ *
18
+ * **Responsibility.**
19
+ * - Owns: per-driver and aggregate counters (`hits`, `misses`, `sets`,
20
+ * `removed`, `errors`), the latency circular buffer, and snapshot
21
+ * computation including hit-rate + percentile calculation.
22
+ * - Does NOT own: event emission (driven by drivers via `BaseCacheDriver.emit`),
23
+ * timing instrumentation (done at the manager level via `recordLatency`),
24
+ * or persistence — every metric resets on `resetMetrics()` and on process
25
+ * restart.
26
+ *
27
+ * @example
28
+ * cache.metrics();
29
+ * // {
30
+ * // hits: 9821, misses: 173, hitRate: 0.983,
31
+ * // latencyMs: { p50: 0.4, p95: 2.1, p99: 8.2, samples: 1000 },
32
+ * // byDriver: { memory: { ... }, redis: { ... } },
33
+ * // startedAt: 1714185600000,
34
+ * // }
35
+ */
36
+ var CacheMetricsCollector = class {
37
+ constructor(bufferSize = DEFAULT_LATENCY_BUFFER_SIZE) {
38
+ this.byDriver = /* @__PURE__ */ new Map();
39
+ this.startedAt = Date.now();
40
+ this.bufferSize = bufferSize;
41
+ this.aggregate = this.createCounters();
42
+ }
43
+ /**
44
+ * Increment the appropriate counters for a cache event. Called from the
45
+ * manager's global listeners (one per event type).
46
+ */
47
+ recordEvent(event, data) {
48
+ const driverBucket = this.bucketFor(data.driver);
49
+ const aggregate = this.aggregate;
50
+ switch (event) {
51
+ case "hit":
52
+ aggregate.hits += 1;
53
+ driverBucket.hits += 1;
54
+ break;
55
+ case "miss":
56
+ aggregate.misses += 1;
57
+ driverBucket.misses += 1;
58
+ break;
59
+ case "set":
60
+ aggregate.sets += 1;
61
+ driverBucket.sets += 1;
62
+ break;
63
+ case "removed":
64
+ aggregate.removed += 1;
65
+ driverBucket.removed += 1;
66
+ break;
67
+ case "error":
68
+ aggregate.errors += 1;
69
+ driverBucket.errors += 1;
70
+ break;
71
+ }
72
+ }
73
+ /**
74
+ * Append a latency sample for `driver`. Called by the manager from its
75
+ * timed wrappers around `get` / `set` / `remove`. Uses circular-buffer
76
+ * semantics: oldest samples are overwritten once the buffer is full.
77
+ */
78
+ recordLatency(driver, durationMs) {
79
+ this.appendLatency(this.aggregate, durationMs);
80
+ this.appendLatency(this.bucketFor(driver), durationMs);
81
+ }
82
+ /**
83
+ * Compute and return the current snapshot. Latency percentiles are
84
+ * derived from a sorted copy of the buffer at call time — O(N log N)
85
+ * on N=1000 is cheap enough that we don't bother caching.
86
+ */
87
+ snapshot() {
88
+ const byDriver = {};
89
+ for (const [driverName, bucket] of this.byDriver) byDriver[driverName] = this.toRow(bucket);
90
+ return {
91
+ ...this.toRow(this.aggregate),
92
+ byDriver,
93
+ startedAt: this.startedAt
94
+ };
95
+ }
96
+ /**
97
+ * Wipe every counter, drop every latency sample, and reset `startedAt`.
98
+ * The collector itself stays subscribed to events.
99
+ */
100
+ reset() {
101
+ this.resetCounters(this.aggregate);
102
+ this.byDriver.clear();
103
+ this.startedAt = Date.now();
104
+ }
105
+ /**
106
+ * Locate the per-driver bucket, creating it on first reference. Driver
107
+ * names are taken verbatim from `CacheEventData.driver`.
108
+ */
109
+ bucketFor(driverName) {
110
+ let bucket = this.byDriver.get(driverName);
111
+ if (!bucket) {
112
+ bucket = this.createCounters();
113
+ this.byDriver.set(driverName, bucket);
114
+ }
115
+ return bucket;
116
+ }
117
+ /**
118
+ * Convert raw counters into the public snapshot row shape. Computes
119
+ * `hitRate` and the latency percentiles on the fly.
120
+ */
121
+ toRow(bucket) {
122
+ const totalReads = bucket.hits + bucket.misses;
123
+ const hitRate = totalReads === 0 ? 0 : bucket.hits / totalReads;
124
+ const latency = this.computeLatency(bucket.latencySamples);
125
+ return {
126
+ hits: bucket.hits,
127
+ misses: bucket.misses,
128
+ sets: bucket.sets,
129
+ removed: bucket.removed,
130
+ errors: bucket.errors,
131
+ hitRate,
132
+ latencyMs: latency,
133
+ startedAt: this.startedAt
134
+ };
135
+ }
136
+ /**
137
+ * Sort a copy of the buffer and pick the percentile entries directly.
138
+ * Empty buffers return zeroed percentiles so consumers can render
139
+ * dashboards without null-checking.
140
+ */
141
+ computeLatency(samples) {
142
+ if (samples.length === 0) return {
143
+ p50: 0,
144
+ p95: 0,
145
+ p99: 0,
146
+ samples: 0
147
+ };
148
+ const sorted = [...samples].sort((a, b) => a - b);
149
+ const pick = (quantile) => {
150
+ return sorted[Math.min(sorted.length - 1, Math.floor(quantile * sorted.length))];
151
+ };
152
+ return {
153
+ p50: pick(.5),
154
+ p95: pick(.95),
155
+ p99: pick(.99),
156
+ samples: sorted.length
157
+ };
158
+ }
159
+ /**
160
+ * Append a latency sample using circular-buffer semantics — overwrite the
161
+ * oldest entry once the buffer is full instead of growing unbounded.
162
+ */
163
+ appendLatency(bucket, durationMs) {
164
+ if (bucket.latencySamples.length < this.bufferSize) {
165
+ bucket.latencySamples.push(durationMs);
166
+ return;
167
+ }
168
+ bucket.latencySamples[bucket.latencyCursor] = durationMs;
169
+ bucket.latencyCursor = (bucket.latencyCursor + 1) % this.bufferSize;
170
+ }
171
+ /** Build a fresh counter row with zeroed totals and an empty buffer. */
172
+ createCounters() {
173
+ return {
174
+ hits: 0,
175
+ misses: 0,
176
+ sets: 0,
177
+ removed: 0,
178
+ errors: 0,
179
+ latencySamples: [],
180
+ latencyCursor: 0
181
+ };
182
+ }
183
+ /** Reset an existing counter row in place. Used by `reset()` for the aggregate. */
184
+ resetCounters(bucket) {
185
+ bucket.hits = 0;
186
+ bucket.misses = 0;
187
+ bucket.sets = 0;
188
+ bucket.removed = 0;
189
+ bucket.errors = 0;
190
+ bucket.latencySamples.length = 0;
191
+ bucket.latencyCursor = 0;
192
+ }
193
+ };
194
+
195
+ //#endregion
196
+ export { CacheMetricsCollector };
197
+ //# sourceMappingURL=metrics.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.mjs","names":[],"sources":["../../../../../@warlock.js/cache/src/metrics.ts"],"sourcesContent":["import type {\n CacheEventData,\n CacheMetricsSnapshot,\n} from \"./types\";\n\n/**\n * Default size of the circular latency-sample buffer. 1000 samples covers\n * \"tell me the current p95\" for every realistic workload while keeping the\n * memory cost negligible (8KB at 8 bytes per number).\n */\nconst DEFAULT_LATENCY_BUFFER_SIZE = 1000;\n\n/**\n * Per-driver counter row tracked inside {@link CacheMetricsCollector}.\n *\n * Same shape as the public {@link CacheMetricsSnapshot} except for the lack\n * of `byDriver` (which is the breakdown itself) and the `latencySamples`\n * array — the buffer that p50/p95/p99 are computed from at snapshot time.\n */\ntype DriverCounters = {\n hits: number;\n misses: number;\n sets: number;\n removed: number;\n errors: number;\n latencySamples: number[];\n /** Pointer into `latencySamples` for the next write — circular buffer. */\n latencyCursor: number;\n};\n\n/**\n * Listens to `CacheManager` events and accumulates running counters + a\n * circular latency buffer per driver. Returned to consumers via\n * `cache.metrics()` as a {@link CacheMetricsSnapshot}.\n *\n * **Role.** Single-instance observability layer attached to the manager.\n * Subscribes once at construction; survives `cache.use()` driver switches\n * because the global event registry on the manager re-attaches handlers to\n * every loaded driver.\n *\n * **Responsibility.**\n * - Owns: per-driver and aggregate counters (`hits`, `misses`, `sets`,\n * `removed`, `errors`), the latency circular buffer, and snapshot\n * computation including hit-rate + percentile calculation.\n * - Does NOT own: event emission (driven by drivers via `BaseCacheDriver.emit`),\n * timing instrumentation (done at the manager level via `recordLatency`),\n * or persistence — every metric resets on `resetMetrics()` and on process\n * restart.\n *\n * @example\n * cache.metrics();\n * // {\n * // hits: 9821, misses: 173, hitRate: 0.983,\n * // latencyMs: { p50: 0.4, p95: 2.1, p99: 8.2, samples: 1000 },\n * // byDriver: { memory: { ... }, redis: { ... } },\n * // startedAt: 1714185600000,\n * // }\n */\nexport class CacheMetricsCollector {\n /**\n * Maximum number of latency samples retained per driver. Older samples\n * are overwritten in arrival order — quantile calc operates on whatever\n * window is currently in the buffer.\n */\n protected readonly bufferSize: number;\n\n /**\n * Aggregate counters across every driver. Mirrors what one driver bucket\n * holds — the snapshot reports both totals and per-driver breakdowns.\n */\n protected readonly aggregate: DriverCounters;\n\n /**\n * Per-driver buckets keyed by driver name (`\"memory\"`, `\"redis\"`, …).\n * Lazy-allocated on first event.\n */\n protected readonly byDriver: Map<string, DriverCounters> = new Map();\n\n /** Millisecond timestamp the collector last reset. */\n protected startedAt: number = Date.now();\n\n public constructor(bufferSize: number = DEFAULT_LATENCY_BUFFER_SIZE) {\n this.bufferSize = bufferSize;\n this.aggregate = this.createCounters();\n }\n\n /**\n * Increment the appropriate counters for a cache event. Called from the\n * manager's global listeners (one per event type).\n */\n public recordEvent(\n event: \"hit\" | \"miss\" | \"set\" | \"removed\" | \"error\",\n data: CacheEventData,\n ): void {\n const driverBucket = this.bucketFor(data.driver);\n const aggregate = this.aggregate;\n\n switch (event) {\n case \"hit\":\n aggregate.hits += 1;\n driverBucket.hits += 1;\n break;\n case \"miss\":\n aggregate.misses += 1;\n driverBucket.misses += 1;\n break;\n case \"set\":\n aggregate.sets += 1;\n driverBucket.sets += 1;\n break;\n case \"removed\":\n aggregate.removed += 1;\n driverBucket.removed += 1;\n break;\n case \"error\":\n aggregate.errors += 1;\n driverBucket.errors += 1;\n break;\n }\n }\n\n /**\n * Append a latency sample for `driver`. Called by the manager from its\n * timed wrappers around `get` / `set` / `remove`. Uses circular-buffer\n * semantics: oldest samples are overwritten once the buffer is full.\n */\n public recordLatency(driver: string, durationMs: number): void {\n this.appendLatency(this.aggregate, durationMs);\n this.appendLatency(this.bucketFor(driver), durationMs);\n }\n\n /**\n * Compute and return the current snapshot. Latency percentiles are\n * derived from a sorted copy of the buffer at call time — O(N log N)\n * on N=1000 is cheap enough that we don't bother caching.\n */\n public snapshot(): CacheMetricsSnapshot {\n const byDriver: Record<string, Omit<CacheMetricsSnapshot, \"byDriver\">> = {};\n\n for (const [driverName, bucket] of this.byDriver) {\n byDriver[driverName] = this.toRow(bucket);\n }\n\n return {\n ...this.toRow(this.aggregate),\n byDriver,\n startedAt: this.startedAt,\n };\n }\n\n /**\n * Wipe every counter, drop every latency sample, and reset `startedAt`.\n * The collector itself stays subscribed to events.\n */\n public reset(): void {\n this.resetCounters(this.aggregate);\n this.byDriver.clear();\n this.startedAt = Date.now();\n }\n\n /**\n * Locate the per-driver bucket, creating it on first reference. Driver\n * names are taken verbatim from `CacheEventData.driver`.\n */\n protected bucketFor(driverName: string): DriverCounters {\n let bucket = this.byDriver.get(driverName);\n\n if (!bucket) {\n bucket = this.createCounters();\n this.byDriver.set(driverName, bucket);\n }\n\n return bucket;\n }\n\n /**\n * Convert raw counters into the public snapshot row shape. Computes\n * `hitRate` and the latency percentiles on the fly.\n */\n protected toRow(bucket: DriverCounters): Omit<CacheMetricsSnapshot, \"byDriver\"> {\n const totalReads = bucket.hits + bucket.misses;\n const hitRate = totalReads === 0 ? 0 : bucket.hits / totalReads;\n const latency = this.computeLatency(bucket.latencySamples);\n\n return {\n hits: bucket.hits,\n misses: bucket.misses,\n sets: bucket.sets,\n removed: bucket.removed,\n errors: bucket.errors,\n hitRate,\n latencyMs: latency,\n startedAt: this.startedAt,\n };\n }\n\n /**\n * Sort a copy of the buffer and pick the percentile entries directly.\n * Empty buffers return zeroed percentiles so consumers can render\n * dashboards without null-checking.\n */\n protected computeLatency(samples: number[]): CacheMetricsSnapshot[\"latencyMs\"] {\n if (samples.length === 0) {\n return { p50: 0, p95: 0, p99: 0, samples: 0 };\n }\n\n const sorted = [...samples].sort((a, b) => a - b);\n const pick = (quantile: number): number => {\n const index = Math.min(sorted.length - 1, Math.floor(quantile * sorted.length));\n\n return sorted[index];\n };\n\n return {\n p50: pick(0.5),\n p95: pick(0.95),\n p99: pick(0.99),\n samples: sorted.length,\n };\n }\n\n /**\n * Append a latency sample using circular-buffer semantics — overwrite the\n * oldest entry once the buffer is full instead of growing unbounded.\n */\n protected appendLatency(bucket: DriverCounters, durationMs: number): void {\n if (bucket.latencySamples.length < this.bufferSize) {\n bucket.latencySamples.push(durationMs);\n\n return;\n }\n\n bucket.latencySamples[bucket.latencyCursor] = durationMs;\n bucket.latencyCursor = (bucket.latencyCursor + 1) % this.bufferSize;\n }\n\n /** Build a fresh counter row with zeroed totals and an empty buffer. */\n protected createCounters(): DriverCounters {\n return {\n hits: 0,\n misses: 0,\n sets: 0,\n removed: 0,\n errors: 0,\n latencySamples: [],\n latencyCursor: 0,\n };\n }\n\n /** Reset an existing counter row in place. Used by `reset()` for the aggregate. */\n protected resetCounters(bucket: DriverCounters): void {\n bucket.hits = 0;\n bucket.misses = 0;\n bucket.sets = 0;\n bucket.removed = 0;\n bucket.errors = 0;\n bucket.latencySamples.length = 0;\n bucket.latencyCursor = 0;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,205 @@
1
+ import { CacheDriver, CacheKey, CacheListAccessor, CacheNamespaceOptions, CacheSetOptions, CacheSimilarHit, CacheSimilarOptions, CacheSwrOptions, CacheTtl, LockOptions, LockOutcome, RememberOptions, ScopedCacheContract, TaggedScopedCacheContract } from "./types.mjs";
2
+
3
+ //#region ../../@warlock.js/cache/src/scoped-cache.d.ts
4
+ /**
5
+ * Scoped view over a cache source. Returned by `cache.namespace(prefix, options?)`.
6
+ *
7
+ * **Role.** A `ScopedCache` is a stateless wrapper that prepends a fixed
8
+ * prefix to every key and applies optional default `ttl` / `tags` to every
9
+ * write. Stores nothing itself — every call forwards to the underlying
10
+ * `source` (typically the `CacheManager`, but any `CacheDriver` works).
11
+ *
12
+ * **Responsibility.**
13
+ * - Owns: prefix-prepending of keys, normalization of nested-scope prefixes,
14
+ * merging scope defaults into write options (`ttl`, `tags`), filtering
15
+ * `similar()` hits to its own scope, and exposing `.clear()` as a sugar
16
+ * for `removeNamespace(prefix)`.
17
+ * - Does NOT own: actual storage, connection lifecycle, event listeners,
18
+ * driver selection, or tag-index bookkeeping (delegated to the source's
19
+ * tagged-cache machinery).
20
+ *
21
+ * Per-call options always win over scope defaults; tags merge additively
22
+ * across (scope defaults + per-call) layers. Nested scopes inherit and may
23
+ * override the parent's defaults — see {@link ScopedCache.namespace}.
24
+ *
25
+ * @example
26
+ * const chat = cache.namespace(`chats.${id}`, { ttl: "30d" });
27
+ *
28
+ * await chat.set("messages.10", msg); // 30d default
29
+ * await chat.set("draft", d, { ttl: "1h" }); // per-call override
30
+ * await chat.namespace("typing", { ttl: "5s" }).set("user.42", true);
31
+ * await chat.clear();
32
+ */
33
+ declare class ScopedCache implements ScopedCacheContract {
34
+ /**
35
+ * Fully-qualified prefix prepended to every key handled by this scope.
36
+ * Normalized through {@link parseCacheKey} on construction so colon-form
37
+ * input (`"chats:10"`) and trailing dots compose cleanly with nested scopes.
38
+ */
39
+ readonly prefix: string;
40
+ /**
41
+ * Underlying cache source. Public-readonly so co-located helpers
42
+ * (`TaggedScopedCache`) can delegate without ceremony — not part of the
43
+ * stable consumer API.
44
+ *
45
+ * @internal
46
+ */
47
+ readonly source: CacheDriver<any, any>;
48
+ /**
49
+ * Defaults applied to every write through this scope. Per-call options
50
+ * override `ttl`; `tags` merge additively across layers.
51
+ *
52
+ * @internal
53
+ */
54
+ readonly defaults: CacheNamespaceOptions;
55
+ /**
56
+ * Build a scope. Constructed via `cache.namespace(prefix, options)` —
57
+ * users never call this directly.
58
+ */
59
+ constructor(source: CacheDriver<any, any>, prefix: string, defaults?: CacheNamespaceOptions);
60
+ /**
61
+ * Build a nested scope. The child's prefix is `parent.child`; child options
62
+ * override the parent's `ttl` and union into `tags`.
63
+ *
64
+ * @example
65
+ * const chat = cache.namespace("chats.10", { ttl: "30d" });
66
+ * const typing = chat.namespace("typing", { ttl: "5s" });
67
+ * // typing.prefix === "chats.10.typing"
68
+ */
69
+ namespace(prefix: string, options?: CacheNamespaceOptions): ScopedCacheContract;
70
+ /**
71
+ * Return a one-shot tagged write handle. The handle's tags merge additively
72
+ * with scope-level defaults — final tag list per write is the union of
73
+ * (scope tags + handle tags + per-call tags), deduped.
74
+ */
75
+ tags(tags: string[]): TaggedScopedCacheContract;
76
+ /**
77
+ * Wipe every entry under this scope's prefix. Sugar over
78
+ * `source.removeNamespace(prefix)` — siblings outside the scope are
79
+ * untouched.
80
+ */
81
+ clear(): Promise<void>;
82
+ /**
83
+ * Read the value at the scoped key. Forwards to the source after prefixing.
84
+ */
85
+ get<T = any>(key: CacheKey): Promise<T | null>;
86
+ /**
87
+ * Check presence of the scoped key without fetching the value.
88
+ */
89
+ has(key: CacheKey): Promise<boolean>;
90
+ /**
91
+ * Batch-read scoped keys. Each input key is prefixed before forwarding.
92
+ */
93
+ many(keys: CacheKey[]): Promise<any[]>;
94
+ /**
95
+ * Read-and-remove. Returns the value or `null`; the entry is gone after.
96
+ */
97
+ pull<T = any>(key: CacheKey): Promise<T | null>;
98
+ /**
99
+ * Write the scoped key. Per-call `ttl`/`tags` win over scope defaults;
100
+ * `expiresAt` is preserved as-is (absolute deadlines are never overridden
101
+ * by the scope's relative-ttl default).
102
+ */
103
+ set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions): Promise<any>;
104
+ /**
105
+ * Batch-write under the scope. Caller's positional `ttl` wins; otherwise
106
+ * the scope default is parsed to seconds (since `setMany` accepts only a
107
+ * numeric ttl).
108
+ */
109
+ setMany(items: Record<string, any>, ttl?: number): Promise<void>;
110
+ /**
111
+ * Atomic create-or-skip on the scoped key. Throws when the underlying
112
+ * source has no `setNX` (driver-specific — Redis-only today).
113
+ */
114
+ setNX(key: CacheKey, value: any, ttl?: number): Promise<boolean>;
115
+ /**
116
+ * Permanent write (no expiration). Bypasses the scope's `ttl` default —
117
+ * `forever` always means forever, regardless of scope policy.
118
+ */
119
+ forever<T = any>(key: CacheKey, value: T): Promise<T>;
120
+ /**
121
+ * Remove a single scoped key.
122
+ */
123
+ remove(key: CacheKey): Promise<void>;
124
+ /**
125
+ * Read-or-compute. Cache-miss writes pick up the scope's default `ttl`
126
+ * and `tags` unless the caller passed an options object that overrides.
127
+ */
128
+ remember<T = any>(key: CacheKey, ttlOrOptions: CacheTtl | RememberOptions, callback: () => Promise<T>): Promise<T>;
129
+ /**
130
+ * Stale-while-revalidate on the scoped key. Scope-level `tags` merge
131
+ * additively with `options.tags`; `freshTtl`/`staleTtl` always come from
132
+ * the caller (no scope-default precedence — the SWR shape is too
133
+ * specific to the call site to inherit).
134
+ */
135
+ swr<T = any>(key: CacheKey, options: CacheSwrOptions, callback: () => Promise<T>): Promise<T>;
136
+ /**
137
+ * Atomic counter increment on the scoped key. TTL is preserved by the
138
+ * underlying driver — scope ttl is only applied on first write via `set`.
139
+ */
140
+ increment(key: CacheKey, value?: number): Promise<number>;
141
+ /**
142
+ * Atomic counter decrement on the scoped key. See {@link increment} for
143
+ * TTL semantics.
144
+ */
145
+ decrement(key: CacheKey, value?: number): Promise<number>;
146
+ /**
147
+ * Atomic read-modify-write. Falls back to the scope's `ttl` when the caller
148
+ * doesn't provide one; the source still keeps the existing entry's TTL on
149
+ * an update unless `options.ttl` is explicitly set.
150
+ */
151
+ update<T = any>(key: CacheKey, fn: (current: T | null) => T | null | Promise<T | null>, options?: {
152
+ ttl?: CacheTtl;
153
+ }): Promise<T | null>;
154
+ /**
155
+ * Shallow-merge a partial object into the scoped entry. Same TTL semantics
156
+ * as {@link update}.
157
+ */
158
+ merge<T extends Record<string, any> = Record<string, any>>(key: CacheKey, partial: Partial<T>, options?: {
159
+ ttl?: CacheTtl;
160
+ }): Promise<T>;
161
+ /**
162
+ * Return a list accessor bound to the scoped key. The accessor itself
163
+ * does its own read-mutate-write under the prefixed entry.
164
+ */
165
+ list<T = any>(key: CacheKey): CacheListAccessor<T>;
166
+ /**
167
+ * Acquire a distributed lock on the scoped key. Caller's TTL wins; when
168
+ * the options form omits `ttl`, the scope default fills in.
169
+ */
170
+ lock<T>(key: CacheKey, ttlOrOptions: CacheTtl | Omit<LockOptions, "driver">, fn: () => Promise<T>): Promise<LockOutcome<T>>;
171
+ /**
172
+ * Similarity retrieval, scope-isolated. Hits whose keys fall outside this
173
+ * scope are filtered out before the result is returned. `topK` applies to
174
+ * the underlying retrieval — when the scope contains fewer than `topK`
175
+ * matches but other scopes do, the caller will see fewer hits than `topK`.
176
+ */
177
+ similar<T = any>(vector: number[], options: CacheSimilarOptions): Promise<CacheSimilarHit<T>[]>;
178
+ /**
179
+ * Build the source-side key by prepending the scope prefix. Object keys
180
+ * are normalized via {@link parseCacheKey} first so they compose with the
181
+ * prefix as plain dot-strings.
182
+ */
183
+ protected scopedKey(key: CacheKey): string;
184
+ /**
185
+ * Coerce the polymorphic 3rd `set` argument into a {@link CacheSetOptions}
186
+ * with scope defaults filled in. Per-call values always win; tags merge
187
+ * additively. `expiresAt` is preserved without injecting the scope's `ttl`
188
+ * default (absolute deadlines override relative ones).
189
+ */
190
+ protected mergeSetOptions(input?: CacheTtl | CacheSetOptions): CacheSetOptions | undefined;
191
+ /**
192
+ * Same merge as {@link mergeSetOptions} but for the `remember()` shape
193
+ * ({@link RememberOptions} — no `expiresAt`).
194
+ */
195
+ protected mergeRememberOptions(input: CacheTtl | RememberOptions): CacheTtl | RememberOptions;
196
+ /**
197
+ * Convert the scope's default `ttl` (which may be a duration string) into
198
+ * seconds, for the few methods (`setMany`, `setNX`) that accept only a
199
+ * numeric ttl.
200
+ */
201
+ protected scopeTtlSeconds(): number | undefined;
202
+ }
203
+ //#endregion
204
+ export { ScopedCache };
205
+ //# sourceMappingURL=scoped-cache.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-cache.d.mts","names":[],"sources":["../../../../../@warlock.js/cache/src/scoped-cache.ts"],"mappings":"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"}