vinext 0.1.0 → 0.1.2

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 (205) hide show
  1. package/README.md +2 -5
  2. package/dist/build/assets-ignore.d.ts +32 -0
  3. package/dist/build/assets-ignore.js +48 -0
  4. package/dist/build/client-build-config.d.ts +33 -1
  5. package/dist/build/client-build-config.js +66 -1
  6. package/dist/check.js +4 -3
  7. package/dist/cli.js +2 -0
  8. package/dist/client/navigation-runtime.d.ts +11 -2
  9. package/dist/client/navigation-runtime.js +1 -1
  10. package/dist/client/vinext-next-data.d.ts +2 -1
  11. package/dist/client/window-next.d.ts +6 -4
  12. package/dist/config/config-matchers.d.ts +31 -5
  13. package/dist/config/config-matchers.js +50 -3
  14. package/dist/config/next-config.d.ts +29 -3
  15. package/dist/config/next-config.js +32 -2
  16. package/dist/deploy.js +47 -304
  17. package/dist/entries/app-rsc-entry.d.ts +8 -2
  18. package/dist/entries/app-rsc-entry.js +61 -5
  19. package/dist/entries/app-rsc-manifest.js +20 -2
  20. package/dist/entries/pages-client-entry.js +1 -1
  21. package/dist/entries/pages-server-entry.js +16 -7
  22. package/dist/index.d.ts +0 -2
  23. package/dist/index.js +233 -280
  24. package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
  25. package/dist/plugins/dynamic-preload-metadata.js +415 -0
  26. package/dist/plugins/og-assets.js +2 -2
  27. package/dist/plugins/optimize-imports.d.ts +8 -4
  28. package/dist/plugins/optimize-imports.js +16 -12
  29. package/dist/plugins/postcss.js +18 -14
  30. package/dist/plugins/require-context.d.ts +6 -0
  31. package/dist/plugins/require-context.js +184 -0
  32. package/dist/plugins/sass.d.ts +53 -24
  33. package/dist/plugins/sass.js +249 -1
  34. package/dist/plugins/wasm-module-import.d.ts +15 -0
  35. package/dist/plugins/wasm-module-import.js +50 -0
  36. package/dist/routing/app-route-graph.d.ts +35 -2
  37. package/dist/routing/app-route-graph.js +179 -8
  38. package/dist/routing/file-matcher.js +1 -1
  39. package/dist/routing/route-pattern.d.ts +2 -1
  40. package/dist/routing/route-pattern.js +16 -1
  41. package/dist/server/api-handler.js +4 -0
  42. package/dist/server/app-browser-entry.js +155 -215
  43. package/dist/server/app-browser-error.d.ts +4 -1
  44. package/dist/server/app-browser-error.js +7 -1
  45. package/dist/server/app-browser-history-controller.d.ts +104 -0
  46. package/dist/server/app-browser-history-controller.js +210 -0
  47. package/dist/server/app-browser-interception-context.d.ts +2 -1
  48. package/dist/server/app-browser-interception-context.js +15 -2
  49. package/dist/server/app-browser-navigation-controller.d.ts +13 -2
  50. package/dist/server/app-browser-navigation-controller.js +83 -4
  51. package/dist/server/app-browser-popstate.d.ts +12 -3
  52. package/dist/server/app-browser-popstate.js +19 -4
  53. package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
  54. package/dist/server/app-browser-rsc-redirect.js +30 -8
  55. package/dist/server/app-browser-state.d.ts +3 -0
  56. package/dist/server/app-browser-state.js +10 -10
  57. package/dist/server/app-browser-visible-commit.js +10 -8
  58. package/dist/server/app-fallback-renderer.d.ts +2 -1
  59. package/dist/server/app-fallback-renderer.js +3 -1
  60. package/dist/server/app-history-state.d.ts +45 -1
  61. package/dist/server/app-history-state.js +109 -1
  62. package/dist/server/app-middleware.js +1 -0
  63. package/dist/server/app-optimistic-routing.js +22 -1
  64. package/dist/server/app-page-boundary-render.d.ts +2 -1
  65. package/dist/server/app-page-boundary-render.js +45 -21
  66. package/dist/server/app-page-cache.js +9 -7
  67. package/dist/server/app-page-dispatch.d.ts +14 -0
  68. package/dist/server/app-page-dispatch.js +21 -6
  69. package/dist/server/app-page-element-builder.d.ts +23 -2
  70. package/dist/server/app-page-element-builder.js +58 -17
  71. package/dist/server/app-page-execution.d.ts +1 -1
  72. package/dist/server/app-page-execution.js +32 -17
  73. package/dist/server/app-page-render.d.ts +7 -1
  74. package/dist/server/app-page-render.js +11 -16
  75. package/dist/server/app-page-request.d.ts +9 -6
  76. package/dist/server/app-page-request.js +14 -10
  77. package/dist/server/app-page-response.d.ts +2 -2
  78. package/dist/server/app-page-response.js +2 -2
  79. package/dist/server/app-page-route-wiring.d.ts +3 -1
  80. package/dist/server/app-page-route-wiring.js +10 -8
  81. package/dist/server/app-page-stream.d.ts +37 -7
  82. package/dist/server/app-page-stream.js +36 -6
  83. package/dist/server/app-pages-bridge.d.ts +16 -0
  84. package/dist/server/app-pages-bridge.js +23 -3
  85. package/dist/server/app-route-handler-cache.d.ts +1 -0
  86. package/dist/server/app-route-handler-cache.js +1 -0
  87. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  88. package/dist/server/app-route-handler-dispatch.js +2 -0
  89. package/dist/server/app-route-handler-execution.d.ts +1 -0
  90. package/dist/server/app-route-handler-execution.js +1 -0
  91. package/dist/server/app-route-handler-response.js +11 -10
  92. package/dist/server/app-route-handler-runtime.d.ts +1 -0
  93. package/dist/server/app-route-handler-runtime.js +15 -3
  94. package/dist/server/app-rsc-handler.d.ts +1 -0
  95. package/dist/server/app-rsc-handler.js +5 -4
  96. package/dist/server/app-rsc-response-finalizer.js +1 -1
  97. package/dist/server/app-rsc-route-matching.d.ts +20 -1
  98. package/dist/server/app-rsc-route-matching.js +29 -4
  99. package/dist/server/app-server-action-execution.d.ts +22 -1
  100. package/dist/server/app-server-action-execution.js +73 -12
  101. package/dist/server/app-ssr-entry.d.ts +6 -0
  102. package/dist/server/app-ssr-entry.js +19 -3
  103. package/dist/server/app-ssr-stream.js +9 -1
  104. package/dist/server/dev-lockfile.js +2 -1
  105. package/dist/server/dev-server.d.ts +1 -1
  106. package/dist/server/dev-server.js +97 -43
  107. package/dist/server/headers.d.ts +8 -1
  108. package/dist/server/headers.js +8 -1
  109. package/dist/server/instrumentation-runtime.d.ts +6 -0
  110. package/dist/server/instrumentation-runtime.js +8 -0
  111. package/dist/server/isr-cache.d.ts +37 -1
  112. package/dist/server/isr-cache.js +85 -1
  113. package/dist/server/isr-decision.d.ts +79 -0
  114. package/dist/server/isr-decision.js +70 -0
  115. package/dist/server/metadata-route-response.js +5 -3
  116. package/dist/server/middleware-runtime.d.ts +13 -0
  117. package/dist/server/middleware-runtime.js +11 -7
  118. package/dist/server/middleware.js +1 -0
  119. package/dist/server/navigation-planner.d.ts +62 -1
  120. package/dist/server/navigation-planner.js +193 -3
  121. package/dist/server/navigation-trace.d.ts +12 -2
  122. package/dist/server/navigation-trace.js +11 -1
  123. package/dist/server/normalize-path.d.ts +0 -8
  124. package/dist/server/normalize-path.js +3 -1
  125. package/dist/server/otel-tracer-extension.d.ts +45 -0
  126. package/dist/server/otel-tracer-extension.js +89 -0
  127. package/dist/server/pages-api-route.d.ts +14 -3
  128. package/dist/server/pages-api-route.js +6 -1
  129. package/dist/server/pages-asset-tags.d.ts +15 -4
  130. package/dist/server/pages-asset-tags.js +18 -12
  131. package/dist/server/pages-data-route.js +5 -1
  132. package/dist/server/pages-node-compat.d.ts +5 -11
  133. package/dist/server/pages-node-compat.js +175 -118
  134. package/dist/server/pages-page-data.d.ts +38 -7
  135. package/dist/server/pages-page-data.js +64 -18
  136. package/dist/server/pages-page-handler.d.ts +10 -2
  137. package/dist/server/pages-page-handler.js +49 -20
  138. package/dist/server/pages-page-response.d.ts +55 -2
  139. package/dist/server/pages-page-response.js +74 -6
  140. package/dist/server/pages-readiness.d.ts +36 -0
  141. package/dist/server/pages-readiness.js +21 -0
  142. package/dist/server/pages-request-pipeline.d.ts +113 -0
  143. package/dist/server/pages-request-pipeline.js +230 -0
  144. package/dist/server/pages-revalidate.d.ts +15 -0
  145. package/dist/server/pages-revalidate.js +19 -0
  146. package/dist/server/prod-server.d.ts +45 -3
  147. package/dist/server/prod-server.js +182 -234
  148. package/dist/server/socket-error-backstop.d.ts +19 -1
  149. package/dist/server/socket-error-backstop.js +77 -4
  150. package/dist/shims/app-router-scroll.js +22 -4
  151. package/dist/shims/cache-runtime.js +39 -2
  152. package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
  153. package/dist/shims/dynamic-preload-chunks.js +77 -0
  154. package/dist/shims/dynamic.d.ts +4 -0
  155. package/dist/shims/dynamic.js +4 -2
  156. package/dist/shims/error-boundary.d.ts +17 -7
  157. package/dist/shims/error-boundary.js +8 -1
  158. package/dist/shims/error.js +37 -11
  159. package/dist/shims/fetch-cache.d.ts +22 -1
  160. package/dist/shims/fetch-cache.js +28 -1
  161. package/dist/shims/hash-scroll.d.ts +1 -0
  162. package/dist/shims/hash-scroll.js +3 -1
  163. package/dist/shims/head.js +6 -1
  164. package/dist/shims/headers.d.ts +16 -2
  165. package/dist/shims/headers.js +37 -1
  166. package/dist/shims/image-config.js +7 -1
  167. package/dist/shims/internal/app-route-detection.d.ts +6 -3
  168. package/dist/shims/internal/app-route-detection.js +10 -6
  169. package/dist/shims/internal/app-router-context.d.ts +5 -0
  170. package/dist/shims/internal/link-status-registry.d.ts +43 -0
  171. package/dist/shims/internal/link-status-registry.js +42 -0
  172. package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
  173. package/dist/shims/internal/route-pattern-for-warning.js +40 -0
  174. package/dist/shims/internal/utils.d.ts +1 -0
  175. package/dist/shims/link.js +20 -6
  176. package/dist/shims/metadata.d.ts +6 -2
  177. package/dist/shims/metadata.js +32 -14
  178. package/dist/shims/navigation.d.ts +9 -18
  179. package/dist/shims/navigation.js +96 -23
  180. package/dist/shims/router-state.d.ts +1 -0
  181. package/dist/shims/router-state.js +2 -0
  182. package/dist/shims/router.d.ts +6 -3
  183. package/dist/shims/router.js +156 -22
  184. package/dist/shims/script-nonce-context.d.ts +1 -1
  185. package/dist/shims/script-nonce-context.js +11 -3
  186. package/dist/shims/server.d.ts +17 -1
  187. package/dist/shims/server.js +31 -6
  188. package/dist/shims/slot.js +1 -1
  189. package/dist/shims/unified-request-context.js +1 -0
  190. package/dist/typegen.js +1 -0
  191. package/dist/utils/client-build-manifest.d.ts +8 -1
  192. package/dist/utils/client-build-manifest.js +41 -6
  193. package/dist/utils/client-entry-manifest.d.ts +11 -0
  194. package/dist/utils/client-entry-manifest.js +29 -0
  195. package/dist/utils/client-runtime-metadata.d.ts +45 -0
  196. package/dist/utils/client-runtime-metadata.js +63 -0
  197. package/dist/utils/hash.d.ts +17 -1
  198. package/dist/utils/hash.js +36 -1
  199. package/dist/utils/lazy-chunks.d.ts +27 -1
  200. package/dist/utils/lazy-chunks.js +65 -1
  201. package/dist/utils/manifest-paths.d.ts +20 -2
  202. package/dist/utils/manifest-paths.js +38 -3
  203. package/dist/utils/path.d.ts +2 -1
  204. package/dist/utils/path.js +5 -1
  205. package/package.json +6 -2
