@rangojs/router 0.0.0-experimental.146 → 0.0.0-experimental.148

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 (45) hide show
  1. package/dist/bin/rango.js +7 -0
  2. package/dist/vite/index.js +823 -235
  3. package/package.json +6 -1
  4. package/skills/mime-routes/SKILL.md +25 -17
  5. package/skills/ppr/SKILL.md +20 -10
  6. package/src/browser/event-controller.ts +16 -2
  7. package/src/browser/rsc-router.tsx +11 -0
  8. package/src/cache/cache-scope.ts +11 -2
  9. package/src/cache/cf/cf-cache-store.ts +60 -2
  10. package/src/cache/memory-segment-store.ts +32 -0
  11. package/src/cache/segment-codec.ts +47 -0
  12. package/src/cache/types.ts +14 -0
  13. package/src/cache/vercel/vercel-cache-store.ts +71 -2
  14. package/src/index.rsc.ts +6 -0
  15. package/src/prerender/build-shell-capture.ts +253 -0
  16. package/src/prerender/shell-manifest-key.ts +20 -0
  17. package/src/prerender/store.ts +10 -1
  18. package/src/router/content-negotiation.ts +47 -5
  19. package/src/router/match-middleware/cache-lookup.ts +12 -1
  20. package/src/router/metrics.ts +17 -2
  21. package/src/router/prerender-match.ts +21 -0
  22. package/src/router/router-interfaces.ts +7 -0
  23. package/src/router/router-options.ts +13 -0
  24. package/src/router.ts +5 -0
  25. package/src/rsc/capture-queue.ts +67 -0
  26. package/src/rsc/handler.ts +4 -2
  27. package/src/rsc/rsc-rendering.ts +131 -23
  28. package/src/rsc/shell-build-manifest.ts +274 -0
  29. package/src/rsc/shell-capture.ts +486 -63
  30. package/src/rsc/shell-serve.ts +44 -0
  31. package/src/rsc/ssr-setup.ts +54 -22
  32. package/src/segment-fragments.ts +124 -0
  33. package/src/server/context.ts +1 -0
  34. package/src/server/request-context.ts +65 -11
  35. package/src/ssr/index.tsx +47 -9
  36. package/src/ssr/ssr-root.tsx +35 -2
  37. package/src/urls/pattern-types.ts +27 -0
  38. package/src/vite/discovery/discover-routers.ts +27 -0
  39. package/src/vite/discovery/prerender-collection.ts +16 -0
  40. package/src/vite/discovery/shell-prerender-phase.ts +397 -0
  41. package/src/vite/discovery/state.ts +44 -0
  42. package/src/vite/plugins/version-plugin.ts +8 -0
  43. package/src/vite/rango.ts +1 -0
  44. package/src/vite/router-discovery.ts +310 -8
  45. package/src/vite/utils/prerender-utils.ts +25 -6
@@ -1,6 +1,201 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res, err) => function __init() {
4
+ if (err) throw err[0];
5
+ try {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ } catch (e) {
8
+ throw err = [e], e;
9
+ }
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+
16
+ // src/vite/debug.ts
17
+ import debugFactory from "debug";
18
+ function createRangoDebugger(namespace) {
19
+ const primary = debugFactory(namespace);
20
+ const shadow = debugFactory(`vite:${namespace}`);
21
+ if (primary.enabled) return primary;
22
+ if (shadow.enabled) return shadow;
23
+ return void 0;
24
+ }
25
+ async function timed(debug12, label, fn) {
26
+ if (!debug12) return await fn();
27
+ const start = performance.now();
28
+ try {
29
+ return await fn();
30
+ } finally {
31
+ debug12("%s (%sms)", label, (performance.now() - start).toFixed(1));
32
+ }
33
+ }
34
+ function timedSync(debug12, label, fn) {
35
+ if (!debug12) return fn();
36
+ const start = performance.now();
37
+ try {
38
+ return fn();
39
+ } finally {
40
+ debug12("%s (%sms)", label, (performance.now() - start).toFixed(1));
41
+ }
42
+ }
43
+ function createCounter(debug12, label) {
44
+ if (!debug12) return void 0;
45
+ let n = 0;
46
+ let totalMs = 0;
47
+ let slowestMs = 0;
48
+ let slowestFile = "";
49
+ const record = (file, ms) => {
50
+ n++;
51
+ totalMs += ms;
52
+ if (ms > slowestMs) {
53
+ slowestMs = ms;
54
+ slowestFile = file;
55
+ }
56
+ };
57
+ return {
58
+ record,
59
+ time(file, fn) {
60
+ const start = performance.now();
61
+ let out;
62
+ try {
63
+ out = fn();
64
+ } catch (err) {
65
+ record(file, performance.now() - start);
66
+ throw err;
67
+ }
68
+ if (out && typeof out.then === "function") {
69
+ return out.finally(
70
+ () => record(file, performance.now() - start)
71
+ );
72
+ }
73
+ record(file, performance.now() - start);
74
+ return out;
75
+ },
76
+ flush() {
77
+ if (n === 0) return;
78
+ debug12(
79
+ "%s: %d files, %sms total, slowest %sms %s",
80
+ label,
81
+ n,
82
+ totalMs.toFixed(1),
83
+ slowestMs.toFixed(1),
84
+ slowestFile
85
+ );
86
+ n = 0;
87
+ totalMs = 0;
88
+ slowestMs = 0;
89
+ slowestFile = "";
90
+ }
91
+ };
92
+ }
93
+ var NS;
94
+ var init_debug = __esm({
95
+ "src/vite/debug.ts"() {
96
+ "use strict";
97
+ NS = {
98
+ config: "rango:config",
99
+ discovery: "rango:discovery",
100
+ routes: "rango:routes",
101
+ prerender: "rango:prerender",
102
+ build: "rango:build",
103
+ dev: "rango:dev",
104
+ transform: "rango:transform",
105
+ chunks: "rango:chunks"
106
+ };
107
+ if (process.env.INTERNAL_RANGO_DEBUG) {
108
+ const existing = debugFactory.disable();
109
+ debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
110
+ }
111
+ }
112
+ });
113
+
114
+ // src/vite/plugins/client-ref-hashing.ts
115
+ var client_ref_hashing_exports = {};
116
+ __export(client_ref_hashing_exports, {
117
+ computeProductionHash: () => computeProductionHash,
118
+ hashClientRefs: () => hashClientRefs,
119
+ hashRefKey: () => hashRefKey,
120
+ transformClientRefs: () => transformClientRefs
121
+ });
122
+ import { relative as relative2 } from "node:path";
123
+ import { createHash as createHash2 } from "node:crypto";
124
+ function hashRefKey(relativeId) {
125
+ return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
126
+ }
127
+ function computeProductionHash(projectRoot, refKey) {
128
+ let toHash;
129
+ if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
130
+ toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
131
+ } else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
132
+ const absPath = decodeURIComponent(
133
+ refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
134
+ );
135
+ toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
136
+ } else if (refKey.startsWith(FS_PREFIX)) {
137
+ const absPath = refKey.slice(FS_PREFIX.length - 1);
138
+ toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
139
+ } else if (refKey.startsWith("/")) {
140
+ toHash = refKey.slice(1);
141
+ } else {
142
+ return refKey;
143
+ }
144
+ return hashRefKey(toHash);
145
+ }
146
+ function transformClientRefs(code, projectRoot) {
147
+ if (!code.includes("registerClientReference")) return null;
148
+ let hasReplacement = false;
149
+ const result = code.replace(
150
+ REGISTER_CLIENT_REF_RE,
151
+ (match, refKey) => {
152
+ const hash = computeProductionHash(projectRoot, refKey);
153
+ if (hash === refKey) return match;
154
+ hasReplacement = true;
155
+ return match.replace(`"${refKey}"`, `"${hash}"`);
156
+ }
157
+ );
158
+ return hasReplacement ? result : null;
159
+ }
160
+ function hashClientRefs(projectRoot) {
161
+ const counter = createCounter(debug7, "hash-client-refs");
162
+ return {
163
+ name: "@rangojs/router:hash-client-refs",
164
+ enforce: "post",
165
+ applyToEnvironment(env) {
166
+ return env.name === "rsc";
167
+ },
168
+ buildEnd() {
169
+ counter?.flush();
170
+ },
171
+ transform(code, id) {
172
+ const start = counter ? performance.now() : 0;
173
+ try {
174
+ const result = transformClientRefs(code, projectRoot);
175
+ if (result === null) return;
176
+ return { code: result, map: null };
177
+ } finally {
178
+ counter?.record(id, performance.now() - start);
179
+ }
180
+ }
181
+ };
182
+ }
183
+ var debug7, CLIENT_PKG_PROXY_PREFIX, CLIENT_IN_SERVER_PKG_PROXY_PREFIX, FS_PREFIX, REGISTER_CLIENT_REF_RE;
184
+ var init_client_ref_hashing = __esm({
185
+ "src/vite/plugins/client-ref-hashing.ts"() {
186
+ "use strict";
187
+ init_debug();
188
+ debug7 = createRangoDebugger(NS.transform);
189
+ CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
190
+ CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
191
+ FS_PREFIX = "/@fs/";
192
+ REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
193
+ }
194
+ });
195
+
1
196
  // src/vite/rango.ts
2
- import { readFileSync as readFileSync7, existsSync as existsSync8 } from "node:fs";
3
- import { resolve as resolve11 } from "node:path";
197
+ import { readFileSync as readFileSync8, existsSync as existsSync9 } from "node:fs";
198
+ import { resolve as resolve12 } from "node:path";
4
199
 
5
200
  // src/vite/plugins/expose-action-id.ts
6
201
  import MagicString from "magic-string";
@@ -251,99 +446,8 @@ function findCallParenAfterGenerics(code, afterCalleeIndex) {
251
446
  return -1;
252
447
  }
253
448
 
254
- // src/vite/debug.ts
255
- import debugFactory from "debug";
256
- var NS = {
257
- config: "rango:config",
258
- discovery: "rango:discovery",
259
- routes: "rango:routes",
260
- prerender: "rango:prerender",
261
- build: "rango:build",
262
- dev: "rango:dev",
263
- transform: "rango:transform",
264
- chunks: "rango:chunks"
265
- };
266
- if (process.env.INTERNAL_RANGO_DEBUG) {
267
- const existing = debugFactory.disable();
268
- debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
269
- }
270
- function createRangoDebugger(namespace) {
271
- const primary = debugFactory(namespace);
272
- const shadow = debugFactory(`vite:${namespace}`);
273
- if (primary.enabled) return primary;
274
- if (shadow.enabled) return shadow;
275
- return void 0;
276
- }
277
- async function timed(debug11, label, fn) {
278
- if (!debug11) return await fn();
279
- const start = performance.now();
280
- try {
281
- return await fn();
282
- } finally {
283
- debug11("%s (%sms)", label, (performance.now() - start).toFixed(1));
284
- }
285
- }
286
- function timedSync(debug11, label, fn) {
287
- if (!debug11) return fn();
288
- const start = performance.now();
289
- try {
290
- return fn();
291
- } finally {
292
- debug11("%s (%sms)", label, (performance.now() - start).toFixed(1));
293
- }
294
- }
295
- function createCounter(debug11, label) {
296
- if (!debug11) return void 0;
297
- let n = 0;
298
- let totalMs = 0;
299
- let slowestMs = 0;
300
- let slowestFile = "";
301
- const record = (file, ms) => {
302
- n++;
303
- totalMs += ms;
304
- if (ms > slowestMs) {
305
- slowestMs = ms;
306
- slowestFile = file;
307
- }
308
- };
309
- return {
310
- record,
311
- time(file, fn) {
312
- const start = performance.now();
313
- let out;
314
- try {
315
- out = fn();
316
- } catch (err) {
317
- record(file, performance.now() - start);
318
- throw err;
319
- }
320
- if (out && typeof out.then === "function") {
321
- return out.finally(
322
- () => record(file, performance.now() - start)
323
- );
324
- }
325
- record(file, performance.now() - start);
326
- return out;
327
- },
328
- flush() {
329
- if (n === 0) return;
330
- debug11(
331
- "%s: %d files, %sms total, slowest %sms %s",
332
- label,
333
- n,
334
- totalMs.toFixed(1),
335
- slowestMs.toFixed(1),
336
- slowestFile
337
- );
338
- n = 0;
339
- totalMs = 0;
340
- slowestMs = 0;
341
- slowestFile = "";
342
- }
343
- };
344
- }
345
-
346
449
  // src/vite/plugins/expose-action-id.ts
450
+ init_debug();
347
451
  var debug = createRangoDebugger(NS.transform);
348
452
  function getRscPluginApi(config) {
349
453
  let plugin = config.plugins.find((p) => p.name === "rsc:minimal");
@@ -1299,10 +1403,14 @@ ${binding.localName}.$$id = "${handlerId}";`;
1299
1403
  return hasChanges;
1300
1404
  }
1301
1405
 
1406
+ // src/vite/plugins/expose-internal-ids.ts
1407
+ init_debug();
1408
+
1302
1409
  // src/vite/plugins/expose-ids/router-transform.ts
1303
1410
  import MagicString2 from "magic-string";
1304
1411
  import path3 from "node:path";
1305
1412
  import { createHash } from "node:crypto";
1413
+ init_debug();
1306
1414
  var debug2 = createRangoDebugger(NS.transform);
1307
1415
  function skipLeadingTrivia(code, start, end) {
1308
1416
  let i = start;
@@ -1922,6 +2030,7 @@ ${lazyImports.join(",\n")}
1922
2030
  // src/vite/plugins/use-cache-transform.ts
1923
2031
  import path5 from "node:path";
1924
2032
  import MagicString4 from "magic-string";
2033
+ init_debug();
1925
2034
  var debug4 = createRangoDebugger(NS.transform);
1926
2035
  var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
1927
2036
  var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
@@ -2115,6 +2224,7 @@ function warnOnNearMissDirectives(ast, fileId, warn) {
2115
2224
  }
2116
2225
 
2117
2226
  // src/vite/plugins/client-ref-dedup.ts
2227
+ init_debug();
2118
2228
  var debug5 = createRangoDebugger(NS.transform);
2119
2229
  var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
2120
2230
  function extractPackageName(absolutePath) {
@@ -2410,7 +2520,7 @@ import { resolve } from "node:path";
2410
2520
  // package.json
2411
2521
  var package_default = {
2412
2522
  name: "@rangojs/router",
2413
- version: "0.0.0-experimental.146",
2523
+ version: "0.0.0-experimental.148",
2414
2524
  description: "Django-inspired RSC router with composable URL patterns",
2415
2525
  keywords: [
2416
2526
  "react",
@@ -2538,6 +2648,11 @@ var package_default = {
2538
2648
  types: "./src/build/index.ts",
2539
2649
  import: "./src/build/index.ts"
2540
2650
  },
2651
+ "./build/shell-capture": {
2652
+ types: "./src/prerender/build-shell-capture.ts",
2653
+ "react-server": "./src/prerender/build-shell-capture.ts",
2654
+ import: "./src/prerender/build-shell-capture.ts"
2655
+ },
2541
2656
  "./host": {
2542
2657
  types: "./src/host/index.ts",
2543
2658
  "react-server": "./src/host/index.ts",
@@ -3849,6 +3964,13 @@ function createVersionPlugin() {
3849
3964
  return {
3850
3965
  name: "@rangojs/router:version",
3851
3966
  enforce: "pre",
3967
+ // The build-time shell capture phase (producer B, #699) stamps entries
3968
+ // with THIS instance's version — the value folded into the shipped worker
3969
+ // — never the discovery temp server's own version-plugin value (a
3970
+ // different Date.now() stamp that would fail the serve-side gate).
3971
+ api: {
3972
+ getBuildVersion: () => currentVersion
3973
+ },
3852
3974
  configResolved(config) {
3853
3975
  isDev = config.command === "serve";
3854
3976
  resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
@@ -3939,6 +4061,7 @@ import * as Vite from "vite";
3939
4061
  import { isAbsolute, resolve as resolve4 } from "node:path";
3940
4062
 
3941
4063
  // src/vite/plugins/performance-tracks.ts
4064
+ init_debug();
3942
4065
  import { readFile } from "node:fs/promises";
3943
4066
  var debug6 = createRangoDebugger(NS.transform);
3944
4067
  var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
@@ -4121,75 +4244,9 @@ function getManualChunks(id) {
4121
4244
  return void 0;
4122
4245
  }
4123
4246
 
4124
- // src/vite/plugins/client-ref-hashing.ts
4125
- import { relative as relative2 } from "node:path";
4126
- import { createHash as createHash2 } from "node:crypto";
4127
- var debug7 = createRangoDebugger(NS.transform);
4128
- var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
4129
- var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
4130
- var FS_PREFIX = "/@fs/";
4131
- function hashRefKey(relativeId) {
4132
- return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
4133
- }
4134
- function computeProductionHash(projectRoot, refKey) {
4135
- let toHash;
4136
- if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
4137
- toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
4138
- } else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
4139
- const absPath = decodeURIComponent(
4140
- refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
4141
- );
4142
- toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
4143
- } else if (refKey.startsWith(FS_PREFIX)) {
4144
- const absPath = refKey.slice(FS_PREFIX.length - 1);
4145
- toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
4146
- } else if (refKey.startsWith("/")) {
4147
- toHash = refKey.slice(1);
4148
- } else {
4149
- return refKey;
4150
- }
4151
- return hashRefKey(toHash);
4152
- }
4153
- var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
4154
- function transformClientRefs(code, projectRoot) {
4155
- if (!code.includes("registerClientReference")) return null;
4156
- let hasReplacement = false;
4157
- const result = code.replace(
4158
- REGISTER_CLIENT_REF_RE,
4159
- (match, refKey) => {
4160
- const hash = computeProductionHash(projectRoot, refKey);
4161
- if (hash === refKey) return match;
4162
- hasReplacement = true;
4163
- return match.replace(`"${refKey}"`, `"${hash}"`);
4164
- }
4165
- );
4166
- return hasReplacement ? result : null;
4167
- }
4168
- function hashClientRefs(projectRoot) {
4169
- const counter = createCounter(debug7, "hash-client-refs");
4170
- return {
4171
- name: "@rangojs/router:hash-client-refs",
4172
- enforce: "post",
4173
- applyToEnvironment(env) {
4174
- return env.name === "rsc";
4175
- },
4176
- buildEnd() {
4177
- counter?.flush();
4178
- },
4179
- transform(code, id) {
4180
- const start = counter ? performance.now() : 0;
4181
- try {
4182
- const result = transformClientRefs(code, projectRoot);
4183
- if (result === null) return;
4184
- return { code: result, map: null };
4185
- } finally {
4186
- counter?.record(id, performance.now() - start);
4187
- }
4188
- }
4189
- };
4190
- }
4191
-
4192
4247
  // src/vite/utils/client-chunks.ts
4248
+ init_debug();
4249
+ init_client_ref_hashing();
4193
4250
  var debugChunks = createRangoDebugger(NS.chunks);
4194
4251
  function isSharedRuntime(meta) {
4195
4252
  return [meta.id, meta.normalizedId].some(
@@ -4545,6 +4602,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
4545
4602
  }
4546
4603
 
4547
4604
  // src/vite/plugins/cjs-to-esm.ts
4605
+ init_debug();
4548
4606
  var debug8 = createRangoDebugger(NS.transform);
4549
4607
  function createCjsToEsmPlugin() {
4550
4608
  let isProduction = false;
@@ -4608,11 +4666,18 @@ function createCjsToEsmPlugin() {
4608
4666
 
4609
4667
  // src/vite/router-discovery.ts
4610
4668
  import { createServer as createViteServer } from "vite";
4611
- import { resolve as resolve10 } from "node:path";
4612
- import { readFileSync as readFileSync6 } from "node:fs";
4669
+ import { resolve as resolve11 } from "node:path";
4670
+ import { readFileSync as readFileSync7 } from "node:fs";
4613
4671
  import { createRequire as createRequire3, register } from "node:module";
4614
4672
  import { pathToFileURL as pathToFileURL2 } from "node:url";
4615
4673
 
4674
+ // src/rsc/shell-serve.ts
4675
+ import React from "react";
4676
+ var DEV_SHELL_PROBE_TIMEOUT_MS = 1e4;
4677
+ function normalizeCaptureTimeout(value) {
4678
+ return typeof value === "number" && Number.isFinite(value) && value >= 1 ? value : void 0;
4679
+ }
4680
+
4616
4681
  // src/vite/inject-client-debug.ts
4617
4682
  function isRouterInternalDebugId(id) {
4618
4683
  if (!id.includes("internal-debug")) return false;
@@ -4773,6 +4838,9 @@ function walk(node, visit) {
4773
4838
  }
4774
4839
  }
4775
4840
 
4841
+ // src/vite/router-discovery.ts
4842
+ init_client_ref_hashing();
4843
+
4776
4844
  // src/vite/utils/bundle-analysis.ts
4777
4845
  function findMatchingParenInBundle(code, openParenPos) {
4778
4846
  let depth = 1;
@@ -4877,6 +4945,9 @@ function createDiscoveryState(entryPath, opts) {
4877
4945
  perRouterManifestDataMap: /* @__PURE__ */ new Map(),
4878
4946
  prerenderManifestEntries: null,
4879
4947
  staticManifestEntries: null,
4948
+ shellCandidates: null,
4949
+ prerenderPayloadValues: null,
4950
+ shellPhaseTempServer: null,
4880
4951
  handlerChunkInfoMap: /* @__PURE__ */ new Map(),
4881
4952
  staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
4882
4953
  rscEntryFileName: null,
@@ -5459,18 +5530,24 @@ function getStagedAssetDir(projectRoot) {
5459
5530
  function resetStagedBuildAssets(projectRoot) {
5460
5531
  rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
5461
5532
  }
5462
- function stageBuildAssetModule(projectRoot, prefix, exportValue) {
5463
- const stagedDir = getStagedAssetDir(projectRoot);
5464
- mkdirSync(stagedDir, { recursive: true });
5533
+ function writeBuildAssetModule(dir, prefix, exportValue) {
5534
+ mkdirSync(dir, { recursive: true });
5465
5535
  const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
5466
5536
  const fileName = `${prefix}-${contentHash}.js`;
5467
- const filePath = resolve7(stagedDir, fileName);
5537
+ const filePath = resolve7(dir, fileName);
5468
5538
  if (!existsSync5(filePath)) {
5469
5539
  writeFileSync2(filePath, `export default ${exportValue};
5470
5540
  `);
5471
5541
  }
5472
5542
  return fileName;
5473
5543
  }
5544
+ function stageBuildAssetModule(projectRoot, prefix, exportValue) {
5545
+ return writeBuildAssetModule(
5546
+ getStagedAssetDir(projectRoot),
5547
+ prefix,
5548
+ exportValue
5549
+ );
5550
+ }
5474
5551
  function copyStagedBuildAssets(projectRoot, fileNames) {
5475
5552
  const stagedDir = getStagedAssetDir(projectRoot);
5476
5553
  const distAssetsDir = resolve7(projectRoot, "dist/rsc/assets");
@@ -5486,6 +5563,7 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
5486
5563
  }
5487
5564
 
5488
5565
  // src/vite/discovery/prerender-collection.ts
5566
+ init_debug();
5489
5567
  var debug9 = createRangoDebugger(NS.prerender);
5490
5568
  async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
5491
5569
  if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
@@ -5693,6 +5771,18 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
5693
5771
  "__pr",
5694
5772
  mainValue
5695
5773
  );
5774
+ if (result.ppr !== void 0 && result.ppr !== false) {
5775
+ (state.shellCandidates ??= []).push({
5776
+ urlPath: entry.urlPath,
5777
+ routeName: result.routeName,
5778
+ paramHash,
5779
+ ppr: result.ppr === true ? true : result.ppr
5780
+ });
5781
+ (state.prerenderPayloadValues ??= /* @__PURE__ */ new Map()).set(
5782
+ mainKey,
5783
+ mainValue
5784
+ );
5785
+ }
5696
5786
  if (result.interceptSegments?.length) {
5697
5787
  const interceptKey = `${result.routeName}/${paramHash}/i`;
5698
5788
  const interceptValue = JSON.stringify({
@@ -5943,6 +6033,8 @@ function describeDiscoveryFailure(err, opts = {}) {
5943
6033
  }
5944
6034
 
5945
6035
  // src/vite/discovery/discover-routers.ts
6036
+ init_debug();
6037
+ init_client_ref_hashing();
5946
6038
  var debug10 = createRangoDebugger(NS.discovery);
5947
6039
  async function discoverRouters(state, rscEnv) {
5948
6040
  if (!state.resolvedEntryPath) return;
@@ -6163,11 +6255,286 @@ async function discoverRouters(state, rscEnv) {
6163
6255
  state.perRouterPrecomputedMap = newPerRouterPrecomputedMap;
6164
6256
  state.perRouterTrieMap = newPerRouterTrieMap;
6165
6257
  state.mergedRouteTrie = newMergedRouteTrie;
6258
+ if (serverMod.setRouteTrie && newMergedRouteTrie) {
6259
+ serverMod.setRouteTrie(newMergedRouteTrie);
6260
+ }
6261
+ const perRouterSetters = [
6262
+ [newPerRouterManifestDataMap, "setRouterManifest"],
6263
+ [newPerRouterTrieMap, "setRouterTrie"],
6264
+ [newPerRouterPrecomputedMap, "setRouterPrecomputedEntries"]
6265
+ ];
6266
+ for (const [map, fn] of perRouterSetters) {
6267
+ const setter = serverMod[fn];
6268
+ if (typeof setter !== "function") continue;
6269
+ for (const [routerId, value] of map) setter(routerId, value);
6270
+ }
6166
6271
  await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
6167
6272
  await renderStaticHandlers(state, rscEnv, registry);
6168
6273
  return serverMod;
6169
6274
  }
6170
6275
 
6276
+ // src/vite/discovery/shell-prerender-phase.ts
6277
+ import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
6278
+ import { join as join4, resolve as resolve8 } from "node:path";
6279
+
6280
+ // src/prerender/shell-manifest-key.ts
6281
+ function buildShellManifestKey(pathname) {
6282
+ return pathname;
6283
+ }
6284
+
6285
+ // src/vite/discovery/shell-prerender-phase.ts
6286
+ init_debug();
6287
+ var debug11 = createRangoDebugger(NS.prerender);
6288
+ async function runShellPrerenderPhase(s, builder) {
6289
+ const tempServer = s.shellPhaseTempServer;
6290
+ if (!s.isBuildMode || !s.shellCandidates?.length || !tempServer) return;
6291
+ const candidates = s.shellCandidates;
6292
+ const startTotal = performance.now();
6293
+ console.log(`[rango] Shell-prerendering ${candidates.length} URL(s)...`);
6294
+ let restoreClientRequire;
6295
+ try {
6296
+ const rscEnv = tempServer.environments?.rsc;
6297
+ const ssrEnv = tempServer.environments?.ssr;
6298
+ if (!rscEnv?.runner || !ssrEnv?.runner) {
6299
+ console.warn(
6300
+ `[rango] shell prerender: temp server runners unavailable (rsc=${String(!!rscEnv?.runner)}, ssr=${String(!!ssrEnv?.runner)}); skipping \u2014 routes keep runtime shell capture.`
6301
+ );
6302
+ return;
6303
+ }
6304
+ const versionPlugin = (builder?.config?.plugins ?? []).find(
6305
+ (p) => p?.name === "@rangojs/router:version"
6306
+ );
6307
+ const buildVersion = versionPlugin?.api?.getBuildVersion?.();
6308
+ if (!buildVersion) {
6309
+ console.warn(
6310
+ "[rango] shell prerender: main build version unavailable; skipping \u2014 routes keep runtime shell capture."
6311
+ );
6312
+ return;
6313
+ }
6314
+ const payloads = s.prerenderPayloadValues ?? /* @__PURE__ */ new Map();
6315
+ const fetchedKeys = /* @__PURE__ */ new Set();
6316
+ globalThis.__loadPrerenderManifestModule = async () => ({
6317
+ default: Object.fromEntries([...payloads.keys()].map((k) => [k, k])),
6318
+ loadPrerenderAsset: async (spec) => {
6319
+ fetchedKeys.add(spec);
6320
+ return { default: JSON.parse(payloads.get(spec)) };
6321
+ }
6322
+ });
6323
+ const ssrRunner = ssrEnv.runner;
6324
+ const ssrPkg = await ssrRunner.import("@rangojs/router/ssr");
6325
+ const ssrDeps = await ssrRunner.import("@rangojs/router/internal/deps/ssr");
6326
+ const reactDomServer = await ssrRunner.import("react-dom/server.edge");
6327
+ const reactDomStatic = await ssrRunner.import("react-dom/static.edge");
6328
+ const htmlStream = await ssrRunner.import(
6329
+ "@rangojs/router/internal/deps/html-stream-server"
6330
+ );
6331
+ const clientOutDir = builder?.environments?.client?.config?.build?.outDir ?? resolve8(s.projectRoot, "dist/client");
6332
+ const clientAssetsDir = join4(clientOutDir, "assets");
6333
+ const entryFile = existsSync6(clientAssetsDir) ? readdirSync2(clientAssetsDir).find((f) => /^index-.*\.js$/.test(f)) : void 0;
6334
+ if (!entryFile) {
6335
+ console.warn(
6336
+ `[rango] shell prerender: built client entry not found under ${clientAssetsDir}; skipping \u2014 routes keep runtime shell capture.`
6337
+ );
6338
+ return;
6339
+ }
6340
+ const base = builder?.config?.base ?? "/";
6341
+ const normalizedBase = base.endsWith("/") ? base : `${base}/`;
6342
+ const bootstrapContent = `import("${normalizedBase}assets/${entryFile}")`;
6343
+ debug11?.("shell prerender bootstrap: %s", bootstrapContent);
6344
+ const minimalPlugin = (tempServer.config?.plugins ?? []).find(
6345
+ (p) => p?.name === "rsc:minimal"
6346
+ );
6347
+ const rscManager = minimalPlugin?.api?.manager;
6348
+ const { computeProductionHash: computeProductionHash2 } = await Promise.resolve().then(() => (init_client_ref_hashing(), client_ref_hashing_exports));
6349
+ let hashToDevKey = /* @__PURE__ */ new Map();
6350
+ const rebuildHashMap = () => {
6351
+ hashToDevKey = /* @__PURE__ */ new Map();
6352
+ const metaMap = rscManager?.clientReferenceMetaMap ?? {};
6353
+ for (const meta of Object.values(metaMap)) {
6354
+ hashToDevKey.set(
6355
+ computeProductionHash2(s.projectRoot, meta.referenceKey),
6356
+ meta.referenceKey
6357
+ );
6358
+ }
6359
+ };
6360
+ const origClientRequire = globalThis.__vite_rsc_client_require__;
6361
+ if (typeof origClientRequire === "function") {
6362
+ restoreClientRequire = () => {
6363
+ globalThis.__vite_rsc_client_require__ = origClientRequire;
6364
+ };
6365
+ globalThis.__vite_rsc_client_require__ = (id) => {
6366
+ const base2 = id.split("$$cache=")[0];
6367
+ let mapped = hashToDevKey.get(base2);
6368
+ if (mapped === void 0) {
6369
+ rebuildHashMap();
6370
+ mapped = hashToDevKey.get(base2);
6371
+ }
6372
+ return origClientRequire(mapped ?? id);
6373
+ };
6374
+ }
6375
+ const captureShellHTML = ssrPkg.createShellCaptureHandler({
6376
+ createFromReadableStream: ssrDeps.createFromReadableStream,
6377
+ renderToReadableStream: reactDomServer.renderToReadableStream ?? reactDomServer.default?.renderToReadableStream,
6378
+ resume: reactDomServer.resume ?? reactDomServer.default?.resume,
6379
+ prerender: reactDomStatic.prerender ?? reactDomStatic.default?.prerender,
6380
+ injectRSCPayload: htmlStream.injectRSCPayload,
6381
+ headScripts: "preinit",
6382
+ loadBootstrapScriptContent: async () => bootstrapContent
6383
+ });
6384
+ const rscRunner = rscEnv.runner;
6385
+ const captureMod = await rscRunner.import(
6386
+ "@rangojs/router/build/shell-capture"
6387
+ );
6388
+ const serverMod = await rscRunner.import("@rangojs/router/server");
6389
+ const registry = serverMod.RouterRegistry;
6390
+ const staged = [];
6391
+ let skipCount = 0;
6392
+ const pathCounts = /* @__PURE__ */ new Map();
6393
+ for (const cand of candidates) {
6394
+ pathCounts.set(cand.urlPath, (pathCounts.get(cand.urlPath) ?? 0) + 1);
6395
+ }
6396
+ for (const cand of candidates) {
6397
+ if ((pathCounts.get(cand.urlPath) ?? 0) > 1) {
6398
+ console.warn(
6399
+ `[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} - pathname claimed by multiple prerender routes; routes keep runtime capture`
6400
+ );
6401
+ skipCount++;
6402
+ continue;
6403
+ }
6404
+ const startUrl = performance.now();
6405
+ const policy = captureMod.resolveBuildPprConfig(cand.ppr);
6406
+ const mainKey = `${cand.routeName}/${cand.paramHash}`;
6407
+ let handled = false;
6408
+ const mismatches = [];
6409
+ for (const [, routerInstance] of registry) {
6410
+ if (typeof routerInstance.match !== "function") continue;
6411
+ try {
6412
+ const res = await captureMod.captureShellForBuild({
6413
+ router: routerInstance,
6414
+ urlPath: cand.urlPath,
6415
+ routeName: cand.routeName,
6416
+ key: `${cand.urlPath}:shell`,
6417
+ ttl: policy.ttl,
6418
+ swr: policy.swr,
6419
+ tags: policy.tags,
6420
+ maxSnapshotBytes: policy.maxSnapshotBytes,
6421
+ captureTimeout: policy.captureTimeout,
6422
+ buildEnv: s.resolvedBuildEnv,
6423
+ buildVersion,
6424
+ captureShellHTML,
6425
+ debug: !!debug11
6426
+ });
6427
+ if (res.outcome === "route-mismatch") {
6428
+ mismatches.push(res.matchedRouteName ?? "(no match)");
6429
+ continue;
6430
+ }
6431
+ handled = true;
6432
+ const elapsed = (performance.now() - startUrl).toFixed(0);
6433
+ if (res.outcome !== "stored" || !res.entry) {
6434
+ console.warn(
6435
+ `[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - capture ${res.outcome}; route keeps runtime capture`
6436
+ );
6437
+ skipCount++;
6438
+ break;
6439
+ }
6440
+ if (!fetchedKeys.has(mainKey)) {
6441
+ console.warn(
6442
+ `[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - capture did not replay the prerender store; route keeps runtime capture`
6443
+ );
6444
+ skipCount++;
6445
+ break;
6446
+ }
6447
+ const value = {
6448
+ entry: res.entry,
6449
+ ttl: policy.ttl,
6450
+ swr: policy.swr,
6451
+ tags: res.tags,
6452
+ routeName: cand.routeName
6453
+ };
6454
+ staged.push({
6455
+ key: buildShellManifestKey(cand.urlPath),
6456
+ value: JSON.stringify(value)
6457
+ });
6458
+ console.log(
6459
+ `[rango] SHELL OK ${cand.urlPath.padEnd(34)} (${elapsed}ms)`
6460
+ );
6461
+ break;
6462
+ } catch (err) {
6463
+ handled = true;
6464
+ const elapsed = (performance.now() - startUrl).toFixed(0);
6465
+ console.warn(
6466
+ `[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - ${err?.message ?? err}; route keeps runtime capture`
6467
+ );
6468
+ skipCount++;
6469
+ break;
6470
+ }
6471
+ }
6472
+ if (!handled) {
6473
+ console.warn(
6474
+ `[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} - no router matched "${cand.routeName}"` + (mismatches.length > 0 ? ` (matched: ${mismatches.join(", ")})` : "") + "; route keeps runtime capture"
6475
+ );
6476
+ skipCount++;
6477
+ }
6478
+ }
6479
+ if (staged.length > 0) {
6480
+ const rscOutDir = builder?.environments?.rsc?.config?.build?.outDir ?? resolve8(s.projectRoot, "dist/rsc");
6481
+ writeShellManifest(s, rscOutDir, staged);
6482
+ }
6483
+ const totalElapsed = (performance.now() - startTotal).toFixed(0);
6484
+ const parts = [`${staged.length} done`];
6485
+ if (skipCount > 0) parts.push(`${skipCount} skipped`);
6486
+ console.log(
6487
+ `[rango] Shell prerender complete: ${parts.join(", ")} (${totalElapsed}ms total)`
6488
+ );
6489
+ } catch (err) {
6490
+ console.warn(
6491
+ `[rango] shell prerender phase failed: ${err?.message ?? err}; routes keep runtime shell capture.`
6492
+ );
6493
+ } finally {
6494
+ delete globalThis.__loadPrerenderManifestModule;
6495
+ restoreClientRequire?.();
6496
+ }
6497
+ }
6498
+ function writeShellManifest(s, rscOutDir, staged) {
6499
+ const rscEntryPath = resolve8(rscOutDir, s.rscEntryFileName ?? "index.js");
6500
+ if (!existsSync6(rscEntryPath)) {
6501
+ console.warn(
6502
+ `[rango] shell prerender: RSC entry not found at ${rscEntryPath}; entries not persisted \u2014 routes keep runtime capture.`
6503
+ );
6504
+ return;
6505
+ }
6506
+ const assetsDir = resolve8(rscOutDir, "assets");
6507
+ let totalBytes = 0;
6508
+ const manifestMap = {};
6509
+ const countedFiles = /* @__PURE__ */ new Set();
6510
+ for (const { key, value } of staged) {
6511
+ const fileName = writeBuildAssetModule(assetsDir, "__ps", value);
6512
+ if (!countedFiles.has(fileName)) {
6513
+ countedFiles.add(fileName);
6514
+ totalBytes += Buffer.byteLength(value) + "export default ;\n".length;
6515
+ }
6516
+ manifestMap[key] = `./assets/${fileName}`;
6517
+ }
6518
+ const manifestCode = [
6519
+ `const m=${jsonParseExpression(manifestMap)};`,
6520
+ `export function loadShellAsset(s){return import(s)}`,
6521
+ `export default m;`,
6522
+ ""
6523
+ ].join("\n");
6524
+ writeFileSync3(resolve8(rscOutDir, "__shell-manifest.js"), manifestCode);
6525
+ totalBytes += Buffer.byteLength(manifestCode);
6526
+ const rscCode = readFileSync4(rscEntryPath, "utf-8");
6527
+ if (!rscCode.includes("__shell-manifest.js")) {
6528
+ const injection = `globalThis.__loadShellManifestModule = () => import("./__shell-manifest.js");
6529
+ `;
6530
+ writeFileSync3(rscEntryPath, injection + rscCode);
6531
+ }
6532
+ const totalKB = (totalBytes / 1024).toFixed(1);
6533
+ console.log(
6534
+ `[rango] Wrote shell assets (${totalKB} KB total, ${staged.length} entries)`
6535
+ );
6536
+ }
6537
+
6171
6538
  // src/vite/discovery/dev-prerender-cache.ts
6172
6539
  function payloadBodiesFromResult(result) {
6173
6540
  const main = JSON.stringify({
@@ -6206,8 +6573,8 @@ function createDevPrerenderCache(maxEntriesPerRouter = MAX_ENTRIES_PER_ROUTER) {
6206
6573
  }
6207
6574
 
6208
6575
  // src/vite/discovery/route-types-writer.ts
6209
- import { dirname as dirname3, join as join4, resolve as resolve8 } from "node:path";
6210
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, unlinkSync as unlinkSync2 } from "node:fs";
6576
+ import { dirname as dirname3, join as join5, resolve as resolve9 } from "node:path";
6577
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7, unlinkSync as unlinkSync2 } from "node:fs";
6211
6578
  function filterUserNamedRoutes(manifest) {
6212
6579
  const filtered = {};
6213
6580
  for (const [name, pattern] of Object.entries(manifest)) {
@@ -6218,10 +6585,10 @@ function filterUserNamedRoutes(manifest) {
6218
6585
  return filtered;
6219
6586
  }
6220
6587
  function writeGenFileIfChanged(state, outPath, source, opts) {
6221
- const existing = existsSync6(outPath) ? readFileSync4(outPath, "utf-8") : null;
6588
+ const existing = existsSync7(outPath) ? readFileSync5(outPath, "utf-8") : null;
6222
6589
  if (existing === source) return;
6223
6590
  markSelfGenWrite(state, outPath, source);
6224
- writeFileSync3(outPath, source);
6591
+ writeFileSync4(outPath, source);
6225
6592
  if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
6226
6593
  }
6227
6594
  function writeCombinedRouteTypesWithTracking(state, opts) {
@@ -6236,10 +6603,10 @@ function writeRouteTypesFiles(state) {
6236
6603
  if (state.perRouterManifests.length === 0) return;
6237
6604
  try {
6238
6605
  const entryDir = dirname3(
6239
- resolve8(state.projectRoot, state.resolvedEntryPath)
6606
+ resolve9(state.projectRoot, state.resolvedEntryPath)
6240
6607
  );
6241
- const oldCombinedPath = join4(entryDir, "named-routes.gen.ts");
6242
- if (existsSync6(oldCombinedPath)) {
6608
+ const oldCombinedPath = join5(entryDir, "named-routes.gen.ts");
6609
+ if (existsSync7(oldCombinedPath)) {
6243
6610
  unlinkSync2(oldCombinedPath);
6244
6611
  console.log(
6245
6612
  `[rango] Removed stale combined route types: ${oldCombinedPath}`
@@ -6320,7 +6687,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
6320
6687
  }
6321
6688
 
6322
6689
  // src/vite/discovery/virtual-module-codegen.ts
6323
- import { dirname as dirname4, basename, join as join5 } from "node:path";
6690
+ import { dirname as dirname4, basename, join as join6 } from "node:path";
6324
6691
  function generateRoutesManifestModule(state) {
6325
6692
  const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
6326
6693
  if (hasManifest) {
@@ -6335,7 +6702,7 @@ function generateRoutesManifestModule(state) {
6335
6702
  /\.(tsx?|jsx?)$/,
6336
6703
  ""
6337
6704
  );
6338
- const genPath = join5(
6705
+ const genPath = join6(
6339
6706
  routerDir,
6340
6707
  `${routerBasename}.named-routes.gen.js`
6341
6708
  ).replaceAll("\\", "/");
@@ -6420,7 +6787,7 @@ function generatePerRouterModule(state, routerId) {
6420
6787
  /\.(tsx?|jsx?)$/,
6421
6788
  ""
6422
6789
  );
6423
- const genPath = join5(
6790
+ const genPath = join6(
6424
6791
  routerDir,
6425
6792
  `${routerBasename}.named-routes.gen.js`
6426
6793
  ).replaceAll("\\", "/");
@@ -6447,13 +6814,13 @@ function generatePerRouterModule(state, routerId) {
6447
6814
  }
6448
6815
 
6449
6816
  // src/vite/discovery/bundle-postprocess.ts
6450
- import { resolve as resolve9 } from "node:path";
6451
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7 } from "node:fs";
6817
+ import { resolve as resolve10 } from "node:path";
6818
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync8 } from "node:fs";
6452
6819
  function postprocessBundle(state) {
6453
6820
  const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
6454
6821
  const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
6455
6822
  if (!hasPrerenderData && !hasStaticData) return;
6456
- const rscEntryPath = resolve9(
6823
+ const rscEntryPath = resolve10(
6457
6824
  state.projectRoot,
6458
6825
  "dist/rsc",
6459
6826
  state.rscEntryFileName ?? "index.js"
@@ -6474,9 +6841,9 @@ function postprocessBundle(state) {
6474
6841
  ];
6475
6842
  for (const target of evictionTargets) {
6476
6843
  for (const info of target.infos) {
6477
- const chunkPath = resolve9(state.projectRoot, "dist/rsc", info.fileName);
6844
+ const chunkPath = resolve10(state.projectRoot, "dist/rsc", info.fileName);
6478
6845
  try {
6479
- const code = readFileSync5(chunkPath, "utf-8");
6846
+ const code = readFileSync6(chunkPath, "utf-8");
6480
6847
  const result = evictHandlerCode(
6481
6848
  code,
6482
6849
  info.exports,
@@ -6484,7 +6851,7 @@ function postprocessBundle(state) {
6484
6851
  target.brand
6485
6852
  );
6486
6853
  if (result) {
6487
- writeFileSync4(chunkPath, result.code);
6854
+ writeFileSync5(chunkPath, result.code);
6488
6855
  const savedKB = (result.savedBytes / 1024).toFixed(1);
6489
6856
  console.log(
6490
6857
  `[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
@@ -6499,8 +6866,8 @@ function postprocessBundle(state) {
6499
6866
  }
6500
6867
  state.handlerChunkInfoMap.clear();
6501
6868
  state.staticHandlerChunkInfoMap.clear();
6502
- if (hasPrerenderData && existsSync7(rscEntryPath)) {
6503
- const rscCode = readFileSync5(rscEntryPath, "utf-8");
6869
+ if (hasPrerenderData && existsSync8(rscEntryPath)) {
6870
+ const rscCode = readFileSync6(rscEntryPath, "utf-8");
6504
6871
  if (!rscCode.includes("__prerender-manifest.js")) {
6505
6872
  try {
6506
6873
  let totalBytes = copyStagedBuildAssets(
@@ -6519,15 +6886,15 @@ function postprocessBundle(state) {
6519
6886
  `export default m;`,
6520
6887
  ""
6521
6888
  ].join("\n");
6522
- const manifestPath = resolve9(
6889
+ const manifestPath = resolve10(
6523
6890
  state.projectRoot,
6524
6891
  "dist/rsc/__prerender-manifest.js"
6525
6892
  );
6526
- writeFileSync4(manifestPath, manifestCode);
6893
+ writeFileSync5(manifestPath, manifestCode);
6527
6894
  totalBytes += Buffer.byteLength(manifestCode);
6528
6895
  const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
6529
6896
  `;
6530
- writeFileSync4(rscEntryPath, injection + rscCode);
6897
+ writeFileSync5(rscEntryPath, injection + rscCode);
6531
6898
  const totalKB = (totalBytes / 1024).toFixed(1);
6532
6899
  console.log(
6533
6900
  `[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
@@ -6539,8 +6906,8 @@ function postprocessBundle(state) {
6539
6906
  }
6540
6907
  }
6541
6908
  }
6542
- if (hasStaticData && existsSync7(rscEntryPath)) {
6543
- const rscCode = readFileSync5(rscEntryPath, "utf-8");
6909
+ if (hasStaticData && existsSync8(rscEntryPath)) {
6910
+ const rscCode = readFileSync6(rscEntryPath, "utf-8");
6544
6911
  if (!rscCode.includes("__static-manifest.js")) {
6545
6912
  try {
6546
6913
  const manifestEntries = [];
@@ -6557,15 +6924,15 @@ function postprocessBundle(state) {
6557
6924
  }
6558
6925
  const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
6559
6926
  `;
6560
- const manifestPath = resolve9(
6927
+ const manifestPath = resolve10(
6561
6928
  state.projectRoot,
6562
6929
  "dist/rsc/__static-manifest.js"
6563
6930
  );
6564
- writeFileSync4(manifestPath, manifestCode);
6931
+ writeFileSync5(manifestPath, manifestCode);
6565
6932
  totalBytes += Buffer.byteLength(manifestCode);
6566
6933
  const injection = `import "./__static-manifest.js";
6567
6934
  `;
6568
- writeFileSync4(rscEntryPath, injection + rscCode);
6935
+ writeFileSync5(rscEntryPath, injection + rscCode);
6569
6936
  const totalKB = (totalBytes / 1024).toFixed(1);
6570
6937
  console.log(
6571
6938
  `[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
@@ -6580,7 +6947,7 @@ function postprocessBundle(state) {
6580
6947
  }
6581
6948
 
6582
6949
  // src/vite/discovery/gate-state.ts
6583
- function createDiscoveryGate(s, debug11) {
6950
+ function createDiscoveryGate(s, debug12) {
6584
6951
  let gatePending = false;
6585
6952
  let gateResolver = () => {
6586
6953
  };
@@ -6589,15 +6956,15 @@ function createDiscoveryGate(s, debug11) {
6589
6956
  let pendingEvents = false;
6590
6957
  const beginGate = () => {
6591
6958
  if (gatePending) return;
6592
- s.discoveryDone = new Promise((resolve12) => {
6593
- gateResolver = resolve12;
6959
+ s.discoveryDone = new Promise((resolve13) => {
6960
+ gateResolver = resolve13;
6594
6961
  });
6595
6962
  gatePending = true;
6596
6963
  };
6597
6964
  const resolveGate = () => {
6598
6965
  if (!gatePending) return;
6599
6966
  if (inProgress || queued || pendingEvents) {
6600
- debug11?.(
6967
+ debug12?.(
6601
6968
  "hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
6602
6969
  inProgress,
6603
6970
  queued,
@@ -6606,7 +6973,7 @@ function createDiscoveryGate(s, debug11) {
6606
6973
  return;
6607
6974
  }
6608
6975
  gatePending = false;
6609
- debug11?.("hmr: discoveryDone resolved");
6976
+ debug12?.("hmr: discoveryDone resolved");
6610
6977
  gateResolver();
6611
6978
  };
6612
6979
  const noteRouteEvent = () => {
@@ -6616,7 +6983,7 @@ function createDiscoveryGate(s, debug11) {
6616
6983
  const runRefreshCycle = async (work) => {
6617
6984
  if (inProgress) {
6618
6985
  queued = true;
6619
- debug11?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
6986
+ debug12?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
6620
6987
  return;
6621
6988
  }
6622
6989
  pendingEvents = false;
@@ -6627,16 +6994,16 @@ function createDiscoveryGate(s, debug11) {
6627
6994
  inProgress = false;
6628
6995
  if (queued) {
6629
6996
  queued = false;
6630
- debug11?.("hmr: consuming queued rediscovery");
6997
+ debug12?.("hmr: consuming queued rediscovery");
6631
6998
  runRefreshCycle(work).catch((err) => {
6632
- debug11?.(
6999
+ debug12?.(
6633
7000
  "hmr: queued cycle rejected \u2014 releasing gate (%s)",
6634
7001
  err instanceof Error ? err.message : String(err)
6635
7002
  );
6636
7003
  resolveGate();
6637
7004
  });
6638
7005
  } else if (pendingEvents) {
6639
- debug11?.(
7006
+ debug12?.(
6640
7007
  "hmr: holding gate for pending events (debounce not yet fired)"
6641
7008
  );
6642
7009
  } else {
@@ -6682,15 +7049,15 @@ function selectForwardableResolvePlugins(plugins) {
6682
7049
  }
6683
7050
  function pickForwardedRunnerConfig(config) {
6684
7051
  const r = config.resolve ?? {};
6685
- const resolve12 = {};
6686
- if (r.alias !== void 0) resolve12.alias = r.alias;
6687
- if (r.dedupe !== void 0) resolve12.dedupe = r.dedupe;
6688
- if (r.conditions !== void 0) resolve12.conditions = r.conditions;
6689
- if (r.mainFields !== void 0) resolve12.mainFields = r.mainFields;
6690
- if (r.extensions !== void 0) resolve12.extensions = r.extensions;
7052
+ const resolve13 = {};
7053
+ if (r.alias !== void 0) resolve13.alias = r.alias;
7054
+ if (r.dedupe !== void 0) resolve13.dedupe = r.dedupe;
7055
+ if (r.conditions !== void 0) resolve13.conditions = r.conditions;
7056
+ if (r.mainFields !== void 0) resolve13.mainFields = r.mainFields;
7057
+ if (r.extensions !== void 0) resolve13.extensions = r.extensions;
6691
7058
  if (r.preserveSymlinks !== void 0)
6692
- resolve12.preserveSymlinks = r.preserveSymlinks;
6693
- if (r.tsconfigPaths !== void 0) resolve12.tsconfigPaths = r.tsconfigPaths;
7059
+ resolve13.preserveSymlinks = r.preserveSymlinks;
7060
+ if (r.tsconfigPaths !== void 0) resolve13.tsconfigPaths = r.tsconfigPaths;
6694
7061
  const userOxc = config.oxc;
6695
7062
  const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
6696
7063
  const oxc = userOxc && typeof userOxc === "object" ? {
@@ -6698,13 +7065,14 @@ function pickForwardedRunnerConfig(config) {
6698
7065
  jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
6699
7066
  } : { jsx: { runtime: "automatic", importSource: "react" } };
6700
7067
  return {
6701
- resolve: resolve12,
7068
+ resolve: resolve13,
6702
7069
  define: config.define,
6703
7070
  oxc
6704
7071
  };
6705
7072
  }
6706
7073
 
6707
7074
  // src/vite/router-discovery.ts
7075
+ init_debug();
6708
7076
  var debugDiscovery = createRangoDebugger(NS.discovery);
6709
7077
  var debugRoutes = createRangoDebugger(NS.routes);
6710
7078
  var debugBuild = createRangoDebugger(NS.build);
@@ -6754,6 +7122,20 @@ async function createTempRscServer(state, options = {}) {
6754
7122
  // hashClientRefs only in build mode — production bundles need hashed refs
6755
7123
  ...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
6756
7124
  createVersionPlugin(),
7125
+ // Before the stub plugin, so "virtual:entry-ssr" resolves to the real
7126
+ // SSR entry when the shell endpoint needs it (see the option doc).
7127
+ ...options.realSsrEntry ? [
7128
+ {
7129
+ name: "@rangojs/router:temp-real-ssr-entry",
7130
+ enforce: "pre",
7131
+ resolveId(id) {
7132
+ return id === "virtual:entry-ssr" ? "\0rango-temp-real-ssr-entry" : null;
7133
+ },
7134
+ load(id) {
7135
+ return id === "\0rango-temp-real-ssr-entry" ? getVirtualEntrySSR(state.opts?.headScripts) : null;
7136
+ }
7137
+ }
7138
+ ] : [],
6757
7139
  createVirtualStubPlugin(),
6758
7140
  createCloudflareProtocolStubPlugin(),
6759
7141
  // Dev prerender must use dev-mode IDs (path-based) to match the workerd
@@ -6777,7 +7159,7 @@ async function resolveBuildEnv(option, factoryCtx) {
6777
7159
  }
6778
7160
  try {
6779
7161
  const userRequire = createRequire3(
6780
- resolve10(factoryCtx.root, "package.json")
7162
+ resolve11(factoryCtx.root, "package.json")
6781
7163
  );
6782
7164
  const wranglerPath = userRequire.resolve("wrangler");
6783
7165
  const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
@@ -6814,6 +7196,12 @@ async function acquireBuildEnv(s, command, mode) {
6814
7196
  globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
6815
7197
  return true;
6816
7198
  }
7199
+ function resetPrerenderCollection(s) {
7200
+ s.prerenderManifestEntries = null;
7201
+ s.staticManifestEntries = null;
7202
+ s.shellCandidates = null;
7203
+ s.prerenderPayloadValues = null;
7204
+ }
6817
7205
  async function releaseBuildEnv(s) {
6818
7206
  if (s.buildEnvDispose) {
6819
7207
  try {
@@ -6878,8 +7266,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
6878
7266
  s.devServer = server;
6879
7267
  server.middlewares.use(internalDebugNoCacheMiddleware());
6880
7268
  let resolveDiscovery;
6881
- const discoveryPromise = new Promise((resolve12) => {
6882
- resolveDiscovery = resolve12;
7269
+ const discoveryPromise = new Promise((resolve13) => {
7270
+ resolveDiscovery = resolve13;
6883
7271
  });
6884
7272
  const gate = createDiscoveryGate(s, debugDiscovery);
6885
7273
  const beginDiscoveryGate = gate.beginGate;
@@ -6969,7 +7357,11 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
6969
7357
  );
6970
7358
  try {
6971
7359
  prerenderTempServer = await createTempRscServer(s, {
6972
- cacheDir: "node_modules/.vite_prerender"
7360
+ cacheDir: "node_modules/.vite_prerender",
7361
+ // The dev /__rsc_shell endpoint drives captureShellHTML in this
7362
+ // server's SSR realm; the entry is only imported when a shell
7363
+ // capture runs, so discovery cost is unchanged.
7364
+ realSsrEntry: true
6973
7365
  });
6974
7366
  const tempRscEnv = prerenderTempServer.environments?.rsc;
6975
7367
  if (tempRscEnv?.runner) {
@@ -7301,6 +7693,162 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
7301
7693
  res.end("No prerender match");
7302
7694
  logResult(404, "no match");
7303
7695
  });
7696
+ server.middlewares.use("/__rsc_shell", async (req, res) => {
7697
+ await s.discoveryDone;
7698
+ const url = new URL(req.url ?? "", "http://localhost");
7699
+ const pathname = url.searchParams.get("pathname");
7700
+ const routeName = url.searchParams.get("routeName");
7701
+ const version = url.searchParams.get("version");
7702
+ const ttlRaw = url.searchParams.get("ttl");
7703
+ if (!pathname || !routeName || !version || !ttlRaw) {
7704
+ res.statusCode = 400;
7705
+ res.end("Missing pathname/routeName/version/ttl");
7706
+ return;
7707
+ }
7708
+ const ttl = Number(ttlRaw);
7709
+ const swrRaw = url.searchParams.get("swr");
7710
+ const swr = swrRaw === null ? void 0 : Number(swrRaw);
7711
+ const tagsRaw = url.searchParams.get("tags");
7712
+ const tags = tagsRaw ? tagsRaw.split(",") : void 0;
7713
+ const maxSnapshotBytesRaw = url.searchParams.get("maxSnapshotBytes");
7714
+ const maxSnapshotBytes = maxSnapshotBytesRaw === null ? void 0 : Number(maxSnapshotBytesRaw);
7715
+ const captureTimeout = normalizeCaptureTimeout(
7716
+ Number(url.searchParams.get("captureTimeout"))
7717
+ );
7718
+ const rscEnvMain = server.environments?.rsc;
7719
+ let rscRealm = null;
7720
+ let ssrRealm = null;
7721
+ let ssrEntryId;
7722
+ if (rscEnvMain?.runner && s.resolvedEntryPath) {
7723
+ try {
7724
+ await rscEnvMain.runner.import(s.resolvedEntryPath);
7725
+ } catch (err) {
7726
+ res.statusCode = 500;
7727
+ res.end(`Shell capture module refresh failed: ${err.message}`);
7728
+ return;
7729
+ }
7730
+ rscRealm = rscEnvMain;
7731
+ ssrRealm = server.environments?.ssr;
7732
+ ssrEntryId = server.environments?.ssr?.config?.build?.rollupOptions?.input?.index ?? VIRTUAL_IDS.ssr;
7733
+ } else {
7734
+ const tempRscEnv = await getOrCreateTempServer();
7735
+ if (tempRscEnv) {
7736
+ try {
7737
+ await importEntryAndRegistry(tempRscEnv);
7738
+ } catch (err) {
7739
+ res.statusCode = 500;
7740
+ res.end(`Shell capture module refresh failed: ${err.message}`);
7741
+ return;
7742
+ }
7743
+ }
7744
+ rscRealm = tempRscEnv;
7745
+ ssrRealm = prerenderTempServer?.environments?.ssr;
7746
+ ssrEntryId = "virtual:entry-ssr";
7747
+ }
7748
+ if (!rscRealm?.runner || !ssrRealm?.runner) {
7749
+ res.statusCode = 503;
7750
+ res.end("Shell capture runners not available");
7751
+ return;
7752
+ }
7753
+ let registry = null;
7754
+ try {
7755
+ const serverMod = await rscRealm.runner.import(
7756
+ "@rangojs/router/server"
7757
+ );
7758
+ registry = serverMod.RouterRegistry ?? null;
7759
+ } catch {
7760
+ registry = null;
7761
+ }
7762
+ if (!registry || registry.size === 0) {
7763
+ res.statusCode = 503;
7764
+ res.end("Shell capture registry not available");
7765
+ return;
7766
+ }
7767
+ const cacheKey = `shell|${pathname}|r=${routeName}|t=${ttl}|s=${swr ?? ""}|g=${(tags ?? []).join("+")}|c=${captureTimeout ?? ""}|v=${version}`;
7768
+ for (const [, routerInstance] of registry) {
7769
+ if (typeof routerInstance.match !== "function") continue;
7770
+ const cached = devPrerenderCache.get(routerInstance, cacheKey);
7771
+ if (cached !== void 0) {
7772
+ res.setHeader("content-type", "application/json");
7773
+ res.setHeader("x-rango-shell-dev", "HIT");
7774
+ res.end(cached);
7775
+ return;
7776
+ }
7777
+ }
7778
+ if (s.devServerOrigin) {
7779
+ try {
7780
+ const probe = await fetch(
7781
+ `${s.devServerOrigin}/__rsc_prerender?pathname=${encodeURIComponent(pathname)}&routeName=${encodeURIComponent(routeName)}`,
7782
+ { signal: AbortSignal.timeout(DEV_SHELL_PROBE_TIMEOUT_MS) }
7783
+ );
7784
+ if (!probe.ok) {
7785
+ res.statusCode = 404;
7786
+ res.end("Route is not prerenderable");
7787
+ return;
7788
+ }
7789
+ } catch {
7790
+ res.statusCode = 404;
7791
+ res.end("Prerender pre-flight failed");
7792
+ return;
7793
+ }
7794
+ }
7795
+ for (const [, routerInstance] of registry) {
7796
+ if (typeof routerInstance.match !== "function") continue;
7797
+ try {
7798
+ const ssrModule = await ssrRealm.runner.import(ssrEntryId);
7799
+ if (typeof ssrModule?.captureShellHTML !== "function") {
7800
+ res.statusCode = 404;
7801
+ res.end("SSR entry has no captureShellHTML");
7802
+ return;
7803
+ }
7804
+ const captureMod = await rscRealm.runner.import(
7805
+ "@rangojs/router/build/shell-capture"
7806
+ );
7807
+ const result = await captureMod.captureShellForBuild({
7808
+ router: routerInstance,
7809
+ urlPath: pathname,
7810
+ routeName,
7811
+ key: `${pathname}:shell`,
7812
+ ttl,
7813
+ swr,
7814
+ tags,
7815
+ maxSnapshotBytes,
7816
+ captureTimeout,
7817
+ buildEnv: s.resolvedBuildEnv,
7818
+ buildVersion: version,
7819
+ captureShellHTML: ssrModule.captureShellHTML,
7820
+ debug: !!debugDiscovery
7821
+ });
7822
+ if (result.outcome === "route-mismatch") continue;
7823
+ if (result.outcome !== "stored" || !result.entry) {
7824
+ res.statusCode = 404;
7825
+ res.end(`Shell capture ${result.outcome}`);
7826
+ return;
7827
+ }
7828
+ const body = JSON.stringify({
7829
+ entry: result.entry,
7830
+ ttl,
7831
+ swr,
7832
+ tags: result.tags,
7833
+ routeName
7834
+ });
7835
+ devPrerenderCache.set(routerInstance, cacheKey, body);
7836
+ res.setHeader("content-type", "application/json");
7837
+ res.setHeader("x-rango-shell-dev", "MISS");
7838
+ res.end(body);
7839
+ return;
7840
+ } catch (err) {
7841
+ console.warn(
7842
+ `[rango] Dev shell capture error for ${pathname} (route keeps runtime capture): ${err.message}`
7843
+ );
7844
+ res.statusCode = 404;
7845
+ res.end(`Shell capture error: ${err.message}`);
7846
+ return;
7847
+ }
7848
+ }
7849
+ res.statusCode = 404;
7850
+ res.end("No router matched");
7851
+ });
7304
7852
  if (opts?.staticRouteTypesGeneration !== false) {
7305
7853
  const isGeneratedRouteFile = (filePath) => filePath.endsWith(".gen.ts") && (filePath.includes("named-routes.gen.ts") || filePath.includes("urls.gen.ts"));
7306
7854
  const regenerateGeneratedRouteFiles = () => {
@@ -7470,7 +8018,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
7470
8018
  }
7471
8019
  const inRecoveryMode = !!s.lastDiscoveryError;
7472
8020
  try {
7473
- const source = readFileSync6(filePath, "utf-8");
8021
+ const source = readFileSync7(filePath, "utf-8");
7474
8022
  const trimmed = source.trimStart();
7475
8023
  const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
7476
8024
  if (!inRecoveryMode && isUseClient) return;
@@ -7501,7 +8049,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
7501
8049
  if (hasCreateRouter) {
7502
8050
  const nestedRouterConflict = findNestedRouterConflict([
7503
8051
  ...s.cachedRouterFiles ?? [],
7504
- resolve10(filePath)
8052
+ resolve11(filePath)
7505
8053
  ]);
7506
8054
  if (nestedRouterConflict) {
7507
8055
  server.config.logger.error(
@@ -7551,8 +8099,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
7551
8099
  const buildStartTime = performance.now();
7552
8100
  debugDiscovery?.("build: start (env=%s)", this.environment?.name ?? "?");
7553
8101
  resetStagedBuildAssets(s.projectRoot);
7554
- s.prerenderManifestEntries = null;
7555
- s.staticManifestEntries = null;
8102
+ resetPrerenderCollection(s);
7556
8103
  await timed(
7557
8104
  debugDiscovery,
7558
8105
  "build acquireBuildEnv",
@@ -7607,20 +8154,59 @@ ${details}`,
7607
8154
  );
7608
8155
  } finally {
7609
8156
  delete globalThis.__rscRouterDiscoveryActive;
7610
- if (tempServer) {
7611
- await timed(
7612
- debugDiscovery,
7613
- "build tempServer.close",
7614
- () => tempServer.close()
7615
- );
8157
+ if (tempServer && s.shellCandidates?.length) {
8158
+ s.shellPhaseTempServer = tempServer;
8159
+ } else {
8160
+ if (tempServer) {
8161
+ await timed(
8162
+ debugDiscovery,
8163
+ "build tempServer.close",
8164
+ () => tempServer.close()
8165
+ );
8166
+ }
8167
+ await releaseBuildEnv(s);
7616
8168
  }
7617
- await releaseBuildEnv(s);
7618
8169
  debugDiscovery?.(
7619
8170
  "build discovery done (%sms)",
7620
8171
  (performance.now() - buildStartTime).toFixed(1)
7621
8172
  );
7622
8173
  }
7623
8174
  },
8175
+ // Post-build PPR shell capture (producer B, #699): runs after EVERY
8176
+ // environment bundle is written — the shell prelude embeds built client
8177
+ // asset URLs (bootstrap entry), which do not exist at buildStart. The
8178
+ // kept temp server and the buildEnv were deferred AS A PAIR in
8179
+ // buildStart's finally; this finally is the pair's success-path owner
8180
+ // (buildEnd below owns the aborted-build path) — the phase itself is a
8181
+ // pure producer and tears down only the globals it installs.
8182
+ buildApp: {
8183
+ order: "post",
8184
+ async handler(builder) {
8185
+ try {
8186
+ await runShellPrerenderPhase(s, builder);
8187
+ } finally {
8188
+ if (s.isBuildMode) {
8189
+ const tempServer = s.shellPhaseTempServer;
8190
+ s.shellPhaseTempServer = null;
8191
+ if (tempServer) await tempServer.close();
8192
+ await releaseBuildEnv(s);
8193
+ }
8194
+ }
8195
+ }
8196
+ },
8197
+ // An environment build failure aborts the builder before the buildApp
8198
+ // post hook — never leak the kept temp server (open handles hang the CLI)
8199
+ // or the deferred buildEnv (a live miniflare proxy).
8200
+ async buildEnd(error) {
8201
+ if (!error || !s.shellPhaseTempServer) return;
8202
+ const tempServer = s.shellPhaseTempServer;
8203
+ s.shellPhaseTempServer = null;
8204
+ try {
8205
+ await tempServer.close();
8206
+ } finally {
8207
+ await releaseBuildEnv(s);
8208
+ }
8209
+ },
7624
8210
  // Suppress vite's HMR cascade for our own gen-file writes.
7625
8211
  //
7626
8212
  // After every cf HMR cycle, refreshTempRscEnv → writeRouteTypesFiles
@@ -7785,6 +8371,7 @@ ${details}`,
7785
8371
  }
7786
8372
 
7787
8373
  // src/vite/rango.ts
8374
+ init_debug();
7788
8375
  var debugConfig = createRangoDebugger(NS.config);
7789
8376
  async function rango(options) {
7790
8377
  const rangoStart = performance.now();
@@ -7929,14 +8516,14 @@ async function rango(options) {
7929
8516
  name: "@rangojs/router:auto-discover",
7930
8517
  config(userConfig) {
7931
8518
  if (routerRef.path) return;
7932
- const root = userConfig.root ? resolve11(process.cwd(), userConfig.root) : process.cwd();
8519
+ const root = userConfig.root ? resolve12(process.cwd(), userConfig.root) : process.cwd();
7933
8520
  const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
7934
8521
  const bulletList = (files) => files.map((f) => " - " + toRootRelative(f)).join("\n");
7935
8522
  if (explicitHostRouter) {
7936
8523
  routerRef.path = normalizeHostRouterEntry(
7937
8524
  explicitHostRouter,
7938
8525
  root,
7939
- existsSync8
8526
+ existsSync9
7940
8527
  );
7941
8528
  routerRef.kind = "host";
7942
8529
  return;
@@ -8117,7 +8704,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
8117
8704
  if (!file.endsWith(".tsx") && !file.endsWith(".ts") && !file.endsWith(".jsx") && !file.endsWith(".js"))
8118
8705
  return;
8119
8706
  try {
8120
- const source = readFileSync7(file, "utf-8");
8707
+ const source = readFileSync8(file, "utf-8");
8121
8708
  if (hasUseClientDirective(source)) {
8122
8709
  return [];
8123
8710
  }
@@ -8144,7 +8731,8 @@ If this is a multi-app host router, export a createHostRouter() instance and set
8144
8731
  preset,
8145
8732
  prerenderOnError: options?.prerender?.onError,
8146
8733
  discovery: options?.discovery,
8147
- clientChunkCtx
8734
+ clientChunkCtx,
8735
+ headScripts: resolvedOptions.headScripts
8148
8736
  })
8149
8737
  );
8150
8738
  if (preset === "vercel") {
@@ -8168,7 +8756,7 @@ function poke() {
8168
8756
  apply: "serve",
8169
8757
  configureServer(server) {
8170
8758
  const stdin = process.stdin;
8171
- const debug11 = process.env.RANGO_POKE_DEBUG === "1";
8759
+ const debug12 = process.env.RANGO_POKE_DEBUG === "1";
8172
8760
  const triggerReload = (source) => {
8173
8761
  server.hot.send({ type: "full-reload", path: "*" });
8174
8762
  server.config.logger.info(` browser reload (${source})`, {
@@ -8201,7 +8789,7 @@ function poke() {
8201
8789
  lines.pop();
8202
8790
  return lines;
8203
8791
  };
8204
- if (debug11) {
8792
+ if (debug12) {
8205
8793
  server.config.logger.info(
8206
8794
  ` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
8207
8795
  { timestamp: true }
@@ -8214,7 +8802,7 @@ function poke() {
8214
8802
  );
8215
8803
  }
8216
8804
  const onData = (data) => {
8217
- if (debug11) {
8805
+ if (debug12) {
8218
8806
  server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
8219
8807
  timestamp: true
8220
8808
  });