vinext 0.0.38 → 0.0.40

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 (245) hide show
  1. package/README.md +33 -20
  2. package/dist/build/nitro-route-rules.d.ts +50 -0
  3. package/dist/build/nitro-route-rules.js +81 -0
  4. package/dist/build/nitro-route-rules.js.map +1 -0
  5. package/dist/build/precompress.d.ts +17 -0
  6. package/dist/build/precompress.js +102 -0
  7. package/dist/build/precompress.js.map +1 -0
  8. package/dist/build/prerender.d.ts +27 -22
  9. package/dist/build/prerender.js +17 -17
  10. package/dist/build/prerender.js.map +1 -1
  11. package/dist/build/report.d.ts +3 -4
  12. package/dist/build/report.js.map +1 -1
  13. package/dist/build/run-prerender.d.ts +3 -4
  14. package/dist/build/run-prerender.js.map +1 -1
  15. package/dist/build/standalone.d.ts +32 -0
  16. package/dist/build/standalone.js +206 -0
  17. package/dist/build/standalone.js.map +1 -0
  18. package/dist/build/static-export.d.ts +17 -29
  19. package/dist/build/static-export.js.map +1 -1
  20. package/dist/check.d.ts +4 -4
  21. package/dist/check.js +1 -1
  22. package/dist/check.js.map +1 -1
  23. package/dist/cli.js +31 -4
  24. package/dist/cli.js.map +1 -1
  25. package/dist/client/instrumentation-client.d.ts +2 -2
  26. package/dist/client/instrumentation-client.js.map +1 -1
  27. package/dist/client/vinext-next-data.d.ts +5 -8
  28. package/dist/cloudflare/index.js +1 -1
  29. package/dist/cloudflare/kv-cache-handler.d.ts +5 -3
  30. package/dist/cloudflare/kv-cache-handler.js +1 -1
  31. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  32. package/dist/cloudflare/tpr.d.ts +35 -27
  33. package/dist/cloudflare/tpr.js +36 -12
  34. package/dist/cloudflare/tpr.js.map +1 -1
  35. package/dist/config/config-matchers.d.ts +2 -2
  36. package/dist/config/config-matchers.js +1 -1
  37. package/dist/config/config-matchers.js.map +1 -1
  38. package/dist/config/dotenv.d.ts +4 -4
  39. package/dist/config/dotenv.js.map +1 -1
  40. package/dist/config/next-config.d.ts +40 -61
  41. package/dist/config/next-config.js +5 -4
  42. package/dist/config/next-config.js.map +1 -1
  43. package/dist/deploy.d.ts +25 -41
  44. package/dist/deploy.js +1 -1
  45. package/dist/deploy.js.map +1 -1
  46. package/dist/entries/app-rsc-entry.d.ts +8 -11
  47. package/dist/entries/app-rsc-entry.js +133 -249
  48. package/dist/entries/app-rsc-entry.js.map +1 -1
  49. package/dist/entries/pages-server-entry.js +1 -3
  50. package/dist/entries/pages-server-entry.js.map +1 -1
  51. package/dist/index.d.ts +49 -28
  52. package/dist/index.js +238 -83
  53. package/dist/index.js.map +1 -1
  54. package/dist/init.d.ts +14 -26
  55. package/dist/init.js +8 -2
  56. package/dist/init.js.map +1 -1
  57. package/dist/plugins/client-reference-dedup.js.map +1 -1
  58. package/dist/plugins/fix-use-server-closure-collision.js.map +1 -1
  59. package/dist/plugins/fonts.d.ts +18 -1
  60. package/dist/plugins/fonts.js +107 -8
  61. package/dist/plugins/fonts.js.map +1 -1
  62. package/dist/plugins/optimize-imports.d.ts +2 -2
  63. package/dist/plugins/optimize-imports.js +4 -4
  64. package/dist/plugins/optimize-imports.js.map +1 -1
  65. package/dist/plugins/server-externals-manifest.d.ts +37 -0
  66. package/dist/plugins/server-externals-manifest.js +83 -0
  67. package/dist/plugins/server-externals-manifest.js.map +1 -0
  68. package/dist/routing/app-router.d.ts +37 -55
  69. package/dist/routing/app-router.js +37 -22
  70. package/dist/routing/app-router.js.map +1 -1
  71. package/dist/routing/file-matcher.d.ts +2 -2
  72. package/dist/routing/file-matcher.js.map +1 -1
  73. package/dist/routing/pages-router.d.ts +6 -11
  74. package/dist/routing/pages-router.js.map +1 -1
  75. package/dist/routing/route-trie.d.ts +2 -2
  76. package/dist/routing/route-trie.js.map +1 -1
  77. package/dist/server/api-handler.js.map +1 -1
  78. package/dist/server/app-browser-entry.js +270 -39
  79. package/dist/server/app-browser-entry.js.map +1 -1
  80. package/dist/server/app-browser-stream.d.ts +6 -6
  81. package/dist/server/app-browser-stream.js.map +1 -1
  82. package/dist/server/app-page-boundary-render.d.ts +8 -8
  83. package/dist/server/app-page-boundary-render.js +2 -2
  84. package/dist/server/app-page-boundary-render.js.map +1 -1
  85. package/dist/server/app-page-boundary.d.ts +13 -11
  86. package/dist/server/app-page-boundary.js +1 -1
  87. package/dist/server/app-page-boundary.js.map +1 -1
  88. package/dist/server/app-page-cache.d.ts +10 -10
  89. package/dist/server/app-page-cache.js.map +1 -1
  90. package/dist/server/app-page-execution.d.ts +10 -10
  91. package/dist/server/app-page-execution.js.map +1 -1
  92. package/dist/server/app-page-probe.d.ts +2 -2
  93. package/dist/server/app-page-probe.js.map +1 -1
  94. package/dist/server/app-page-render.d.ts +4 -4
  95. package/dist/server/app-page-render.js.map +1 -1
  96. package/dist/server/app-page-request.d.ts +12 -12
  97. package/dist/server/app-page-request.js.map +1 -1
  98. package/dist/server/app-page-response.d.ts +30 -19
  99. package/dist/server/app-page-response.js +26 -7
  100. package/dist/server/app-page-response.js.map +1 -1
  101. package/dist/server/app-page-route-wiring.d.ts +79 -0
  102. package/dist/server/app-page-route-wiring.js +165 -0
  103. package/dist/server/app-page-route-wiring.js.map +1 -0
  104. package/dist/server/app-page-stream.d.ts +18 -18
  105. package/dist/server/app-page-stream.js +3 -0
  106. package/dist/server/app-page-stream.js.map +1 -1
  107. package/dist/server/app-route-handler-cache.d.ts +2 -2
  108. package/dist/server/app-route-handler-cache.js.map +1 -1
  109. package/dist/server/app-route-handler-execution.d.ts +6 -6
  110. package/dist/server/app-route-handler-execution.js.map +1 -1
  111. package/dist/server/app-route-handler-policy.d.ts +8 -8
  112. package/dist/server/app-route-handler-policy.js.map +1 -1
  113. package/dist/server/app-route-handler-response.d.ts +6 -6
  114. package/dist/server/app-route-handler-response.js +4 -1
  115. package/dist/server/app-route-handler-response.js.map +1 -1
  116. package/dist/server/app-route-handler-runtime.d.ts +4 -4
  117. package/dist/server/app-route-handler-runtime.js.map +1 -1
  118. package/dist/server/app-router-entry.d.ts +6 -1
  119. package/dist/server/app-router-entry.js +9 -2
  120. package/dist/server/app-router-entry.js.map +1 -1
  121. package/dist/server/app-ssr-entry.d.ts +4 -4
  122. package/dist/server/app-ssr-entry.js.map +1 -1
  123. package/dist/server/app-ssr-stream.d.ts +2 -2
  124. package/dist/server/app-ssr-stream.js +1 -3
  125. package/dist/server/app-ssr-stream.js.map +1 -1
  126. package/dist/server/dev-module-runner.d.ts +2 -2
  127. package/dist/server/dev-module-runner.js.map +1 -1
  128. package/dist/server/dev-server.js +5 -7
  129. package/dist/server/dev-server.js.map +1 -1
  130. package/dist/server/image-optimization.d.ts +7 -12
  131. package/dist/server/image-optimization.js.map +1 -1
  132. package/dist/server/instrumentation.d.ts +8 -12
  133. package/dist/server/instrumentation.js +1 -1
  134. package/dist/server/instrumentation.js.map +1 -1
  135. package/dist/server/isr-cache.d.ts +2 -2
  136. package/dist/server/isr-cache.js.map +1 -1
  137. package/dist/server/metadata-routes.d.ts +14 -19
  138. package/dist/server/metadata-routes.js.map +1 -1
  139. package/dist/server/middleware.d.ts +9 -17
  140. package/dist/server/middleware.js +1 -1
  141. package/dist/server/middleware.js.map +1 -1
  142. package/dist/server/pages-api-route.d.ts +6 -6
  143. package/dist/server/pages-api-route.js.map +1 -1
  144. package/dist/server/pages-i18n.d.ts +4 -4
  145. package/dist/server/pages-i18n.js.map +1 -1
  146. package/dist/server/pages-node-compat.d.ts +10 -10
  147. package/dist/server/pages-node-compat.js.map +1 -1
  148. package/dist/server/pages-page-data.d.ts +22 -22
  149. package/dist/server/pages-page-data.js.map +1 -1
  150. package/dist/server/pages-page-response.d.ts +8 -8
  151. package/dist/server/pages-page-response.js.map +1 -1
  152. package/dist/server/prod-server.d.ts +20 -15
  153. package/dist/server/prod-server.js +198 -55
  154. package/dist/server/prod-server.js.map +1 -1
  155. package/dist/server/seed-cache.js.map +1 -1
  156. package/dist/server/static-file-cache.d.ts +57 -0
  157. package/dist/server/static-file-cache.js +219 -0
  158. package/dist/server/static-file-cache.js.map +1 -0
  159. package/dist/server/worker-utils.d.ts +4 -1
  160. package/dist/server/worker-utils.js +31 -1
  161. package/dist/server/worker-utils.js.map +1 -1
  162. package/dist/shims/app.d.ts +2 -2
  163. package/dist/shims/cache-runtime.d.ts +6 -9
  164. package/dist/shims/cache-runtime.js.map +1 -1
  165. package/dist/shims/cache.d.ts +28 -31
  166. package/dist/shims/cache.js.map +1 -1
  167. package/dist/shims/config.d.ts +2 -2
  168. package/dist/shims/config.js.map +1 -1
  169. package/dist/shims/dynamic.d.ts +2 -2
  170. package/dist/shims/dynamic.js +5 -7
  171. package/dist/shims/dynamic.js.map +1 -1
  172. package/dist/shims/error-boundary.d.ts +19 -10
  173. package/dist/shims/error-boundary.js +23 -3
  174. package/dist/shims/error-boundary.js.map +1 -1
  175. package/dist/shims/error.d.ts +2 -2
  176. package/dist/shims/error.js.map +1 -1
  177. package/dist/shims/fetch-cache.d.ts +4 -4
  178. package/dist/shims/fetch-cache.js.map +1 -1
  179. package/dist/shims/font-google-base.d.ts +4 -4
  180. package/dist/shims/font-google-base.js.map +1 -1
  181. package/dist/shims/font-local.d.ts +6 -6
  182. package/dist/shims/font-local.js.map +1 -1
  183. package/dist/shims/form.d.ts +4 -8
  184. package/dist/shims/form.js +4 -6
  185. package/dist/shims/form.js.map +1 -1
  186. package/dist/shims/head-state.d.ts +2 -2
  187. package/dist/shims/head-state.js.map +1 -1
  188. package/dist/shims/head.d.ts +2 -2
  189. package/dist/shims/head.js +18 -20
  190. package/dist/shims/head.js.map +1 -1
  191. package/dist/shims/headers.d.ts +4 -4
  192. package/dist/shims/headers.js.map +1 -1
  193. package/dist/shims/i18n-context.d.ts +2 -2
  194. package/dist/shims/i18n-context.js.map +1 -1
  195. package/dist/shims/i18n-state.d.ts +2 -2
  196. package/dist/shims/i18n-state.js.map +1 -1
  197. package/dist/shims/image-config.d.ts +2 -2
  198. package/dist/shims/image-config.js.map +1 -1
  199. package/dist/shims/image.d.ts +5 -6
  200. package/dist/shims/image.js.map +1 -1
  201. package/dist/shims/internal/app-router-context.d.ts +6 -6
  202. package/dist/shims/internal/app-router-context.js.map +1 -1
  203. package/dist/shims/internal/utils.d.ts +2 -2
  204. package/dist/shims/internal/utils.js.map +1 -1
  205. package/dist/shims/layout-segment-context.d.ts +12 -5
  206. package/dist/shims/layout-segment-context.js +9 -4
  207. package/dist/shims/layout-segment-context.js.map +1 -1
  208. package/dist/shims/legacy-image.d.ts +5 -8
  209. package/dist/shims/legacy-image.js.map +1 -1
  210. package/dist/shims/link.d.ts +21 -31
  211. package/dist/shims/link.js +4 -58
  212. package/dist/shims/link.js.map +1 -1
  213. package/dist/shims/metadata.d.ts +23 -31
  214. package/dist/shims/metadata.js.map +1 -1
  215. package/dist/shims/navigation-state.d.ts +2 -2
  216. package/dist/shims/navigation-state.js.map +1 -1
  217. package/dist/shims/navigation.d.ts +118 -18
  218. package/dist/shims/navigation.js +377 -116
  219. package/dist/shims/navigation.js.map +1 -1
  220. package/dist/shims/request-context.d.ts +2 -2
  221. package/dist/shims/request-context.js.map +1 -1
  222. package/dist/shims/router-state.d.ts +4 -4
  223. package/dist/shims/router-state.js.map +1 -1
  224. package/dist/shims/router.d.ts +28 -47
  225. package/dist/shims/router.js +127 -38
  226. package/dist/shims/router.js.map +1 -1
  227. package/dist/shims/script.d.ts +16 -31
  228. package/dist/shims/script.js.map +1 -1
  229. package/dist/shims/server.d.ts +27 -14
  230. package/dist/shims/server.js +91 -73
  231. package/dist/shims/server.js.map +1 -1
  232. package/dist/shims/slot.d.ts +28 -0
  233. package/dist/shims/slot.js +49 -0
  234. package/dist/shims/slot.js.map +1 -0
  235. package/dist/shims/unified-request-context.d.ts +3 -5
  236. package/dist/shims/unified-request-context.js.map +1 -1
  237. package/dist/shims/web-vitals.d.ts +2 -2
  238. package/dist/shims/web-vitals.js.map +1 -1
  239. package/dist/utils/lazy-chunks.d.ts +34 -0
  240. package/dist/utils/lazy-chunks.js +50 -0
  241. package/dist/utils/lazy-chunks.js.map +1 -0
  242. package/dist/utils/vinext-root.d.ts +24 -0
  243. package/dist/utils/vinext-root.js +31 -0
  244. package/dist/utils/vinext-root.js.map +1 -0
  245. package/package.json +1 -2
@@ -24,7 +24,9 @@ const appRouteHandlerCachePath = resolveEntryPath("../server/app-route-handler-c
24
24
  const appPageCachePath = resolveEntryPath("../server/app-page-cache.js", import.meta.url);
25
25
  const appPageExecutionPath = resolveEntryPath("../server/app-page-execution.js", import.meta.url);
26
26
  const appPageBoundaryRenderPath = resolveEntryPath("../server/app-page-boundary-render.js", import.meta.url);
27
+ const appPageRouteWiringPath = resolveEntryPath("../server/app-page-route-wiring.js", import.meta.url);
27
28
  const appPageRenderPath = resolveEntryPath("../server/app-page-render.js", import.meta.url);
29
+ const appPageResponsePath = resolveEntryPath("../server/app-page-response.js", import.meta.url);
28
30
  const appPageRequestPath = resolveEntryPath("../server/app-page-request.js", import.meta.url);
29
31
  const appRouteHandlerResponsePath = resolveEntryPath("../server/app-route-handler-response.js", import.meta.url);
30
32
  const routeTriePath = resolveEntryPath("../routing/route-trie.js", import.meta.url);
@@ -50,6 +52,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
50
52
  const bodySizeLimit = config?.bodySizeLimit ?? 1 * 1024 * 1024;
51
53
  const i18nConfig = config?.i18n ?? null;
52
54
  const hasPagesDir = config?.hasPagesDir ?? false;
55
+ const publicFiles = config?.publicFiles ?? [];
53
56
  const imports = [];
54
57
  const importMap = /* @__PURE__ */ new Map();
55
58
  let importIdx = 0;
@@ -65,7 +68,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
65
68
  if (route.pagePath) getImportVar(route.pagePath);
66
69
  if (route.routePath) getImportVar(route.routePath);
67
70
  for (const layout of route.layouts) getImportVar(layout);
68
- for (const tmpl of route.templates) getImportVar(tmpl);
71
+ for (const tmpl of route.templates) if (tmpl) getImportVar(tmpl);
69
72
  if (route.loadingPath) getImportVar(route.loadingPath);
70
73
  if (route.errorPath) getImportVar(route.errorPath);
71
74
  if (route.layoutErrorPaths) {
@@ -86,17 +89,15 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
86
89
  }
87
90
  const routeEntries = routes.map((route) => {
88
91
  const layoutVars = route.layouts.map((l) => getImportVar(l));
89
- const templateVars = route.templates.map((t) => getImportVar(t));
92
+ const templateVars = route.templates.map((t) => t ? getImportVar(t) : "null");
90
93
  const notFoundVars = (route.notFoundPaths || []).map((nf) => nf ? getImportVar(nf) : "null");
91
94
  const slotEntries = route.parallelSlots.map((slot) => {
92
- const interceptEntries = slot.interceptingRoutes.map((ir) => {
93
- return ` {
95
+ const interceptEntries = slot.interceptingRoutes.map((ir) => ` {
94
96
  convention: ${JSON.stringify(ir.convention)},
95
97
  targetPattern: ${JSON.stringify(ir.targetPattern)},
96
98
  page: ${getImportVar(ir.pagePath)},
97
99
  params: ${JSON.stringify(ir.params)},
98
- }`;
99
- });
100
+ }`);
100
101
  return ` ${JSON.stringify(slot.name)}: {
101
102
  page: ${slot.pagePath ? getImportVar(slot.pagePath) : "null"},
102
103
  default: ${slot.defaultPath ? getImportVar(slot.defaultPath) : "null"},
@@ -104,6 +105,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
104
105
  loading: ${slot.loadingPath ? getImportVar(slot.loadingPath) : "null"},
105
106
  error: ${slot.errorPath ? getImportVar(slot.errorPath) : "null"},
106
107
  layoutIndex: ${slot.layoutIndex},
108
+ routeSegments: ${JSON.stringify(slot.routeSegments)},
107
109
  intercepts: [
108
110
  ${interceptEntries.join(",\n")}
109
111
  ],
@@ -206,13 +208,11 @@ function renderToReadableStream(model, options) {
206
208
  }
207
209
  }));
208
210
  }
209
- import { createElement, Suspense, Fragment } from "react";
211
+ import { createElement } from "react";
210
212
  import { setNavigationContext as _setNavigationContextOrig, getNavigationContext as _getNavigationContext } from "next/navigation";
211
213
  import { setHeadersContext, headersContextFromRequest, getDraftModeCookieHeader, getAndClearPendingCookies, consumeDynamicUsage, markDynamicUsage, applyMiddlewareRequestHeaders, getHeadersContext, setHeadersAccessPhase } from "next/headers";
212
214
  import { NextRequest, NextFetchEvent } from "next/server";
213
- import { ErrorBoundary, NotFoundBoundary } from "vinext/error-boundary";
214
- import { LayoutSegmentProvider } from "vinext/layout-segment-context";
215
- import { MetadataHead, mergeMetadata, resolveModuleMetadata, ViewportHead, mergeViewport, resolveModuleViewport } from "vinext/metadata";
215
+ import { mergeMetadata, resolveModuleMetadata, mergeViewport, resolveModuleViewport } from "vinext/metadata";
216
216
  ${middlewarePath ? `import * as middlewareModule from ${JSON.stringify(middlewarePath.replace(/\\/g, "/"))};` : ""}
217
217
  ${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(instrumentationPath.replace(/\\/g, "/"))};` : ""}
218
218
  ${effectiveMetaRoutes.length > 0 ? `import { sitemapToXml, robotsToText, manifestToJson } from ${JSON.stringify(metadataRoutesPath)};` : ""}
@@ -244,9 +244,16 @@ import {
244
244
  renderAppPageErrorBoundary as __renderAppPageErrorBoundary,
245
245
  renderAppPageHttpAccessFallback as __renderAppPageHttpAccessFallback,
246
246
  } from ${JSON.stringify(appPageBoundaryRenderPath)};
247
+ import {
248
+ buildAppPageRouteElement as __buildAppPageRouteElement,
249
+ resolveAppPageChildSegments as __resolveAppPageChildSegments,
250
+ } from ${JSON.stringify(appPageRouteWiringPath)};
247
251
  import {
248
252
  renderAppPageLifecycle as __renderAppPageLifecycle,
249
253
  } from ${JSON.stringify(appPageRenderPath)};
254
+ import {
255
+ mergeMiddlewareResponseHeaders as __mergeMiddlewareResponseHeaders,
256
+ } from ${JSON.stringify(appPageResponsePath)};
250
257
  import {
251
258
  buildAppPageElement as __buildAppPageElement,
252
259
  resolveAppPageIntercept as __resolveAppPageIntercept,
@@ -411,38 +418,6 @@ function makeThenableParams(obj) {
411
418
  return Object.assign(Promise.resolve(plain), plain);
412
419
  }
413
420
 
414
- // Resolve route tree segments to actual values using matched params.
415
- // Dynamic segments like [id] are replaced with param values, catch-all
416
- // segments like [...slug] are joined with "/", and route groups are kept as-is.
417
- function __resolveChildSegments(routeSegments, treePosition, params) {
418
- var raw = routeSegments.slice(treePosition);
419
- var result = [];
420
- for (var j = 0; j < raw.length; j++) {
421
- var seg = raw[j];
422
- // Optional catch-all: [[...param]]
423
- if (seg.indexOf("[[...") === 0 && seg.charAt(seg.length - 1) === "]" && seg.charAt(seg.length - 2) === "]") {
424
- var pn = seg.slice(5, -2);
425
- var v = params[pn];
426
- // Skip empty optional catch-all (e.g., visiting /blog on [[...slug]] route)
427
- if (Array.isArray(v) && v.length === 0) continue;
428
- if (v == null) continue;
429
- result.push(Array.isArray(v) ? v.join("/") : v);
430
- // Catch-all: [...param]
431
- } else if (seg.indexOf("[...") === 0 && seg.charAt(seg.length - 1) === "]") {
432
- var pn2 = seg.slice(4, -1);
433
- var v2 = params[pn2];
434
- result.push(Array.isArray(v2) ? v2.join("/") : (v2 || seg));
435
- // Dynamic: [param]
436
- } else if (seg.charAt(0) === "[" && seg.charAt(seg.length - 1) === "]" && seg.indexOf(".") === -1) {
437
- var pn3 = seg.slice(1, -1);
438
- result.push(params[pn3] || seg);
439
- } else {
440
- result.push(seg);
441
- }
442
- }
443
- return result;
444
- }
445
-
446
421
  // djb2 hash — matches Next.js's stringHash for digest generation.
447
422
  // Produces a stable numeric string from error message + stack.
448
423
  function __errorDigest(str) {
@@ -642,7 +617,7 @@ async function renderHTTPAccessFallbackPage(route, statusCode, isRscRequest, req
642
617
  makeThenableParams,
643
618
  matchedParams: opts?.matchedParams ?? route?.params ?? {},
644
619
  requestUrl: request.url,
645
- resolveChildSegments: __resolveChildSegments,
620
+ resolveChildSegments: __resolveAppPageChildSegments,
646
621
  rootForbiddenModule: rootForbiddenModule,
647
622
  rootLayouts: rootLayouts,
648
623
  rootNotFoundModule: rootNotFoundModule,
@@ -688,7 +663,7 @@ async function renderErrorBoundaryPage(route, error, isRscRequest, request, matc
688
663
  makeThenableParams,
689
664
  matchedParams: matchedParams ?? route?.params ?? {},
690
665
  requestUrl: request.url,
691
- resolveChildSegments: __resolveChildSegments,
666
+ resolveChildSegments: __resolveAppPageChildSegments,
692
667
  rootLayouts: rootLayouts,
693
668
  route,
694
669
  renderToReadableStream,
@@ -706,6 +681,21 @@ function matchRoute(url) {
706
681
  return _trieMatch(_routeTrie, urlParts);
707
682
  }
708
683
 
684
+ function __createStaticFileSignal(pathname, _mwCtx) {
685
+ const headers = new Headers({
686
+ "x-vinext-static-file": encodeURIComponent(pathname),
687
+ });
688
+ if (_mwCtx.headers) {
689
+ for (const [key, value] of _mwCtx.headers) {
690
+ headers.append(key, value);
691
+ }
692
+ }
693
+ return new Response(null, {
694
+ status: _mwCtx.status ?? 200,
695
+ headers,
696
+ });
697
+ }
698
+
709
699
  // matchPattern is kept for findIntercept (linear scan over small interceptLookup array).
710
700
  function matchPattern(urlParts, patternParts) {
711
701
  const params = Object.create(null);
@@ -854,12 +844,10 @@ async function buildPageElement(route, params, opts, searchParams) {
854
844
  const resolvedMetadata = metadataList.length > 0 ? mergeMetadata(metadataList) : null;
855
845
  const resolvedViewport = mergeViewport(viewportList);
856
846
 
857
- // Build nested layout tree from outermost to innermost.
858
- // Next.js 16 passes params/searchParams as Promises (async pattern)
859
- // but pre-16 code accesses them as plain objects (params.id).
860
- // makeThenableParams() normalises null-prototype + preserves both patterns.
861
- const asyncParams = makeThenableParams(params);
862
- const pageProps = { params: asyncParams };
847
+ // Build the route tree from the leaf page, then delegate the boundary/layout/
848
+ // template/segment wiring to a typed runtime helper so the generated entry
849
+ // stays thin and the wiring logic can be unit tested directly.
850
+ const pageProps = { params: makeThenableParams(params) };
863
851
  if (searchParams) {
864
852
  // Always provide searchParams prop when the URL object is available, even
865
853
  // when the query string is empty -- pages that do "await searchParams" need
@@ -875,192 +863,25 @@ async function buildPageElement(route, params, opts, searchParams) {
875
863
  // dynamic, and this avoids false positives from React internals.
876
864
  if (hasSearchParams) markDynamicUsage();
877
865
  }
878
- let element = createElement(PageComponent, pageProps);
879
-
880
- // Wrap page with empty segment provider so useSelectedLayoutSegments()
881
- // returns [] when called from inside a page component (leaf node).
882
- element = createElement(LayoutSegmentProvider, { childSegments: [] }, element);
883
-
884
- // Add metadata + viewport head tags (React 19 hoists title/meta/link to <head>)
885
- // Next.js always injects charset and default viewport even when no metadata/viewport
886
- // is exported. We replicate that by always emitting these essential head elements.
887
- {
888
- const headElements = [];
889
- // Always emit <meta charset="utf-8"> — Next.js includes this on every page
890
- headElements.push(createElement("meta", { charSet: "utf-8" }));
891
- if (resolvedMetadata) headElements.push(createElement(MetadataHead, { metadata: resolvedMetadata }));
892
- headElements.push(createElement(ViewportHead, { viewport: resolvedViewport }));
893
- element = createElement(Fragment, null, ...headElements, element);
894
- }
895
-
896
- // Wrap with loading.tsx Suspense if present
897
- if (route.loading?.default) {
898
- element = createElement(
899
- Suspense,
900
- { fallback: createElement(route.loading.default) },
901
- element,
902
- );
903
- }
904
-
905
- // Wrap with the leaf's error.tsx ErrorBoundary if it's not already covered
906
- // by a per-layout error boundary (i.e., the leaf has error.tsx but no layout).
907
- // Per-layout error boundaries are interleaved with layouts below.
908
- {
909
- const lastLayoutError = route.errors ? route.errors[route.errors.length - 1] : null;
910
- if (route.error?.default && route.error !== lastLayoutError) {
911
- element = createElement(ErrorBoundary, {
912
- fallback: route.error.default,
913
- children: element,
914
- });
915
- }
916
- }
917
-
918
- // Wrap with NotFoundBoundary so client-side notFound() renders not-found.tsx
919
- // instead of crashing the React tree. Must be above ErrorBoundary since
920
- // ErrorBoundary re-throws notFound errors.
921
- // Pre-render the not-found component as a React element since it may be a
922
- // server component (not a client reference) and can't be passed as a function prop.
923
- {
924
- const NotFoundComponent = route.notFound?.default ?? ${rootNotFoundVar ? `${rootNotFoundVar}?.default` : "null"};
925
- if (NotFoundComponent) {
926
- element = createElement(NotFoundBoundary, {
927
- fallback: createElement(NotFoundComponent),
928
- children: element,
929
- });
930
- }
931
- }
932
-
933
- // Wrap with templates (innermost first, then outer)
934
- // Templates are like layouts but re-mount on navigation (client-side concern).
935
- // On the server, they just wrap the content like layouts do.
936
- if (route.templates) {
937
- for (let i = route.templates.length - 1; i >= 0; i--) {
938
- const TemplateComponent = route.templates[i]?.default;
939
- if (TemplateComponent) {
940
- element = createElement(TemplateComponent, { children: element, params });
941
- }
942
- }
943
- }
944
-
945
- // Wrap with layouts (innermost first, then outer).
946
- // At each layout level, first wrap with that level's error boundary (if any)
947
- // so the boundary is inside the layout and catches errors from children.
948
- // This matches Next.js behavior: Layout > ErrorBoundary > children.
949
- // Parallel slots are passed as named props to the innermost layout
950
- // (the layout at the same directory level as the page/slots)
951
- for (let i = route.layouts.length - 1; i >= 0; i--) {
952
- // Wrap with per-layout error boundary before wrapping with layout.
953
- // This places the ErrorBoundary inside the layout, catching errors
954
- // from child segments (matching Next.js per-segment error handling).
955
- if (route.errors && route.errors[i]?.default) {
956
- element = createElement(ErrorBoundary, {
957
- fallback: route.errors[i].default,
958
- children: element,
959
- });
960
- }
961
-
962
- const LayoutComponent = route.layouts[i]?.default;
963
- if (LayoutComponent) {
964
- // Per-layout NotFoundBoundary: wraps this layout's children so that
965
- // notFound() thrown from a child layout is caught here.
966
- // Matches Next.js behavior where each segment has its own boundary.
967
- // The boundary at level N catches errors from Layout[N+1] and below,
968
- // but NOT from Layout[N] itself (which propagates to level N-1).
969
- {
970
- const LayoutNotFound = route.notFounds?.[i]?.default;
971
- if (LayoutNotFound) {
972
- element = createElement(NotFoundBoundary, {
973
- fallback: createElement(LayoutNotFound),
974
- children: element,
975
- });
976
- }
977
- }
978
-
979
- const layoutProps = { children: element, params: makeThenableParams(params) };
980
-
981
- // Add parallel slot elements to the layout that defines them.
982
- // Each slot has a layoutIndex indicating which layout it belongs to.
983
- if (route.slots) {
984
- for (const [slotName, slotMod] of Object.entries(route.slots)) {
985
- // Attach slot to the layout at its layoutIndex, or to the innermost layout if -1
986
- const targetIdx = slotMod.layoutIndex >= 0 ? slotMod.layoutIndex : route.layouts.length - 1;
987
- if (i !== targetIdx) continue;
988
- // Check if this slot has an intercepting route that should activate
989
- let SlotPage = null;
990
- let slotParams = params;
991
-
992
- if (opts && opts.interceptSlot === slotName && opts.interceptPage) {
993
- // Use the intercepting route's page component
994
- SlotPage = opts.interceptPage.default;
995
- slotParams = opts.interceptParams || params;
996
- } else {
997
- SlotPage = slotMod.page?.default || slotMod.default?.default;
998
- }
999
-
1000
- if (SlotPage) {
1001
- let slotElement = createElement(SlotPage, { params: makeThenableParams(slotParams) });
1002
- // Wrap with slot-specific layout if present.
1003
- // In Next.js, @slot/layout.tsx wraps the slot's page content
1004
- // before it is passed as a prop to the parent layout.
1005
- const SlotLayout = slotMod.layout?.default;
1006
- if (SlotLayout) {
1007
- slotElement = createElement(SlotLayout, {
1008
- children: slotElement,
1009
- params: makeThenableParams(slotParams),
1010
- });
1011
- }
1012
- // Wrap with slot-specific loading if present
1013
- if (slotMod.loading?.default) {
1014
- slotElement = createElement(Suspense,
1015
- { fallback: createElement(slotMod.loading.default) },
1016
- slotElement,
1017
- );
1018
- }
1019
- // Wrap with slot-specific error boundary if present
1020
- if (slotMod.error?.default) {
1021
- slotElement = createElement(ErrorBoundary, {
1022
- fallback: slotMod.error.default,
1023
- children: slotElement,
1024
- });
1025
- }
1026
- layoutProps[slotName] = slotElement;
866
+ return __buildAppPageRouteElement({
867
+ element: createElement(PageComponent, pageProps),
868
+ globalErrorModule: ${globalErrorVar ? globalErrorVar : "null"},
869
+ makeThenableParams,
870
+ matchedParams: params,
871
+ resolvedMetadata,
872
+ resolvedViewport,
873
+ rootNotFoundModule: ${rootNotFoundVar ? rootNotFoundVar : "null"},
874
+ route,
875
+ slotOverrides:
876
+ opts && opts.interceptSlot && opts.interceptPage
877
+ ? {
878
+ [opts.interceptSlot]: {
879
+ pageModule: opts.interceptPage,
880
+ params: opts.interceptParams || params,
881
+ },
1027
882
  }
1028
- }
1029
- }
1030
-
1031
- element = createElement(LayoutComponent, layoutProps);
1032
-
1033
- // Wrap the layout with LayoutSegmentProvider so useSelectedLayoutSegments()
1034
- // called INSIDE this layout gets the correct child segments. We resolve the
1035
- // route tree segments using actual param values and pass them through context.
1036
- // We wrap the layout (not just children) because hooks are called from
1037
- // components rendered inside the layout's own JSX.
1038
- const treePos = route.layoutTreePositions ? route.layoutTreePositions[i] : 0;
1039
- const childSegs = __resolveChildSegments(route.routeSegments || [], treePos, params);
1040
- element = createElement(LayoutSegmentProvider, { childSegments: childSegs }, element);
1041
- }
1042
- }
1043
-
1044
- // Wrap with global error boundary if app/global-error.tsx exists.
1045
- // This must be present in both HTML and RSC paths so the component tree
1046
- // structure matches — otherwise React reconciliation on client-side navigation
1047
- // would see a mismatched tree and destroy/recreate the DOM.
1048
- //
1049
- // For RSC requests (client-side nav), this provides error recovery on the client.
1050
- // For HTML requests (initial page load), the ErrorBoundary catches during SSR
1051
- // but produces double <html>/<body> (root layout + global-error). The request
1052
- // handler detects this via the rscOnError flag and re-renders without layouts.
1053
- ${globalErrorVar ? `
1054
- const GlobalErrorComponent = ${globalErrorVar}.default;
1055
- if (GlobalErrorComponent) {
1056
- element = createElement(ErrorBoundary, {
1057
- fallback: GlobalErrorComponent,
1058
- children: element,
1059
- });
1060
- }
1061
- ` : ""}
1062
-
1063
- return element;
883
+ : null,
884
+ });
1064
885
  }
1065
886
 
1066
887
  ${middlewarePath ? generateMiddlewareMatcherCode("modern") : ""}
@@ -1071,6 +892,7 @@ const __i18nConfig = ${JSON.stringify(i18nConfig)};
1071
892
  const __configRedirects = ${JSON.stringify(redirects)};
1072
893
  const __configRewrites = ${JSON.stringify(rewrites)};
1073
894
  const __configHeaders = ${JSON.stringify(headers)};
895
+ const __publicFiles = new Set(${JSON.stringify(publicFiles)});
1074
896
  const __allowedOrigins = ${JSON.stringify(allowedOrigins)};
1075
897
 
1076
898
  ${generateDevOriginCheckCode(config?.allowedDevOrigins)}
@@ -1269,6 +1091,9 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1269
1091
  let pathname = __normalizePath(decodedUrlPathname);
1270
1092
 
1271
1093
  ${bp ? `
1094
+ if (!hasBasePath(pathname, __basePath) && !pathname.startsWith("/__vinext/")) {
1095
+ return new Response("Not Found", { status: 404 });
1096
+ }
1272
1097
  // Strip basePath prefix
1273
1098
  pathname = stripBasePath(pathname, __basePath);
1274
1099
  ` : ""}
@@ -1616,6 +1441,18 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1616
1441
  }
1617
1442
  }
1618
1443
 
1444
+ // Serve public/ files as filesystem routes after middleware and before
1445
+ // afterFiles/fallback rewrites, matching Next.js routing semantics.
1446
+ if (
1447
+ (request.method === "GET" || request.method === "HEAD") &&
1448
+ !pathname.endsWith(".rsc") &&
1449
+ __publicFiles.has(cleanPathname)
1450
+ ) {
1451
+ setHeadersContext(null);
1452
+ setNavigationContext(null);
1453
+ return __createStaticFileSignal(cleanPathname, _mwCtx);
1454
+ }
1455
+
1619
1456
  // Set navigation context for Server Components.
1620
1457
  // Note: Headers context is already set by runWithRequestContext in the handler wrapper.
1621
1458
  setNavigationContext({
@@ -1671,7 +1508,10 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1671
1508
  returnValue = { ok: true, data };
1672
1509
  } catch (e) {
1673
1510
  // Detect redirect() / permanentRedirect() called inside the action.
1674
- // These throw errors with digest "NEXT_REDIRECT;replace;url[;status]".
1511
+ // These throw errors with digest "NEXT_REDIRECT;<type>;<url>[;<status>]".
1512
+ // The type field is empty when redirect() was called without an explicit
1513
+ // type argument. In Server Action context, Next.js defaults to "push" so
1514
+ // the Back button works after form submissions.
1675
1515
  // The URL is encodeURIComponent-encoded to prevent semicolons in the URL
1676
1516
  // from corrupting the delimiter-based digest format.
1677
1517
  if (e && typeof e === "object" && "digest" in e) {
@@ -1680,7 +1520,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1680
1520
  const parts = digest.split(";");
1681
1521
  actionRedirect = {
1682
1522
  url: decodeURIComponent(parts[2]),
1683
- type: parts[1] || "replace", // "push" or "replace"
1523
+ type: parts[1] || "push", // Server Action → default "push"
1684
1524
  status: parts[3] ? parseInt(parts[3], 10) : 307,
1685
1525
  };
1686
1526
  returnValue = { ok: true, data: undefined };
@@ -1716,10 +1556,14 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1716
1556
  const redirectHeaders = new Headers({
1717
1557
  "Content-Type": "text/x-component; charset=utf-8",
1718
1558
  "Vary": "RSC, Accept",
1719
- "x-action-redirect": actionRedirect.url,
1720
- "x-action-redirect-type": actionRedirect.type,
1721
- "x-action-redirect-status": String(actionRedirect.status),
1722
1559
  });
1560
+ // Merge middleware headers first so the framework's own redirect control
1561
+ // headers below are always authoritative and cannot be clobbered by
1562
+ // middleware that happens to set x-action-redirect* keys.
1563
+ __mergeMiddlewareResponseHeaders(redirectHeaders, _mwCtx.headers);
1564
+ redirectHeaders.set("x-action-redirect", actionRedirect.url);
1565
+ redirectHeaders.set("x-action-redirect-type", actionRedirect.type);
1566
+ redirectHeaders.set("x-action-redirect-status", String(actionRedirect.status));
1723
1567
  for (const cookie of actionPendingCookies) {
1724
1568
  redirectHeaders.append("Set-Cookie", cookie);
1725
1569
  }
@@ -1739,7 +1583,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1739
1583
  searchParams: url.searchParams,
1740
1584
  params: actionParams,
1741
1585
  });
1742
- element = buildPageElement(actionRoute, actionParams, undefined, url.searchParams);
1586
+ element = await buildPageElement(actionRoute, actionParams, undefined, url.searchParams);
1743
1587
  } else {
1744
1588
  element = createElement("div", null, "Page not found");
1745
1589
  }
@@ -1762,15 +1606,15 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1762
1606
  const actionPendingCookies = getAndClearPendingCookies();
1763
1607
  const actionDraftCookie = getDraftModeCookieHeader();
1764
1608
 
1765
- const actionHeaders = { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" };
1766
- const actionResponse = new Response(rscStream, { headers: actionHeaders });
1609
+ const actionHeaders = new Headers({ "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" });
1610
+ __mergeMiddlewareResponseHeaders(actionHeaders, _mwCtx.headers);
1767
1611
  if (actionPendingCookies.length > 0 || actionDraftCookie) {
1768
1612
  for (const cookie of actionPendingCookies) {
1769
- actionResponse.headers.append("Set-Cookie", cookie);
1613
+ actionHeaders.append("Set-Cookie", cookie);
1770
1614
  }
1771
- if (actionDraftCookie) actionResponse.headers.append("Set-Cookie", actionDraftCookie);
1615
+ if (actionDraftCookie) actionHeaders.append("Set-Cookie", actionDraftCookie);
1772
1616
  }
1773
- return actionResponse;
1617
+ return new Response(rscStream, { status: _mwCtx.status ?? 200, headers: actionHeaders });
1774
1618
  } catch (err) {
1775
1619
  getAndClearPendingCookies(); // Clear pending cookies on error
1776
1620
  console.error("[vinext] Server action error:", err);
@@ -2150,7 +1994,31 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2150
1994
  },
2151
1995
  isRscRequest,
2152
1996
  matchSourceRouteParams(pattern) {
2153
- return matchRoute(pattern)?.params ?? {};
1997
+ // Extract actual URL param values by prefix-matching the request pathname
1998
+ // against the source route's pattern. This handles all interception conventions:
1999
+ // (.) same-level, (..) one-level-up, and (...) root — the source pattern's
2000
+ // dynamic segments that align with the URL get their real values extracted.
2001
+ // We must NOT use matchRoute(pattern) here: the trie would match the literal
2002
+ // ":param" strings as dynamic segment values, returning e.g. {id: ":id"}.
2003
+ const patternParts = pattern.split("/").filter(Boolean);
2004
+ const urlParts = cleanPathname.split("/").filter(Boolean);
2005
+ const params = Object.create(null);
2006
+ for (let i = 0; i < patternParts.length; i++) {
2007
+ const pp = patternParts[i];
2008
+ if (pp.endsWith("+") || pp.endsWith("*")) {
2009
+ // urlParts.slice(i) safely returns [] when i >= urlParts.length,
2010
+ // which is the correct value for optional catch-all with zero segments.
2011
+ params[pp.slice(1, -1)] = urlParts.slice(i);
2012
+ break;
2013
+ }
2014
+ if (i >= urlParts.length) break;
2015
+ if (pp.startsWith(":")) {
2016
+ params[pp.slice(1)] = urlParts[i];
2017
+ } else if (pp !== urlParts[i]) {
2018
+ break;
2019
+ }
2020
+ }
2021
+ return params;
2154
2022
  },
2155
2023
  renderInterceptResponse(sourceRoute, interceptElement) {
2156
2024
  const interceptOnError = createRscOnErrorHandler(
@@ -2165,8 +2033,11 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2165
2033
  // by the client, and async server components that run during consumption need the
2166
2034
  // context to still be live. The AsyncLocalStorage scope from runWithRequestContext
2167
2035
  // handles cleanup naturally when all async continuations complete.
2036
+ const interceptHeaders = new Headers({ "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" });
2037
+ __mergeMiddlewareResponseHeaders(interceptHeaders, _mwCtx.headers);
2168
2038
  return new Response(interceptStream, {
2169
- headers: { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" },
2039
+ status: _mwCtx.status ?? 200,
2040
+ headers: interceptHeaders,
2170
2041
  });
2171
2042
  },
2172
2043
  searchParams: url.searchParams,
@@ -2217,6 +2088,19 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2217
2088
  // rscCssTransform — no manual loadCss() call needed.
2218
2089
  const _hasLoadingBoundary = !!(route.loading && route.loading.default);
2219
2090
  const _asyncLayoutParams = makeThenableParams(params);
2091
+ // Convert URLSearchParams to a plain object then wrap in makeThenableParams()
2092
+ // so probePage() passes the same shape that buildPageElement() gives to the
2093
+ // real render. Without this, pages that destructure await-ed searchParams
2094
+ // throw TypeError during probe.
2095
+ const _probeSearchObj = {};
2096
+ url.searchParams.forEach(function(v, k) {
2097
+ if (k in _probeSearchObj) {
2098
+ _probeSearchObj[k] = Array.isArray(_probeSearchObj[k]) ? _probeSearchObj[k].concat(v) : [_probeSearchObj[k], v];
2099
+ } else {
2100
+ _probeSearchObj[k] = v;
2101
+ }
2102
+ });
2103
+ const _asyncSearchParams = makeThenableParams(_probeSearchObj);
2220
2104
  return __renderAppPageLifecycle({
2221
2105
  cleanPathname,
2222
2106
  clearRequestContext() {
@@ -2262,7 +2146,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2262
2146
  return LayoutComp({ params: _asyncLayoutParams, children: null });
2263
2147
  },
2264
2148
  probePage() {
2265
- return PageComponent({ params });
2149
+ return PageComponent({ params: _asyncLayoutParams, searchParams: _asyncSearchParams });
2266
2150
  },
2267
2151
  revalidateSeconds,
2268
2152
  renderErrorBoundaryResponse(renderErr) {