@@ -0,0 +1,36 @@
1
+ import { VinextNextData } from "../client/vinext-next-data.js";
2
+ import { PagesPageModule } from "./pages-page-data.js";
3
+
4
+ //#region src/server/pages-readiness.d.ts
5
+ /**
6
+ * Shared Pages Router readiness modeling.
7
+ *
8
+ * The initial `router.isReady` value for the `next/navigation` compat hooks is
9
+ * derived from the page/_app data-fetching exports plus the configured-rewrites
10
+ * flag, serialized into `__NEXT_DATA__`. The dev SSR handler and the production
11
+ * Pages page handler must compute this identically so server HTML and client
12
+ * hydration agree — see `getPagesNavigationIsReadyFromSerializedState` in
13
+ * `shims/router.ts`.
14
+ */
15
+ /**
16
+ * The serialized readiness flags (gssp/gsp/gip/appGip/autoExport +
17
+ * `__vinext.hasRewrites`) that gate the initial Pages Router `router.isReady`.
18
+ * The field names/types are projected from the canonical `VinextNextData` so
19
+ * this stays in lockstep with the `__NEXT_DATA__` shape it feeds into.
20
+ */
21
+ type PagesReadinessNextData = Pick<VinextNextData, "gssp" | "gsp" | "gip" | "appGip" | "autoExport"> & {
22
+ __vinext: Pick<NonNullable<VinextNextData["__vinext"]>, "hasRewrites">;
23
+ };
24
+ /**
25
+ * Build the readiness flags for a Pages Router render. Shared by the dev and
26
+ * production Pages render paths.
27
+ */
28
+ declare function buildPagesReadinessNextData(options: {
29
+ pageModule: PagesPageModule;
30
+ appComponent: {
31
+ getInitialProps?: unknown;
32
+ } | null | undefined;
33
+ hasRewrites: boolean;
34
+ }): PagesReadinessNextData;
35
+ //#endregion
36
+ export { buildPagesReadinessNextData };
@@ -0,0 +1,21 @@
1
+ //#region src/server/pages-readiness.ts
2
+ /**
3
+ * Build the readiness flags for a Pages Router render. Shared by the dev and
4
+ * production Pages render paths.
5
+ */
6
+ function buildPagesReadinessNextData(options) {
7
+ const hasPageGssp = typeof options.pageModule.getServerSideProps === "function";
8
+ const hasPageGsp = typeof options.pageModule.getStaticProps === "function";
9
+ const hasPageGip = typeof options.pageModule.default?.getInitialProps === "function";
10
+ const hasAppGip = typeof options.appComponent?.getInitialProps === "function";
11
+ return {
12
+ gssp: hasPageGssp,
13
+ gsp: hasPageGsp,
14
+ gip: hasPageGip,
15
+ appGip: hasAppGip,
16
+ autoExport: !hasPageGssp && !hasPageGsp && !hasPageGip && !hasAppGip,
17
+ __vinext: { hasRewrites: options.hasRewrites }
18
+ };
19
+ }
20
+ //#endregion
21
+ export { buildPagesReadinessNextData };
@@ -0,0 +1,113 @@
1
+ import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config/next-config.js";
2
+ import { HeaderRecord } from "./request-pipeline.js";
3
+
4
+ //#region src/server/pages-request-pipeline.d.ts
5
+ type PagesRenderOptions = {
6
+ isDataReq?: boolean;
7
+ renderErrorPageOnMiss?: boolean;
8
+ };
9
+ type MiddlewareResult = {
10
+ continue: boolean;
11
+ redirectUrl?: string;
12
+ redirectStatus?: number;
13
+ rewriteUrl?: string;
14
+ rewriteStatus?: number;
15
+ status?: number;
16
+ responseHeaders?: Iterable<[string, string]>;
17
+ response?: Response;
18
+ waitUntilPromises?: Promise<unknown>[];
19
+ };
20
+ type PagesPipelineDeps = {
21
+ basePath: string;
22
+ trailingSlash: boolean;
23
+ i18nConfig: NextI18nConfig | null;
24
+ configRedirects: NextRedirect[];
25
+ configRewrites: {
26
+ beforeFiles: NextRewrite[];
27
+ afterFiles: NextRewrite[];
28
+ fallback: NextRewrite[];
29
+ };
30
+ configHeaders: NextHeader[];
31
+ hadBasePath: boolean;
32
+ isDataReq: boolean;
33
+ isDataRequest: boolean;
34
+ ctx?: unknown;
35
+ rawSearch?: string;
36
+ matchPageRoute?: ((pathname: string, request: Request) => {
37
+ route: {
38
+ isDynamic: boolean;
39
+ };
40
+ } | null) | null;
41
+ runMiddleware?: ((request: Request, ctx: unknown, opts: {
42
+ isDataRequest: boolean;
43
+ }) => Promise<MiddlewareResult>) | null;
44
+ renderPage?: ((request: Request, resolvedUrl: string, options?: PagesRenderOptions, stagedHeaders?: Headers) => Promise<Response>) | null;
45
+ handleApi?: ((request: Request, apiUrl: string, ctx: unknown) => Promise<Response>) | null;
46
+ /**
47
+ * Optional override for proxying external rewrite destinations.
48
+ * When supplied, the pipeline calls this instead of proxyExternalRequest(currentRequest, url).
49
+ * Receives the pipeline's current request (with post-middleware headers applied) and the
50
+ * external target URL. Dev adapters supply this to forward the original Node req body
51
+ * (which is not included in the pipeline's body-less Web Request).
52
+ */
53
+ proxyExternal?: ((currentRequest: Request, externalUrl: string) => Promise<Response>) | null;
54
+ /**
55
+ * Optional public-directory static file server (Node prod only).
56
+ * Called post-middleware (so middleware can intercept/redirect public files) with the
57
+ * original basePath-stripped pathname and the staged middleware response headers.
58
+ * The callback writes the file to its own output (Node `res`) and resolves `true` when
59
+ * it served the request; the pipeline then returns `{ type: "handled" }`. Resolves `false`
60
+ * to fall through to rewrites/render. Worker/dev adapters omit this — their public files
61
+ * are served by the asset binding / Vite respectively.
62
+ */
63
+ serveStaticFile?: ((requestPathname: string, stagedHeaders: HeaderRecord) => Promise<boolean>) | null;
64
+ };
65
+ /**
66
+ * Wrap an adapter's `runMiddleware` callback so middleware receives the original
67
+ * (pre-basePath-stripping) URL. Adapters strip the basePath before handing the
68
+ * request to `runPagesRequest`, but Next.js passes the un-stripped URL to the
69
+ * middleware adapter so `request.nextUrl.basePath` reflects whether the URL
70
+ * actually had the basePath prefix. Requests outside the basePath
71
+ * (`hadBasePath === false`) are passed through untouched so middleware sees
72
+ * `nextUrl.basePath === ""` and can redirect them into the basePath
73
+ * (see the middleware-base-path e2e test / #1830).
74
+ *
75
+ * Shared by the Node prod server (prod-server.ts) and the generated Pages
76
+ * Router worker entry (deploy.ts) to keep the two adapters in sync.
77
+ */
78
+ declare function wrapMiddlewareWithBasePath(runMiddleware: NonNullable<PagesPipelineDeps["runMiddleware"]>, basePath: string, hadBasePath: boolean): NonNullable<PagesPipelineDeps["runMiddleware"]>;
79
+ type PagesPipelineResult = {
80
+ type: "response";
81
+ response: Response;
82
+ defaultContentType?: string;
83
+ } | {
84
+ type: "handled";
85
+ } | {
86
+ type: "render";
87
+ resolvedUrl: string;
88
+ renderOptions: PagesRenderOptions | undefined;
89
+ stagedHeaders: HeaderRecord; /** Post-middleware request headers — dev adapters apply these to req.headers before SSR. */
90
+ requestHeaders: Headers;
91
+ middlewareStatus: number | undefined;
92
+ isDataReq: boolean;
93
+ } | {
94
+ type: "api";
95
+ apiUrl: string;
96
+ stagedHeaders: HeaderRecord; /** Post-middleware request headers — dev adapters apply these to req.headers before API handler. */
97
+ requestHeaders: Headers;
98
+ middlewareStatus: number | undefined;
99
+ } | {
100
+ type: "next";
101
+ };
102
+ /**
103
+ * Run the Pages Router request pipeline.
104
+ *
105
+ * ASSUMPTION: request already has internal headers filtered and basePath stripped.
106
+ * The adapter is responsible for that pre-processing before calling runPagesRequest.
107
+ * The adapter also handles: open-redirect guard, _next/static 404, image optimization,
108
+ * _next/data normalization, Node decode/normalize/400, public-file serving.
109
+ * runPagesRequest receives a "clean" request with basePath-stripped URL.
110
+ */
111
+ declare function runPagesRequest(request: Request, deps: PagesPipelineDeps): Promise<PagesPipelineResult>;
112
+ //#endregion
113
+ export { MiddlewareResult, PagesPipelineDeps, PagesPipelineResult, PagesRenderOptions, runPagesRequest, wrapMiddlewareWithBasePath };
@@ -0,0 +1,230 @@
1
+ import { addBasePathToPathname, hasBasePath } from "../utils/base-path.js";
2
+ import { applyMiddlewareRequestHeaders, isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
3
+ import { applyConfigHeadersToHeaderRecord, normalizeTrailingSlash } from "./request-pipeline.js";
4
+ import { mergeRewriteQuery } from "../utils/query.js";
5
+ import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
6
+ import { mergeHeaders } from "./worker-utils.js";
7
+ //#region src/server/pages-request-pipeline.ts
8
+ /**
9
+ * Wrap an adapter's `runMiddleware` callback so middleware receives the original
10
+ * (pre-basePath-stripping) URL. Adapters strip the basePath before handing the
11
+ * request to `runPagesRequest`, but Next.js passes the un-stripped URL to the
12
+ * middleware adapter so `request.nextUrl.basePath` reflects whether the URL
13
+ * actually had the basePath prefix. Requests outside the basePath
14
+ * (`hadBasePath === false`) are passed through untouched so middleware sees
15
+ * `nextUrl.basePath === ""` and can redirect them into the basePath
16
+ * (see the middleware-base-path e2e test / #1830).
17
+ *
18
+ * Shared by the Node prod server (prod-server.ts) and the generated Pages
19
+ * Router worker entry (deploy.ts) to keep the two adapters in sync.
20
+ */
21
+ function wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath) {
22
+ if (!hadBasePath || !basePath) return runMiddleware;
23
+ return (request, ctx, opts) => {
24
+ const mwUrl = new URL(request.url);
25
+ mwUrl.pathname = addBasePathToPathname(mwUrl.pathname, basePath);
26
+ return runMiddleware(new Request(mwUrl, request), ctx, opts);
27
+ };
28
+ }
29
+ /**
30
+ * Run the Pages Router request pipeline.
31
+ *
32
+ * ASSUMPTION: request already has internal headers filtered and basePath stripped.
33
+ * The adapter is responsible for that pre-processing before calling runPagesRequest.
34
+ * The adapter also handles: open-redirect guard, _next/static 404, image optimization,
35
+ * _next/data normalization, Node decode/normalize/400, public-file serving.
36
+ * runPagesRequest receives a "clean" request with basePath-stripped URL.
37
+ */
38
+ async function runPagesRequest(request, deps) {
39
+ const { basePath, trailingSlash, i18nConfig, configRedirects, configRewrites, configHeaders, hadBasePath, isDataReq, isDataRequest } = deps;
40
+ const proxyExternal = (currentReq, externalUrl) => deps.proxyExternal ? deps.proxyExternal(currentReq, externalUrl) : proxyExternalRequest(currentReq, externalUrl);
41
+ const url = new URL(request.url);
42
+ let pathname = url.pathname;
43
+ const search = url.search;
44
+ const basePathState = {
45
+ basePath,
46
+ hadBasePath
47
+ };
48
+ {
49
+ const trailingSlashRedirect = normalizeTrailingSlash(pathname, basePath, trailingSlash, search);
50
+ if (trailingSlashRedirect) return {
51
+ type: "response",
52
+ response: trailingSlashRedirect
53
+ };
54
+ }
55
+ const reqCtx = requestContextFromRequest(request);
56
+ const requestHostname = i18nConfig ? url.hostname : "";
57
+ const matchPathname = i18nConfig ? normalizeDefaultLocalePathname(pathname, i18nConfig, { hostname: requestHostname }) : pathname;
58
+ if (configRedirects.length) {
59
+ const redirect = matchRedirect(matchPathname, configRedirects, reqCtx, basePathState);
60
+ if (redirect) {
61
+ const location = preserveRedirectDestinationQuery(sanitizeDestination(basePath && hadBasePath && !isExternalUrl(redirect.destination) && !hasBasePath(redirect.destination, basePath) ? basePath + redirect.destination : redirect.destination), deps.rawSearch ?? search);
62
+ return {
63
+ type: "response",
64
+ response: new Response(null, {
65
+ status: redirect.permanent ? 308 : 307,
66
+ headers: { Location: location }
67
+ })
68
+ };
69
+ }
70
+ }
71
+ let resolvedUrl = pathname + search;
72
+ const middlewareHeaders = {};
73
+ let middlewareStatus;
74
+ if (typeof deps.runMiddleware === "function") {
75
+ const result = await deps.runMiddleware(request, deps.ctx ?? null, { isDataRequest });
76
+ if (result.waitUntilPromises && result.waitUntilPromises.length > 0) {
77
+ const ctx = deps.ctx;
78
+ if (ctx && typeof ctx.waitUntil === "function") for (const p of result.waitUntilPromises) ctx.waitUntil(p);
79
+ else Promise.allSettled(result.waitUntilPromises);
80
+ }
81
+ if (!result.continue) {
82
+ if (result.redirectUrl) {
83
+ const redirectHeaders = { Location: result.redirectUrl };
84
+ if (result.responseHeaders) for (const [key, value] of result.responseHeaders) {
85
+ const existing = redirectHeaders[key];
86
+ if (existing === void 0) redirectHeaders[key] = value;
87
+ else if (Array.isArray(existing)) existing.push(value);
88
+ else redirectHeaders[key] = [existing, value];
89
+ }
90
+ const headers = new Headers();
91
+ for (const [k, v] of Object.entries(redirectHeaders)) if (Array.isArray(v)) for (const item of v) headers.append(k, item);
92
+ else headers.set(k, v);
93
+ return {
94
+ type: "response",
95
+ response: new Response(null, {
96
+ status: result.redirectStatus ?? 307,
97
+ headers
98
+ })
99
+ };
100
+ }
101
+ if (result.response) return {
102
+ type: "response",
103
+ response: result.response
104
+ };
105
+ }
106
+ if (result.responseHeaders) for (const [key, value] of result.responseHeaders) if (key === "set-cookie") {
107
+ const existing = middlewareHeaders[key];
108
+ if (Array.isArray(existing)) existing.push(value);
109
+ else if (existing) middlewareHeaders[key] = [existing, value];
110
+ else middlewareHeaders[key] = [value];
111
+ } else middlewareHeaders[key] = value;
112
+ if (result.rewriteUrl) resolvedUrl = result.rewriteUrl;
113
+ middlewareStatus = result.status ?? result.rewriteStatus;
114
+ }
115
+ const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, request, { preserveCredentialHeaders: isExternalUrl(resolvedUrl) });
116
+ request = postMwReq;
117
+ let resolvedPathname = resolvedUrl.split("?")[0];
118
+ const matchResolvedPathname = (p) => i18nConfig ? normalizeDefaultLocalePathname(p, i18nConfig, { hostname: requestHostname }) : p;
119
+ if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
120
+ configHeaders,
121
+ pathname: matchPathname,
122
+ requestContext: reqCtx,
123
+ basePathState
124
+ });
125
+ if (isExternalUrl(resolvedUrl)) return {
126
+ type: "response",
127
+ response: mergeHeaders(await proxyExternal(request, resolvedUrl), middlewareHeaders, void 0)
128
+ };
129
+ if (deps.serveStaticFile) {
130
+ if (await deps.serveStaticFile(pathname, middlewareHeaders)) return { type: "handled" };
131
+ }
132
+ let configRewriteFired = false;
133
+ if (configRewrites.beforeFiles?.length) {
134
+ const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), configRewrites.beforeFiles, postMwReqCtx, basePathState);
135
+ if (rewritten) {
136
+ if (isExternalUrl(rewritten)) return {
137
+ type: "response",
138
+ response: await proxyExternal(request, rewritten)
139
+ };
140
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
141
+ resolvedPathname = resolvedUrl.split("?")[0];
142
+ configRewriteFired = true;
143
+ }
144
+ }
145
+ if (basePath && !hadBasePath && !configRewriteFired) return {
146
+ type: "response",
147
+ response: new Response("This page could not be found", {
148
+ status: 404,
149
+ headers: { "Content-Type": "text/html; charset=utf-8" }
150
+ })
151
+ };
152
+ const apiLookupUrl = stripI18nLocaleForApiRoute(resolvedUrl, i18nConfig);
153
+ 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
+ type: "api",
161
+ apiUrl: apiLookupUrl,
162
+ stagedHeaders: middlewareHeaders,
163
+ requestHeaders: request.headers,
164
+ middlewareStatus
165
+ };
166
+ const pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
167
+ let resolvedPathnameChanged = false;
168
+ if ((!pageMatch || pageMatch.route.isDynamic) && configRewrites.afterFiles?.length) {
169
+ const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), configRewrites.afterFiles, postMwReqCtx, basePathState);
170
+ if (rewritten) {
171
+ if (isExternalUrl(rewritten)) return {
172
+ type: "response",
173
+ response: await proxyExternal(request, rewritten)
174
+ };
175
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
176
+ resolvedPathname = resolvedUrl.split("?")[0];
177
+ resolvedPathnameChanged = true;
178
+ }
179
+ }
180
+ if (typeof deps.renderPage === "function") {
181
+ const renderPageMatch = resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch;
182
+ const shouldDeferErrorPageOnMiss = !isDataReq && !isDataRequest && !!deps.matchPageRoute && !renderPageMatch;
183
+ const initialRenderOptions = shouldDeferErrorPageOnMiss ? { renderErrorPageOnMiss: false } : isDataReq ? { isDataReq: true } : void 0;
184
+ const stagedHeaders = new Headers();
185
+ for (const [k, v] of Object.entries(middlewareHeaders)) if (Array.isArray(v)) for (const item of v) stagedHeaders.append(k, item);
186
+ else stagedHeaders.set(k, v);
187
+ let response = await deps.renderPage(request, resolvedUrl, initialRenderOptions, stagedHeaders);
188
+ 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
+ }
199
+ }
200
+ if (response.status === 404 && shouldDeferErrorPageOnMiss && !matchedFallbackRewrite) response = await deps.renderPage(request, resolvedUrl, void 0, stagedHeaders);
201
+ const merged = mergeHeaders(response, middlewareHeaders, middlewareStatus);
202
+ if (merged !== response) merged.__vinextStreamedHtmlResponse = response.__vinextStreamedHtmlResponse;
203
+ return {
204
+ type: "response",
205
+ response: merged,
206
+ defaultContentType: "text/html"
207
+ };
208
+ }
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
+ }
218
+ }
219
+ return {
220
+ type: "render",
221
+ resolvedUrl,
222
+ renderOptions: isDataReq ? { isDataReq: true } : void 0,
223
+ stagedHeaders: middlewareHeaders,
224
+ requestHeaders: request.headers,
225
+ middlewareStatus,
226
+ isDataReq
227
+ };
228
+ }
229
+ //#endregion
230
+ export { runPagesRequest, wrapMiddlewareWithBasePath };
@@ -0,0 +1,15 @@
1
+ import { IncomingMessage } from "node:http";
2
+
3
+ //#region src/server/pages-revalidate.d.ts
4
+ type RevalidateOptions = {
5
+ /**
6
+ * Only revalidate the path if it was already generated (cached). Mirrors
7
+ * Next.js's `unstable_onlyGenerated`: sets the
8
+ * `x-prerender-revalidate-if-generated` header and makes a 404 response count
9
+ * as a successful no-op rather than an error.
10
+ */
11
+ unstable_onlyGenerated?: boolean;
12
+ };
13
+ declare function performOnDemandRevalidate(source: IncomingMessage | Headers, urlPath: string, opts?: RevalidateOptions): Promise<void>;
14
+ //#endregion
15
+ export { RevalidateOptions, performOnDemandRevalidate };
@@ -0,0 +1,19 @@
1
+ import "./headers.js";
2
+ import { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, getRevalidateSecret } from "./isr-cache.js";
3
+ import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
4
+ //#region src/server/pages-revalidate.ts
5
+ async function performOnDemandRevalidate(source, urlPath, opts = {}) {
6
+ if (typeof urlPath !== "string" || !urlPath.startsWith("/")) throw new Error(`Invalid urlPath provided to revalidate(), must be a path e.g. /blog/post-1, received ${urlPath}`);
7
+ const proto = resolveRequestProtocol(source);
8
+ const host = resolveRequestHost(source, "localhost");
9
+ const target = new URL(urlPath, `${proto}://${host}`);
10
+ const headers = { [PRERENDER_REVALIDATE_HEADER]: getRevalidateSecret() };
11
+ if (opts.unstable_onlyGenerated) headers[PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER] = "1";
12
+ const res = await fetch(target, {
13
+ method: "HEAD",
14
+ headers
15
+ });
16
+ if (!(res.headers.get("x-nextjs-cache")?.toUpperCase() === "REVALIDATED" || res.status === 200 || res.status === 404 && opts.unstable_onlyGenerated === true)) throw new Error(`Failed to revalidate ${urlPath}: ${res.status}`);
17
+ }
18
+ //#endregion
19
+ export { performOnDemandRevalidate };
@@ -3,6 +3,44 @@ import { resolveRequestHost, trustProxy, trustedHosts } from "./proxy-trust.js";
3
3
  import { IncomingMessage, ServerResponse } from "node:http";
