@ultimat3/manifest 27.6.1 → 27.8.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/manifest",
3
- "version": "27.6.1",
3
+ "version": "27.8.0",
4
4
  "description": "x.manifest.json: deterministic generated facts, contract diff, AGENTS.md budget",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,11 +32,11 @@
32
32
  "test": "bun test"
33
33
  },
34
34
  "dependencies": {
35
- "@ultimat3/action": "27.6.1",
36
- "@ultimat3/core": "27.6.1",
37
- "@ultimat3/entity": "27.6.1",
38
- "@ultimat3/jobs": "27.6.1",
39
- "@ultimat3/query": "27.6.1",
40
- "@ultimat3/realtime": "27.6.1"
35
+ "@ultimat3/action": "27.8.0",
36
+ "@ultimat3/core": "27.8.0",
37
+ "@ultimat3/entity": "27.8.0",
38
+ "@ultimat3/jobs": "27.8.0",
39
+ "@ultimat3/query": "27.8.0",
40
+ "@ultimat3/realtime": "27.8.0"
41
41
  }
42
42
  }
@@ -70,6 +70,7 @@ export function diffRoutes(
70
70
  'revalidate tags changed',
71
71
  ),
72
72
  );
73
+ changes.push(...diffRevalidate(path, route, next));
73
74
  }
74
75
  for (const route of after) {
75
76
  if (!beforeByUrl.has(route.url)) {
@@ -79,6 +80,43 @@ export function diffRoutes(
79
80
  return changes;
80
81
  }
81
82
 
83
+ /**
84
+ * What an invalidation does to the route's stored pages and what they are keyed on. `onInvalidate`
85
+ * is written for every `isr` route, so two manifests that both carry it both know `maxStale` and
86
+ * `query` — and only then is an ABSENT one of those a value ("undeclared") rather than no evidence.
87
+ */
88
+ function diffRevalidate(
89
+ path: string,
90
+ route: RouteFact,
91
+ next: RouteFact,
92
+ ): readonly ManifestChange[] {
93
+ if (route.onInvalidate === undefined || next.onInvalidate === undefined) return [];
94
+ const declared = (value: unknown): unknown => (value === undefined ? null : value);
95
+ return [
96
+ ...diffScalar(
97
+ 'internal',
98
+ `${path}.onInvalidate`,
99
+ route.onInvalidate,
100
+ next.onInvalidate,
101
+ (from, to) => `onInvalidate ${from} -> ${to}`,
102
+ ),
103
+ ...diffJson(
104
+ 'internal',
105
+ `${path}.maxStale`,
106
+ declared(route.maxStale),
107
+ declared(next.maxStale),
108
+ 'revalidate maxStale changed',
109
+ ),
110
+ ...diffJson(
111
+ 'internal',
112
+ `${path}.query`,
113
+ declared(route.query),
114
+ declared(next.query),
115
+ 'revalidate query changed',
116
+ ),
117
+ ];
118
+ }
119
+
82
120
  /** The structural sibling of `diffScalar`: absent on either side is still no evidence. */
83
121
  function diffJson(
84
122
  kind: ManifestChange['kind'],
package/src/schema.ts CHANGED
@@ -36,6 +36,16 @@ export interface RouteFact {
36
36
  readonly offline?: OfflineStrategy;
37
37
  readonly hydrate?: HydrateStrategy;
38
38
  readonly revalidateTags?: readonly string[];
39
+ /**
40
+ * An `isr` route's `revalidate.onInvalidate`, written for EVERY `isr` route — `'stale'` too — so
41
+ * a route flipping `'purge'` back to `'stale'` is a change `x manifest diff` can see. Its
42
+ * presence is also what says this manifest knows the two keys below.
43
+ */
44
+ readonly onInvalidate?: 'stale' | 'purge';
45
+ /** `revalidate.maxStale`, as declared; absent when the route declared none. */
46
+ readonly maxStale?: string | number;
47
+ /** `revalidate.query`, sorted; absent when the route declared none (it keys on the whole query). */
48
+ readonly query?: readonly string[];
39
49
  readonly budget?: { readonly js?: string };
40
50
  /** Which surface the route lives in — `site` may never import from `app`. */
41
51
  readonly surface?: 'site' | 'app' | 'api';