@dcsv-io/d2-caching-abstractions 0.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 (51) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +263 -0
  3. package/dist/i-cache-atomic.d.ts +69 -0
  4. package/dist/i-cache-atomic.d.ts.map +1 -0
  5. package/dist/i-cache-atomic.js +5 -0
  6. package/dist/i-cache-atomic.js.map +1 -0
  7. package/dist/i-cache-basic.d.ts +90 -0
  8. package/dist/i-cache-basic.d.ts.map +1 -0
  9. package/dist/i-cache-basic.js +5 -0
  10. package/dist/i-cache-basic.js.map +1 -0
  11. package/dist/i-cache-broadcast.d.ts +47 -0
  12. package/dist/i-cache-broadcast.d.ts.map +1 -0
  13. package/dist/i-cache-broadcast.js +5 -0
  14. package/dist/i-cache-broadcast.js.map +1 -0
  15. package/dist/i-cache-invalidation-backplane.d.ts +73 -0
  16. package/dist/i-cache-invalidation-backplane.d.ts.map +1 -0
  17. package/dist/i-cache-invalidation-backplane.js +5 -0
  18. package/dist/i-cache-invalidation-backplane.js.map +1 -0
  19. package/dist/i-cache-serializer.d.ts +35 -0
  20. package/dist/i-cache-serializer.d.ts.map +1 -0
  21. package/dist/i-cache-serializer.js +5 -0
  22. package/dist/i-cache-serializer.js.map +1 -0
  23. package/dist/i-cache-set.d.ts +59 -0
  24. package/dist/i-cache-set.d.ts.map +1 -0
  25. package/dist/i-cache-set.js +5 -0
  26. package/dist/i-cache-set.js.map +1 -0
  27. package/dist/i-distributed-cache.d.ts +25 -0
  28. package/dist/i-distributed-cache.d.ts.map +1 -0
  29. package/dist/i-distributed-cache.js +5 -0
  30. package/dist/i-distributed-cache.js.map +1 -0
  31. package/dist/i-local-cache.d.ts +18 -0
  32. package/dist/i-local-cache.d.ts.map +1 -0
  33. package/dist/i-local-cache.js +5 -0
  34. package/dist/i-local-cache.js.map +1 -0
  35. package/dist/i-tiered-cache.d.ts +31 -0
  36. package/dist/i-tiered-cache.d.ts.map +1 -0
  37. package/dist/i-tiered-cache.js +5 -0
  38. package/dist/i-tiered-cache.js.map +1 -0
  39. package/dist/index.d.ts +13 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +6 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/input-failures.d.ts +27 -0
  44. package/dist/input-failures.d.ts.map +1 -0
  45. package/dist/input-failures.js +45 -0
  46. package/dist/input-failures.js.map +1 -0
  47. package/dist/local-cache-options.d.ts +40 -0
  48. package/dist/local-cache-options.d.ts.map +1 -0
  49. package/dist/local-cache-options.js +22 -0
  50. package/dist/local-cache-options.js.map +1 -0
  51. package/package.json +31 -0
@@ -0,0 +1,47 @@
1
+ import type { D2Result } from "@dcsv-io/d2-result";
2
+ /**
3
+ * Write surface that publishes invalidation messages via a registered
4
+ * {@link ICacheInvalidationBackplane} after the underlying write
5
+ * completes. Subscribers (typically tiered caches in other instances)
6
+ * drop their L1 copy of the affected key on receipt.
7
+ *
8
+ * Implemented by both {@link IDistributedCache} (so callers writing
9
+ * directly to L2 can still bust other instances' L1) and
10
+ * {@link ITieredCache} (which writes both tiers and broadcasts in one
11
+ * call).
12
+ *
13
+ * **Registration error carve-out:** `*AndBroadcast*` methods **throw**
14
+ * (not `D2Result`) when no `ICacheInvalidationBackplane` was registered
15
+ * with the cache. Registration error is a construction-time / wiring
16
+ * concern, not a per-call failure. Use the plain `set` / `remove` if
17
+ * you don't intend to broadcast.
18
+ */
19
+ export interface ICacheBroadcast {
20
+ /**
21
+ * Writes a value AND publishes an invalidation message via the
22
+ * registered {@link ICacheInvalidationBackplane}.
23
+ *
24
+ * @throws When no backplane was registered with the cache.
25
+ */
26
+ setAndBroadcast<T>(key: string, value: T, expirationMs?: number, signal?: AbortSignal): Promise<D2Result>;
27
+ /**
28
+ * Bulk-write counterpart of {@link setAndBroadcast}.
29
+ *
30
+ * @throws When no backplane was registered with the cache.
31
+ */
32
+ setManyAndBroadcast<T>(entries: ReadonlyMap<string, T>, expirationMs?: number, signal?: AbortSignal): Promise<D2Result>;
33
+ /**
34
+ * Removes a key AND publishes an invalidation message so other
35
+ * instances drop their L1 copies.
36
+ *
37
+ * @throws When no backplane was registered with the cache.
38
+ */
39
+ removeAndBroadcast(key: string, signal?: AbortSignal): Promise<D2Result>;
40
+ /**
41
+ * Bulk-remove + broadcast invalidation per key.
42
+ *
43
+ * @throws When no backplane was registered with the cache.
44
+ */
45
+ removeManyAndBroadcast(keys: readonly string[], signal?: AbortSignal): Promise<D2Result>;
46
+ }
47
+ //# sourceMappingURL=i-cache-broadcast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-broadcast.d.ts","sourceRoot":"","sources":["../src/i-cache-broadcast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,eAAe,CAAC,CAAC,EACf,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB;;;;OAIG;IACH,mBAAmB,CAAC,CAAC,EACnB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EAC/B,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB;;;;;OAKG;IACH,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEzE;;;;OAIG;IACH,sBAAsB,CACpB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-cache-broadcast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-broadcast.js","sourceRoot":"","sources":["../src/i-cache-broadcast.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,73 @@
1
+ import type { D2Result } from "@dcsv-io/d2-result";
2
+ /**
3
+ * Pub/sub backplane for cross-instance cache invalidation. Publishers
4
+ * fire when a caller uses one of the `*AndBroadcast*` variants on
5
+ * {@link ITieredCache} or {@link IDistributedCache}, or when any code
6
+ * calls {@link publishInvalidation} directly. Subscribers (typically
7
+ * tiered caches in other instances) receive the key and act on it —
8
+ * usually by dropping the named entry from their L1.
9
+ *
10
+ * Extends {@link AsyncDisposable}. Runtime: Node ≥ 20 (global
11
+ * `Symbol.asyncDispose`). Package `lib` includes `ESNext.Disposable`
12
+ * so the types resolve.
13
+ *
14
+ * **Contract (twin of .NET `ICacheInvalidationBackplane` remarks):**
15
+ *
16
+ * 1. **Everyone acts** — no sender-ID filter; the publisher receives
17
+ * its own messages.
18
+ * 2. **At-most-once** delivery (missed message → next read hits L2).
19
+ * 3. **Dispose unsubscribes** — disposing a subscription **removes that
20
+ * handler from fan-out** and **stops further invalidation key
21
+ * delivery** to it (primary .NET Subscribe law). Signal abort alone
22
+ * is **not** sufficient — unsubscribe is the delivery-stop guarantee.
23
+ * 4. **Signal-on-dispose** — the handler's `AbortSignal` is aborted when
24
+ * the **subscription** is disposed (accompanies unsubscribe; does not
25
+ * replace it).
26
+ * 5. **Handler isolation** — one handler throw must not break delivery
27
+ * to other handlers.
28
+ * 6. **Multi-sub independence** — each `subscribe` returns its own
29
+ * disposable; subscriptions are independent.
30
+ * 7. **Dispose idempotency** — disposing a subscription (or the
31
+ * backplane) more than once is safe (no throw).
32
+ * 8. **Backplane dispose cascade** — disposing the backplane tears down
33
+ * shared provider resources, unsubscribes remaining handlers, and
34
+ * cancels in-flight handler work.
35
+ *
36
+ * Provider-agnostic — Redis pub/sub is the default implementation, but
37
+ * the same interface can wrap Postgres LISTEN/NOTIFY, an in-process
38
+ * channel for tests, etc.
39
+ */
40
+ export interface ICacheInvalidationBackplane extends AsyncDisposable {
41
+ /**
42
+ * Subscribes to receive invalidation messages. The handler is invoked
43
+ * once per received key (including keys this instance published).
44
+ * Implementations isolate errors per handler — one handler throwing
45
+ * does not affect delivery to other handlers.
46
+ *
47
+ * @param handler - Callback invoked for every received invalidation
48
+ * key. Receives the key and an optional `AbortSignal` tied to
49
+ * subscription lifetime (aborted when the returned subscription is
50
+ * disposed).
51
+ * @returns Disposable subscription. Dispose to **unsubscribe** (stop
52
+ * further key delivery to this handler); typically held as a field
53
+ * on the subscriber and disposed in the subscriber's own disposal
54
+ * so the subscription lifetime matches the subscriber.
55
+ */
56
+ subscribe(handler: (key: string, signal?: AbortSignal) => void | Promise<void>): AsyncDisposable;
57
+ /**
58
+ * Publishes an invalidation message for a single key. Every
59
+ * subscriber (across every connected instance, including this one)
60
+ * receives the key.
61
+ *
62
+ * @returns `ok`; failure on backplane error.
63
+ */
64
+ publishInvalidation(key: string, signal?: AbortSignal): Promise<D2Result>;
65
+ /**
66
+ * Bulk-publish counterpart of {@link publishInvalidation}.
67
+ * Implementations may pipeline the publishes for fewer round-trips.
68
+ *
69
+ * @returns `ok`; failure on backplane error.
70
+ */
71
+ publishInvalidationMany(keys: readonly string[], signal?: AbortSignal): Promise<D2Result>;
72
+ }
73
+ //# sourceMappingURL=i-cache-invalidation-backplane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-invalidation-backplane.d.ts","sourceRoot":"","sources":["../src/i-cache-invalidation-backplane.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,WAAW,2BAA4B,SAAQ,eAAe;IAClE;;;;;;;;;;;;;;OAcG;IACH,SAAS,CACP,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACnE,eAAe,CAAC;IAEnB;;;;;;OAMG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1E;;;;;OAKG;IACH,uBAAuB,CACrB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-cache-invalidation-backplane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-invalidation-backplane.js","sourceRoot":"","sources":["../src/i-cache-invalidation-backplane.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,35 @@
1
+ import type { D2Result } from "@dcsv-io/d2-result";
2
+ /**
3
+ * Pluggable serialization seam for distributed caches. Local caches
4
+ * store objects directly and do not need this. This package owns the
5
+ * port only; a default JSON implementation is part of the
6
+ * `@dcsv-io/d2-caching-distributed-redis` package surface. Provider-specific
7
+ * impls may swap in MessagePack, Protobuf, etc., for size or perf wins.
8
+ *
9
+ * Impl failure codes (not defined here — reuse existing catalogs when
10
+ * implementing): `COULD_NOT_BE_SERIALIZED` /
11
+ * `COULD_NOT_BE_DESERIALIZED`.
12
+ */
13
+ export interface ICacheSerializer {
14
+ /**
15
+ * Stable identifier for the serialization format (free string, e.g.
16
+ * `"application/json"`). Allows mixed-serializer DLQs / archive
17
+ * blobs to round-trip safely.
18
+ */
19
+ readonly contentType: string;
20
+ /**
21
+ * Serializes `value` to bytes.
22
+ *
23
+ * @returns `ok(bytes)`; failure with a serialize error code on
24
+ * serializer error.
25
+ */
26
+ serialize<T>(value: T): D2Result<Uint8Array>;
27
+ /**
28
+ * Deserializes `bytes` back to a value.
29
+ *
30
+ * @returns `ok(value)`; failure with a deserialize error code on
31
+ * deserializer error.
32
+ */
33
+ deserialize<T>(bytes: Uint8Array): D2Result<T>;
34
+ }
35
+ //# sourceMappingURL=i-cache-serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-serializer.d.ts","sourceRoot":"","sources":["../src/i-cache-serializer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IAE7C;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;CAChD"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-cache-serializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-serializer.js","sourceRoot":"","sources":["../src/i-cache-serializer.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,59 @@
1
+ import type { D2Result } from "@dcsv-io/d2-result";
2
+ /**
3
+ * Distributed-set primitives — add-to-set, cardinality, membership.
4
+ * Maps to Redis SADD / SCARD / SREM / SISMEMBER. Only on
5
+ * {@link IDistributedCache}; per-process set-cardinality has no
6
+ * realistic use case (it's a single-instance counter that can't
7
+ * aggregate across the cluster), and tiered composition would silently
8
+ * hide the cluster-wide nature of the operation.
9
+ *
10
+ * The motivating use case is rate-limiting "fingerprint too common"
11
+ * detection: track distinct IPs ever observed for a given fingerprint,
12
+ * compare cardinality against a threshold to decide whether the
13
+ * fingerprint is shared widely enough to be unreliable. Other
14
+ * plausible uses include distinct-user counts per feature flag,
15
+ * active-session tracking by org, and any bounded-cardinality
16
+ * "have I seen X for Y" check.
17
+ *
18
+ * **Counter width:** `number` (not `bigint`) is an intentional TS
19
+ * ergonomic delta vs .NET `long`. Implementations must stay within
20
+ * `Number.MAX_SAFE_INTEGER`.
21
+ */
22
+ export interface ICacheSet {
23
+ /**
24
+ * Adds a member to the set at `key`. The set is created on first
25
+ * add.
26
+ *
27
+ * **TTL-on-create-only:** optional `expirationMs` is applied **only
28
+ * when the set is created**; subsequent adds on an existing set
29
+ * **preserve the existing TTL**.
30
+ *
31
+ * @returns `ok(true)` if the member was newly added. `ok(false)` if
32
+ * the member already existed in the set. Failure on backing-store
33
+ * error.
34
+ */
35
+ setAdd(key: string, member: string, expirationMs?: number, signal?: AbortSignal): Promise<D2Result<boolean>>;
36
+ /**
37
+ * Returns the cardinality (number of distinct members) of the set at
38
+ * `key`. Absent set → `ok(0)`.
39
+ *
40
+ * @returns `ok(count)`. Failure on backing-store error.
41
+ */
42
+ setCardinality(key: string, signal?: AbortSignal): Promise<D2Result<number>>;
43
+ /**
44
+ * Removes a member from the set at `key`. **Idempotent** — succeeds
45
+ * whether the member existed or not.
46
+ *
47
+ * @returns `ok(true)` if the member was present and removed.
48
+ * `ok(false)` if the member was absent. Failure on backing-store
49
+ * error.
50
+ */
51
+ setRemove(key: string, member: string, signal?: AbortSignal): Promise<D2Result<boolean>>;
52
+ /**
53
+ * Returns whether `member` is in the set at `key`.
54
+ *
55
+ * @returns `ok(true|false)`. Failure on backing-store error.
56
+ */
57
+ setContains(key: string, member: string, signal?: AbortSignal): Promise<D2Result<boolean>>;
58
+ }
59
+ //# sourceMappingURL=i-cache-set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-set.d.ts","sourceRoot":"","sources":["../src/i-cache-set.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;;;;;;OAWG;IACH,MAAM,CACJ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAE9B;;;;;OAKG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAE7E;;;;;;;OAOG;IACH,SAAS,CACP,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAE9B;;;;OAIG;IACH,WAAW,CACT,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;CAC/B"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-cache-set.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-cache-set.js","sourceRoot":"","sources":["../src/i-cache-set.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,25 @@
1
+ import type { ICacheAtomic } from "./i-cache-atomic.js";
2
+ import type { ICacheBasic } from "./i-cache-basic.js";
3
+ import type { ICacheBroadcast } from "./i-cache-broadcast.js";
4
+ import type { ICacheSet } from "./i-cache-set.js";
5
+ /**
6
+ * Cluster-scoped cache backed by a remote store (e.g. Redis). Atomic
7
+ * primitives coordinate cluster-wide. The {@link ICacheBroadcast}
8
+ * surface coordinates with tiered consumers in other instances so
9
+ * their L1 entries get busted in lockstep.
10
+ *
11
+ * Composes {@link ICacheBasic} + {@link ICacheAtomic} +
12
+ * {@link ICacheBroadcast} + {@link ICacheSet}.
13
+ *
14
+ * **Marker vs {@link ITieredCache}:** shared building blocks
15
+ * (Basic + Atomic + Broadcast) are method-identical. **`ICacheSet` is
16
+ * only on `IDistributedCache`** (not full structural identity). The
17
+ * marker name carries behavioral intent at the dependency site: reading
18
+ * `IDistributedCache` tells you the cache talks to the remote store on
19
+ * every read (no L1), so freshness matters more than read speed for
20
+ * this consumer (e.g. rate-limit counters, lock state, ephemeral
21
+ * session data).
22
+ */
23
+ export interface IDistributedCache extends ICacheBasic, ICacheAtomic, ICacheBroadcast, ICacheSet {
24
+ }
25
+ //# sourceMappingURL=i-distributed-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-distributed-cache.d.ts","sourceRoot":"","sources":["../src/i-distributed-cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,iBACf,SAAQ,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS;CAAG"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-distributed-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-distributed-cache.js","sourceRoot":"","sources":["../src/i-distributed-cache.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,18 @@
1
+ import type { ICacheAtomic } from "./i-cache-atomic.js";
2
+ import type { ICacheBasic } from "./i-cache-basic.js";
3
+ /**
4
+ * Per-process in-memory cache. Atomic primitives operate at process
5
+ * scope — they do not coordinate across instances. There is no
6
+ * broadcast surface because nothing outside this process can observe
7
+ * local cache state.
8
+ *
9
+ * The interface name documents the cache scope at the dependency site.
10
+ * Reading `ILocalCache` at an inject site tells you, without looking
11
+ * at registration, that this cache lives in process memory and dies
12
+ * with the process.
13
+ *
14
+ * Composes {@link ICacheBasic} + {@link ICacheAtomic} only.
15
+ */
16
+ export interface ILocalCache extends ICacheBasic, ICacheAtomic {
17
+ }
18
+ //# sourceMappingURL=i-local-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-local-cache.d.ts","sourceRoot":"","sources":["../src/i-local-cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW,EAAE,YAAY;CAAG"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-local-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-local-cache.js","sourceRoot":"","sources":["../src/i-local-cache.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,31 @@
1
+ import type { ICacheAtomic } from "./i-cache-atomic.js";
2
+ import type { ICacheBasic } from "./i-cache-basic.js";
3
+ import type { ICacheBroadcast } from "./i-cache-broadcast.js";
4
+ /**
5
+ * Composed L1 (in-process) + L2 (remote) cache. Reads check L1 first,
6
+ * fall through to L2 on miss, populate L1 with whatever L2 returned.
7
+ * Writes go L2-first — L1 only writes if L2 succeeded — so partial-write
8
+ * states are impossible and the result is binary (success or the L2
9
+ * failure bubbled up). Atomic primitives route through L2 (the source
10
+ * of truth) and invalidate / refresh L1 as a side effect.
11
+ *
12
+ * Composes {@link ICacheBasic} + {@link ICacheAtomic} +
13
+ * {@link ICacheBroadcast}. **Does NOT compose {@link ICacheSet}** —
14
+ * set primitives are cluster-only and tiered composition would
15
+ * silently hide their cluster-wide nature. Callers needing
16
+ * SADD/SCARD inject {@link IDistributedCache} directly.
17
+ *
18
+ * **Marker vs {@link IDistributedCache}:** shared building blocks
19
+ * (Basic + Atomic + Broadcast) are method-identical. The marker name
20
+ * carries behavioral intent: reading `ITieredCache` tells you reads
21
+ * served from L1 are sub-microsecond, L1 stays cluster-coherent via
22
+ * the broadcast backplane, and per-tier expirations are kept in
23
+ * lockstep so L1 never outlives L2.
24
+ *
25
+ * Use this for read-heavy entity data where freshness within a few
26
+ * seconds is acceptable. Prefer {@link IDistributedCache} when every
27
+ * read must hit the canonical store.
28
+ */
29
+ export interface ITieredCache extends ICacheBasic, ICacheAtomic, ICacheBroadcast {
30
+ }
31
+ //# sourceMappingURL=i-tiered-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-tiered-cache.d.ts","sourceRoot":"","sources":["../src/i-tiered-cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,YACf,SAAQ,WAAW,EAAE,YAAY,EAAE,eAAe;CAAG"}
@@ -0,0 +1,5 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export {};
5
+ //# sourceMappingURL=i-tiered-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-tiered-cache.js","sourceRoot":"","sources":["../src/i-tiered-cache.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E"}
@@ -0,0 +1,13 @@
1
+ export type { ICacheBasic } from "./i-cache-basic.js";
2
+ export type { ICacheAtomic } from "./i-cache-atomic.js";
3
+ export type { ICacheBroadcast } from "./i-cache-broadcast.js";
4
+ export type { ICacheSet } from "./i-cache-set.js";
5
+ export type { ILocalCache } from "./i-local-cache.js";
6
+ export type { IDistributedCache } from "./i-distributed-cache.js";
7
+ export type { ITieredCache } from "./i-tiered-cache.js";
8
+ export type { ICacheInvalidationBackplane } from "./i-cache-invalidation-backplane.js";
9
+ export type { ICacheSerializer } from "./i-cache-serializer.js";
10
+ export type { LocalCacheOptions } from "./local-cache-options.js";
11
+ export { LOCAL_CACHE_DEFAULTS, createLocalCacheOptions, } from "./local-cache-options.js";
12
+ export { InputFailures } from "./input-failures.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AACvF,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ export { LOCAL_CACHE_DEFAULTS, createLocalCacheOptions, } from "./local-cache-options.js";
5
+ export { InputFailures } from "./input-failures.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAY1E,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { type D2Result } from "@dcsv-io/d2-result";
2
+ export declare const InputFailures: {
3
+ /**
4
+ * Builds a `D2Result` / `D2Result<T>` input failure for a missing
5
+ * (null / empty / falsey) required parameter.
6
+ *
7
+ * @param paramName - Parameter name (use a string literal matching
8
+ * the call-site argument name).
9
+ */
10
+ required: {
11
+ (paramName: string): D2Result;
12
+ <T>(paramName: string): D2Result<T>;
13
+ };
14
+ /**
15
+ * Builds a `D2Result` / `D2Result<T>` input failure for a present but
16
+ * invalid parameter value (range, non-finite, non-safe-integer, etc.).
17
+ * Does **not** use `NOT_NULL_VIOLATION` — the value is present.
18
+ *
19
+ * @param paramName - Parameter name (use a string literal matching
20
+ * the call-site argument name).
21
+ */
22
+ invalid: {
23
+ (paramName: string): D2Result;
24
+ <T>(paramName: string): D2Result<T>;
25
+ };
26
+ };
27
+ //# sourceMappingURL=input-failures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-failures.d.ts","sourceRoot":"","sources":["../src/input-failures.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,oBAAoB,CAAC;AAwB5B,eAAO,MAAM,aAAa;IACxB;;;;;;OAMG;cACuB;QACxB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC9B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;KACrC;IAED;;;;;;;OAOG;aACqB;QACtB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC9B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;KACrC;CACF,CAAC"}
@@ -0,0 +1,45 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ import { TK } from "@dcsv-io/d2-i18n-keys";
5
+ import { inputError, validationFailed, } from "@dcsv-io/d2-result";
6
+ /**
7
+ * Pre-built `D2Result` input-failure responses for cache impls.
8
+ * Keeps the cache surface pure errors-as-values instead of mixing in
9
+ * throws for caller mistakes.
10
+ *
11
+ * Constructors / DI registration still throw — that is a different
12
+ * lifecycle concern from per-call input validation.
13
+ *
14
+ * Twin of .NET `DcsvIo.D2.Caching.InputFailures`.
15
+ */
16
+ function requiredImpl(paramName) {
17
+ return validationFailed({
18
+ inputErrors: [inputError(paramName, [TK.common.errors.NOT_NULL_VIOLATION])],
19
+ });
20
+ }
21
+ function invalidImpl(paramName) {
22
+ return validationFailed({
23
+ inputErrors: [inputError(paramName, [TK.common.errors.VALIDATION_FAILED])],
24
+ });
25
+ }
26
+ export const InputFailures = {
27
+ /**
28
+ * Builds a `D2Result` / `D2Result<T>` input failure for a missing
29
+ * (null / empty / falsey) required parameter.
30
+ *
31
+ * @param paramName - Parameter name (use a string literal matching
32
+ * the call-site argument name).
33
+ */
34
+ required: requiredImpl,
35
+ /**
36
+ * Builds a `D2Result` / `D2Result<T>` input failure for a present but
37
+ * invalid parameter value (range, non-finite, non-safe-integer, etc.).
38
+ * Does **not** use `NOT_NULL_VIOLATION` — the value is present.
39
+ *
40
+ * @param paramName - Parameter name (use a string literal matching
41
+ * the call-site argument name).
42
+ */
43
+ invalid: invalidImpl,
44
+ };
45
+ //# sourceMappingURL=input-failures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-failures.js","sourceRoot":"","sources":["../src/input-failures.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAE1E,OAAO,EAAE,EAAE,EAAE,MAAM,uBAAuB,CAAC;AAC3C,OAAO,EACL,UAAU,EACV,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;GASG;AACH,SAAS,YAAY,CAAW,SAAiB;IAC/C,OAAO,gBAAgB,CAAI;QACzB,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;KAC5E,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAW,SAAiB;IAC9C,OAAO,gBAAgB,CAAI;QACzB,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;KAC3E,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B;;;;;;OAMG;IACH,QAAQ,EAAE,YAGT;IAED;;;;;;;OAOG;IACH,OAAO,EAAE,WAGR;CACF,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Configuration knobs for an {@link ILocalCache} implementation.
3
+ * Defaults are tuned for typical microservice workloads (100K entries,
4
+ * 1-hour default TTL).
5
+ *
6
+ * Per-entry size accounting is intentionally NOT exposed — the default
7
+ * implementation always counts entries as size 1 so `maxEntries`
8
+ * behaves as the literal entry-count cap most callers expect.
9
+ *
10
+ * No options validation on this POCO (mirrors .NET — no range check /
11
+ * ValidateOnStart). The factory does not fail on absurd values;
12
+ * enforcement belongs in the local-default implementation.
13
+ */
14
+ export interface LocalCacheOptions {
15
+ /**
16
+ * Maximum number of entries before LRU-ish eviction kicks in.
17
+ * Default 100_000.
18
+ */
19
+ maxEntries: number;
20
+ /**
21
+ * Default TTL (milliseconds) applied to entries written without an
22
+ * explicit expiration. Default 3_600_000 (1 hour).
23
+ */
24
+ defaultExpirationMs: number;
25
+ /**
26
+ * Optional key prefix automatically prepended to every cache key.
27
+ * Useful when multiple caches share a process and the caller wants
28
+ * namespace isolation (e.g. `"jwks:"`) without coordinating keys
29
+ * explicitly. Default is empty string (no prefix).
30
+ */
31
+ keyPrefix: string;
32
+ }
33
+ export declare const LOCAL_CACHE_DEFAULTS: Readonly<LocalCacheOptions>;
34
+ /**
35
+ * Builds a mutable {@link LocalCacheOptions} by merging an optional
36
+ * partial over {@link LOCAL_CACHE_DEFAULTS}. Always returns a fresh
37
+ * object (not shared with the defaults constant).
38
+ */
39
+ export declare function createLocalCacheOptions(partial?: Partial<LocalCacheOptions>): LocalCacheOptions;
40
+ //# sourceMappingURL=local-cache-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-cache-options.d.ts","sourceRoot":"","sources":["../src/local-cache-options.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,iBAAiB,CAI5D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACnC,iBAAiB,CAOnB"}
@@ -0,0 +1,22 @@
1
+ // -----------------------------------------------------------------------
2
+ // Copyright (c) DCSV. Licensed under the Apache License, Version 2.0.
3
+ // -----------------------------------------------------------------------
4
+ // Numeric twin of .NET LocalCacheOptions (MaxEntries=100_000, DefaultExpiration=1h, KeyPrefix="").
5
+ export const LOCAL_CACHE_DEFAULTS = {
6
+ maxEntries: 100_000,
7
+ defaultExpirationMs: 3_600_000,
8
+ keyPrefix: "",
9
+ };
10
+ /**
11
+ * Builds a mutable {@link LocalCacheOptions} by merging an optional
12
+ * partial over {@link LOCAL_CACHE_DEFAULTS}. Always returns a fresh
13
+ * object (not shared with the defaults constant).
14
+ */
15
+ export function createLocalCacheOptions(partial) {
16
+ return {
17
+ maxEntries: partial?.maxEntries ?? LOCAL_CACHE_DEFAULTS.maxEntries,
18
+ defaultExpirationMs: partial?.defaultExpirationMs ?? LOCAL_CACHE_DEFAULTS.defaultExpirationMs,
19
+ keyPrefix: partial?.keyPrefix ?? LOCAL_CACHE_DEFAULTS.keyPrefix,
20
+ };
21
+ }
22
+ //# sourceMappingURL=local-cache-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-cache-options.js","sourceRoot":"","sources":["../src/local-cache-options.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAqC1E,mGAAmG;AACnG,MAAM,CAAC,MAAM,oBAAoB,GAAgC;IAC/D,UAAU,EAAE,OAAO;IACnB,mBAAmB,EAAE,SAAS;IAC9B,SAAS,EAAE,EAAE;CACd,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAoC;IAEpC,OAAO;QACL,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,oBAAoB,CAAC,UAAU;QAClE,mBAAmB,EACjB,OAAO,EAAE,mBAAmB,IAAI,oBAAoB,CAAC,mBAAmB;QAC1E,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,oBAAoB,CAAC,SAAS;KAChE,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@dcsv-io/d2-caching-abstractions",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "dependencies": {
17
+ "@dcsv-io/d2-i18n-keys": "0.1.1",
18
+ "@dcsv-io/d2-result": "0.1.1"
19
+ },
20
+ "devDependencies": {
21
+ "@vitest/coverage-v8": "4.0.18",
22
+ "typescript": "5.9.3",
23
+ "vitest": "4.0.18"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -b",
27
+ "test": "vitest run",
28
+ "test:coverage": "vitest run --coverage",
29
+ "type-check:test": "tsc -p tsconfig.test.json"
30
+ }
31
+ }