4
4
 
5
5
  //#region src/server/prod-server.d.ts
6
+ /**
7
+ * Import a built server entry module (App Router RSC entry or Pages Router
8
+ * server entry) by absolute file path.
9
+ *
10
+ * The first import of a given path uses the plain file:// URL with NO query
11
+ * string. This is load-bearing: code-split builds emit lazy chunks that
12
+ * import the entry back by bare specifier (default Vite builds on both
13
+ * supported majors — Rollup on Vite 7 and Rolldown on Vite 8 — hoist modules
14
+ * shared between the entry's static graph and lazy route chunks into the
15
+ * entry chunk, which the chunks then import as e.g. "../../index.js").
16
+ * Node keys its ESM cache on the full URL including the query string, so if
17
+ * the server imported the entry as `index.js?t=<mtime>`, a chunk's bare
18
+ * back-import would evaluate the entire server bundle a second time and
19
+ * module-level singletons (db pools, service registries) would silently
20
+ * diverge between the two copies. See
21
+ * https://github.com/cloudflare/vinext/issues/1923.
22
+ *
23
+ * A `?t=<mtime>` query string is appended only when the same path is
24
+ * imported again after a rebuild (different mtime) — e.g. test suites that
25
+ * rebuild a fixture to the same output path within one process — where the
26
+ * bare URL's cache entry would return the stale previous build. Note this
27
+ * rebuild branch trades the single-instance guarantee back: chunks that
28
+ * import the entry by bare path still resolve to the FIRST build's cache
29
+ * entry, so freshness and single-instance only hold together on the first
30
+ * import of a path. Production processes import each entry path exactly
31
+ * once and always get both.
32
+ *
33
+ * The entry is imported via its canonical real path: the bundler
34
+ * canonicalizes module ids with fs.realpathSync.native, so chunks evaluate
35
+ * under realpath-based URLs and their relative imports resolve to realpath
36
+ * URLs too. Importing the entry through a symlinked path (macOS /var/...
37
+ * tmpdirs, symlinked deploy directories) would otherwise create a second
38
+ * instance keyed on the symlinked URL.
39
+ *
40
+ * Exported for direct unit testing of the URL choice.
41
+ */
42
+ declare function resolveServerEntryImportUrl(entryPath: string): string;
43
+ declare function importServerEntryModule(entryPath: string): Promise<any>;
6
44
  type ProdServerOptions = {
7
45
  /** Port to listen on */port?: number; /** Host to bind to */
8
46
  host?: string; /** Path to the build output directory */
@@ -29,8 +67,12 @@ declare function mergeResponseHeaders(middlewareHeaders: Record<string, string |
29
67
  /**
30
68
  * Merge middleware/config headers and an optional status override into a new
31
69
  * Web Response while preserving the original body stream when allowed.
32
- * Keep this in sync with server/worker-utils.ts and the generated copy in
33
- * deploy.ts.
70
+ *
71
+ * This is the canonical {@link mergeHeaders} (server/worker-utils.ts) with the
72
+ * arguments in (headers, response) order. The request path now calls
73
+ * `runPagesRequest`, which uses `mergeHeaders` directly; this wrapper is retained
74
+ * only for its existing tests and any external callers, so there is a single
75
+ * implementation to keep in sync. (deploy.ts still emits its own generated copy.)
34
76
  */
35
77
  declare function mergeWebResponse(middlewareHeaders: Record<string, string | string[]>, response: Response, statusOverride?: number): Response;
36
78
  /**
@@ -101,4 +143,4 @@ declare function resolveAppRouterPrerenderSeeder(entryModule: unknown): AppRoute
101
143
  */
102
144
  declare function resolveAppRouterAssetPath(pathname: string, assetPathPrefix: string, assetPrefix: string): string | null;
103
145
  //#endregion
104
- export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, ProdServerOptions, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
146
+ export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, ProdServerOptions, importServerEntryModule, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };