vinext 0.1.2 → 0.1.3

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 (199) hide show
  1. package/dist/build/prerender.d.ts +9 -1
  2. package/dist/build/prerender.js +41 -12
  3. package/dist/build/run-prerender.d.ts +10 -2
  4. package/dist/build/run-prerender.js +15 -1
  5. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  6. package/dist/client/app-nav-failure-handler.js +44 -0
  7. package/dist/client/vinext-next-data.d.ts +18 -1
  8. package/dist/client/window-next.d.ts +2 -1
  9. package/dist/client/window-next.js +12 -1
  10. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  11. package/dist/config/config-matchers.js +73 -14
  12. package/dist/config/next-config.d.ts +46 -4
  13. package/dist/config/next-config.js +147 -48
  14. package/dist/deploy.d.ts +30 -11
  15. package/dist/deploy.js +180 -99
  16. package/dist/entries/app-browser-entry.d.ts +9 -3
  17. package/dist/entries/app-browser-entry.js +21 -3
  18. package/dist/entries/app-rsc-entry.d.ts +2 -0
  19. package/dist/entries/app-rsc-entry.js +64 -5
  20. package/dist/entries/app-rsc-manifest.js +2 -0
  21. package/dist/entries/app-ssr-entry.js +1 -1
  22. package/dist/entries/pages-client-entry.js +53 -8
  23. package/dist/entries/pages-server-entry.js +41 -5
  24. package/dist/index.js +200 -62
  25. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  26. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  27. package/dist/plugins/optimize-imports.d.ts +2 -1
  28. package/dist/plugins/optimize-imports.js +11 -9
  29. package/dist/plugins/postcss.js +7 -7
  30. package/dist/plugins/typeof-window.d.ts +14 -0
  31. package/dist/plugins/typeof-window.js +150 -0
  32. package/dist/routing/app-route-graph.d.ts +2 -1
  33. package/dist/routing/app-route-graph.js +44 -14
  34. package/dist/routing/file-matcher.d.ts +10 -1
  35. package/dist/routing/file-matcher.js +22 -1
  36. package/dist/routing/pages-router.js +3 -3
  37. package/dist/routing/utils.d.ts +35 -6
  38. package/dist/routing/utils.js +59 -7
  39. package/dist/server/api-handler.d.ts +6 -1
  40. package/dist/server/api-handler.js +21 -15
  41. package/dist/server/app-browser-action-result.d.ts +19 -6
  42. package/dist/server/app-browser-action-result.js +19 -10
  43. package/dist/server/app-browser-entry.js +167 -90
  44. package/dist/server/app-browser-error.d.ts +10 -6
  45. package/dist/server/app-browser-error.js +43 -8
  46. package/dist/server/app-browser-hydration.d.ts +2 -0
  47. package/dist/server/app-browser-hydration.js +1 -0
  48. package/dist/server/app-browser-navigation-controller.d.ts +4 -2
  49. package/dist/server/app-browser-navigation-controller.js +23 -2
  50. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  51. package/dist/server/app-browser-server-action-navigation.js +9 -0
  52. package/dist/server/app-browser-stream.js +86 -43
  53. package/dist/server/app-elements-wire.d.ts +6 -1
  54. package/dist/server/app-elements-wire.js +14 -4
  55. package/dist/server/app-elements.d.ts +2 -2
  56. package/dist/server/app-elements.js +2 -2
  57. package/dist/server/app-fallback-renderer.d.ts +1 -0
  58. package/dist/server/app-fallback-renderer.js +3 -1
  59. package/dist/server/app-optimistic-routing.js +2 -2
  60. package/dist/server/app-page-boundary-render.d.ts +1 -0
  61. package/dist/server/app-page-boundary-render.js +27 -14
  62. package/dist/server/app-page-cache-render.d.ts +53 -0
  63. package/dist/server/app-page-cache-render.js +91 -0
  64. package/dist/server/app-page-cache.d.ts +16 -2
  65. package/dist/server/app-page-cache.js +62 -1
  66. package/dist/server/app-page-dispatch.d.ts +26 -0
  67. package/dist/server/app-page-dispatch.js +149 -92
  68. package/dist/server/app-page-element-builder.d.ts +1 -0
  69. package/dist/server/app-page-element-builder.js +5 -2
  70. package/dist/server/app-page-execution.d.ts +6 -1
  71. package/dist/server/app-page-execution.js +21 -1
  72. package/dist/server/app-page-probe.d.ts +1 -0
  73. package/dist/server/app-page-probe.js +4 -0
  74. package/dist/server/app-page-render-observation.d.ts +3 -1
  75. package/dist/server/app-page-render-observation.js +17 -1
  76. package/dist/server/app-page-render.d.ts +12 -1
  77. package/dist/server/app-page-render.js +42 -4
  78. package/dist/server/app-page-request.d.ts +2 -0
  79. package/dist/server/app-page-request.js +2 -1
  80. package/dist/server/app-page-route-wiring.d.ts +3 -1
  81. package/dist/server/app-page-route-wiring.js +14 -5
  82. package/dist/server/app-page-stream.d.ts +15 -3
  83. package/dist/server/app-page-stream.js +11 -5
  84. package/dist/server/app-pages-bridge.d.ts +18 -0
  85. package/dist/server/app-pages-bridge.js +22 -5
  86. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  87. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  88. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  89. package/dist/server/app-ppr-fallback-shell.js +8 -1
  90. package/dist/server/app-route-handler-dispatch.js +9 -2
  91. package/dist/server/app-route-handler-policy.d.ts +1 -0
  92. package/dist/server/app-router-entry.js +5 -0
  93. package/dist/server/app-rsc-cache-busting.js +2 -0
  94. package/dist/server/app-rsc-handler.d.ts +25 -0
  95. package/dist/server/app-rsc-handler.js +154 -54
  96. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  97. package/dist/server/app-rsc-route-matching.js +2 -0
  98. package/dist/server/app-segment-config.d.ts +9 -1
  99. package/dist/server/app-segment-config.js +12 -3
  100. package/dist/server/app-server-action-execution.d.ts +1 -0
  101. package/dist/server/app-server-action-execution.js +42 -13
  102. package/dist/server/app-ssr-entry.d.ts +2 -0
  103. package/dist/server/app-ssr-entry.js +83 -10
  104. package/dist/server/cache-control.js +4 -0
  105. package/dist/server/dev-server.d.ts +2 -2
  106. package/dist/server/dev-server.js +244 -51
  107. package/dist/server/hybrid-route-priority.d.ts +22 -0
  108. package/dist/server/hybrid-route-priority.js +33 -0
  109. package/dist/server/image-optimization.d.ts +18 -9
  110. package/dist/server/image-optimization.js +37 -23
  111. package/dist/server/implicit-tags.d.ts +2 -1
  112. package/dist/server/implicit-tags.js +4 -1
  113. package/dist/server/navigation-planner.d.ts +133 -30
  114. package/dist/server/navigation-planner.js +114 -0
  115. package/dist/server/navigation-trace.d.ts +8 -1
  116. package/dist/server/navigation-trace.js +8 -1
  117. package/dist/server/pages-api-route.d.ts +6 -0
  118. package/dist/server/pages-api-route.js +13 -2
  119. package/dist/server/pages-asset-tags.d.ts +2 -1
  120. package/dist/server/pages-asset-tags.js +6 -2
  121. package/dist/server/pages-data-route.d.ts +8 -1
  122. package/dist/server/pages-data-route.js +11 -2
  123. package/dist/server/pages-get-initial-props.d.ts +54 -4
  124. package/dist/server/pages-get-initial-props.js +43 -1
  125. package/dist/server/pages-node-compat.js +2 -2
  126. package/dist/server/pages-page-data.d.ts +11 -2
  127. package/dist/server/pages-page-data.js +204 -33
  128. package/dist/server/pages-page-handler.d.ts +4 -2
  129. package/dist/server/pages-page-handler.js +59 -22
  130. package/dist/server/pages-page-response.d.ts +2 -1
  131. package/dist/server/pages-page-response.js +7 -4
  132. package/dist/server/pages-request-pipeline.d.ts +1 -0
  133. package/dist/server/pages-request-pipeline.js +73 -36
  134. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  135. package/dist/server/pregenerated-concrete-paths.js +2 -19
  136. package/dist/server/prerender-manifest.d.ts +33 -0
  137. package/dist/server/prerender-manifest.js +54 -0
  138. package/dist/server/prerender-route-params.d.ts +1 -2
  139. package/dist/server/prod-server.js +9 -3
  140. package/dist/server/request-pipeline.d.ts +3 -15
  141. package/dist/server/request-pipeline.js +58 -47
  142. package/dist/server/rsc-stream-hints.d.ts +5 -1
  143. package/dist/server/rsc-stream-hints.js +6 -1
  144. package/dist/server/seed-cache.js +10 -18
  145. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  146. package/dist/shims/app-router-scroll-state.js +14 -2
  147. package/dist/shims/app-router-scroll.d.ts +3 -0
  148. package/dist/shims/app-router-scroll.js +28 -18
  149. package/dist/shims/cache-runtime.js +3 -2
  150. package/dist/shims/cache.d.ts +1 -0
  151. package/dist/shims/cache.js +1 -1
  152. package/dist/shims/cdn-cache.d.ts +5 -5
  153. package/dist/shims/dynamic-preload-chunks.js +6 -4
  154. package/dist/shims/error-boundary.d.ts +2 -0
  155. package/dist/shims/error-boundary.js +7 -0
  156. package/dist/shims/error.js +3 -2
  157. package/dist/shims/error.react-server.d.ts +9 -0
  158. package/dist/shims/error.react-server.js +6 -0
  159. package/dist/shims/fetch-cache.d.ts +3 -1
  160. package/dist/shims/fetch-cache.js +45 -20
  161. package/dist/shims/hash-scroll.js +6 -1
  162. package/dist/shims/headers.js +29 -4
  163. package/dist/shims/internal/als-registry.js +28 -1
  164. package/dist/shims/internal/app-route-detection.js +8 -17
  165. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  166. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  167. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  168. package/dist/shims/internal/navigation-untracked.js +55 -0
  169. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  170. package/dist/shims/internal/pages-data-target.js +17 -8
  171. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  172. package/dist/shims/internal/pages-router-accessor.js +13 -0
  173. package/dist/shims/internal/router-context.d.ts +2 -1
  174. package/dist/shims/internal/router-context.js +3 -1
  175. package/dist/shims/link.js +12 -5
  176. package/dist/shims/navigation.d.ts +8 -2
  177. package/dist/shims/navigation.js +61 -31
  178. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  179. package/dist/shims/ppr-fallback-shell.js +28 -7
  180. package/dist/shims/router.d.ts +13 -2
  181. package/dist/shims/router.js +419 -128
  182. package/dist/shims/server.d.ts +16 -1
  183. package/dist/shims/server.js +44 -12
  184. package/dist/shims/unified-request-context.js +1 -0
  185. package/dist/utils/built-asset-url.d.ts +4 -0
  186. package/dist/utils/built-asset-url.js +11 -0
  187. package/dist/utils/commonjs-loader.d.ts +16 -0
  188. package/dist/utils/commonjs-loader.js +100 -0
  189. package/dist/utils/deployment-id.d.ts +8 -0
  190. package/dist/utils/deployment-id.js +22 -0
  191. package/dist/utils/html-limited-bots.d.ts +18 -1
  192. package/dist/utils/html-limited-bots.js +23 -1
  193. package/dist/utils/parse-cookie.d.ts +13 -0
  194. package/dist/utils/parse-cookie.js +52 -0
  195. package/dist/utils/path.d.ts +7 -1
  196. package/dist/utils/path.js +9 -1
  197. package/package.json +2 -2
  198. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  199. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -31,6 +31,7 @@ type VinextConfigSubset = {
31
31
  assetPrefix: string;
32
32
  trailingSlash: boolean;
33
33
  expireTime?: number;
34
+ htmlLimitedBots?: string;
34
35
  clientTraceMetadata?: readonly string[];
35
36
  disableOptimizedLoading: boolean;
36
37
  };
@@ -73,8 +74,8 @@ type CreatePagesPageHandlerOptions = {
73
74
  renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>; /** `safeJsonStringify` from `vinext/html`. */
74
75
  safeJsonStringify: (value: unknown) => string; /** `sanitizeDestination` from the config-matchers module. */
75
76
  sanitizeDestination: (dest: string) => string; /** Build the React page element for a given set of page props. */
76
- createPageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null, pageProps: Record<string, unknown>) => ReactNode; /** Build the element with optional App/Component enhancers (for _document). */
77
- enhancePageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null, pageProps: Record<string, unknown>, opts: RenderPageEnhancers) => ReactNode; /** The `_app` page component (or null). */
77
+ createPageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null, props: Record<string, unknown>) => ReactNode; /** Build the element with optional App/Component enhancers (for _document). */
78
+ enhancePageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null, props: Record<string, unknown>, opts: RenderPageEnhancers) => ReactNode; /** The `_app` page component (or null). */
78
79
  AppComponent: ComponentType | null; /** The `_document` page component (or null). */
79
80
  DocumentComponent: ComponentType | null;
80
81
  };
@@ -82,6 +83,7 @@ type RenderPageOptions = {
82
83
  isDataReq?: boolean;
83
84
  statusCode?: number;
84
85
  asPath?: string;
86
+ originalUrl?: string;
85
87
  renderErrorPageOnMiss?: boolean;
86
88
  __isInternalErrorRender?: boolean;
87
89
  __forcedRoute?: PageRoute;
@@ -7,13 +7,14 @@ import { NEVER_CACHE_CONTROL } from "./cache-control.js";
7
7
  import "./isr-decision.js";
8
8
  import { PRERENDER_REVALIDATE_HEADER, isOnDemandRevalidateRequest, isrCacheKey, isrGet, isrSet, triggerBackgroundRegeneration } from "./isr-cache.js";
9
9
  import { ensureFetchPatch } from "../shims/fetch-cache.js";
10
+ import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
10
11
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
11
12
  import { getScriptNonceFromHeaderSources } from "./csp.js";
12
13
  import { resolvePagesI18nRequest } from "./pages-i18n.js";
13
14
  import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
14
15
  import { buildPagesReadinessNextData } from "./pages-readiness.js";
15
16
  import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
16
- import { buildNextDataJsonResponse, buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
17
+ import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
17
18
  import { createPagesReqRes } from "./pages-node-compat.js";
18
19
  import { collectAssetTags, resolveClientModuleUrl } from "./pages-asset-tags.js";
19
20
  import { renderPagesPageResponse } from "./pages-page-response.js";
@@ -48,19 +49,38 @@ function createPagesPageHandler(opts) {
48
49
  }
49
50
  async function renderPage(request, url, manifest, middlewareHeaders, options) {
50
51
  let isDataReq = !!(options && options.isDataReq);
52
+ const requestUrl = new URL(request.url);
53
+ const rawOriginalUrl = options && typeof options.originalUrl === "string" ? options.originalUrl : requestUrl.pathname + requestUrl.search;
54
+ const originalRequestUrl = new URL(rawOriginalUrl, requestUrl);
55
+ const originalRequestPathAndSearch = originalRequestUrl.pathname + originalRequestUrl.search;
56
+ let dataRequestPathname = null;
57
+ let dataRequestSearch = "";
58
+ const initialDataNorm = normalizePagesDataRequest(request, buildId);
51
59
  if (!isDataReq) {
52
- const dataNorm = normalizePagesDataRequest(request, buildId);
53
- if (dataNorm.notFoundResponse) return dataNorm.notFoundResponse;
54
- if (dataNorm.isDataReq) {
60
+ if (initialDataNorm.notFoundResponse) return initialDataNorm.notFoundResponse;
61
+ if (initialDataNorm.isDataReq) {
55
62
  isDataReq = true;
63
+ dataRequestPathname = initialDataNorm.normalizedPathname;
64
+ dataRequestSearch = initialDataNorm.search;
56
65
  if (url && url.startsWith("/_next/data/")) {
57
66
  const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
58
- url = dataNorm.normalizedPathname + qs;
67
+ url = initialDataNorm.normalizedPathname + qs;
59
68
  }
60
69
  }
70
+ } else if (initialDataNorm.isDataReq) {
71
+ dataRequestPathname = initialDataNorm.normalizedPathname;
72
+ dataRequestSearch = initialDataNorm.search;
73
+ }
74
+ if (isDataReq && dataRequestPathname === null && buildId) {
75
+ const originalDataMatch = parseNextDataPathname(originalRequestUrl.pathname, buildId);
76
+ if (originalDataMatch) {
77
+ dataRequestPathname = originalDataMatch.pagePathname;
78
+ dataRequestSearch = originalRequestUrl.search;
79
+ }
61
80
  }
62
81
  const statusCode = options && typeof options.statusCode === "number" ? options.statusCode : void 0;
63
- const asPath = options && typeof options.asPath === "string" ? options.asPath : void 0;
82
+ const defaultAsPath = isDataReq && dataRequestPathname ? dataRequestPathname + dataRequestSearch : originalRequestPathAndSearch;
83
+ const asPath = options && typeof options.asPath === "string" ? options.asPath : defaultAsPath;
64
84
  const renderErrorPageOnMiss = !(options && options.renderErrorPageOnMiss === false);
65
85
  const isInternalErrorRender = !!(options && options.__isInternalErrorRender);
66
86
  const err = options && options.err;
@@ -143,8 +163,8 @@ function createPagesPageHandler(opts) {
143
163
  });
144
164
  if (methodResponse) return methodResponse;
145
165
  }
146
- const pageModuleUrl = resolveClientModuleUrl(manifest, route.filePath, vinextConfig.basePath, vinextConfig.assetPrefix);
147
- const appModuleUrl = resolveClientModuleUrl(manifest, appAssetPath, vinextConfig.basePath, vinextConfig.assetPrefix);
166
+ const pageModuleUrl = resolveClientModuleUrl(manifest, route.filePath, vinextConfig.basePath, vinextConfig.assetPrefix, process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID);
167
+ const appModuleUrl = resolveClientModuleUrl(manifest, appAssetPath, vinextConfig.basePath, vinextConfig.assetPrefix, process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID);
148
168
  const serializedPagesNextData = {
149
169
  ...pagesNextData,
150
170
  __vinext: {
@@ -159,24 +179,30 @@ function createPagesPageHandler(opts) {
159
179
  let allFontPreloads = [];
160
180
  try {
161
181
  allFontPreloads = getFontPreloads();
162
- if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + p.href + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
182
+ if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + appendAssetDeploymentIdQuery(p.href) + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
163
183
  } catch {}
184
+ const pagesResolvedUrl = (new URL(routeUrl, originalRequestUrl).pathname || "/") + originalRequestUrl.search;
164
185
  const pageDataResult = await resolvePagesPageData({
165
186
  isDataReq,
166
187
  err,
167
188
  applyRequestContexts: applySSRContext,
168
189
  buildId,
169
190
  deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID,
191
+ htmlLimitedBots: vinextConfig.htmlLimitedBots,
170
192
  createGsspReqRes() {
171
193
  return createPagesReqRes({
172
194
  body: void 0,
173
195
  query,
174
196
  request,
175
- url: routeUrl
197
+ url: originalRequestPathAndSearch
176
198
  });
177
199
  },
178
- createPageElement(currentPageProps) {
179
- const el = createPageElement(PageComponent, AppComponent, currentPageProps);
200
+ createAppTree(appTreeProps) {
201
+ const el = createPageElement(PageComponent, AppComponent, appTreeProps);
202
+ return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
203
+ },
204
+ createPageElement(currentProps) {
205
+ const el = createPageElement(PageComponent, AppComponent, currentProps);
180
206
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
181
207
  },
182
208
  fontLinkHeader,
@@ -188,15 +214,17 @@ function createPagesPageHandler(opts) {
188
214
  isBuildTimePrerendering: typeof process !== "undefined" && process.env && process.env.VINEXT_PRERENDER === "1",
189
215
  isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER)),
190
216
  pageModule,
217
+ AppComponent,
191
218
  params,
192
219
  query,
193
220
  asPath: renderAsPath ?? routeUrl,
221
+ resolvedUrl: pagesResolvedUrl,
194
222
  renderIsrPassToStringAsync,
195
223
  route: { isDynamic: route.isDynamic },
196
224
  routePattern,
197
225
  routeUrl,
198
226
  runInFreshUnifiedContext(callback) {
199
- return runWithRequestContext(createRequestContext({ executionContext: getRequestExecutionContext() }), async () => {
227
+ return runWithRequestContext(createRequestContext({ executionContext: null }), async () => {
200
228
  ensureFetchPatch();
201
229
  return callback();
202
230
  });
@@ -224,10 +252,17 @@ function createPagesPageHandler(opts) {
224
252
  }
225
253
  if (pageDataResult.kind === "response") return pageDataResult.response;
226
254
  let pageProps = pageDataResult.pageProps;
227
- if (routePattern === "/_error" && typeof renderStatusCode === "number") pageProps = {
228
- ...pageProps,
229
- statusCode: renderStatusCode
230
- };
255
+ let renderProps = pageDataResult.props;
256
+ if (routePattern === "/_error" && typeof renderStatusCode === "number") {
257
+ pageProps = {
258
+ ...pageProps,
259
+ statusCode: renderStatusCode
260
+ };
261
+ renderProps = {
262
+ ...renderProps,
263
+ pageProps
264
+ };
265
+ }
231
266
  const gsspRes = pageDataResult.gsspRes;
232
267
  const isrRevalidateSeconds = pageDataResult.isrRevalidateSeconds;
233
268
  const isFallbackRender = pageDataResult.isFallback === true;
@@ -264,7 +299,7 @@ function createPagesPageHandler(opts) {
264
299
  const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
265
300
  if (deploymentId) init.headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
266
301
  }
267
- return buildNextDataJsonResponse(pageProps, safeJsonStringify, init);
302
+ return buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, init);
268
303
  }
269
304
  const pageModuleIds = [];
270
305
  if (route.filePath) pageModuleIds.push(route.filePath);
@@ -276,18 +311,19 @@ function createPagesPageHandler(opts) {
276
311
  scriptNonce,
277
312
  disableOptimizedLoading: vinextConfig.disableOptimizedLoading,
278
313
  basePath: vinextConfig.basePath,
279
- assetPrefix: vinextConfig.assetPrefix
314
+ assetPrefix: vinextConfig.assetPrefix,
315
+ deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID
280
316
  }),
281
317
  buildId,
282
318
  clearSsrContext() {
283
319
  if (typeof setSSRContext === "function") setSSRContext(null);
284
320
  },
285
- createPageElement(currentPageProps) {
286
- const el = createPageElement(PageComponent, AppComponent, currentPageProps);
321
+ createPageElement(currentProps) {
322
+ const el = createPageElement(PageComponent, AppComponent, currentProps);
287
323
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
288
324
  },
289
325
  enhancePageElement(renderPageOpts) {
290
- const el = enhancePageElement(PageComponent, AppComponent, pageProps, renderPageOpts);
326
+ const el = enhancePageElement(PageComponent, AppComponent, renderProps, renderPageOpts);
291
327
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
292
328
  },
293
329
  DocumentComponent,
@@ -306,6 +342,7 @@ function createPagesPageHandler(opts) {
306
342
  i18n: buildI18nRenderContext(i18nConfig, locale, currentDefaultLocale, domainLocales),
307
343
  isFallback: isFallbackRender,
308
344
  pageProps,
345
+ props: renderProps,
309
346
  params,
310
347
  renderDocumentToString(element) {
311
348
  return renderToStringAsync(element);
@@ -93,6 +93,7 @@ type RenderPagesPageResponseOptions = {
93
93
  */
94
94
  isFallback?: boolean;
95
95
  pageProps: Record<string, unknown>;
96
+ props?: Record<string, unknown>;
96
97
  params: Record<string, unknown>;
97
98
  renderDocumentToString: (element: ReactNode) => Promise<string>;
98
99
  renderToReadableStream: (element: ReactNode) => Promise<ReadableStream<Uint8Array>>;
@@ -127,7 +128,7 @@ type RenderPagesPageResponseOptions = {
127
128
  */
128
129
  requestCacheControl?: string;
129
130
  };
130
- declare function buildPagesNextDataScript(options: Pick<RenderPagesPageResponseOptions, "buildId" | "i18n" | "isFallback" | "pageProps" | "params" | "routePattern" | "safeJsonStringify" | "scriptNonce" | "nextData"> & {
131
+ declare function buildPagesNextDataScript(options: Pick<RenderPagesPageResponseOptions, "buildId" | "i18n" | "isFallback" | "pageProps" | "props" | "params" | "routePattern" | "safeJsonStringify" | "scriptNonce" | "nextData"> & {
131
132
  vinext?: VinextNextData["__vinext"];
132
133
  }): string;
133
134
  declare function renderPagesPageResponse(options: RenderPagesPageResponseOptions): Promise<Response>;
@@ -5,6 +5,7 @@ import { fnv1a52 } from "../utils/hash.js";
5
5
  import { encodeCacheTag } from "../utils/encode-cache-tag.js";
6
6
  import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
7
7
  import { buildMissIsrCacheControl } from "./isr-decision.js";
8
+ import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
8
9
  import { withScriptNonce } from "../shims/script-nonce-context.js";
9
10
  import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from "./html.js";
10
11
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
@@ -62,14 +63,14 @@ function requestsNoCache(cacheControl) {
62
63
  function buildPagesFontHeadHtml(fontLinks, fontPreloads, fontStyles, scriptNonce) {
63
64
  let html = "";
64
65
  const nonceAttr = createNonceAttribute(scriptNonce);
65
- for (const link of fontLinks) html += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(link)}" />\n `;
66
- for (const preload of fontPreloads) html += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(preload.href)}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n `;
66
+ for (const link of fontLinks) html += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(link))}" />\n `;
67
+ for (const preload of fontPreloads) html += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(preload.href))}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n `;
67
68
  if (fontStyles.length > 0) html += `<style data-vinext-fonts${nonceAttr}>${fontStyles.join("\n")}</style>\n `;
68
69
  return html;
69
70
  }
70
71
  function buildPagesNextDataScript(options) {
71
72
  const nextDataPayload = {
72
- props: { pageProps: options.pageProps },
73
+ props: options.props ?? { pageProps: options.pageProps },
73
74
  page: options.routePattern,
74
75
  query: options.params,
75
76
  buildId: options.buildId,
@@ -171,6 +172,7 @@ function applyGsspHeaders(headers, gsspRes, statusCode) {
171
172
  return statusCode ?? gsspRes.statusCode;
172
173
  }
173
174
  async function renderPagesPageResponse(options) {
175
+ const renderProps = options.props ?? { pageProps: options.pageProps };
174
176
  options.resetSSRHead?.();
175
177
  await options.flushPreloads?.();
176
178
  const fontHeadHTML = buildPagesFontHeadHtml(options.getFontLinks(), options.fontPreloads, options.getFontStyles(), options.scriptNonce);
@@ -179,6 +181,7 @@ async function renderPagesPageResponse(options) {
179
181
  i18n: options.i18n,
180
182
  isFallback: options.isFallback,
181
183
  pageProps: options.pageProps,
184
+ props: renderProps,
182
185
  params: options.params,
183
186
  routePattern: options.routePattern,
184
187
  safeJsonStringify: options.safeJsonStringify,
@@ -205,7 +208,7 @@ async function renderPagesPageResponse(options) {
205
208
  controller.close();
206
209
  } });
207
210
  else {
208
- const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(options.pageProps)), options.scriptNonce);
211
+ const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(renderProps)), options.scriptNonce);
209
212
  bodyStream = await options.renderToReadableStream(pageElement);
210
213
  }
211
214
  if (documentRenderPage.status === "skipped") await callDocumentGetInitialProps(options.DocumentComponent, options.setDocumentInitialHead);
@@ -5,6 +5,7 @@ import { HeaderRecord } from "./request-pipeline.js";
5
5
  type PagesRenderOptions = {
6
6
  isDataReq?: boolean;
7
7
  renderErrorPageOnMiss?: boolean;
8
+ originalUrl?: string;
8
9
  };
9
10
  type MiddlewareResult = {
10
11
  continue: boolean;
@@ -1,6 +1,6 @@
1
1
  import { addBasePathToPathname, hasBasePath } from "../utils/base-path.js";
2
2
  import { applyMiddlewareRequestHeaders, isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
3
- import { applyConfigHeadersToHeaderRecord, normalizeTrailingSlash } from "./request-pipeline.js";
3
+ import { applyConfigHeadersToHeaderRecord, cloneRequestWithUrl, normalizeTrailingSlash } from "./request-pipeline.js";
4
4
  import { mergeRewriteQuery } from "../utils/query.js";
5
5
  import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
6
6
  import { mergeHeaders } from "./worker-utils.js";
@@ -68,7 +68,8 @@ async function runPagesRequest(request, deps) {
68
68
  };
69
69
  }
70
70
  }
71
- let resolvedUrl = pathname + search;
71
+ const originalResolvedUrl = pathname + search;
72
+ let resolvedUrl = originalResolvedUrl;
72
73
  const middlewareHeaders = {};
73
74
  let middlewareStatus;
74
75
  if (typeof deps.runMiddleware === "function") {
@@ -114,7 +115,12 @@ async function runPagesRequest(request, deps) {
114
115
  }
115
116
  const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, request, { preserveCredentialHeaders: isExternalUrl(resolvedUrl) });
116
117
  request = postMwReq;
117
- let resolvedPathname = resolvedUrl.split("?")[0];
118
+ const pathnameForResolvedUrl = (value) => value.split("#", 1)[0].split("?", 1)[0];
119
+ const rewriteRequestContext = () => ({
120
+ ...postMwReqCtx,
121
+ query: new URL(resolvedUrl, url).searchParams
122
+ });
123
+ let resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
118
124
  const matchResolvedPathname = (p) => i18nConfig ? normalizeDefaultLocalePathname(p, i18nConfig, { hostname: requestHostname }) : p;
119
125
  if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
120
126
  configHeaders,
@@ -130,15 +136,15 @@ async function runPagesRequest(request, deps) {
130
136
  if (await deps.serveStaticFile(pathname, middlewareHeaders)) return { type: "handled" };
131
137
  }
132
138
  let configRewriteFired = false;
133
- if (configRewrites.beforeFiles?.length) {
134
- const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), configRewrites.beforeFiles, postMwReqCtx, basePathState);
139
+ for (const rewrite of configRewrites.beforeFiles ?? []) {
140
+ const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
135
141
  if (rewritten) {
136
142
  if (isExternalUrl(rewritten)) return {
137
143
  type: "response",
138
144
  response: await proxyExternal(request, rewritten)
139
145
  };
140
146
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
141
- resolvedPathname = resolvedUrl.split("?")[0];
147
+ resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
142
148
  configRewriteFired = true;
143
149
  }
144
150
  }
@@ -151,34 +157,61 @@ async function runPagesRequest(request, deps) {
151
157
  };
152
158
  const apiLookupUrl = stripI18nLocaleForApiRoute(resolvedUrl, i18nConfig);
153
159
  const apiLookupPathname = apiLookupUrl.split("?")[0];
154
- if (apiLookupPathname.startsWith("/api/") || apiLookupPathname === "/api") if (typeof deps.handleApi === "function") return {
155
- type: "response",
156
- defaultContentType: "application/octet-stream",
157
- response: mergeHeaders(await deps.handleApi(request, apiLookupUrl, deps.ctx ?? null), middlewareHeaders, middlewareStatus)
158
- };
159
- else return {
160
+ if (apiLookupPathname.startsWith("/api/") || apiLookupPathname === "/api") if (typeof deps.handleApi === "function") {
161
+ let apiRequest = request;
162
+ if (basePath && hadBasePath) {
163
+ const apiRequestUrl = new URL(request.url);
164
+ apiRequestUrl.pathname = addBasePathToPathname(apiRequestUrl.pathname, basePath);
165
+ apiRequest = cloneRequestWithUrl(request, apiRequestUrl.toString());
166
+ }
167
+ return {
168
+ type: "response",
169
+ defaultContentType: "application/octet-stream",
170
+ response: mergeHeaders(await deps.handleApi(apiRequest, apiLookupUrl, deps.ctx ?? null), middlewareHeaders, middlewareStatus)
171
+ };
172
+ } else return {
160
173
  type: "api",
161
174
  apiUrl: apiLookupUrl,
162
175
  stagedHeaders: middlewareHeaders,
163
176
  requestHeaders: request.headers,
164
177
  middlewareStatus
165
178
  };
166
- const pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
179
+ let pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
167
180
  let resolvedPathnameChanged = false;
168
- if ((!pageMatch || pageMatch.route.isDynamic) && configRewrites.afterFiles?.length) {
169
- const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), configRewrites.afterFiles, postMwReqCtx, basePathState);
181
+ if (!pageMatch || pageMatch.route.isDynamic) for (const rewrite of configRewrites.afterFiles ?? []) {
182
+ const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
170
183
  if (rewritten) {
171
184
  if (isExternalUrl(rewritten)) return {
172
185
  type: "response",
173
186
  response: await proxyExternal(request, rewritten)
174
187
  };
175
188
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
176
- resolvedPathname = resolvedUrl.split("?")[0];
189
+ resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
177
190
  resolvedPathnameChanged = true;
191
+ pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
192
+ if (pageMatch) break;
178
193
  }
179
194
  }
195
+ const refreshDataRewriteHeader = () => {
196
+ if ((isDataReq || isDataRequest) && resolvedUrl !== originalResolvedUrl && !isExternalUrl(resolvedUrl)) middlewareHeaders["x-nextjs-rewrite"] = resolvedUrl;
197
+ else delete middlewareHeaders["x-nextjs-rewrite"];
198
+ };
199
+ refreshDataRewriteHeader();
180
200
  if (typeof deps.renderPage === "function") {
181
- const renderPageMatch = resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch;
201
+ let renderPageMatch = pageMatch;
202
+ if ((isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
203
+ const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
204
+ if (!fallbackRewrite) continue;
205
+ if (isExternalUrl(fallbackRewrite)) return {
206
+ type: "response",
207
+ response: await proxyExternal(request, fallbackRewrite)
208
+ };
209
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
210
+ resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
211
+ renderPageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
212
+ refreshDataRewriteHeader();
213
+ if (renderPageMatch) break;
214
+ }
182
215
  const shouldDeferErrorPageOnMiss = !isDataReq && !isDataRequest && !!deps.matchPageRoute && !renderPageMatch;
183
216
  const initialRenderOptions = shouldDeferErrorPageOnMiss ? { renderErrorPageOnMiss: false } : isDataReq ? { isDataReq: true } : void 0;
184
217
  const stagedHeaders = new Headers();
@@ -186,16 +219,18 @@ async function runPagesRequest(request, deps) {
186
219
  else stagedHeaders.set(k, v);
187
220
  let response = await deps.renderPage(request, resolvedUrl, initialRenderOptions, stagedHeaders);
188
221
  let matchedFallbackRewrite = false;
189
- if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) {
190
- const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), configRewrites.fallback, postMwReqCtx, basePathState);
191
- if (fallbackRewrite) {
192
- if (isExternalUrl(fallbackRewrite)) return {
193
- type: "response",
194
- response: await proxyExternal(request, fallbackRewrite)
195
- };
196
- response = await deps.renderPage(request, mergeRewriteQuery(resolvedUrl, fallbackRewrite), void 0, stagedHeaders);
197
- matchedFallbackRewrite = true;
198
- }
222
+ if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
223
+ const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
224
+ if (!fallbackRewrite) continue;
225
+ if (isExternalUrl(fallbackRewrite)) return {
226
+ type: "response",
227
+ response: await proxyExternal(request, fallbackRewrite)
228
+ };
229
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
230
+ resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
231
+ response = await deps.renderPage(request, resolvedUrl, void 0, stagedHeaders);
232
+ matchedFallbackRewrite = true;
233
+ if (response.status !== 404) break;
199
234
  }
200
235
  if (response.status === 404 && shouldDeferErrorPageOnMiss && !matchedFallbackRewrite) response = await deps.renderPage(request, resolvedUrl, void 0, stagedHeaders);
201
236
  const merged = mergeHeaders(response, middlewareHeaders, middlewareStatus);
@@ -206,16 +241,18 @@ async function runPagesRequest(request, deps) {
206
241
  defaultContentType: "text/html"
207
242
  };
208
243
  }
209
- if (!(resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch) && configRewrites.fallback?.length) {
210
- const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), configRewrites.fallback, postMwReqCtx, basePathState);
211
- if (fallbackRewrite) {
212
- if (isExternalUrl(fallbackRewrite)) return {
213
- type: "response",
214
- response: await proxyExternal(request, fallbackRewrite)
215
- };
216
- resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
217
- }
244
+ if (!(resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch) && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
245
+ const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
246
+ if (!fallbackRewrite) continue;
247
+ if (isExternalUrl(fallbackRewrite)) return {
248
+ type: "response",
249
+ response: await proxyExternal(request, fallbackRewrite)
250
+ };
251
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
252
+ resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
253
+ if (deps.matchPageRoute?.(resolvedPathname, request)) break;
218
254
  }
255
+ refreshDataRewriteHeader();
219
256
  return {
220
257
  type: "render",
221
258
  resolvedUrl,
@@ -4,28 +4,12 @@ declare global {
4
4
  }
5
5
  declare function normalizePregeneratedPathname(pathname: string): string;
6
6
  declare function clearPregeneratedConcretePaths(): void;
7
- /**
8
- * Records a concrete URL path for a route pattern. The pathname is normalized
9
- * here so this is the single source of truth: every caller — the Worker global
10
- * table and the Node `seed-cache.ts` path — stores the canonical form that
11
- * matches the runtime `cleanPathname` lookup without having to pre-normalize.
12
- */
13
7
  declare function addPregeneratedConcretePath(routePattern: string, pathname: string): void;
14
- /**
15
- * Returns the live backing `Set` for a route pattern (not a copy) to keep
16
- * lookups allocation-free on the serving hot path. The `ReadonlySet` type
17
- * forbids mutation at compile time. Callers must treat the result as
18
- * point-in-time and must NOT retain it across a re-seed: each
19
- * `initPregeneratedPathsFromGlobals` call runs `clearPregeneratedConcretePaths`,
20
- * which empties the map, leaving any previously-returned reference stale. Read
21
- * it, use it, drop it — never cache the reference.
22
- */
23
8
  declare function getRenderedConcreteUrlPathsForRoute(routePattern: string): ReadonlySet<string> | undefined;
24
9
  /**
25
10
  * Populate the registry from `globalThis.__VINEXT_PREGENERATED_CONCRETE_PATHS`.
26
11
  * No-op when the global is not set (Node path — seed-cache handles it later).
27
- * `addPregeneratedConcretePath` normalizes each pathname so it matches the
28
- * runtime `cleanPathname`.
12
+ * Pathnames are normalised so they match the runtime `cleanPathname`.
29
13
  */
30
14
  declare function initPregeneratedPathsFromGlobals(): void;
31
15
  //#endregion
@@ -16,38 +16,21 @@ const concreteUrlPathsByRoute = /* @__PURE__ */ new Map();
16
16
  function clearPregeneratedConcretePaths() {
17
17
  concreteUrlPathsByRoute.clear();
18
18
  }
19
- /**
20
- * Records a concrete URL path for a route pattern. The pathname is normalized
21
- * here so this is the single source of truth: every caller — the Worker global
22
- * table and the Node `seed-cache.ts` path — stores the canonical form that
23
- * matches the runtime `cleanPathname` lookup without having to pre-normalize.
24
- */
25
19
  function addPregeneratedConcretePath(routePattern, pathname) {
26
- const normalized = normalizePregeneratedPathname(pathname);
27
20
  let paths = concreteUrlPathsByRoute.get(routePattern);
28
21
  if (!paths) {
29
22
  paths = /* @__PURE__ */ new Set();
30
23
  concreteUrlPathsByRoute.set(routePattern, paths);
31
24
  }
32
- paths.add(normalized);
25
+ paths.add(normalizePregeneratedPathname(pathname));
33
26
  }
34
- /**
35
- * Returns the live backing `Set` for a route pattern (not a copy) to keep
36
- * lookups allocation-free on the serving hot path. The `ReadonlySet` type
37
- * forbids mutation at compile time. Callers must treat the result as
38
- * point-in-time and must NOT retain it across a re-seed: each
39
- * `initPregeneratedPathsFromGlobals` call runs `clearPregeneratedConcretePaths`,
40
- * which empties the map, leaving any previously-returned reference stale. Read
41
- * it, use it, drop it — never cache the reference.
42
- */
43
27
  function getRenderedConcreteUrlPathsForRoute(routePattern) {
44
28
  return concreteUrlPathsByRoute.get(routePattern);
45
29
  }
46
30
  /**
47
31
  * Populate the registry from `globalThis.__VINEXT_PREGENERATED_CONCRETE_PATHS`.
48
32
  * No-op when the global is not set (Node path — seed-cache handles it later).
49
- * `addPregeneratedConcretePath` normalizes each pathname so it matches the
50
- * runtime `cleanPathname`.
33
+ * Pathnames are normalised so they match the runtime `cleanPathname`.
51
34
  */
52
35
  function initPregeneratedPathsFromGlobals() {
53
36
  const raw = globalThis.__VINEXT_PREGENERATED_CONCRETE_PATHS;
@@ -0,0 +1,33 @@
1
+ //#region src/server/prerender-manifest.d.ts
2
+ type PrerenderManifestRoute = {
3
+ route: string;
4
+ status?: string;
5
+ revalidate?: number | false;
6
+ expire?: number;
7
+ path?: string;
8
+ router?: string;
9
+ fallback?: boolean;
10
+ };
11
+ type PrerenderManifest = {
12
+ buildId?: string;
13
+ trailingSlash?: boolean;
14
+ routes?: PrerenderManifestRoute[];
15
+ };
16
+ declare function readPrerenderManifest(manifestPath: string): PrerenderManifest | null;
17
+ declare function getRenderedAppRoutes(routes: PrerenderManifestRoute[]): PrerenderManifestRoute[];
18
+ /**
19
+ * Returns true when `pathname` contains bracket-delimited route params,
20
+ * indicating it is a fallback-shell placeholder (e.g. `/en/blog/[slug]`)
21
+ * rather than a concrete rendered URL.
22
+ */
23
+ declare function isFallbackShellArtifactPath(pathname: string, route?: PrerenderManifestRoute): boolean;
24
+ /**
25
+ * Build the pregenerated concrete-path payload table from a prerender manifest.
26
+ *
27
+ * Filters out fallback-shell placeholder paths and groups remaining concrete
28
+ * paths by route pattern. Returns an empty array when the manifest has no
29
+ * rendered App routes or all routes are fallback-shell artifacts.
30
+ */
31
+ declare function buildPregeneratedConcretePathTable(manifest: PrerenderManifest): Array<[string, string[]]>;
32
+ //#endregion
33
+ export { buildPregeneratedConcretePathTable, getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest };
@@ -0,0 +1,54 @@
1
+ import fs from "node:fs";
2
+ //#region src/server/prerender-manifest.ts
3
+ function readPrerenderManifest(manifestPath) {
4
+ if (!fs.existsSync(manifestPath)) return null;
5
+ try {
6
+ return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
7
+ } catch (error) {
8
+ console.warn(`[vinext] Failed to read prerender manifest at ${manifestPath}:`, error);
9
+ return null;
10
+ }
11
+ }
12
+ function getRenderedAppRoutes(routes) {
13
+ return routes.filter((r) => r.status === "rendered" && r.router === "app");
14
+ }
15
+ function groupRoutesByPattern(routes) {
16
+ const byPattern = /* @__PURE__ */ new Map();
17
+ for (const r of routes) {
18
+ const pathname = r.path ?? r.route;
19
+ const existing = byPattern.get(r.route);
20
+ if (existing) existing.push(pathname);
21
+ else byPattern.set(r.route, [pathname]);
22
+ }
23
+ return byPattern;
24
+ }
25
+ /**
26
+ * Returns true when `pathname` contains bracket-delimited route params,
27
+ * indicating it is a fallback-shell placeholder (e.g. `/en/blog/[slug]`)
28
+ * rather than a concrete rendered URL.
29
+ */
30
+ function isFallbackShellArtifactPath(pathname, route) {
31
+ if (route?.fallback === true) return true;
32
+ if (route?.fallback === void 0) {
33
+ if (process.env.NODE_ENV !== "production") console.warn("[vinext] Legacy manifest detected: missing `fallback` flag for route. Using bracket heuristic for fallback-shell detection. A concrete URL containing literal brackets may be misclassified as a fallback shell.");
34
+ return pathname.includes("[") || pathname.includes("]");
35
+ }
36
+ return false;
37
+ }
38
+ /**
39
+ * Build the pregenerated concrete-path payload table from a prerender manifest.
40
+ *
41
+ * Filters out fallback-shell placeholder paths and groups remaining concrete
42
+ * paths by route pattern. Returns an empty array when the manifest has no
43
+ * rendered App routes or all routes are fallback-shell artifacts.
44
+ */
45
+ function buildPregeneratedConcretePathTable(manifest) {
46
+ const routes = manifest?.routes;
47
+ if (!routes?.length) return [];
48
+ const concreteRoutes = getRenderedAppRoutes(routes).filter((r) => {
49
+ return !isFallbackShellArtifactPath(r.path ?? r.route, r);
50
+ });
51
+ return Array.from(groupRoutesByPattern(concreteRoutes).entries());
52
+ }
53
+ //#endregion
54
+ export { buildPregeneratedConcretePathTable, getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest };
@@ -5,7 +5,6 @@ type PrerenderRouteParamsPayload = {
5
5
  params: PrerenderRouteParams;
6
6
  routePattern: string;
7
7
  };
8
- /** @public exported for #1716 serving consumers; not yet referenced in-repo */
9
8
  type PrerenderRouteParamsRouteMatch = {
10
9
  kind: "exact";
11
10
  params: PrerenderRouteParams;
@@ -21,4 +20,4 @@ declare function prerenderRouteParamsPayloadMatchesRoute(payload: PrerenderRoute
21
20
  declare function matchPrerenderRouteParamsPayload(payload: PrerenderRouteParamsPayload | null, routePattern: string, params: PrerenderRouteParams): PrerenderRouteParamsRouteMatch | null;
22
21
  declare function encodePrerenderRouteParams(pattern: string, params: PrerenderRouteParams, fallbackParamNames?: readonly string[]): PrerenderRouteParamsPayload | null;
23
22
  //#endregion
24
- export { PrerenderRouteParams, PrerenderRouteParamsPayload, PrerenderRouteParamsRouteMatch, encodePrerenderRouteParams, matchPrerenderRouteParamsPayload, prerenderRouteParamsPayloadMatchesRoute, readTrustedPrerenderRouteParams, readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader };
23
+ export { PrerenderRouteParams, PrerenderRouteParamsPayload, encodePrerenderRouteParams, matchPrerenderRouteParamsPayload, prerenderRouteParamsPayloadMatchesRoute, readTrustedPrerenderRouteParams, readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader };