@mandujs/core 0.21.0 → 0.22.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 +94 -69
- package/src/auth/__tests__/login.test.ts +419 -0
- package/src/auth/__tests__/password.test.ts +122 -0
- package/src/auth/__tests__/reset.test.ts +296 -0
- package/src/auth/__tests__/tokens.test.ts +274 -0
- package/src/auth/__tests__/verification.test.ts +274 -0
- package/src/auth/index.ts +76 -0
- package/src/auth/login.ts +225 -0
- package/src/auth/password.ts +120 -0
- package/src/auth/reset.ts +243 -0
- package/src/auth/tokens.ts +612 -0
- package/src/auth/verification.ts +253 -0
- package/src/bundler/__tests__/cli-bench-utils.test.ts +149 -0
- package/src/bundler/__tests__/cold-start.test.ts +504 -0
- package/src/bundler/__tests__/csp-nonce.test.ts +278 -0
- package/src/bundler/__tests__/dev-reliability.test.ts +619 -0
- package/src/bundler/__tests__/extended-watch.test.ts +710 -0
- package/src/bundler/__tests__/fast-refresh.test.ts +596 -0
- package/src/bundler/__tests__/hdr.test.ts +353 -0
- package/src/bundler/__tests__/hmr-client.test.ts +532 -0
- package/src/bundler/__tests__/manifest-schema.test.ts +266 -0
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -0
- package/src/bundler/__tests__/slot-dispatch.test.ts +573 -0
- package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -0
- package/src/bundler/__tests__/vendor-cache.test.ts +455 -0
- package/src/bundler/build.test.ts +8 -1
- package/src/bundler/build.ts +310 -18
- package/src/bundler/css.ts +326 -323
- package/src/bundler/dev.ts +1611 -59
- package/src/bundler/fast-refresh-plugin.ts +307 -0
- package/src/bundler/hmr-types.ts +252 -0
- package/src/bundler/manifest-schema.ts +301 -0
- package/src/bundler/safe-build.test.ts +128 -0
- package/src/bundler/safe-build.ts +77 -0
- package/src/bundler/scenario-matrix.ts +229 -0
- package/src/bundler/types.ts +11 -0
- package/src/bundler/vendor-cache-types.ts +130 -0
- package/src/bundler/vendor-cache.ts +526 -0
- package/src/client/router.ts +214 -56
- package/src/db/__tests__/db.test.ts +485 -0
- package/src/db/index.ts +513 -0
- package/src/db/migrations/__tests__/runner.test.ts +661 -0
- package/src/db/migrations/history-table.ts +345 -0
- package/src/db/migrations/lock.ts +269 -0
- package/src/db/migrations/runner.ts +633 -0
- package/src/desktop/__tests__/smoke.test.ts +100 -0
- package/src/desktop/__tests__/window.test.ts +172 -0
- package/src/desktop/__tests__/worker.test.ts +266 -0
- package/src/desktop/index.ts +43 -0
- package/src/desktop/types.ts +158 -0
- package/src/desktop/window.ts +492 -0
- package/src/desktop/worker.ts +180 -0
- package/src/email/__tests__/email.test.ts +355 -0
- package/src/email/index.ts +282 -0
- package/src/email/resend.ts +163 -0
- package/src/email/smtp.ts +64 -0
- package/src/filling/__tests__/session-sqlite.test.ts +454 -0
- package/src/filling/context.ts +72 -78
- package/src/filling/cookie-codec.ts +299 -0
- package/src/filling/deps.ts +25 -1
- package/src/filling/filling.ts +28 -3
- package/src/filling/session-sqlite.ts +617 -0
- package/src/filling/session.ts +265 -216
- package/src/guard/decision-memory.test.ts +52 -22
- package/src/id/__tests__/id.test.ts +120 -0
- package/src/id/index.ts +105 -0
- package/src/kitchen/index.ts +2 -2
- package/src/kitchen/kitchen-handler.ts +86 -0
- package/src/kitchen/stream/activity-sse.ts +2 -1
- package/src/middleware/csrf.ts +328 -0
- package/src/middleware/index.ts +40 -0
- package/src/middleware/oauth/__tests__/oauth.test.ts +574 -0
- package/src/middleware/oauth/index.ts +505 -0
- package/src/middleware/oauth/providers.ts +115 -0
- package/src/middleware/rate-limit/__tests__/rate-limit.test.ts +642 -0
- package/src/middleware/rate-limit/index.ts +522 -0
- package/src/middleware/rate-limit/sqlite-store.ts +382 -0
- package/src/middleware/secure/__tests__/secure.test.ts +360 -0
- package/src/middleware/secure/csp.ts +193 -0
- package/src/middleware/secure/index.ts +417 -0
- package/src/middleware/session.ts +174 -0
- package/src/observability/event-bus.ts +81 -79
- package/src/paths.ts +37 -0
- package/src/perf/hmr-markers.ts +215 -0
- package/src/perf/index.ts +104 -0
- package/src/resource/__tests__/generator.test.ts +603 -2
- package/src/resource/ddl/__tests__/diff.test.ts +639 -0
- package/src/resource/ddl/__tests__/emit.test.ts +799 -0
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -0
- package/src/resource/ddl/diff.ts +392 -0
- package/src/resource/ddl/emit.ts +548 -0
- package/src/resource/ddl/persistence-types.ts +218 -0
- package/src/resource/ddl/snapshot.ts +447 -0
- package/src/resource/ddl/type-map.ts +223 -0
- package/src/resource/ddl/types.ts +232 -0
- package/src/resource/generator-repo.ts +610 -0
- package/src/resource/generator-schema.ts +476 -0
- package/src/resource/generator.ts +117 -1
- package/src/resource/index.ts +17 -1
- package/src/resource/schema.ts +30 -0
- package/src/router/fs-scanner.ts +3 -0
- package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -0
- package/src/runtime/__tests__/hdr-client.test.ts +223 -0
- package/src/runtime/__tests__/http-errors.test.ts +117 -0
- package/src/runtime/__tests__/not-found.test.ts +152 -0
- package/src/runtime/boundary.tsx +21 -1
- package/src/runtime/fast-refresh-runtime.ts +322 -0
- package/src/runtime/fast-refresh-types.ts +128 -0
- package/src/runtime/hmr-client.ts +409 -0
- package/src/runtime/http-errors.ts +113 -0
- package/src/runtime/index.ts +6 -0
- package/src/runtime/logger.ts +678 -677
- package/src/runtime/not-found.ts +93 -0
- package/src/runtime/redirect.ts +133 -0
- package/src/runtime/server.ts +518 -20
- package/src/runtime/ssr.ts +340 -10
- package/src/runtime/streaming-ssr.ts +222 -19
- package/src/scheduler/__tests__/scheduler.test.ts +514 -0
- package/src/scheduler/index.ts +343 -0
- package/src/storage/s3/__tests__/s3.test.ts +479 -0
- package/src/storage/s3/index.ts +412 -0
- package/src/testing/index.ts +58 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 7.0 — 36-scenario HMR test matrix (3 project forms × 12 change kinds)
|
|
3
|
+
*
|
|
4
|
+
* This module is the SINGLE SOURCE OF TRUTH for the matrix that:
|
|
5
|
+
* - Agent E (R2) builds the Playwright test harness around
|
|
6
|
+
* - Agent F (R3) asserts latency targets against
|
|
7
|
+
* - Any future regression test iterates over
|
|
8
|
+
*
|
|
9
|
+
* The matrix intentionally enumerates every combination even when a cell
|
|
10
|
+
* is trivially n/a (e.g. `island.client.tsx` in a pure-SSG project with
|
|
11
|
+
* zero islands) — `expectedBehavior: "n/a"` keeps the matrix square so
|
|
12
|
+
* the iteration loop doesn't need per-cell conditionals.
|
|
13
|
+
*
|
|
14
|
+
* References:
|
|
15
|
+
* docs/bun/phase-7-team-plan.md §3.3
|
|
16
|
+
* docs/bun/phase-7-diagnostics/performance-reliability.md §4 (매트릭스 초안)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ============================================
|
|
20
|
+
// Dimensions
|
|
21
|
+
// ============================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Three representative project shapes. Each R2 E fixture corresponds to
|
|
25
|
+
* one of these.
|
|
26
|
+
*/
|
|
27
|
+
export const PROJECT_FORMS = [
|
|
28
|
+
"pure-ssg", // no hydration, SSR → HTML only
|
|
29
|
+
"hybrid", // some pages with islands, some SSR-only
|
|
30
|
+
"full-interactive", // every route has at least one island
|
|
31
|
+
] as const;
|
|
32
|
+
|
|
33
|
+
export type ProjectForm = (typeof PROJECT_FORMS)[number];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* File change kinds the matrix covers. Order matters only for stable
|
|
37
|
+
* report output — the iterating test runner relies on `for (const k of
|
|
38
|
+
* CHANGE_KINDS)`.
|
|
39
|
+
*
|
|
40
|
+
* Kept in sync with `docs/bun/phase-7-diagnostics/performance-reliability.md §4`.
|
|
41
|
+
*/
|
|
42
|
+
export const CHANGE_KINDS = [
|
|
43
|
+
"app/page.tsx",
|
|
44
|
+
"app/slot.ts",
|
|
45
|
+
"app/layout.tsx",
|
|
46
|
+
"app/contract.ts", // Agent D new coverage
|
|
47
|
+
"spec/resource.ts", // Agent D new coverage
|
|
48
|
+
"app/middleware.ts", // Agent D new coverage
|
|
49
|
+
"island.client.tsx",
|
|
50
|
+
"src/shared/**",
|
|
51
|
+
"src/top-level.ts", // Agent A new coverage (B1 fix)
|
|
52
|
+
"css",
|
|
53
|
+
"mandu.config.ts", // Agent D new coverage
|
|
54
|
+
".env", // Agent D new coverage
|
|
55
|
+
] as const;
|
|
56
|
+
|
|
57
|
+
export type ChangeKind = (typeof CHANGE_KINDS)[number];
|
|
58
|
+
|
|
59
|
+
// ============================================
|
|
60
|
+
// Cell shape
|
|
61
|
+
// ============================================
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Every matrix cell's expected outcome. The test harness picks the
|
|
65
|
+
* right assertion strategy based on this field.
|
|
66
|
+
*
|
|
67
|
+
* - `"island-update"` : expect `island-update` WS message; DOM patch
|
|
68
|
+
* without full navigation; form/scroll preserved.
|
|
69
|
+
* - `"full-reload"` : expect `full-reload` or `reload` WS message;
|
|
70
|
+
* fresh HTML; previous state cleared.
|
|
71
|
+
* - `"prerender-regen"` : Pure-SSR common-dir path; expect #188 fix —
|
|
72
|
+
* new HTML reachable after reload.
|
|
73
|
+
* - `"css-update"` : expect `css-update`; <link> re-timestamped; no
|
|
74
|
+
* full reload.
|
|
75
|
+
* - `"server-restart"` : expect `mandu.config.ts` / `.env` auto-restart;
|
|
76
|
+
* dev server responds on same port after delay.
|
|
77
|
+
* - `"code-regen"` : expect contract/resource artifact regenerated
|
|
78
|
+
* AND handler re-registered (no browser event
|
|
79
|
+
* needed unless UI-visible).
|
|
80
|
+
* - `"n/a"` : combination impossible in that project form
|
|
81
|
+
* (e.g. island change in pure-ssg).
|
|
82
|
+
*/
|
|
83
|
+
export type ExpectedBehavior =
|
|
84
|
+
| "island-update"
|
|
85
|
+
| "full-reload"
|
|
86
|
+
| "prerender-regen"
|
|
87
|
+
| "css-update"
|
|
88
|
+
| "server-restart"
|
|
89
|
+
| "code-regen"
|
|
90
|
+
| "n/a";
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A single matrix cell. Agent E materializes one Playwright test per
|
|
94
|
+
* cell; Agent F measures `REBUILD_TOTAL` on the same cells and asserts
|
|
95
|
+
* latency against the target.
|
|
96
|
+
*/
|
|
97
|
+
export interface ScenarioCell {
|
|
98
|
+
projectForm: ProjectForm;
|
|
99
|
+
changeKind: ChangeKind;
|
|
100
|
+
expectedBehavior: ExpectedBehavior;
|
|
101
|
+
/**
|
|
102
|
+
* Target `REBUILD_TOTAL` P95 in ms. `null` for `n/a` cells or
|
|
103
|
+
* `server-restart` (restart time varies by project startup).
|
|
104
|
+
*/
|
|
105
|
+
latencyTargetMs: number | null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================
|
|
109
|
+
// The 36 cells
|
|
110
|
+
// ============================================
|
|
111
|
+
|
|
112
|
+
/** Total cell count — mirrored in tests so they fail loudly if the
|
|
113
|
+
* matrix shape changes.
|
|
114
|
+
*
|
|
115
|
+
* NOTE: Declared BEFORE `SCENARIO_CELLS` so `buildMatrix()` — which runs
|
|
116
|
+
* during the `SCENARIO_CELLS` initializer and references this constant
|
|
117
|
+
* for its sanity check — does not hit a TDZ ReferenceError. The pair is
|
|
118
|
+
* still conceptually "matrix shape" metadata; they're co-located. */
|
|
119
|
+
export const EXPECTED_CELL_COUNT = PROJECT_FORMS.length * CHANGE_KINDS.length;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Pre-computed matrix. Derived once at module load so importers don't
|
|
123
|
+
* pay the lookup cost per test.
|
|
124
|
+
*/
|
|
125
|
+
export const SCENARIO_CELLS: readonly ScenarioCell[] = buildMatrix();
|
|
126
|
+
|
|
127
|
+
/** Look up a single cell. O(n) — matrix is small. */
|
|
128
|
+
export function findCell(
|
|
129
|
+
projectForm: ProjectForm,
|
|
130
|
+
changeKind: ChangeKind,
|
|
131
|
+
): ScenarioCell {
|
|
132
|
+
const cell = SCENARIO_CELLS.find(
|
|
133
|
+
(c) => c.projectForm === projectForm && c.changeKind === changeKind,
|
|
134
|
+
);
|
|
135
|
+
if (!cell) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`No scenario cell for ${projectForm} × ${changeKind}. Add it to scenario-matrix.ts.`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return cell;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ============================================
|
|
144
|
+
// Matrix construction
|
|
145
|
+
// ============================================
|
|
146
|
+
|
|
147
|
+
function buildMatrix(): ScenarioCell[] {
|
|
148
|
+
const cells: ScenarioCell[] = [];
|
|
149
|
+
for (const projectForm of PROJECT_FORMS) {
|
|
150
|
+
for (const changeKind of CHANGE_KINDS) {
|
|
151
|
+
cells.push({
|
|
152
|
+
projectForm,
|
|
153
|
+
changeKind,
|
|
154
|
+
expectedBehavior: classifyBehavior(projectForm, changeKind),
|
|
155
|
+
latencyTargetMs: classifyTarget(projectForm, changeKind),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (cells.length !== EXPECTED_CELL_COUNT) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`scenario-matrix.ts built ${cells.length} cells, expected ${EXPECTED_CELL_COUNT}.`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return cells;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function classifyBehavior(
|
|
168
|
+
projectForm: ProjectForm,
|
|
169
|
+
changeKind: ChangeKind,
|
|
170
|
+
): ExpectedBehavior {
|
|
171
|
+
// Island changes only apply to forms with islands.
|
|
172
|
+
if (changeKind === "island.client.tsx") {
|
|
173
|
+
return projectForm === "pure-ssg" ? "n/a" : "island-update";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// CSS is always style-swap.
|
|
177
|
+
if (changeKind === "css") return "css-update";
|
|
178
|
+
|
|
179
|
+
// Config / env always restart.
|
|
180
|
+
if (changeKind === "mandu.config.ts" || changeKind === ".env") {
|
|
181
|
+
return "server-restart";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Contract / resource trigger code-gen + handler re-register.
|
|
185
|
+
if (changeKind === "app/contract.ts" || changeKind === "spec/resource.ts") {
|
|
186
|
+
return "code-regen";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/shared + src/top-level in pure-SSG needs the #188 prerender path.
|
|
190
|
+
if (
|
|
191
|
+
projectForm === "pure-ssg" &&
|
|
192
|
+
(changeKind === "src/shared/**" || changeKind === "src/top-level.ts")
|
|
193
|
+
) {
|
|
194
|
+
return "prerender-regen";
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Everything else is a full reload (SSR-rendered page, layout, slot,
|
|
198
|
+
// middleware, common deps in hybrid/interactive projects). Full reload
|
|
199
|
+
// is the honest fallback — SSR has no React state to preserve.
|
|
200
|
+
return "full-reload";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function classifyTarget(
|
|
204
|
+
projectForm: ProjectForm,
|
|
205
|
+
changeKind: ChangeKind,
|
|
206
|
+
): number | null {
|
|
207
|
+
const behavior = classifyBehavior(projectForm, changeKind);
|
|
208
|
+
switch (behavior) {
|
|
209
|
+
case "n/a":
|
|
210
|
+
return null;
|
|
211
|
+
case "island-update":
|
|
212
|
+
return 50; // HMR_PERF_TARGETS.ISLAND_REBUILD_P95_MS
|
|
213
|
+
case "css-update":
|
|
214
|
+
return 100; // HMR_PERF_TARGETS.CSS_REBUILD_P95_MS
|
|
215
|
+
case "server-restart":
|
|
216
|
+
return null; // project-dependent, not an HMR target
|
|
217
|
+
case "code-regen":
|
|
218
|
+
return 400; // regen is heavier than a plain rebuild
|
|
219
|
+
case "prerender-regen":
|
|
220
|
+
return 400; // fan-out across all prerendered routes
|
|
221
|
+
case "full-reload":
|
|
222
|
+
// src/shared in hybrid/interactive → common-dir rebuild (400ms),
|
|
223
|
+
// otherwise a single SSR page (200ms).
|
|
224
|
+
if (changeKind === "src/shared/**" || changeKind === "src/top-level.ts") {
|
|
225
|
+
return 400; // HMR_PERF_TARGETS.COMMON_DIR_REBUILD_P95_MS
|
|
226
|
+
}
|
|
227
|
+
return 200; // HMR_PERF_TARGETS.SSR_REBUILD_P95_MS
|
|
228
|
+
}
|
|
229
|
+
}
|
package/src/bundler/types.ts
CHANGED
|
@@ -73,6 +73,17 @@ export interface BundleManifest {
|
|
|
73
73
|
vendor: string;
|
|
74
74
|
/** Client-side Router 런타임 */
|
|
75
75
|
router?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Phase 7.1 B-2: dev-only Fast Refresh assets. Absent in prod
|
|
78
|
+
* manifests so the HTML preamble short-circuits without trying to
|
|
79
|
+
* load a nonexistent URL.
|
|
80
|
+
*/
|
|
81
|
+
fastRefresh?: {
|
|
82
|
+
/** Bundled `react-refresh/runtime` (e.g. `/.mandu/client/_vendor-react-refresh.js`). */
|
|
83
|
+
runtime: string;
|
|
84
|
+
/** Mandu's glue module exposing `installGlobal` / `__MANDU_HMR__`. */
|
|
85
|
+
glue: string;
|
|
86
|
+
};
|
|
76
87
|
};
|
|
77
88
|
/** Import map for bare specifiers (react, react-dom, etc.) */
|
|
78
89
|
importMap?: {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 7.2 — Tier 2 vendor shim disk cache contract.
|
|
3
|
+
*
|
|
4
|
+
* Cold start breakdown (R0.3 diagnostic): the largest remaining cost is
|
|
5
|
+
* `buildVendorShims` rebuilding `_vendor-react.js`, `_vendor-react-dom.js`,
|
|
6
|
+
* `_vendor-react-refresh.js`, and `_fast-refresh-runtime.js` on every
|
|
7
|
+
* `mandu dev` invocation. These outputs are **deterministic per React /
|
|
8
|
+
* React-DOM / react-refresh / Bun version combination**, so Agent A's
|
|
9
|
+
* Phase 7.2.S2 caches them on disk and reuses them across boots.
|
|
10
|
+
*
|
|
11
|
+
* This file is the CONTRACT between the cache writer (Agent A in
|
|
12
|
+
* `bundler/vendor-cache.ts`) and any reader (bench scripts, audit
|
|
13
|
+
* tools). Do NOT add logic here — pure types only.
|
|
14
|
+
*
|
|
15
|
+
* Cache key composition (hash input, order-preserved):
|
|
16
|
+
* 1. Bun runtime version (`Bun.version`)
|
|
17
|
+
* 2. React package version (from the project's resolved `react/package.json`)
|
|
18
|
+
* 3. React-DOM package version
|
|
19
|
+
* 4. react-refresh package version
|
|
20
|
+
* 5. Mandu version (`@mandujs/core/package.json`) — shim source evolves
|
|
21
|
+
*
|
|
22
|
+
* Any miss invalidates every entry — we do not support per-entry
|
|
23
|
+
* invalidation to keep the manifest trivial (N=4 shims isn't worth it).
|
|
24
|
+
*
|
|
25
|
+
* References:
|
|
26
|
+
* docs/bun/phase-7-2-team-plan.md §2.2
|
|
27
|
+
* docs/bun/phase-7-1-diagnostics/cold-start-breakdown.md (source of the ~150ms target)
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ============================================
|
|
31
|
+
// Manifest shape
|
|
32
|
+
// ============================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Single cache entry — one `_vendor-*.js` output.
|
|
36
|
+
*/
|
|
37
|
+
export interface VendorCacheEntry {
|
|
38
|
+
/** Relative path inside `VENDOR_CACHE_DIR`. No leading slash. */
|
|
39
|
+
path: string;
|
|
40
|
+
/** Bytes on disk. Verification hint — mismatch → invalidate. */
|
|
41
|
+
size: number;
|
|
42
|
+
/** SHA-256 of the cached content. Tamper detection. */
|
|
43
|
+
hash: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `.mandu/vendor-cache/vendor-cache.json` — loaded at boot to decide
|
|
48
|
+
* cache hit vs miss.
|
|
49
|
+
*/
|
|
50
|
+
export interface VendorCacheManifest {
|
|
51
|
+
/** Format version. Bump on breaking manifest changes. */
|
|
52
|
+
version: 1;
|
|
53
|
+
|
|
54
|
+
/** `Bun.version` at write time. Any mismatch → wholesale miss. */
|
|
55
|
+
bunVersion: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Resolved versions of the four npm packages that feed the shims.
|
|
59
|
+
* Order matches the hash input above.
|
|
60
|
+
*/
|
|
61
|
+
reactVersion: string;
|
|
62
|
+
reactDomVersion: string;
|
|
63
|
+
reactRefreshVersion: string;
|
|
64
|
+
|
|
65
|
+
/** `@mandujs/core` version — shim source code evolves with Mandu. */
|
|
66
|
+
manduCoreVersion: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Map from shim logical id (e.g. `"react"`, `"react-dom"`,
|
|
70
|
+
* `"react-refresh-runtime"`, `"fast-refresh-glue"`) to on-disk entry.
|
|
71
|
+
* Writer is expected to include exactly the four keys above.
|
|
72
|
+
*/
|
|
73
|
+
entries: Record<string, VendorCacheEntry>;
|
|
74
|
+
|
|
75
|
+
/** ISO 8601 timestamp. Provenance only — not used by hit/miss logic. */
|
|
76
|
+
generatedAt: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================
|
|
80
|
+
// Constants — location + filename
|
|
81
|
+
// ============================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Relative to project root. All cache files go here.
|
|
85
|
+
*
|
|
86
|
+
* Kept inside `.mandu/` (already gitignored) so cache survives branch
|
|
87
|
+
* switches but not `git clean -fdx`. Intentional: heavy operations
|
|
88
|
+
* re-run on hard clean, routine workflow stays warm.
|
|
89
|
+
*/
|
|
90
|
+
export const VENDOR_CACHE_DIR = ".mandu/vendor-cache";
|
|
91
|
+
|
|
92
|
+
/** Filename of the manifest inside `VENDOR_CACHE_DIR`. */
|
|
93
|
+
export const VENDOR_CACHE_FILENAME = "vendor-cache.json";
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Safety limit — if the cache grows past this, invalidate and rebuild.
|
|
97
|
+
* The four shims total ~25 KB today; 10 MB is overly generous but
|
|
98
|
+
* catches pathological disk corruption.
|
|
99
|
+
*/
|
|
100
|
+
export const VENDOR_CACHE_MAX_BYTES = 10 * 1024 * 1024;
|
|
101
|
+
|
|
102
|
+
// ============================================
|
|
103
|
+
// Hit/miss result — returned by the cache reader
|
|
104
|
+
// ============================================
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Branded result so callers (build.ts) don't need to re-read the
|
|
108
|
+
* manifest to know why.
|
|
109
|
+
*/
|
|
110
|
+
export type VendorCacheResult =
|
|
111
|
+
| { kind: "hit"; manifest: VendorCacheManifest }
|
|
112
|
+
| {
|
|
113
|
+
kind: "miss";
|
|
114
|
+
reason:
|
|
115
|
+
| "no-manifest" // first boot
|
|
116
|
+
| "version-mismatch" // any of the 5 version fields changed
|
|
117
|
+
| "missing-entry" // manifest references a file that doesn't exist
|
|
118
|
+
| "hash-mismatch" // tamper / partial write
|
|
119
|
+
| "size-mismatch" // same as above, cheaper first-pass check
|
|
120
|
+
| "format-version"; // manifest.version !== 1
|
|
121
|
+
/** Populated when reason === "version-mismatch" — which field. */
|
|
122
|
+
mismatchedField?: keyof Pick<
|
|
123
|
+
VendorCacheManifest,
|
|
124
|
+
| "bunVersion"
|
|
125
|
+
| "reactVersion"
|
|
126
|
+
| "reactDomVersion"
|
|
127
|
+
| "reactRefreshVersion"
|
|
128
|
+
| "manduCoreVersion"
|
|
129
|
+
>;
|
|
130
|
+
};
|