vinext 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/dist/build/client-build-config.d.ts +11 -2
  2. package/dist/build/client-build-config.js +17 -6
  3. package/dist/build/css-url-assets.d.ts +1 -1
  4. package/dist/build/css-url-assets.js +9 -7
  5. package/dist/build/prerender.js +3 -1
  6. package/dist/cache/cache-adapters-virtual.js +1 -1
  7. package/dist/client/pages-router-link-navigation.d.ts +33 -7
  8. package/dist/client/pages-router-link-navigation.js +32 -2
  9. package/dist/client/vinext-next-data.js +2 -0
  10. package/dist/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +1 -1
  11. package/dist/config/config-matchers.d.ts +11 -1
  12. package/dist/config/config-matchers.js +14 -2
  13. package/dist/config/tsconfig-paths.js +14 -1
  14. package/dist/deploy.js +20 -13
  15. package/dist/entries/app-rsc-entry.js +27 -22
  16. package/dist/entries/pages-client-entry.js +14 -13
  17. package/dist/entries/pages-server-entry.js +8 -27
  18. package/dist/index.js +365 -147
  19. package/dist/plugins/css-data-url.js +30 -26
  20. package/dist/plugins/dynamic-preload-metadata.js +2 -4
  21. package/dist/plugins/extensionless-dynamic-import.js +27 -24
  22. package/dist/plugins/fonts.js +5 -4
  23. package/dist/plugins/import-meta-url.js +21 -15
  24. package/dist/plugins/instrumentation-client.js +1 -1
  25. package/dist/plugins/middleware-server-only.js +7 -6
  26. package/dist/plugins/og-assets.js +48 -46
  27. package/dist/plugins/optimize-imports.js +9 -3
  28. package/dist/plugins/remove-console.d.ts +7 -1
  29. package/dist/plugins/remove-console.js +4 -1
  30. package/dist/plugins/require-context.js +21 -20
  31. package/dist/plugins/strip-server-exports.d.ts +16 -8
  32. package/dist/plugins/strip-server-exports.js +496 -46
  33. package/dist/routing/app-route-graph.js +2 -2
  34. package/dist/server/app-bfcache-identity.d.ts +26 -0
  35. package/dist/server/app-bfcache-identity.js +127 -0
  36. package/dist/server/app-browser-action-result.js +1 -1
  37. package/dist/server/app-browser-entry.js +22 -12
  38. package/dist/server/app-browser-navigation-controller.d.ts +1 -1
  39. package/dist/server/app-browser-navigation-controller.js +1 -1
  40. package/dist/server/app-browser-state.d.ts +3 -22
  41. package/dist/server/app-browser-state.js +23 -139
  42. package/dist/server/app-browser-stream.js +1 -1
  43. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  44. package/dist/server/app-browser-visible-commit.js +3 -2
  45. package/dist/server/app-fallback-renderer.d.ts +1 -1
  46. package/dist/server/app-layout-param-observation.d.ts +1 -1
  47. package/dist/server/app-layout-param-observation.js +1 -1
  48. package/dist/server/app-middleware.js +2 -1
  49. package/dist/server/app-page-boundary-render.d.ts +1 -1
  50. package/dist/server/app-page-boundary.js +1 -1
  51. package/dist/server/app-page-cache-finalizer.d.ts +62 -0
  52. package/dist/server/app-page-cache-finalizer.js +122 -0
  53. package/dist/server/app-page-cache-render.d.ts +2 -2
  54. package/dist/server/app-page-cache-render.js +1 -1
  55. package/dist/server/app-page-cache.d.ts +2 -53
  56. package/dist/server/app-page-cache.js +5 -131
  57. package/dist/server/app-page-dispatch.d.ts +2 -2
  58. package/dist/server/app-page-dispatch.js +10 -8
  59. package/dist/server/app-page-probe.js +3 -2
  60. package/dist/server/app-page-render-observation.js +2 -2
  61. package/dist/server/app-page-render.d.ts +3 -3
  62. package/dist/server/app-page-render.js +3 -2
  63. package/dist/server/app-page-stream.d.ts +2 -9
  64. package/dist/server/app-page-stream.js +1 -35
  65. package/dist/server/app-pages-bridge.d.ts +5 -1
  66. package/dist/server/app-pages-bridge.js +5 -13
  67. package/dist/server/app-request-context.d.ts +1 -2
  68. package/dist/server/app-request-context.js +2 -1
  69. package/dist/server/app-route-handler-dispatch.js +3 -2
  70. package/dist/server/app-route-handler-execution.d.ts +1 -1
  71. package/dist/server/app-route-handler-execution.js +1 -1
  72. package/dist/server/app-route-handler-response.d.ts +1 -1
  73. package/dist/server/app-router-entry.js +2 -1
  74. package/dist/server/app-rsc-handler.d.ts +3 -0
  75. package/dist/server/app-rsc-handler.js +73 -31
  76. package/dist/server/app-rsc-response-finalizer.js +1 -1
  77. package/dist/server/app-rsc-route-matching.js +6 -2
  78. package/dist/server/app-server-action-execution.d.ts +1 -1
  79. package/dist/server/app-server-action-execution.js +10 -6
  80. package/dist/server/app-ssr-entry.d.ts +1 -1
  81. package/dist/server/app-ssr-entry.js +12 -38
  82. package/dist/server/app-ssr-router-instance.d.ts +6 -0
  83. package/dist/server/app-ssr-router-instance.js +24 -0
  84. package/dist/server/app-ssr-stream.js +1 -1
  85. package/dist/server/artifact-compatibility.js +1 -1
  86. package/dist/server/before-interactive-head.d.ts +17 -0
  87. package/dist/server/before-interactive-head.js +35 -0
  88. package/dist/server/client-reuse-manifest.js +1 -1
  89. package/dist/server/csp.js +1 -4
  90. package/dist/server/defer-until-stream-consumed.d.ts +7 -0
  91. package/dist/server/defer-until-stream-consumed.js +34 -0
  92. package/dist/server/dev-server.js +82 -37
  93. package/dist/server/instrumentation.js +1 -1
  94. package/dist/server/isr-cache.d.ts +1 -1
  95. package/dist/server/isr-cache.js +1 -1
  96. package/dist/server/isr-decision.d.ts +1 -1
  97. package/dist/server/middleware-matcher.js +20 -9
  98. package/dist/server/middleware-runtime.d.ts +3 -4
  99. package/dist/server/middleware-runtime.js +4 -2
  100. package/dist/server/navigation-planner.d.ts +3 -12
  101. package/dist/server/navigation-planner.js +24 -0
  102. package/dist/server/navigation-trace.d.ts +2 -1
  103. package/dist/server/navigation-trace.js +1 -0
  104. package/dist/server/open-redirect.d.ts +12 -0
  105. package/dist/server/open-redirect.js +21 -0
  106. package/dist/server/operation-token.d.ts +40 -0
  107. package/dist/server/operation-token.js +85 -0
  108. package/dist/server/pages-data-route.d.ts +1 -1
  109. package/dist/server/pages-data-route.js +7 -4
  110. package/dist/server/pages-dev-module-url.d.ts +4 -0
  111. package/dist/server/pages-dev-module-url.js +15 -0
  112. package/dist/server/pages-document-initial-props.d.ts +4 -15
  113. package/dist/server/pages-document-initial-props.js +27 -56
  114. package/dist/server/pages-i18n.js +2 -2
  115. package/dist/server/pages-page-data.d.ts +1 -1
  116. package/dist/server/pages-page-data.js +3 -1
  117. package/dist/server/pages-page-handler.js +3 -1
  118. package/dist/server/pages-page-response.d.ts +3 -1
  119. package/dist/server/pages-page-response.js +6 -6
  120. package/dist/server/pages-readiness.js +1 -1
  121. package/dist/server/pages-request-pipeline.d.ts +7 -7
  122. package/dist/server/pages-request-pipeline.js +63 -21
  123. package/dist/server/prod-server.d.ts +3 -1
  124. package/dist/server/prod-server.js +43 -11
  125. package/dist/server/request-pipeline.d.ts +1 -24
  126. package/dist/server/request-pipeline.js +1 -33
  127. package/dist/server/seed-cache.d.ts +1 -1
  128. package/dist/server/static-file-cache.js +16 -4
  129. package/dist/shims/before-interactive-context.d.ts +14 -3
  130. package/dist/shims/cache-handler.d.ts +106 -0
  131. package/dist/shims/cache-handler.js +176 -0
  132. package/dist/shims/cache-request-state.d.ts +47 -0
  133. package/dist/shims/cache-request-state.js +126 -0
  134. package/dist/shims/cache-runtime.d.ts +2 -2
  135. package/dist/shims/cache-runtime.js +3 -14
  136. package/dist/shims/cache.d.ts +3 -231
  137. package/dist/shims/cache.js +17 -383
  138. package/dist/shims/cdn-cache.d.ts +1 -1
  139. package/dist/shims/cdn-cache.js +1 -1
  140. package/dist/shims/document.d.ts +15 -20
  141. package/dist/shims/document.js +5 -8
  142. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  143. package/dist/shims/error-boundary-navigation.js +44 -0
  144. package/dist/shims/error-boundary.js +10 -8
  145. package/dist/shims/error.js +2 -1
  146. package/dist/shims/fetch-cache.js +1 -1
  147. package/dist/shims/form.js +1 -1
  148. package/dist/shims/image.js +74 -9
  149. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -0
  150. package/dist/shims/internal/app-page-props-cache-key.js +16 -0
  151. package/dist/shims/internal/navigation-untracked.js +2 -1
  152. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +6 -7
  153. package/dist/shims/internal/pages-data-fetch-dedup.js +67 -14
  154. package/dist/shims/internal/pages-data-target.js +1 -1
  155. package/dist/shims/layout-segment-context.d.ts +1 -1
  156. package/dist/shims/layout-segment-context.js +2 -1
  157. package/dist/shims/link.js +38 -17
  158. package/dist/shims/metadata.js +4 -4
  159. package/dist/shims/navigation-context-state.d.ts +40 -0
  160. package/dist/shims/navigation-context-state.js +116 -0
  161. package/dist/shims/navigation-errors.d.ts +55 -0
  162. package/dist/shims/navigation-errors.js +110 -0
  163. package/dist/shims/navigation-server.d.ts +3 -0
  164. package/dist/shims/navigation-server.js +3 -0
  165. package/dist/shims/navigation-state.d.ts +1 -2
  166. package/dist/shims/navigation-state.js +2 -1
  167. package/dist/shims/navigation.d.ts +3 -291
  168. package/dist/shims/navigation.js +16 -445
  169. package/dist/shims/navigation.react-server.d.ts +2 -2
  170. package/dist/shims/navigation.react-server.js +3 -1
  171. package/dist/shims/request-state-types.d.ts +3 -3
  172. package/dist/shims/router.d.ts +6 -2
  173. package/dist/shims/router.js +99 -20
  174. package/dist/shims/script.js +9 -5
  175. package/dist/shims/slot.js +3 -1
  176. package/dist/shims/unified-request-context.d.ts +2 -2
  177. package/dist/utils/has-trailing-comma.d.ts +24 -0
  178. package/dist/utils/has-trailing-comma.js +62 -0
  179. package/dist/utils/text-stream.d.ts +1 -1
  180. package/dist/utils/text-stream.js +2 -2
  181. package/dist/utils/virtual-module.d.ts +5 -0
  182. package/dist/utils/virtual-module.js +0 -0
  183. package/dist/utils/vite-version.d.ts +12 -1
  184. package/dist/utils/vite-version.js +9 -1
  185. package/package.json +5 -1
@@ -3,6 +3,7 @@ declare const NAVIGATION_TRACE_SCHEMA_VERSION = 0;
3
3
  type NavigationTraceSchemaVersion = 0;
4
4
  declare const NavigationTraceReasonCodes: {
5
5
  cacheProofRejected: "NC_CACHE_REJECT";
6
+ cacheReuseTokenRejected: "NC_CACHE_TOKEN_REJECT";
6
7
  commitCurrent: "NC_COMMIT";
7
8
  crossDocumentFlight: "NC_CROSS_DOC_FLIGHT";
8
9
  fetchFresh: "NC_FETCH_FRESH";
@@ -42,7 +43,7 @@ declare const NavigationTraceTransactionCodes: {
42
43
  type NavigationTraceReasonCode = (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];
43
44
  type NavigationTraceTransactionCode = (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];
44
45
  type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;
45
- type NavigationTraceFieldName = "activeNavigationId" | "cacheProofCode" | "cacheProofMode" | "cacheProofReuseClass" | "cacheProofScope" | "currentRootLayoutTreePath" | "currentVisibleCommitVersion" | "nextRootLayoutTreePath" | "eventKind" | "fetchResultSource" | "freshFetchReason" | "operationLane" | "pendingOperationId" | "redirectDepth" | "redirectSignal" | "startedVisibleCommitVersion" | "startedNavigationId" | "targetHref" | "traverseDirection";
46
+ type NavigationTraceFieldName = "activeNavigationId" | "cacheProofCode" | "cacheProofMode" | "cacheProofReuseClass" | "cacheProofScope" | "cacheReuseTokenReason" | "currentRootLayoutTreePath" | "currentVisibleCommitVersion" | "nextRootLayoutTreePath" | "eventKind" | "fetchResultSource" | "freshFetchReason" | "operationLane" | "pendingOperationId" | "redirectDepth" | "redirectSignal" | "startedVisibleCommitVersion" | "startedNavigationId" | "targetHref" | "traverseDirection";
46
47
  type NavigationTraceFieldValue = string | number | boolean | null;
47
48
  type NavigationTraceFields = Readonly<Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>>;
48
49
  type NavigationTraceEntry = Readonly<{
@@ -2,6 +2,7 @@
2
2
  const NAVIGATION_TRACE_SCHEMA_VERSION = 0;
3
3
  const NavigationTraceReasonCodes = {
4
4
  cacheProofRejected: "NC_CACHE_REJECT",
5
+ cacheReuseTokenRejected: "NC_CACHE_TOKEN_REJECT",
5
6
  commitCurrent: "NC_COMMIT",
6
7
  crossDocumentFlight: "NC_CROSS_DOC_FLIGHT",
7
8
  fetchFresh: "NC_FETCH_FRESH",
@@ -0,0 +1,12 @@
1
+ //#region src/server/open-redirect.d.ts
2
+ /**
3
+ * Returns true if a request pathname looks like a protocol-relative open
4
+ * redirect, in either literal or percent-encoded form.
5
+ *
6
+ * A pathname is considered "open redirect shaped" when its first segment,
7
+ * after decoding backslashes and encoded delimiters, would cause a browser
8
+ * to resolve a `Location` containing the pathname as protocol-relative.
9
+ */
10
+ declare function isOpenRedirectShaped(rawPathname: string): boolean;
11
+ //#endregion
12
+ export { isOpenRedirectShaped };
@@ -0,0 +1,21 @@
1
+ //#region src/server/open-redirect.ts
2
+ /**
3
+ * Returns true if a request pathname looks like a protocol-relative open
4
+ * redirect, in either literal or percent-encoded form.
5
+ *
6
+ * A pathname is considered "open redirect shaped" when its first segment,
7
+ * after decoding backslashes and encoded delimiters, would cause a browser
8
+ * to resolve a `Location` containing the pathname as protocol-relative.
9
+ */
10
+ function isOpenRedirectShaped(rawPathname) {
11
+ if (!rawPathname.startsWith("/")) return false;
12
+ const afterSlash = rawPathname.slice(1);
13
+ if (afterSlash.startsWith("/") || afterSlash.startsWith("\\")) return true;
14
+ if (afterSlash.length >= 3 && afterSlash[0] === "%") {
15
+ const encoded = afterSlash.slice(0, 3).toLowerCase();
16
+ if (encoded === "%5c" || encoded === "%2f") return true;
17
+ }
18
+ return false;
19
+ }
20
+ //#endregion
21
+ export { isOpenRedirectShaped };
@@ -0,0 +1,40 @@
1
+ //#region src/server/operation-token.d.ts
2
+ type OperationLane = "hmr" | "navigation" | "prefetch" | "refresh" | "server-action" | "traverse";
3
+ type OperationToken = {
4
+ operationId: number;
5
+ lane: OperationLane;
6
+ navigationId: number;
7
+ baseVisibleCommitVersion: number;
8
+ graphVersion: string | null;
9
+ deploymentVersion: string | null;
10
+ targetSnapshotFingerprint: string;
11
+ cacheVariantFingerprint?: string;
12
+ };
13
+ declare const verifiedOperationTokenBrand: unique symbol;
14
+ type VerifiedOperationToken = OperationToken & {
15
+ readonly [verifiedOperationTokenBrand]: true;
16
+ };
17
+ type OperationTokenAuthority = {
18
+ activeNavigationId: number;
19
+ visibleCommitVersion: number;
20
+ graphVersion: string | null;
21
+ installedCacheVariantFingerprint: string | null;
22
+ };
23
+ type OperationTokenDimension = "navigation" | "visibleCommit" | "graphVersion" | "cacheVariant";
24
+ type OperationTokenRejectionReason = "staleNavigation" | "staleVisibleCommit" | "graphVersionMismatch" | "graphVersionMissing" | "cacheVariantMismatch" | "cacheVariantMissing";
25
+ type OperationTokenVerdict = {
26
+ readonly authorized: true;
27
+ readonly token: VerifiedOperationToken;
28
+ } | {
29
+ readonly authorized: false;
30
+ readonly reason: OperationTokenRejectionReason;
31
+ };
32
+ type OperationTokenVerificationPolicy = {
33
+ check: readonly OperationTokenDimension[];
34
+ require: readonly OperationTokenDimension[];
35
+ };
36
+ declare function verifyOperationToken(token: OperationToken, authority: OperationTokenAuthority, policy: OperationTokenVerificationPolicy): OperationTokenVerdict;
37
+ declare function verifyOperationTokenForCommit(token: OperationToken, authority: Pick<OperationTokenAuthority, "activeNavigationId" | "visibleCommitVersion">): OperationTokenVerdict;
38
+ declare function verifyOperationTokenForCacheReuse(token: OperationToken, authority: Pick<OperationTokenAuthority, "graphVersion" | "installedCacheVariantFingerprint">): OperationTokenVerdict;
39
+ //#endregion
40
+ export { OperationLane, OperationToken, OperationTokenAuthority, OperationTokenRejectionReason, OperationTokenVerdict, OperationTokenVerificationPolicy, VerifiedOperationToken, verifyOperationToken, verifyOperationTokenForCacheReuse, verifyOperationTokenForCommit };
@@ -0,0 +1,85 @@
1
+ //#region src/server/operation-token.ts
2
+ const DIMENSION_ORDER = [
3
+ "navigation",
4
+ "visibleCommit",
5
+ "graphVersion",
6
+ "cacheVariant"
7
+ ];
8
+ function evaluateDimension(dimension, token, authority) {
9
+ switch (dimension) {
10
+ case "navigation": return token.navigationId === authority.activeNavigationId ? { kind: "satisfied" } : {
11
+ kind: "mismatch",
12
+ reason: "staleNavigation"
13
+ };
14
+ case "visibleCommit": return token.baseVisibleCommitVersion === authority.visibleCommitVersion ? { kind: "satisfied" } : {
15
+ kind: "mismatch",
16
+ reason: "staleVisibleCommit"
17
+ };
18
+ case "graphVersion":
19
+ if (token.graphVersion === null || authority.graphVersion === null) return {
20
+ kind: "absent",
21
+ missingReason: "graphVersionMissing"
22
+ };
23
+ return token.graphVersion === authority.graphVersion ? { kind: "satisfied" } : {
24
+ kind: "mismatch",
25
+ reason: "graphVersionMismatch"
26
+ };
27
+ case "cacheVariant": {
28
+ const tokenVariant = token.cacheVariantFingerprint;
29
+ const installedVariant = authority.installedCacheVariantFingerprint;
30
+ if (tokenVariant === void 0 || installedVariant === null) return {
31
+ kind: "absent",
32
+ missingReason: "cacheVariantMissing"
33
+ };
34
+ return tokenVariant === installedVariant ? { kind: "satisfied" } : {
35
+ kind: "mismatch",
36
+ reason: "cacheVariantMismatch"
37
+ };
38
+ }
39
+ default: throw new Error("[vinext] Unknown operation-token dimension: " + String(dimension));
40
+ }
41
+ }
42
+ function verifyOperationToken(token, authority, policy) {
43
+ const required = new Set(policy.require);
44
+ const evaluated = new Set([...policy.check, ...policy.require]);
45
+ for (const dimension of DIMENSION_ORDER) {
46
+ if (!evaluated.has(dimension)) continue;
47
+ const status = evaluateDimension(dimension, token, authority);
48
+ if (status.kind === "mismatch") return {
49
+ authorized: false,
50
+ reason: status.reason
51
+ };
52
+ if (status.kind === "absent" && required.has(dimension)) return {
53
+ authorized: false,
54
+ reason: status.missingReason
55
+ };
56
+ }
57
+ return {
58
+ authorized: true,
59
+ token
60
+ };
61
+ }
62
+ function verifyOperationTokenForCommit(token, authority) {
63
+ return verifyOperationToken(token, {
64
+ activeNavigationId: authority.activeNavigationId,
65
+ visibleCommitVersion: authority.visibleCommitVersion,
66
+ graphVersion: token.graphVersion,
67
+ installedCacheVariantFingerprint: token.cacheVariantFingerprint ?? null
68
+ }, {
69
+ check: ["navigation", "visibleCommit"],
70
+ require: ["navigation", "visibleCommit"]
71
+ });
72
+ }
73
+ function verifyOperationTokenForCacheReuse(token, authority) {
74
+ return verifyOperationToken(token, {
75
+ activeNavigationId: token.navigationId,
76
+ visibleCommitVersion: token.baseVisibleCommitVersion,
77
+ graphVersion: authority.graphVersion,
78
+ installedCacheVariantFingerprint: authority.installedCacheVariantFingerprint
79
+ }, {
80
+ check: ["graphVersion", "cacheVariant"],
81
+ require: []
82
+ });
83
+ }
84
+ //#endregion
85
+ export { verifyOperationToken, verifyOperationTokenForCacheReuse, verifyOperationTokenForCommit };
@@ -116,6 +116,6 @@ type NormalizePagesDataRequestResult = {
116
116
  * Extracted from `entries/pages-server-entry.ts` so both `renderPage` and
117
117
  * `runMiddleware` share a single implementation.
118
118
  */
119
- declare function normalizePagesDataRequest(request: Request, buildId: string | null): NormalizePagesDataRequestResult;
119
+ declare function normalizePagesDataRequest(request: Request, buildId: string | null, basePath?: string): NormalizePagesDataRequestResult;
120
120
  //#endregion
121
121
  export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
@@ -1,3 +1,4 @@
1
+ import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
1
2
  import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
2
3
  //#region src/server/pages-data-route.ts
3
4
  /**
@@ -123,16 +124,18 @@ function buildNextDataNotFoundResponse() {
123
124
  * Extracted from `entries/pages-server-entry.ts` so both `renderPage` and
124
125
  * `runMiddleware` share a single implementation.
125
126
  */
126
- function normalizePagesDataRequest(request, buildId) {
127
+ function normalizePagesDataRequest(request, buildId, basePath = "") {
127
128
  const reqUrl = new URL(request.url);
128
- if (!isNextDataPathname(reqUrl.pathname)) return {
129
+ const hadBasePath = !!basePath && hasBasePath(reqUrl.pathname, basePath);
130
+ const dataPathname = basePath ? stripBasePath(reqUrl.pathname, basePath) : reqUrl.pathname;
131
+ if (!isNextDataPathname(dataPathname)) return {
129
132
  isDataReq: false,
130
133
  request,
131
134
  normalizedPathname: null,
132
135
  search: "",
133
136
  notFoundResponse: null
134
137
  };
135
- const dataMatch = buildId ? parseNextDataPathname(reqUrl.pathname, buildId) : null;
138
+ const dataMatch = buildId ? parseNextDataPathname(dataPathname, buildId) : null;
136
139
  if (!dataMatch) return {
137
140
  isDataReq: false,
138
141
  request,
@@ -141,7 +144,7 @@ function normalizePagesDataRequest(request, buildId) {
141
144
  notFoundResponse: buildNextDataNotFoundResponse()
142
145
  };
143
146
  const normalizedUrl = new URL(reqUrl);
144
- normalizedUrl.pathname = dataMatch.pagePathname;
147
+ normalizedUrl.pathname = hadBasePath ? addBasePathToPathname(dataMatch.pagePathname, basePath) : dataMatch.pagePathname;
145
148
  return {
146
149
  isDataReq: true,
147
150
  request: new Request(normalizedUrl, request),
@@ -0,0 +1,4 @@
1
+ //#region src/server/pages-dev-module-url.d.ts
2
+ declare function createPagesDevModuleUrl(viteRoot: string, moduleFilePath: string, viteBase: string): string;
3
+ //#endregion
4
+ export { createPagesDevModuleUrl };
@@ -0,0 +1,15 @@
1
+ import path from "node:path";
2
+ //#region src/server/pages-dev-module-url.ts
3
+ function normalizeBase(base) {
4
+ if (!base || base === "/") return "/";
5
+ return `/${base.replace(/^\/+|\/+$/g, "")}/`;
6
+ }
7
+ function encodeModulePath(modulePath) {
8
+ return encodeURI(modulePath).replace(/%5B/gi, "[").replace(/%5D/gi, "]").replace(/\?/g, "%3F").replace(/#/g, "%23");
9
+ }
10
+ function createPagesDevModuleUrl(viteRoot, moduleFilePath, viteBase) {
11
+ const relativePath = (/^[A-Za-z]:[\\/]/.test(viteRoot) ? path.win32 : path).relative(viteRoot, moduleFilePath).replace(/\\/g, "/");
12
+ return normalizeBase(viteBase) + encodeModulePath(relativePath);
13
+ }
14
+ //#endregion
15
+ export { createPagesDevModuleUrl };
@@ -45,12 +45,6 @@ type DocumentRenderPageInput = {
45
45
  * the head nodes returned by `getInitialProps` (forward them to
46
46
  * `setDocumentInitialHead()` — do NOT call
47
47
  * `callDocumentGetInitialProps()` as well).
48
- * - `consumed` — `getInitialProps` WAS invoked but no body was produced
49
- * (it never called `renderPage`, returned no `{ html }`, or
50
- * threw). Callers must NOT re-invoke `getInitialProps` (that
51
- * would call it a second time) — render the streaming body,
52
- * spread `docProps` (possibly empty) onto `<Document>`, and
53
- * forward `head` to `setDocumentInitialHead()`.
54
48
  */
55
49
  type RunDocumentRenderPageResult = {
56
50
  status: "skipped";
@@ -60,10 +54,6 @@ type RunDocumentRenderPageResult = {
60
54
  stylesHTML: string;
61
55
  docProps: Record<string, unknown>;
62
56
  head: ReactNode[];
63
- } | {
64
- status: "consumed";
65
- docProps: Record<string, unknown>;
66
- head: ReactNode[];
67
57
  };
68
58
  /**
69
59
  * Run a user `_document.getInitialProps()` with a `ctx.renderPage()` that
@@ -75,11 +65,10 @@ type RunDocumentRenderPageResult = {
75
65
  * prod (`pages-page-response.ts`) and dev (`dev-server.ts`) SSR pipelines so
76
66
  * the `getInitialProps` + `renderPage` contract lives in one place.
77
67
  *
78
- * `getInitialProps` is invoked at most once here. When this returns `consumed`
79
- * or `rendered`, callers MUST treat that as the single invocation and must not
80
- * call `loadUserDocumentInitialProps` (which would invoke it again — and, for a
81
- * throwing override, surface the error as a 500 rather than the clean fallback
82
- * this contract guarantees).
68
+ * `getInitialProps` is invoked at most once here. When this returns `rendered`,
69
+ * callers MUST treat that as the single invocation and must not call
70
+ * `loadUserDocumentInitialProps` again. Errors intentionally propagate to the
71
+ * Pages Router's normal error-page pipeline, matching Next.js.
83
72
  *
84
73
  * @see .nextjs-ref/packages/next/src/server/render.tsx (search `renderPage`)
85
74
  */
@@ -19,19 +19,19 @@ import React from "react";
19
19
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/render.tsx
20
20
  * (search for `loadDocumentInitialProps` and `documentElement`).
21
21
  *
22
- * vinext only forwards `docProps`. The full `DocumentContext`
23
- * (`renderPage`, `defaultGetInitialProps`, `pathname`, `query`, `req`, `res`,
24
- * `err`, `asPath`) is not yet plumbed through. The common upstream pattern
22
+ * `runDocumentRenderPage()` supplies `renderPage`, `defaultGetInitialProps`,
23
+ * and the request pathname/query/asPath fields needed by the common upstream
24
+ * pattern:
25
25
  *
26
26
  * static async getInitialProps(ctx) {
27
27
  * const initialProps = await Document.getInitialProps(ctx)
28
28
  * return { ...initialProps, docValue }
29
29
  * }
30
30
  *
31
- * works because the base `Document.getInitialProps` shim in
32
- * `shims/document.tsx` returns `{ html: "" }` and ignores `ctx`. User
33
- * overrides that *only* read `ctx` will see `undefined` fields — that is a
34
- * separate gap tracked alongside the shim TODO.
31
+ * The standalone `loadUserDocumentInitialProps()` compatibility path supplies
32
+ * an empty default render result because it is only used after the body has
33
+ * already been produced. Request-only fields such as req/res remain outside
34
+ * that compatibility helper.
35
35
  *
36
36
  * Returns `null` when the user did not override the base shim (the static
37
37
  * `getInitialProps` reference still points at the shim's stub) so callers
@@ -47,7 +47,7 @@ async function loadUserDocumentInitialProps(DocumentComponent) {
47
47
  const getInitialProps = DocumentComponent.getInitialProps;
48
48
  if (typeof getInitialProps !== "function") return null;
49
49
  if (getInitialProps === BASE_GET_INITIAL_PROPS) return null;
50
- const result = await getInitialProps({});
50
+ const result = await getInitialProps({ defaultGetInitialProps: async () => ({ html: "" }) });
51
51
  return result && typeof result === "object" ? result : null;
52
52
  }
53
53
  /**
@@ -60,11 +60,10 @@ async function loadUserDocumentInitialProps(DocumentComponent) {
60
60
  * prod (`pages-page-response.ts`) and dev (`dev-server.ts`) SSR pipelines so
61
61
  * the `getInitialProps` + `renderPage` contract lives in one place.
62
62
  *
63
- * `getInitialProps` is invoked at most once here. When this returns `consumed`
64
- * or `rendered`, callers MUST treat that as the single invocation and must not
65
- * call `loadUserDocumentInitialProps` (which would invoke it again — and, for a
66
- * throwing override, surface the error as a 500 rather than the clean fallback
67
- * this contract guarantees).
63
+ * `getInitialProps` is invoked at most once here. When this returns `rendered`,
64
+ * callers MUST treat that as the single invocation and must not call
65
+ * `loadUserDocumentInitialProps` again. Errors intentionally propagate to the
66
+ * Pages Router's normal error-page pipeline, matching Next.js.
68
67
  *
69
68
  * @see .nextjs-ref/packages/next/src/server/render.tsx (search `renderPage`)
70
69
  */
@@ -74,58 +73,30 @@ async function runDocumentRenderPage(input) {
74
73
  if (DocCtor.getInitialProps === BASE_GET_INITIAL_PROPS) return { status: "skipped" };
75
74
  if (!input.enhancePageElement) return { status: "skipped" };
76
75
  const enhancePageElement = input.enhancePageElement;
77
- let renderPageCalled = false;
78
76
  const renderPage = async (opts = {}) => {
79
- renderPageCalled = true;
80
- const wrapped = withScriptNonce(enhancePageElement(opts), input.scriptNonce);
77
+ const wrapped = withScriptNonce(enhancePageElement(typeof opts === "function" ? { enhanceComponent: opts } : opts), input.scriptNonce);
81
78
  return {
82
79
  html: await readStreamAsText(await input.renderToReadableStream(wrapped)),
83
80
  head: []
84
81
  };
85
82
  };
86
- let docInitialProps;
87
- try {
88
- docInitialProps = await DocCtor.getInitialProps({
89
- renderPage,
90
- defaultGetInitialProps: async (ctx) => {
91
- const result = await (ctx.renderPage ?? renderPage)({ enhanceApp: (App) => (props) => React.createElement(App, props) });
92
- return {
93
- html: result.html,
94
- head: result.head ?? [],
95
- styles: void 0
96
- };
97
- },
98
- ...input.context
99
- });
100
- } catch (err) {
101
- console.error("[vinext] _document.getInitialProps() threw:", err);
102
- return {
103
- status: "consumed",
104
- docProps: {},
105
- head: []
106
- };
107
- }
83
+ const docInitialProps = await DocCtor.getInitialProps({
84
+ renderPage,
85
+ defaultGetInitialProps: async (ctx) => {
86
+ const result = await ctx.renderPage({ enhanceApp: (App) => (props) => React.createElement(App, props) });
87
+ return {
88
+ html: result.html,
89
+ head: result.head ?? [],
90
+ styles: void 0
91
+ };
92
+ },
93
+ ...input.context
94
+ });
108
95
  const { html: _html, head: rawHead, styles: _styles, ...docProps } = docInitialProps ?? {};
109
96
  const head = Array.isArray(rawHead) ? rawHead : [];
110
- if (!renderPageCalled) return {
111
- status: "consumed",
112
- docProps,
113
- head
114
- };
115
- if (!docInitialProps || typeof docInitialProps.html !== "string") {
116
- console.error(`[vinext] "${DocCtor.displayName ?? DocCtor.name ?? "Document"}.getInitialProps()" did not return an object with a string "html" prop`);
117
- return {
118
- status: "consumed",
119
- docProps,
120
- head
121
- };
122
- }
97
+ if (!docInitialProps || typeof docInitialProps.html !== "string") throw new Error(`"${DocCtor.displayName ?? DocCtor.name ?? "Document"}.getInitialProps()" should resolve to an object with a "html" prop set with a valid html string`);
123
98
  let stylesHTML = "";
124
- if (docInitialProps.styles != null) try {
125
- stylesHTML = await input.renderStylesToString(React.createElement(React.Fragment, null, docInitialProps.styles));
126
- } catch (err) {
127
- console.error("[vinext] Failed to render _document.getInitialProps() styles:", err);
128
- }
99
+ if (docInitialProps.styles != null) stylesHTML = await input.renderStylesToString(React.createElement(React.Fragment, null, docInitialProps.styles));
129
100
  return {
130
101
  status: "rendered",
131
102
  bodyHtml: docInitialProps.html,
@@ -127,8 +127,8 @@ function parseCookieLocaleFromHeader(cookieHeader, i18nConfig) {
127
127
  } catch {
128
128
  return null;
129
129
  }
130
- if (i18nConfig.locales.includes(value)) return value;
131
- return null;
130
+ const lowerValue = value.toLowerCase();
131
+ return i18nConfig.locales.find((locale) => locale.toLowerCase() === lowerValue) ?? null;
132
132
  }
133
133
  function formatLocalizedRootPath(locale, defaultLocale, basePath = "", trailingSlash = false, search = "") {
134
134
  if (locale.toLowerCase() === defaultLocale.toLowerCase()) return void 0;
@@ -1,6 +1,6 @@
1
1
  import { Route } from "../routing/pages-router.js";
2
2
  import { VinextNextData } from "../client/vinext-next-data.js";
3
- import { CachedPagesValue } from "../shims/cache.js";
3
+ import { CachedPagesValue } from "../shims/cache-handler.js";
4
4
  import { ISRCacheEntry } from "./isr-cache.js";
5
5
  import { PagesGsspResponse, PagesI18nRenderContext, PagesNextDataExtras } from "./pages-page-response.js";
6
6
  import { ReactNode } from "react";
@@ -198,7 +198,9 @@ function applyBotETagAndCheck(cachedResponse, html, options) {
198
198
  function rewritePagesCachedHtml(cachedHtml, freshBody, nextDataScript) {
199
199
  const bodyStart = cachedHtml.indexOf("<div id=\"__next\">");
200
200
  const contentStart = bodyStart >= 0 ? bodyStart + 17 : -1;
201
- const nextDataStart = cachedHtml.indexOf("<script>window.__NEXT_DATA__");
201
+ const canonicalNextDataStart = cachedHtml.search(/<script\b(?=[^>]*\bid=["']__NEXT_DATA__["'])(?=[^>]*\btype=["']application\/json["'])[^>]*>/);
202
+ const legacyNextDataStart = cachedHtml.indexOf("<script>window.__NEXT_DATA__");
203
+ const nextDataStart = canonicalNextDataStart >= 0 ? canonicalNextDataStart : legacyNextDataStart;
202
204
  if (contentStart >= 0 && nextDataStart >= 0) {
203
205
  const region = cachedHtml.slice(contentStart, nextDataStart);
204
206
  const lastCloseDiv = region.lastIndexOf("</div>");
@@ -184,7 +184,7 @@ function createPagesPageHandler(opts) {
184
184
  const pagesResolvedUrl = (new URL(routeUrl, originalRequestUrl).pathname || "/") + originalRequestUrl.search;
185
185
  const pageDataResult = await resolvePagesPageData({
186
186
  isDataReq,
187
- err,
187
+ err: err instanceof Error ? err : void 0,
188
188
  applyRequestContexts: applySSRContext,
189
189
  buildId,
190
190
  deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID,
@@ -327,6 +327,7 @@ function createPagesPageHandler(opts) {
327
327
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
328
328
  },
329
329
  DocumentComponent,
330
+ err: err instanceof Error ? err : void 0,
330
331
  flushPreloads: typeof flushPreloads === "function" ? flushPreloads : void 0,
331
332
  fontLinkHeader,
332
333
  fontPreloads: allFontPreloads,
@@ -344,6 +345,7 @@ function createPagesPageHandler(opts) {
344
345
  pageProps,
345
346
  props: renderProps,
346
347
  params,
348
+ query,
347
349
  renderDocumentToString(element) {
348
350
  return renderToStringAsync(element);
349
351
  },
@@ -1,5 +1,5 @@
1
1
  import { VinextNextData } from "../client/vinext-next-data.js";
2
- import { CachedPagesValue } from "../shims/cache.js";
2
+ import { CachedPagesValue } from "../shims/cache-handler.js";
3
3
  import { RenderPageEnhancers } from "./pages-document-initial-props.js";
4
4
  import { ComponentType, ReactNode } from "react";
5
5
 
@@ -66,6 +66,7 @@ type RenderPagesPageResponseOptions = {
66
66
  */
67
67
  enhancePageElement?: ((opts: RenderPageEnhancers) => ReactNode) | undefined;
68
68
  DocumentComponent: ComponentType | null;
69
+ err?: Error;
69
70
  flushPreloads?: (() => Promise<void> | void) | undefined;
70
71
  fontLinkHeader: string;
71
72
  fontPreloads: PagesFontPreload[];
@@ -95,6 +96,7 @@ type RenderPagesPageResponseOptions = {
95
96
  pageProps: Record<string, unknown>;
96
97
  props?: Record<string, unknown>;
97
98
  params: Record<string, unknown>;
99
+ query?: Record<string, unknown>;
98
100
  renderDocumentToString: (element: ReactNode) => Promise<string>;
99
101
  renderToReadableStream: (element: ReactNode) => Promise<ReadableStream<Uint8Array>>;
100
102
  resetSSRHead?: (() => void) | undefined;
@@ -1,13 +1,13 @@
1
1
  import { getRequestExecutionContext } from "../shims/request-context.js";
2
2
  import { reportRequestError } from "./instrumentation.js";
3
3
  import { setCacheStateHeaders } from "./cache-headers.js";
4
- import { fnv1a52 } from "../utils/hash.js";
5
- import { encodeCacheTag } from "../utils/encode-cache-tag.js";
6
4
  import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
7
5
  import { buildMissIsrCacheControl } from "./isr-decision.js";
6
+ import { fnv1a52 } from "../utils/hash.js";
7
+ import { encodeCacheTag } from "../utils/encode-cache-tag.js";
8
8
  import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
9
9
  import { withScriptNonce } from "../shims/script-nonce-context.js";
10
- import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from "./html.js";
10
+ import { createNonceAttribute, escapeHtmlAttr } from "./html.js";
11
11
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
12
12
  import { readStreamAsText } from "../utils/text-stream.js";
13
13
  import { loadUserDocumentInitialProps, runDocumentRenderPage } from "./pages-document-initial-props.js";
@@ -89,8 +89,7 @@ function buildPagesNextDataScript(options) {
89
89
  ...options.nextData?.__vinext,
90
90
  ...options.vinext
91
91
  };
92
- const localeGlobals = options.i18n.locales ? `;window.__VINEXT_LOCALE__=${options.safeJsonStringify(options.i18n.locale)};window.__VINEXT_LOCALES__=${options.safeJsonStringify(options.i18n.locales)};window.__VINEXT_DEFAULT_LOCALE__=${options.safeJsonStringify(options.i18n.defaultLocale)}` : "";
93
- return createInlineScriptTag(`window.__NEXT_DATA__ = ${options.safeJsonStringify(nextDataPayload)}${localeGlobals}`, options.scriptNonce);
92
+ return `<script id="__NEXT_DATA__" type="application/json"${createNonceAttribute(options.scriptNonce)}>${options.safeJsonStringify(nextDataPayload)}<\/script>`;
94
93
  }
95
94
  async function buildPagesShellHtml(bodyMarker, fontHeadHTML, nextDataScript, options) {
96
95
  if (options.DocumentComponent) {
@@ -197,8 +196,9 @@ async function renderPagesPageResponse(options) {
197
196
  renderStylesToString: async (element) => readStreamAsText(await options.renderToReadableStream(element)),
198
197
  scriptNonce: options.scriptNonce,
199
198
  context: {
199
+ err: options.err,
200
200
  pathname: options.routePattern,
201
- query: options.params,
201
+ query: options.query ?? options.params,
202
202
  asPath: options.routeUrl
203
203
  }
204
204
  });
@@ -10,7 +10,7 @@ function buildPagesReadinessNextData(options) {
10
10
  const hasAppGip = typeof options.appComponent?.getInitialProps === "function";
11
11
  return {
12
12
  gssp: hasPageGssp,
13
- gsp: hasPageGsp,
13
+ gsp: hasPageGsp ? true : void 0,
14
14
  gip: hasPageGip,
15
15
  appGip: hasAppGip,
16
16
  autoExport: !hasPageGssp && !hasPageGsp && !hasPageGip && !hasAppGip,
@@ -7,6 +7,8 @@ type PagesRenderOptions = {
7
7
  renderErrorPageOnMiss?: boolean;
8
8
  originalUrl?: string;
9
9
  };
10
+ type FilesystemRoutePhase = "direct" | "beforeFiles" | "afterFiles" | "fallback";
11
+ declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>): Promise<Response | false>;
10
12
  type MiddlewareResult = {
11
13
  continue: boolean;
12
14
  redirectUrl?: string;
@@ -53,15 +55,13 @@ type PagesPipelineDeps = {
53
55
  */
54
56
  proxyExternal?: ((currentRequest: Request, externalUrl: string) => Promise<Response>) | null;
55
57
  /**
56
- * Optional public-directory static file server (Node prod only).
58
+ * Optional filesystem/static-asset probe supplied by each runtime adapter.
57
59
  * Called post-middleware (so middleware can intercept/redirect public files) with the
58
60
  * original basePath-stripped pathname and the staged middleware response headers.
59
- * The callback writes the file to its own output (Node `res`) and resolves `true` when
60
- * it served the request; the pipeline then returns `{ type: "handled" }`. Resolves `false`
61
- * to fall through to rewrites/render. Worker/dev adapters omit this — their public files
62
- * are served by the asset binding / Vite respectively.
61
+ * Node may write directly to `res` and return true; dev/Workers return a Response.
62
+ * Resolves false to continue through rewrites, API routes, and page rendering.
63
63
  */
64
- serveStaticFile?: ((requestPathname: string, stagedHeaders: HeaderRecord) => Promise<boolean>) | null;
64
+ serveFilesystemRoute?: ((requestPathname: string, stagedHeaders: HeaderRecord, phase: FilesystemRoutePhase) => Promise<boolean | Response>) | null;
65
65
  };
66
66
  /**
67
67
  * Wrap an adapter's `runMiddleware` callback so middleware receives the original
@@ -111,4 +111,4 @@ type PagesPipelineResult = {
111
111
  */
112
112
  declare function runPagesRequest(request: Request, deps: PagesPipelineDeps): Promise<PagesPipelineResult>;
113
113
  //#endregion
114
- export { MiddlewareResult, PagesPipelineDeps, PagesPipelineResult, PagesRenderOptions, runPagesRequest, wrapMiddlewareWithBasePath };
114
+ export { FilesystemRoutePhase, MiddlewareResult, PagesPipelineDeps, PagesPipelineResult, PagesRenderOptions, fetchWorkerFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath };