@ultimat3/cache 8.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CLAUDE.md +11 -0
  2. package/package.json +2 -2
  3. package/src/tiers.ts +11 -4
package/CLAUDE.md CHANGED
@@ -34,6 +34,17 @@ Tier 1. Tagged caching + THE invalidation graph.
34
34
  - One graph. `graph.ts` exports functions over module state and **no constructor** — do not
35
35
  add one, do not add a second registry anywhere else.
36
36
  - Tag order is `TIER_ORDER`, never registration order. `sortTiers()` enforces it.
37
+ - **The rung NAMES are `@ultimat3/core`'s (`CACHE_TIERS`); the ladder is this package's.**
38
+ `TierName` is an alias of core's `CacheTierName` and `TIER_ORDER` IS `CACHE_TIERS` — the same
39
+ array object, which `tier-vocabulary.test.ts` asserts by identity. Tier 0 owns the spelling
40
+ because `app.config.ts`'s `cache.tiers` names the same rungs and core is the only place a tier-0
41
+ declaration and this package can both see. It was spelled twice until 2026-08-22 (issue #293):
42
+ config accepted `memo | lru | shared | isr | cdn`, so `cache: { tiers: ['isr'] }` typechecked and
43
+ selected nothing, and `sortTiers` would have placed either unknown name at `-1` — AHEAD of the
44
+ request memo. Adding a rung is an edit to `packages/core/src/cache-vocabulary.ts` plus a factory
45
+ here; `scripts/render-modes.ts` refuses a second declaration of the set anywhere in `packages/*/src`.
46
+ **`isr` is not and never was a tier** — it is a `RenderMode`; the `'isr'` in `invalidate.ts` is an
47
+ ISR ROUTE queued for regeneration (`DependentKind = 'isr-route'`), which is a different subject.
37
48
  - **`bestEffort()` is public, and it is the only sanctioned way to swallow a cache refusal.** A
38
49
  store outside this package that wraps its own `try/catch` degrades invisibly, and a second
39
50
  failure log nobody reads is what this bounded one exists to prevent. Its label is `TierLabel` —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/cache",
3
- "version": "8.0.0",
3
+ "version": "9.0.0",
4
4
  "description": "Tagged caching: request memo, LRU, Redis, CDN — one invalidation graph",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,6 +31,6 @@
31
31
  "test": "bun test"
32
32
  },
33
33
  "dependencies": {
34
- "@ultimat3/core": "8.0.0"
34
+ "@ultimat3/core": "9.0.0"
35
35
  }
36
36
  }
package/src/tiers.ts CHANGED
@@ -3,8 +3,8 @@
3
3
  // so a deployment can omit Redis (single node) or add the CDN tier without touching call
4
4
  // sites. Order is data, not control flow.
5
5
 
6
- import type { Clock } from '@ultimat3/core';
7
- import { systemClock } from '@ultimat3/core';
6
+ import type { CacheTierName, Clock } from '@ultimat3/core';
7
+ import { CACHE_TIERS, systemClock } from '@ultimat3/core';
8
8
  import { CacheJitterInvalidError, CacheTtlInvalidError } from './errors';
9
9
  import type { CacheFence } from './fence';
10
10
  import { markInvalidated, sampleFence } from './fence';
@@ -13,10 +13,17 @@ import { createSingleFlight } from './single-flight';
13
13
  import type { CacheTag } from './tags';
14
14
  import { bestEffort } from './tier-failures';
15
15
 
16
- export type TierName = 'request-memo' | 'lru' | 'redis' | 'cdn';
16
+ /**
17
+ * The rungs, spelled in `@ultimat3/core` and nowhere else. Tier 0 owns the NAMES because
18
+ * `app.config.ts` names them too and core is the one place a tier-0 declaration and this package
19
+ * can both see; the ladder — order, promotion, fan-out — is still this file's. Aliased rather than
20
+ * re-exported under core's name so the ~30 call sites that already import `TierName` keep working:
21
+ * one declaration, two names, against one declaration each in two packages that disagreed.
22
+ */
23
+ export type TierName = CacheTierName;
17
24
 
18
25
  /** Read order. Index in this array is the tier's distance from the request. */
19
- export const TIER_ORDER: readonly TierName[] = ['request-memo', 'lru', 'redis', 'cdn'];
26
+ export const TIER_ORDER: readonly TierName[] = CACHE_TIERS;
20
27
 
21
28
  /**
22
29
  * Who a swallowed refusal is attributed to in `recentTierFailures()` and the `/_x` panel: every