vinext 0.1.4 → 0.1.5

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 (126) hide show
  1. package/dist/build/css-url-assets.d.ts +1 -1
  2. package/dist/build/css-url-assets.js +9 -7
  3. package/dist/build/prerender.js +2 -1
  4. package/dist/cache/cache-adapters-virtual.js +1 -1
  5. package/dist/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +1 -1
  6. package/dist/entries/app-rsc-entry.js +24 -20
  7. package/dist/entries/pages-server-entry.js +2 -1
  8. package/dist/index.js +187 -146
  9. package/dist/plugins/css-data-url.js +30 -26
  10. package/dist/plugins/extensionless-dynamic-import.js +27 -24
  11. package/dist/plugins/import-meta-url.js +21 -15
  12. package/dist/plugins/instrumentation-client.js +1 -1
  13. package/dist/plugins/middleware-server-only.js +7 -6
  14. package/dist/plugins/og-assets.js +48 -46
  15. package/dist/plugins/optimize-imports.js +9 -3
  16. package/dist/plugins/remove-console.d.ts +7 -1
  17. package/dist/plugins/remove-console.js +4 -1
  18. package/dist/plugins/require-context.js +21 -20
  19. package/dist/plugins/strip-server-exports.d.ts +7 -1
  20. package/dist/plugins/strip-server-exports.js +4 -1
  21. package/dist/server/app-bfcache-identity.d.ts +26 -0
  22. package/dist/server/app-bfcache-identity.js +127 -0
  23. package/dist/server/app-browser-entry.js +14 -11
  24. package/dist/server/app-browser-navigation-controller.js +1 -1
  25. package/dist/server/app-browser-state.d.ts +2 -21
  26. package/dist/server/app-browser-state.js +4 -128
  27. package/dist/server/app-browser-stream.js +1 -1
  28. package/dist/server/app-browser-visible-commit.js +3 -2
  29. package/dist/server/app-fallback-renderer.d.ts +1 -1
  30. package/dist/server/app-layout-param-observation.d.ts +1 -1
  31. package/dist/server/app-layout-param-observation.js +1 -1
  32. package/dist/server/app-middleware.js +2 -1
  33. package/dist/server/app-page-boundary-render.d.ts +1 -1
  34. package/dist/server/app-page-boundary.js +1 -1
  35. package/dist/server/app-page-cache-finalizer.d.ts +62 -0
  36. package/dist/server/app-page-cache-finalizer.js +122 -0
  37. package/dist/server/app-page-cache-render.d.ts +2 -2
  38. package/dist/server/app-page-cache-render.js +1 -1
  39. package/dist/server/app-page-cache.d.ts +2 -53
  40. package/dist/server/app-page-cache.js +5 -131
  41. package/dist/server/app-page-dispatch.d.ts +2 -2
  42. package/dist/server/app-page-dispatch.js +10 -8
  43. package/dist/server/app-page-probe.js +3 -2
  44. package/dist/server/app-page-render-observation.js +2 -2
  45. package/dist/server/app-page-render.d.ts +3 -3
  46. package/dist/server/app-page-render.js +3 -2
  47. package/dist/server/app-page-stream.d.ts +2 -9
  48. package/dist/server/app-page-stream.js +1 -35
  49. package/dist/server/app-request-context.d.ts +1 -2
  50. package/dist/server/app-request-context.js +2 -1
  51. package/dist/server/app-route-handler-dispatch.js +3 -2
  52. package/dist/server/app-route-handler-execution.d.ts +1 -1
  53. package/dist/server/app-route-handler-execution.js +1 -1
  54. package/dist/server/app-route-handler-response.d.ts +1 -1
  55. package/dist/server/app-router-entry.js +2 -1
  56. package/dist/server/app-rsc-handler.js +22 -16
  57. package/dist/server/app-rsc-response-finalizer.js +1 -1
  58. package/dist/server/app-server-action-execution.d.ts +1 -1
  59. package/dist/server/app-server-action-execution.js +5 -4
  60. package/dist/server/app-ssr-entry.d.ts +1 -1
  61. package/dist/server/app-ssr-entry.js +11 -9
  62. package/dist/server/app-ssr-router-instance.d.ts +6 -0
  63. package/dist/server/app-ssr-router-instance.js +24 -0
  64. package/dist/server/app-ssr-stream.js +1 -1
  65. package/dist/server/artifact-compatibility.js +1 -1
  66. package/dist/server/client-reuse-manifest.js +1 -1
  67. package/dist/server/defer-until-stream-consumed.d.ts +7 -0
  68. package/dist/server/defer-until-stream-consumed.js +34 -0
  69. package/dist/server/dev-server.js +1 -1
  70. package/dist/server/instrumentation.js +1 -1
  71. package/dist/server/isr-cache.d.ts +1 -1
  72. package/dist/server/isr-cache.js +1 -1
  73. package/dist/server/isr-decision.d.ts +1 -1
  74. package/dist/server/middleware-matcher.js +8 -6
  75. package/dist/server/middleware-runtime.js +2 -2
  76. package/dist/server/open-redirect.d.ts +12 -0
  77. package/dist/server/open-redirect.js +21 -0
  78. package/dist/server/pages-page-data.d.ts +1 -1
  79. package/dist/server/pages-page-response.d.ts +1 -1
  80. package/dist/server/pages-page-response.js +2 -2
  81. package/dist/server/prod-server.js +2 -1
  82. package/dist/server/request-pipeline.d.ts +1 -24
  83. package/dist/server/request-pipeline.js +1 -33
  84. package/dist/server/seed-cache.d.ts +1 -1
  85. package/dist/shims/cache-handler.d.ts +106 -0
  86. package/dist/shims/cache-handler.js +176 -0
  87. package/dist/shims/cache-request-state.d.ts +47 -0
  88. package/dist/shims/cache-request-state.js +126 -0
  89. package/dist/shims/cache-runtime.d.ts +2 -2
  90. package/dist/shims/cache-runtime.js +3 -14
  91. package/dist/shims/cache.d.ts +3 -231
  92. package/dist/shims/cache.js +17 -383
  93. package/dist/shims/cdn-cache.d.ts +1 -1
  94. package/dist/shims/cdn-cache.js +1 -1
  95. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  96. package/dist/shims/error-boundary-navigation.js +44 -0
  97. package/dist/shims/error-boundary.js +10 -8
  98. package/dist/shims/error.js +2 -1
  99. package/dist/shims/fetch-cache.js +1 -1
  100. package/dist/shims/form.js +1 -1
  101. package/dist/shims/image.js +67 -9
  102. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -0
  103. package/dist/shims/internal/app-page-props-cache-key.js +16 -0
  104. package/dist/shims/internal/navigation-untracked.js +2 -1
  105. package/dist/shims/layout-segment-context.d.ts +1 -1
  106. package/dist/shims/layout-segment-context.js +2 -1
  107. package/dist/shims/link.js +2 -2
  108. package/dist/shims/navigation-context-state.d.ts +40 -0
  109. package/dist/shims/navigation-context-state.js +116 -0
  110. package/dist/shims/navigation-errors.d.ts +55 -0
  111. package/dist/shims/navigation-errors.js +110 -0
  112. package/dist/shims/navigation-server.d.ts +3 -0
  113. package/dist/shims/navigation-server.js +3 -0
  114. package/dist/shims/navigation-state.d.ts +1 -2
  115. package/dist/shims/navigation-state.js +2 -1
  116. package/dist/shims/navigation.d.ts +3 -291
  117. package/dist/shims/navigation.js +14 -445
  118. package/dist/shims/navigation.react-server.d.ts +2 -2
  119. package/dist/shims/navigation.react-server.js +3 -1
  120. package/dist/shims/request-state-types.d.ts +3 -3
  121. package/dist/shims/script.js +1 -1
  122. package/dist/shims/slot.js +3 -1
  123. package/dist/shims/unified-request-context.d.ts +2 -2
  124. package/dist/utils/virtual-module.d.ts +5 -0
  125. package/dist/utils/virtual-module.js +0 -0
  126. package/package.json +5 -1
@@ -1,3 +1,4 @@
1
+ import { VIRTUAL_MODULE_ID_RE } from "../utils/virtual-module.js";
1
2
  import { collectBindingNames, forEachAstChild, hasRange, isAstRecord, isIdentifierNamed, nodeArray } from "./ast-utils.js";
2
3
  import { tryRealpathSync } from "../build/ssr-manifest.js";
3
4
  import path from "node:path";
@@ -32,18 +33,26 @@ function createImportMetaUrlPlugin(options) {
32
33
  outputDirs = [config.build.outDir];
33
34
  rootPaths = createRootPaths(root, { outputDirs });
34
35
  },
35
- transform(code, id) {
36
- if (!mayContainSourceIdentityToken(code)) return null;
37
- const paths = getRootPaths();
38
- if (!paths) return null;
39
- const canonicalId = transformableModuleCanonicalId(cleanModuleId(id), paths);
40
- if (!canonicalId) return null;
41
- const rewritten = rewriteCanonicalSourceIdentity(code, canonicalId, paths, this.environment?.name === "client" ? "client" : "server");
42
- if (!rewritten) return null;
43
- return {
44
- code: rewritten.code,
45
- map: rewritten.map
46
- };
36
+ transform: {
37
+ filter: {
38
+ id: {
39
+ include: /\.(?:[cm]?[jt]s|[jt]sx)(?:\?.*)?$/,
40
+ exclude: [/[\\/]node_modules[\\/]/, VIRTUAL_MODULE_ID_RE]
41
+ },
42
+ code: /import\.meta(?:\.|\?\.)url|__filename|__dirname/
43
+ },
44
+ handler(code, id) {
45
+ const paths = getRootPaths();
46
+ if (!paths) return null;
47
+ const canonicalId = transformableModuleCanonicalId(cleanModuleId(id), paths);
48
+ if (!canonicalId) return null;
49
+ const rewritten = rewriteCanonicalSourceIdentity(code, canonicalId, paths, this.environment?.name === "client" ? "client" : "server");
50
+ if (!rewritten) return null;
51
+ return {
52
+ code: rewritten.code,
53
+ map: rewritten.map
54
+ };
55
+ }
47
56
  }
48
57
  };
49
58
  }
@@ -120,9 +129,6 @@ function mayContainImportMetaUrl(code) {
120
129
  function mayContainServerCjsGlobal(code) {
121
130
  return code.includes("__filename") || code.includes("__dirname");
122
131
  }
123
- function mayContainSourceIdentityToken(code) {
124
- return mayContainImportMetaUrl(code) || mayContainServerCjsGlobal(code);
125
- }
126
132
  function excludedRelativePrefixes(canonicalRoot, normalizedRoot, options) {
127
133
  const prefixes = new Set([
128
134
  ".next",
@@ -8,7 +8,7 @@ function createInstrumentationClientTransformPlugin(getInstrumentationClientPath
8
8
  transform(code, id) {
9
9
  const instrumentationClientPath = getInstrumentationClientPath();
10
10
  if (!instrumentationClientPath) return null;
11
- if (normalizePath(id.split("?", 1)[0]) !== normalizePath(instrumentationClientPath)) return null;
11
+ if (normalizePath(id.split("?", 1)[0]) !== instrumentationClientPath) return null;
12
12
  if (code.includes("__vinextInstrumentationClientStart")) return null;
13
13
  const ast = parseAst(code);
14
14
  let insertPos = 0;
@@ -1,3 +1,4 @@
1
+ import { normalizePathSeparators } from "../utils/path.js";
1
2
  //#region src/plugins/middleware-server-only.ts
2
3
  /**
3
4
  * Allow `import 'server-only'` from middleware (and any module reachable
@@ -44,16 +45,16 @@
44
45
  */
45
46
  function createMiddlewareServerOnlyPlugin(options) {
46
47
  const tainted = /* @__PURE__ */ new Set();
48
+ function canonicalizeId(id) {
49
+ const queryIndex = id.indexOf("?");
50
+ return normalizePathSeparators(queryIndex === -1 ? id : id.slice(0, queryIndex));
51
+ }
47
52
  function isTainted(id) {
48
53
  if (!id) return false;
49
- if (tainted.has(id)) return true;
50
- const queryIndex = id.indexOf("?");
51
- if (queryIndex !== -1) return tainted.has(id.slice(0, queryIndex));
52
- return false;
54
+ return tainted.has(canonicalizeId(id));
53
55
  }
54
56
  function addTainted(id) {
55
- const queryIndex = id.indexOf("?");
56
- tainted.add(queryIndex === -1 ? id : id.slice(0, queryIndex));
57
+ tainted.add(canonicalizeId(id));
57
58
  }
58
59
  return {
59
60
  name: "vinext:middleware-server-only",
@@ -25,54 +25,56 @@ function createOgInlineFetchAssetsPlugin() {
25
25
  buildStart() {
26
26
  if (isBuild) cache.clear();
27
27
  },
28
- async transform(code, id) {
29
- if (!code.includes("import.meta.url")) return null;
30
- const useCache = isBuild;
31
- const moduleDir = path.dirname(id);
32
- let newCode = code;
33
- let didReplace = false;
34
- const readAsBase64 = async (absPath) => {
35
- const cached = useCache ? cache.get(absPath) : void 0;
36
- if (cached !== void 0) return cached;
37
- try {
38
- const b64 = (await fs.promises.readFile(absPath)).toString("base64");
39
- if (useCache) cache.set(absPath, b64);
40
- return b64;
41
- } catch {
42
- return null;
28
+ transform: {
29
+ filter: { code: "import.meta.url" },
30
+ async handler(code, id) {
31
+ const useCache = isBuild;
32
+ const moduleDir = path.dirname(id);
33
+ let newCode = code;
34
+ let didReplace = false;
35
+ const readAsBase64 = async (absPath) => {
36
+ const cached = useCache ? cache.get(absPath) : void 0;
37
+ if (cached !== void 0) return cached;
38
+ try {
39
+ const b64 = (await fs.promises.readFile(absPath)).toString("base64");
40
+ if (useCache) cache.set(absPath, b64);
41
+ return b64;
42
+ } catch {
43
+ return null;
44
+ }
45
+ };
46
+ if (code.includes("fetch(")) for (const match of code.matchAll(/fetch\(\s*new URL\(\s*(["'])(\.[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)(?:\.then\(\s*(?:function\s*\([^)]*\)|\([^)]*\)\s*=>)\s*\{?\s*return\s+[^.]+\.arrayBuffer\(\)\s*;?\s*\}?\s*,?\s*\)|\.then\(\s*\([^)]*\)\s*=>\s*[^.]+\.arrayBuffer\(\)\s*,?\s*\))/g)) {
47
+ const fullMatch = match[0];
48
+ const relPath = match[2];
49
+ const fileBase64 = await readAsBase64(path.resolve(moduleDir, relPath));
50
+ if (fileBase64 === null) continue;
51
+ const inlined = [
52
+ `(function(){`,
53
+ `var b=${JSON.stringify(fileBase64)};`,
54
+ `var r=atob(b);`,
55
+ `var a=new Uint8Array(r.length);`,
56
+ `for(var i=0;i<r.length;i++)a[i]=r.charCodeAt(i);`,
57
+ `return Promise.resolve(a.buffer);`,
58
+ `})()`
59
+ ].join("");
60
+ newCode = newCode.replaceAll(fullMatch, inlined);
61
+ didReplace = true;
43
62
  }
44
- };
45
- if (code.includes("fetch(")) for (const match of code.matchAll(/fetch\(\s*new URL\(\s*(["'])(\.[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)(?:\.then\(\s*(?:function\s*\([^)]*\)|\([^)]*\)\s*=>)\s*\{?\s*return\s+[^.]+\.arrayBuffer\(\)\s*;?\s*\}?\s*,?\s*\)|\.then\(\s*\([^)]*\)\s*=>\s*[^.]+\.arrayBuffer\(\)\s*,?\s*\))/g)) {
46
- const fullMatch = match[0];
47
- const relPath = match[2];
48
- const fileBase64 = await readAsBase64(path.resolve(moduleDir, relPath));
49
- if (fileBase64 === null) continue;
50
- const inlined = [
51
- `(function(){`,
52
- `var b=${JSON.stringify(fileBase64)};`,
53
- `var r=atob(b);`,
54
- `var a=new Uint8Array(r.length);`,
55
- `for(var i=0;i<r.length;i++)a[i]=r.charCodeAt(i);`,
56
- `return Promise.resolve(a.buffer);`,
57
- `})()`
58
- ].join("");
59
- newCode = newCode.replaceAll(fullMatch, inlined);
60
- didReplace = true;
61
- }
62
- if (code.includes("readFileSync(")) for (const match of newCode.matchAll(/[a-zA-Z_$][a-zA-Z0-9_$]*\.readFileSync\(\s*(?:[a-zA-Z_$][a-zA-Z0-9_$]*\.)?fileURLToPath\(\s*new URL\(\s*(["'])(\.[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)\s*\)/g)) {
63
- const fullMatch = match[0];
64
- const relPath = match[2];
65
- const fileBase64 = await readAsBase64(path.resolve(moduleDir, relPath));
66
- if (fileBase64 === null) continue;
67
- const inlined = `Buffer.from(${JSON.stringify(fileBase64)},"base64")`;
68
- newCode = newCode.replaceAll(fullMatch, inlined);
69
- didReplace = true;
63
+ if (code.includes("readFileSync(")) for (const match of newCode.matchAll(/[a-zA-Z_$][a-zA-Z0-9_$]*\.readFileSync\(\s*(?:[a-zA-Z_$][a-zA-Z0-9_$]*\.)?fileURLToPath\(\s*new URL\(\s*(["'])(\.[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)\s*\)/g)) {
64
+ const fullMatch = match[0];
65
+ const relPath = match[2];
66
+ const fileBase64 = await readAsBase64(path.resolve(moduleDir, relPath));
67
+ if (fileBase64 === null) continue;
68
+ const inlined = `Buffer.from(${JSON.stringify(fileBase64)},"base64")`;
69
+ newCode = newCode.replaceAll(fullMatch, inlined);
70
+ didReplace = true;
71
+ }
72
+ if (!didReplace) return null;
73
+ return {
74
+ code: newCode,
75
+ map: null
76
+ };
70
77
  }
71
- if (!didReplace) return null;
72
- return {
73
- code: newCode,
74
- map: null
75
- };
76
78
  }
77
79
  };
78
80
  }
@@ -1,5 +1,6 @@
1
1
  import { normalizePathSeparators } from "../utils/path.js";
2
2
  import { escapeRegExp } from "../utils/regex.js";
3
+ import { VIRTUAL_MODULE_ID_RE } from "../utils/virtual-module.js";
3
4
  import { getAstName } from "./ast-utils.js";
4
5
  import { createRequire } from "node:module";
5
6
  import path from "node:path";
@@ -445,12 +446,17 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
445
446
  return await this.resolve(source, barrelEntry, { skipSelf: true }) ?? void 0;
446
447
  },
447
448
  transform: {
448
- filter: { id: { include: /\.(tsx?|jsx?|mjs)$/ } },
449
- async handler(code, id) {
449
+ filter: {
450
+ id: {
451
+ include: /\.(tsx?|jsx?|mjs)$/,
452
+ exclude: VIRTUAL_MODULE_ID_RE
453
+ },
454
+ code: /\bimport\b[\s\S]*\bfrom\b/
455
+ },
456
+ async handler(code) {
450
457
  const env = this.environment;
451
458
  if (env?.name === "client") return null;
452
459
  const preferReactServer = env?.name === "rsc";
453
- if (id.startsWith("\0")) return null;
454
460
  const packages = optimizedPackages;
455
461
  if (!hasOptimizedImportSource(code)) return null;
456
462
  let ast;
@@ -1,7 +1,13 @@
1
+ import MagicString from "magic-string";
2
+
1
3
  //#region src/plugins/remove-console.d.ts
2
4
  type RemoveConsoleConfig = boolean | {
3
5
  exclude: string[];
4
6
  };
7
+ type RemoveConsoleResult = {
8
+ code: string;
9
+ map: ReturnType<MagicString["generateMap"]>;
10
+ };
5
11
  /**
6
12
  * Walk the AST body looking for expression statements whose expression is a
7
13
  * CallExpression with a callee of `console.<identifier>`. When found, check
@@ -10,6 +16,6 @@ type RemoveConsoleConfig = boolean | {
10
16
  *
11
17
  * Returns `null` if no console calls are removed.
12
18
  */
13
- declare function removeConsoleCalls(code: string, config: RemoveConsoleConfig): string | null;
19
+ declare function removeConsoleCalls(code: string, config: RemoveConsoleConfig): RemoveConsoleResult | null;
14
20
  //#endregion
15
21
  export { removeConsoleCalls };
@@ -168,7 +168,10 @@ function removeConsoleCalls(code, config) {
168
168
  }
169
169
  for (const node of ast.body) walk(node);
170
170
  if (!changed) return null;
171
- return s.toString();
171
+ return {
172
+ code: s.toString(),
173
+ map: s.generateMap({ hires: "boundary" })
174
+ };
172
175
  }
173
176
  //#endregion
174
177
  export { removeConsoleCalls };
@@ -16,30 +16,31 @@ function createRequireContextPlugin() {
16
16
  return {
17
17
  name: "vinext:require-context",
18
18
  enforce: "pre",
19
- transform(code, id) {
20
- if (!mayContainRequireContext(code)) return null;
21
- const lang = langForId(id);
22
- if (!lang) return null;
23
- let ast;
24
- try {
25
- ast = parseAst(code, { lang });
26
- } catch {
27
- return null;
19
+ transform: {
20
+ filter: {
21
+ id: /\.(?:[cm]?[jt]s|[jt]sx)(?:\?.*)?$/i,
22
+ code: /\brequire\b[\s\S]*\.context/
23
+ },
24
+ handler(code, id) {
25
+ const lang = langForId(id);
26
+ let ast;
27
+ try {
28
+ ast = parseAst(code, { lang });
29
+ } catch {
30
+ return null;
31
+ }
32
+ const calls = collectRequireContextCalls(ast);
33
+ if (calls.length === 0) return null;
34
+ const output = new MagicString(code);
35
+ for (const call of calls) output.overwrite(call.range.start, call.range.end, buildReplacement(call));
36
+ return {
37
+ code: output.toString(),
38
+ map: output.generateMap({ hires: "boundary" })
39
+ };
28
40
  }
29
- const calls = collectRequireContextCalls(ast);
30
- if (calls.length === 0) return null;
31
- const output = new MagicString(code);
32
- for (const call of calls) output.overwrite(call.range.start, call.range.end, buildReplacement(call));
33
- return {
34
- code: output.toString(),
35
- map: output.generateMap({ hires: "boundary" })
36
- };
37
41
  }
38
42
  };
39
43
  }
40
- function mayContainRequireContext(code) {
41
- return code.includes("require") && code.includes(".context");
42
- }
43
44
  function langForId(id) {
44
45
  const clean = id.split("?", 1)[0];
45
46
  const dot = clean.lastIndexOf(".");
@@ -1,7 +1,13 @@
1
+ import MagicString from "magic-string";
2
+
1
3
  //#region src/plugins/strip-server-exports.d.ts
2
4
  declare function hasServerExportCandidate(code: string): boolean;
3
5
  declare function hasExportAllCandidate(code: string): boolean;
4
6
  declare function validatePageExports(code: string): void;
7
+ type StripServerExportsResult = {
8
+ code: string;
9
+ map: ReturnType<MagicString["generateMap"]>;
10
+ };
5
11
  /**
6
12
  * Strip server-only Pages Router data-fetching exports and their unique
7
13
  * dependency graph from browser bundles.
@@ -10,6 +16,6 @@ declare function validatePageExports(code: string): void;
10
16
  * - test/unit/babel-plugin-next-ssg-transform.test.ts
11
17
  * - crates/next-custom-transforms/src/transforms/strip_page_exports.rs
12
18
  */
13
- declare function stripServerExports(code: string): string | null;
19
+ declare function stripServerExports(code: string): StripServerExportsResult | null;
14
20
  //#endregion
15
21
  export { hasExportAllCandidate, hasServerExportCandidate, stripServerExports, validatePageExports };
@@ -509,7 +509,10 @@ function stripServerExports(code) {
509
509
  string.overwrite(edit.start, edit.end, edit.replacement);
510
510
  lastStart = edit.start;
511
511
  }
512
- return string.toString();
512
+ return {
513
+ code: string.toString(),
514
+ map: string.generateMap({ hires: "boundary" })
515
+ };
513
516
  }
514
517
  //#endregion
515
518
  export { hasExportAllCandidate, hasServerExportCandidate, stripServerExports, validatePageExports };
@@ -0,0 +1,26 @@
1
+ import { AppElements } from "./app-elements-wire.js";
2
+ import { BfcacheIdMap } from "./app-history-state.js";
3
+
4
+ //#region src/server/app-bfcache-identity.d.ts
5
+ type BfcacheStateKeyMap = Readonly<Record<string, string>>;
6
+ declare function createInitialBfcacheIdMap(elements: AppElements): BfcacheIdMap;
7
+ declare function createBfcacheSegmentStateKeyMap(options: {
8
+ elements: AppElements;
9
+ pathname: string;
10
+ }): BfcacheStateKeyMap;
11
+ declare function createNextBfcacheIdMap(options: {
12
+ current: BfcacheIdMap;
13
+ currentElements: AppElements;
14
+ currentPathname: string;
15
+ elements: AppElements;
16
+ nextPathname: string;
17
+ restored?: BfcacheIdMap | null;
18
+ reuseCurrent?: boolean;
19
+ }): BfcacheIdMap;
20
+ declare function preserveBfcacheIdsForMergedElements(options: {
21
+ elements: AppElements;
22
+ next: BfcacheIdMap;
23
+ previous: BfcacheIdMap;
24
+ }): BfcacheIdMap;
25
+ //#endregion
26
+ export { BfcacheStateKeyMap, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
@@ -0,0 +1,127 @@
1
+ import { countConsumedPathnameSegments, isInvisibleSegment, normalizePathnameForRouteMatch, splitPathSegments } from "../routing/utils.js";
2
+ import { normalizePath } from "./normalize-path.js";
3
+ import { AppElementsWire } from "./app-elements-wire.js";
4
+ import "./app-elements.js";
5
+ import "./app-bfcache-id.js";
6
+ import { isBfcacheSegmentId } from "./app-history-state.js";
7
+ //#region src/server/app-bfcache-identity.ts
8
+ let nextBfcacheId = 0;
9
+ function rememberBfcacheId(value) {
10
+ const match = /^_b_(\d+)_$/.exec(value);
11
+ if (!match) return;
12
+ nextBfcacheId = Math.max(nextBfcacheId, Number(match[1]));
13
+ }
14
+ function mintBfcacheId() {
15
+ nextBfcacheId += 1;
16
+ return `_b_${nextBfcacheId}_`;
17
+ }
18
+ function getVisibleTreePathSegments(treePath) {
19
+ return splitPathSegments(treePath).filter((segment) => !isInvisibleSegment(segment));
20
+ }
21
+ function getTreePathIdentityPrefix(pathname, treePath) {
22
+ const pathnameSegments = splitPathSegments(pathname);
23
+ const consumedPathnameSegments = countConsumedPathnameSegments(getVisibleTreePathSegments(treePath), pathnameSegments.length);
24
+ if (consumedPathnameSegments === 0) return "/";
25
+ return `/${pathnameSegments.slice(0, consumedPathnameSegments).join("/")}`;
26
+ }
27
+ function readAppElementsMetadata(elements) {
28
+ let metadata;
29
+ try {
30
+ metadata = AppElementsWire.readMetadata(elements);
31
+ } catch {
32
+ return null;
33
+ }
34
+ const slotBindingsBySlotId = /* @__PURE__ */ new Map();
35
+ for (const binding of metadata.slotBindings) slotBindingsBySlotId.set(binding.slotId, binding);
36
+ return {
37
+ metadata,
38
+ slotBindingsBySlotId
39
+ };
40
+ }
41
+ function createActiveSlotIdentity(id, parsed) {
42
+ const activeSlotBinding = parsed?.slotBindingsBySlotId.get(id);
43
+ if (activeSlotBinding?.activeRouteId != null) return `${id}@${activeSlotBinding.activeRouteId}`;
44
+ const interception = parsed?.metadata.interception;
45
+ if (interception?.slotId !== id) return null;
46
+ return `${id}@${interception.targetRouteId}`;
47
+ }
48
+ /**
49
+ * Derive BFCache identity from AppElements wire keys. Keep wire-key parsing
50
+ * contained here until vinext has a route-manifest authority equivalent to
51
+ * Next.js CacheNode or segment-cache state.
52
+ */
53
+ function createBfcacheSegmentIdentity(id, options) {
54
+ const parsed = AppElementsWire.parseElementKey(id);
55
+ if (!parsed) return null;
56
+ if (parsed.kind === "page") return `${id}@${options.pathname}`;
57
+ if (parsed.kind === "slot") {
58
+ const activeSlotIdentity = createActiveSlotIdentity(id, options.metadata);
59
+ if (activeSlotIdentity !== null) return activeSlotIdentity;
60
+ return `${id}@${getTreePathIdentityPrefix(options.pathname, parsed.treePath)}`;
61
+ }
62
+ if (parsed.kind === "layout" || parsed.kind === "template") return `${id}@${getTreePathIdentityPrefix(options.pathname, parsed.treePath)}`;
63
+ return null;
64
+ }
65
+ function collectBfcacheSegmentIds(elements, parsed) {
66
+ const ids = new Set(Object.keys(elements));
67
+ const metadata = parsed === void 0 ? readAppElementsMetadata(elements) : parsed;
68
+ for (const layoutId of metadata?.metadata.layoutIds ?? []) ids.add(layoutId);
69
+ return Array.from(ids).filter(isBfcacheSegmentId);
70
+ }
71
+ function createInitialBfcacheIdMap(elements) {
72
+ const ids = {};
73
+ for (const id of collectBfcacheSegmentIds(elements)) ids[id] = "0";
74
+ return ids;
75
+ }
76
+ function normalizeBfcachePathname(pathname) {
77
+ const normalized = normalizePath(normalizePathnameForRouteMatch(pathname));
78
+ return normalized.length > 1 ? normalized.replace(/\/$/, "") : normalized;
79
+ }
80
+ function createBfcacheSegmentStateKeyMap(options) {
81
+ const metadata = readAppElementsMetadata(options.elements);
82
+ const normalizedPathname = normalizeBfcachePathname(options.pathname);
83
+ const stateKeys = {};
84
+ for (const id of collectBfcacheSegmentIds(options.elements, metadata)) {
85
+ const stateKey = createBfcacheSegmentIdentity(id, {
86
+ metadata,
87
+ pathname: normalizedPathname
88
+ });
89
+ if (stateKey !== null) stateKeys[id] = stateKey;
90
+ }
91
+ return stateKeys;
92
+ }
93
+ function createNextBfcacheIdMap(options) {
94
+ const current = options.reuseCurrent === false ? {} : options.current;
95
+ for (const value of Object.values(current)) rememberBfcacheId(value);
96
+ for (const value of Object.values(options.restored ?? {})) rememberBfcacheId(value);
97
+ const currentMetadata = readAppElementsMetadata(options.currentElements);
98
+ const nextMetadata = readAppElementsMetadata(options.elements);
99
+ const currentPathname = normalizeBfcachePathname(options.currentPathname);
100
+ const nextPathname = normalizeBfcachePathname(options.nextPathname);
101
+ const ids = {};
102
+ for (const id of collectBfcacheSegmentIds(options.elements, nextMetadata)) {
103
+ const currentValue = createBfcacheSegmentIdentity(id, {
104
+ metadata: currentMetadata,
105
+ pathname: currentPathname
106
+ }) === createBfcacheSegmentIdentity(id, {
107
+ metadata: nextMetadata,
108
+ pathname: nextPathname
109
+ }) ? current[id] : void 0;
110
+ const value = options.restored?.[id] ?? currentValue ?? mintBfcacheId();
111
+ ids[id] = value;
112
+ rememberBfcacheId(value);
113
+ }
114
+ return ids;
115
+ }
116
+ function preserveBfcacheIdsForMergedElements(options) {
117
+ const ids = {};
118
+ for (const id of collectBfcacheSegmentIds(options.elements)) {
119
+ const value = options.next[id] ?? options.previous[id];
120
+ if (value === void 0) continue;
121
+ ids[id] = value;
122
+ rememberBfcacheId(value);
123
+ }
124
+ return ids;
125
+ }
126
+ //#endregion
127
+ export { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
@@ -6,25 +6,28 @@ import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } fr
6
6
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
7
7
  import { installWindowNext, setWindowNextInternalSourcePage } from "../client/window-next.js";
8
8
  import { retryScrollTo, scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
9
- import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
10
- import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
11
- import { clearAppNavigationFailureTarget, installAppNavigationFailureListeners } from "../client/app-nav-failure-handler.js";
12
- import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
13
- import { readHistoryStatePreviousNextUrl } from "./app-history-state.js";
14
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
15
- import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
16
- import { navigationPlanner } from "./navigation-planner.js";
17
- import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
18
- import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, getBfcacheIdMapContext, getClientNavigationRenderContext, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, isRedirectError, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, useRouter } from "../shims/navigation.js";
9
+ import { getBfcacheIdMapContext, setNavigationContext } from "../shims/navigation-context-state.js";
10
+ import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
19
11
  import DefaultGlobalError from "../shims/default-global-error.js";
12
+ import { clearAppNavigationFailureTarget, installAppNavigationFailureListeners } from "../client/app-nav-failure-handler.js";
20
13
  import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../shims/error-boundary.js";
14
+ import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
21
15
  import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
22
16
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
17
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
18
+ import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
19
+ import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
23
20
  import "../client/instrumentation-client.js";
21
+ import { readHistoryStatePreviousNextUrl } from "./app-history-state.js";
22
+ import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
24
23
  import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
25
24
  import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
25
+ import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
26
+ import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
27
+ import { navigationPlanner } from "./navigation-planner.js";
28
+ import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, getClientNavigationRenderContext, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
26
29
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
27
- import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl, resolveServerActionRequestState } from "./app-browser-state.js";
30
+ import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl, resolveServerActionRequestState } from "./app-browser-state.js";
28
31
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch } from "./app-browser-navigation-controller.js";
29
32
  import { applyServerActionResultDecision } from "./app-browser-server-action-navigation.js";
30
33
  import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition } from "./app-browser-hydration.js";
@@ -1,8 +1,8 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
3
3
  import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
4
- import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
5
4
  import { shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
5
+ import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
6
6
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit } from "./app-browser-state.js";
7
7
  import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
8
8
  import { startTransition, useInsertionEffect, useLayoutEffect } from "react";
@@ -3,8 +3,9 @@ import { CacheEntryReuseProof } from "./cache-proof.js";
3
3
  import { AppElements, AppElementsInterception, AppElementsSlotBinding, LayoutFlags } from "./app-elements-wire.js";
4
4
  import { NavigationTrace } from "./navigation-trace.js";
5
5
  import { OperationLane } from "./operation-token.js";
6
- import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
7
6
  import { BfcacheIdMap, HistoryTraversalIntent, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
7
+ import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
8
+ import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
8
9
 
9
10
  //#region src/server/app-browser-state.d.ts
10
11
  type OperationRecordBase = {
@@ -70,7 +71,6 @@ type AppNavigationPayloadOrigin = Readonly<{
70
71
  } | {
71
72
  origin: "visited-cache";
72
73
  }>;
73
- type BfcacheStateKeyMap = Readonly<Record<string, string>>;
74
74
  declare const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN: AppNavigationPayloadOrigin;
75
75
  declare const VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN: AppNavigationPayloadOrigin;
76
76
  type PendingNavigationCommitDisposition = "dispatch" | "hard-navigate" | "skip";
@@ -91,25 +91,6 @@ type NonDispatchPendingNavigationCommitDispositionDecision = {
91
91
  trace: NavigationTrace;
92
92
  };
93
93
  type PendingNavigationCommitDispositionDecision = DispatchPendingNavigationCommitDispositionDecision | NonDispatchPendingNavigationCommitDispositionDecision;
94
- declare function createInitialBfcacheIdMap(elements: AppElements): BfcacheIdMap;
95
- declare function createBfcacheSegmentStateKeyMap(options: {
96
- elements: AppElements;
97
- pathname: string;
98
- }): BfcacheStateKeyMap;
99
- declare function createNextBfcacheIdMap(options: {
100
- current: BfcacheIdMap;
101
- currentElements: AppElements;
102
- currentPathname: string;
103
- elements: AppElements;
104
- nextPathname: string;
105
- restored?: BfcacheIdMap | null;
106
- reuseCurrent?: boolean;
107
- }): BfcacheIdMap;
108
- declare function preserveBfcacheIdsForMergedElements(options: {
109
- elements: AppElements;
110
- next: BfcacheIdMap;
111
- previous: BfcacheIdMap;
112
- }): BfcacheIdMap;
113
94
  declare function isCacheRestorableAppPayloadMetadata(metadata: CacheRestorableAppPayloadMetadata): metadata is CacheRestorableAppPayloadMetadata & {
114
95
  cacheEntryReuseProof: CacheEntryReuseProof;
115
96
  };