vinext 1.0.0-beta.0 → 1.0.0-beta.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.
- package/README.md +21 -2
- package/dist/build/assets-ignore.js +1 -1
- package/dist/build/clean-output.js +1 -1
- package/dist/build/client-build-config.js +7 -4
- package/dist/build/css-url-assets.js +3 -3
- package/dist/build/google-fonts/fallback-metrics.js +1 -1
- package/dist/build/google-fonts/font-metadata.js +1 -1
- package/dist/build/inject-pregenerated-paths.js +1 -1
- package/dist/build/inline-css.js +2 -5
- package/dist/build/module-dependency-cache.d.ts +4 -0
- package/dist/build/module-dependency-cache.js +13 -0
- package/dist/build/next-client-runtime-manifests.js +1 -1
- package/dist/build/pages-client-assets-module.js +1 -1
- package/dist/build/precompress.js +7 -7
- package/dist/build/prerender-paths.d.ts +2 -2
- package/dist/build/prerender-paths.js +10 -15
- package/dist/build/prerender-server-pool.js +2 -2
- package/dist/build/prerender.js +1 -1
- package/dist/build/preview-credentials.d.ts +11 -0
- package/dist/build/preview-credentials.js +19 -0
- package/dist/build/report.d.ts +8 -4
- package/dist/build/report.js +14 -6
- package/dist/build/run-prerender.d.ts +2 -11
- package/dist/build/run-prerender.js +2 -10
- package/dist/build/server-manifest.js +1 -1
- package/dist/build/ssr-manifest.d.ts +4 -0
- package/dist/build/ssr-manifest.js +10 -6
- package/dist/build/standalone.js +37 -37
- package/dist/cache/cache-adapters-virtual.d.ts +1 -17
- package/dist/cache/cache-adapters-virtual.js +20 -11
- package/dist/check.d.ts +0 -16
- package/dist/check.js +27 -36
- package/dist/cli.js +61 -55
- package/dist/client/instrumentation-client-inject.js +1 -1
- package/dist/client/pages-router-link-navigation.js +1 -1
- package/dist/config/config-matchers.d.ts +13 -37
- package/dist/config/config-matchers.js +33 -123
- package/dist/config/dotenv.js +1 -1
- package/dist/config/next-config.d.ts +7 -3
- package/dist/config/next-config.js +84 -15
- package/dist/config/prerender.d.ts +2 -2
- package/dist/config/prerender.js +7 -15
- package/dist/config/request-context.d.ts +14 -0
- package/dist/config/request-context.js +26 -0
- package/dist/config/server-external-packages.js +1 -1
- package/dist/config/tsconfig-paths.js +2 -2
- package/dist/{node_modules/.pnpm/am-i-vibing@0.5.0/node_modules → deps/.pnpm/am-i-vibing@0.5.0/deps}/am-i-vibing/dist/detector-1yx2Hoe0.js +2 -2
- package/dist/deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js +50 -0
- package/dist/entries/app-rsc-entry.js +39 -14
- package/dist/entries/app-rsc-manifest.js +21 -4
- package/dist/entries/pages-client-entry.js +6 -5
- package/dist/entries/pages-server-entry.js +18 -28
- package/dist/entries/runtime-entry-module.js +2 -2
- package/dist/index.js +314 -230
- package/dist/init-cloudflare.js +1 -1
- package/dist/init-platform.js +1 -1
- package/dist/init.d.ts +6 -4
- package/dist/init.js +25 -27
- package/dist/plugins/ast-utils.js +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +7 -7
- package/dist/plugins/extensionless-dynamic-import.js +1 -1
- package/dist/plugins/fonts.js +3 -3
- package/dist/plugins/ignore-dynamic-requests.js +13 -8
- package/dist/plugins/import-meta-url.js +16 -17
- package/dist/plugins/middleware-export-validation.js +1 -1
- package/dist/plugins/middleware-server-only.js +2 -2
- package/dist/plugins/og-asset-ownership.js +7 -6
- package/dist/plugins/og-assets.js +5 -6
- package/dist/plugins/optimize-imports.js +12 -13
- package/dist/plugins/postcss.js +1 -1
- package/dist/plugins/remove-console.js +1 -1
- package/dist/plugins/require-context.js +1 -1
- package/dist/plugins/sass.js +2 -2
- package/dist/plugins/server-externals-manifest.js +1 -1
- package/dist/plugins/strip-server-exports.js +1 -1
- package/dist/plugins/styled-jsx.js +3 -2
- package/dist/plugins/typeof-window.js +1 -1
- package/dist/routing/app-route-graph.d.ts +16 -15
- package/dist/routing/app-route-graph.js +86 -88
- package/dist/routing/app-router.d.ts +0 -5
- package/dist/routing/app-router.js +12 -11
- package/dist/routing/file-matcher.d.ts +13 -28
- package/dist/routing/file-matcher.js +31 -44
- package/dist/routing/pages-router.js +26 -32
- package/dist/routing/route-matching.d.ts +14 -1
- package/dist/routing/route-matching.js +13 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +7 -4
- package/dist/routing/route-trie.d.ts +5 -1
- package/dist/routing/route-trie.js +5 -2
- package/dist/server/api-handler.js +41 -33
- package/dist/server/app-browser-entry.js +18 -11
- package/dist/server/app-browser-history-controller.d.ts +1 -1
- package/dist/server/app-browser-history-controller.js +3 -3
- package/dist/server/app-browser-navigation-controller.js +4 -2
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-elements-wire.d.ts +2 -1
- package/dist/server/app-fallback-renderer.d.ts +11 -0
- package/dist/server/app-fallback-renderer.js +16 -2
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +26 -2
- package/dist/server/app-page-boundary-render.js +190 -55
- package/dist/server/app-page-cache-finalizer.d.ts +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-dispatch.d.ts +12 -2
- package/dist/server/app-page-dispatch.js +37 -51
- package/dist/server/app-page-element-builder.d.ts +8 -2
- package/dist/server/app-page-element-builder.js +112 -27
- package/dist/server/app-page-execution.d.ts +3 -1
- package/dist/server/app-page-execution.js +31 -39
- package/dist/server/app-page-head.d.ts +54 -2
- package/dist/server/app-page-head.js +164 -78
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +106 -0
- package/dist/server/app-page-render.d.ts +2 -2
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-request.d.ts +12 -0
- package/dist/server/app-page-request.js +134 -14
- package/dist/server/app-page-route-wiring.d.ts +9 -0
- package/dist/server/app-page-route-wiring.js +44 -4
- package/dist/server/app-post-middleware-context.d.ts +1 -1
- package/dist/server/app-post-middleware-context.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +31 -17
- package/dist/server/app-route-handler-execution.d.ts +6 -1
- package/dist/server/app-route-handler-execution.js +41 -15
- package/dist/server/app-route-handler-policy.d.ts +2 -0
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-module-loader.d.ts +3 -1
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-route-tree-prefetch.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +1 -1
- package/dist/server/app-rsc-cache-busting.js +1 -1
- package/dist/server/app-rsc-errors.d.ts +1 -1
- package/dist/server/app-rsc-errors.js +12 -2
- package/dist/server/app-rsc-handler.d.ts +10 -5
- package/dist/server/app-rsc-handler.js +51 -23
- package/dist/server/app-rsc-redirect-flight.d.ts +66 -0
- package/dist/server/app-rsc-redirect-flight.js +71 -0
- package/dist/server/app-rsc-request-normalization.d.ts +3 -2
- package/dist/server/app-rsc-request-normalization.js +8 -2
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
- package/dist/server/app-rsc-response-finalizer.js +5 -11
- package/dist/server/app-rsc-route-matching.d.ts +20 -0
- package/dist/server/app-rsc-route-matching.js +87 -11
- package/dist/server/app-segment-config.js +15 -5
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +8 -6
- package/dist/server/app-ssr-entry.js +4 -1
- package/dist/server/app-ssr-stream.d.ts +2 -7
- package/dist/server/app-ssr-stream.js +5 -10
- package/dist/server/cache-proof.js +1 -1
- package/dist/server/config-headers.d.ts +24 -0
- package/dist/server/config-headers.js +52 -0
- package/dist/server/default-global-error-module.d.ts +3 -1
- package/dist/server/default-not-found-module.d.ts +3 -1
- package/dist/server/dev-initial-server-error.d.ts +1 -1
- package/dist/server/dev-lockfile.js +2 -3
- package/dist/server/dev-route-files.js +1 -1
- package/dist/server/dev-server.js +281 -173
- package/dist/server/dev-stack-sourcemap.js +4 -3
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/image-optimization.js +2 -2
- package/dist/server/implicit-tags.js +2 -1
- package/dist/server/instrumentation.js +2 -2
- package/dist/server/isr-cache.d.ts +1 -1
- package/dist/server/isr-cache.js +1 -1
- package/dist/server/metadata-routes.js +4 -4
- package/dist/server/middleware-matcher-pattern.d.ts +22 -0
- package/dist/server/middleware-matcher-pattern.js +219 -0
- package/dist/server/middleware-matcher.d.ts +2 -7
- package/dist/server/middleware-matcher.js +13 -60
- package/dist/server/middleware-path-to-regexp.d.ts +14 -0
- package/dist/server/middleware-path-to-regexp.js +228 -0
- package/dist/server/middleware-response-headers.js +1 -1
- package/dist/server/middleware-runtime.js +5 -4
- package/dist/server/middleware.d.ts +2 -1
- package/dist/server/middleware.js +3 -2
- package/dist/server/navigation-planner.d.ts +2 -0
- package/dist/server/navigation-planner.js +8 -2
- package/dist/server/next-error-digest.d.ts +9 -24
- package/dist/server/next-error-digest.js +23 -15
- package/dist/server/operation-token.js +1 -1
- package/dist/server/pages-body-parser-config.js +2 -1
- package/dist/server/pages-data-route.d.ts +11 -1
- package/dist/server/pages-data-route.js +16 -1
- package/dist/server/pages-dev-hydration.d.ts +14 -0
- package/dist/server/pages-dev-hydration.js +83 -0
- package/dist/server/pages-dev-module-url.js +2 -2
- package/dist/server/pages-get-initial-props.d.ts +15 -2
- package/dist/server/pages-get-initial-props.js +16 -6
- package/dist/server/pages-node-compat.d.ts +13 -6
- package/dist/server/pages-node-compat.js +44 -45
- package/dist/server/pages-page-data.d.ts +4 -2
- package/dist/server/pages-page-data.js +20 -10
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +74 -43
- package/dist/server/pages-page-response.d.ts +2 -2
- package/dist/server/pages-page-response.js +1 -1
- package/dist/server/pages-preview.d.ts +26 -0
- package/dist/server/pages-preview.js +165 -0
- package/dist/server/pages-readiness.d.ts +5 -4
- package/dist/server/pages-readiness.js +4 -2
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +25 -11
- package/dist/server/pages-router-entry.js +6 -0
- package/dist/server/prerender-route-params.js +2 -2
- package/dist/server/prod-server.d.ts +1 -4
- package/dist/server/prod-server.js +44 -30
- package/dist/server/request-pipeline.d.ts +15 -29
- package/dist/server/request-pipeline.js +25 -60
- package/dist/server/rsc-stream-hints.js +122 -18
- package/dist/server/seed-cache.js +1 -1
- package/dist/server/socket-error-backstop.js +1 -1
- package/dist/server/static-file-cache.js +7 -8
- package/dist/server/worker-utils.js +1 -1
- package/dist/shims/app.d.ts +1 -1
- package/dist/shims/cache-request-state.d.ts +27 -1
- package/dist/shims/cache-request-state.js +60 -1
- package/dist/shims/cache-runtime.d.ts +12 -1
- package/dist/shims/cache-runtime.js +22 -7
- package/dist/shims/cache.d.ts +5 -5
- package/dist/shims/cache.js +28 -11
- package/dist/shims/constants.js +1 -1
- package/dist/shims/document.d.ts +42 -83
- package/dist/shims/document.js +62 -53
- package/dist/shims/dynamic.d.ts +5 -25
- package/dist/shims/dynamic.js +29 -8
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error.d.ts +22 -6
- package/dist/shims/error.js +53 -15
- package/dist/shims/fetch-cache.js +13 -4
- package/dist/shims/font-google-base.d.ts +11 -4
- package/dist/shims/font-local.d.ts +10 -3
- package/dist/shims/font-utils.js +1 -1
- package/dist/shims/form.d.ts +1 -1
- package/dist/shims/head.d.ts +13 -2
- package/dist/shims/head.js +6 -6
- package/dist/shims/headers.d.ts +28 -31
- package/dist/shims/headers.js +115 -53
- package/dist/shims/image.d.ts +27 -37
- package/dist/shims/image.js +21 -14
- package/dist/shims/internal/cookie-serialize.d.ts +3 -1
- package/dist/shims/internal/cookie-serialize.js +3 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +5 -3
- package/dist/shims/internal/utils.d.ts +3 -3
- package/dist/shims/layout-segment-context.d.ts +1 -1
- package/dist/shims/legacy-image.d.ts +3 -37
- package/dist/shims/legacy-image.js +6 -16
- package/dist/shims/link.d.ts +16 -21
- package/dist/shims/link.js +25 -13
- package/dist/shims/navigation-context-state.d.ts +1 -1
- package/dist/shims/navigation-errors.d.ts +2 -1
- package/dist/shims/navigation-errors.js +9 -13
- package/dist/shims/navigation.d.ts +8 -4
- package/dist/shims/navigation.js +29 -18
- package/dist/shims/next-shims-augmentations.d.ts +1 -0
- package/dist/shims/next-shims-public.d.ts +1 -0
- package/dist/shims/public-shim-map.json.js +103 -0
- package/dist/shims/readonly-url-search-params.d.ts +3 -3
- package/dist/shims/readonly-url-search-params.js +3 -3
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router.d.ts +57 -22
- package/dist/shims/router.js +178 -46
- package/dist/shims/script.d.ts +6 -10
- package/dist/shims/script.js +7 -4
- package/dist/shims/server.d.ts +45 -22
- package/dist/shims/server.js +46 -7
- package/dist/shims/slot.d.ts +1 -1
- package/dist/shims/thenable-params.js +1 -1
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/url-safety.d.ts +1 -1
- package/dist/shims/url-safety.js +2 -2
- package/dist/typegen.d.ts +8 -2
- package/dist/typegen.js +84 -25
- package/dist/utils/client-build-manifest.js +2 -2
- package/dist/utils/client-entry-manifest.js +1 -1
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/commonjs-loader.js +3 -3
- package/dist/utils/domain-locale.d.ts +2 -2
- package/dist/utils/external-url.d.ts +5 -0
- package/dist/utils/external-url.js +7 -0
- package/dist/utils/mdx-scan.js +1 -1
- package/dist/utils/path.d.ts +1 -13
- package/dist/utils/path.js +1 -15
- package/dist/utils/plugin-options.d.ts +4 -0
- package/dist/utils/plugin-options.js +8 -0
- package/dist/utils/project.d.ts +0 -6
- package/dist/utils/project.js +2 -8
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.js +1 -1
- package/dist/utils/redirect-digest.d.ts +9 -0
- package/dist/utils/redirect-digest.js +25 -0
- package/dist/utils/regex-safety.d.ts +8 -0
- package/dist/utils/regex-safety.js +737 -0
- package/dist/utils/vinext-root.js +1 -1
- package/dist/utils/vite-version.d.ts +5 -2
- package/dist/utils/vite-version.js +43 -17
- package/package.json +16 -4
- /package/dist/build/google-fonts/{fallback-metrics-data.js → fallback-metrics-data.json.js} +0 -0
- /package/dist/build/google-fonts/{font-data.js → font-data.json.js} +0 -0
- /package/dist/{node_modules/.pnpm/process-ancestry@0.1.0/node_modules → deps/.pnpm/process-ancestry@0.1.0/deps}/process-ancestry/dist/index.js +0 -0
|
@@ -33,11 +33,11 @@ type PagesFontPreload = {
|
|
|
33
33
|
/**
|
|
34
34
|
* The `__NEXT_DATA__` fields beyond the always-present core that the Pages
|
|
35
35
|
* renderer serializes: the `__vinext` block plus the readiness flags
|
|
36
|
-
* (gssp/gsp/gip/appGip/autoExport/isExperimentalCompile) the client uses to
|
|
36
|
+
* (gssp/gsp/gip/appGip/autoExport/nextExport/isExperimentalCompile) the client uses to
|
|
37
37
|
* recompute the initial `router.isReady`. Shared by every render path
|
|
38
38
|
* (initial, ISR regeneration) so they emit identical readiness state.
|
|
39
39
|
*/
|
|
40
|
-
type PagesNextDataExtras = Pick<VinextNextData, "__vinext" | "appGip" | "autoExport" | "gip" | "gsp" | "gssp" | "isExperimentalCompile">;
|
|
40
|
+
type PagesNextDataExtras = Pick<VinextNextData, "__vinext" | "appGip" | "autoExport" | "gip" | "gsp" | "gssp" | "isExperimentalCompile" | "nextExport">;
|
|
41
41
|
type PagesI18nRenderContext = {
|
|
42
42
|
locale?: string;
|
|
43
43
|
locales?: string[];
|
|
@@ -72,7 +72,7 @@ function buildPagesNextDataScript(options) {
|
|
|
72
72
|
const nextDataPayload = {
|
|
73
73
|
props: options.props ?? { pageProps: options.pageProps },
|
|
74
74
|
page: options.routePattern,
|
|
75
|
-
query: options.params,
|
|
75
|
+
query: options.isFallback === true ? {} : options.params,
|
|
76
76
|
buildId: options.buildId,
|
|
77
77
|
isFallback: options.isFallback === true
|
|
78
78
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/server/pages-preview.d.ts
|
|
2
|
+
declare const PAGES_PREVIEW_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
|
|
3
|
+
type PagesPreviewData = object | string;
|
|
4
|
+
type PagesPreviewState = {
|
|
5
|
+
data: PagesPreviewData | false;
|
|
6
|
+
shouldClear: boolean;
|
|
7
|
+
};
|
|
8
|
+
type PreviewResponse = {
|
|
9
|
+
getHeader(name: string): string | number | boolean | string[] | undefined;
|
|
10
|
+
setHeader(name: string, value: string | number | boolean | string[]): unknown;
|
|
11
|
+
};
|
|
12
|
+
declare function getPagesPreviewModeId(): string;
|
|
13
|
+
declare function getPagesPreviewState(cookieHeader: string | string[] | null | undefined, options?: {
|
|
14
|
+
isOnDemandRevalidate?: boolean;
|
|
15
|
+
}): PagesPreviewState;
|
|
16
|
+
declare function setPagesDraftMode(response: PreviewResponse, enabled: boolean): void;
|
|
17
|
+
declare function setPagesPreviewData(response: PreviewResponse, data: PagesPreviewData, options?: {
|
|
18
|
+
maxAge?: number;
|
|
19
|
+
path?: string;
|
|
20
|
+
}): void;
|
|
21
|
+
declare function clearPagesPreviewData(response: PreviewResponse, options?: {
|
|
22
|
+
path?: string;
|
|
23
|
+
}): void;
|
|
24
|
+
declare function appendPagesPreviewClearCookies(headers: Headers): void;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { PAGES_PREVIEW_CACHE_CONTROL, PagesPreviewData, PagesPreviewState, appendPagesPreviewClearCookies, clearPagesPreviewData, getPagesPreviewModeId, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { parseCookieHeader } from "../utils/parse-cookie.js";
|
|
2
|
+
import { createCipheriv, createDecipheriv, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
3
|
+
//#region src/server/pages-preview.ts
|
|
4
|
+
const PAGES_PREVIEW_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
|
|
5
|
+
const pagesPreviewCookiesCleared = Symbol("__prerender_bypass");
|
|
6
|
+
let devCredentials;
|
|
7
|
+
function decodeKey(value) {
|
|
8
|
+
if (!value || !/^[0-9a-f]{64}$/i.test(value)) return null;
|
|
9
|
+
return Buffer.from(value, "hex");
|
|
10
|
+
}
|
|
11
|
+
function getPagesPreviewCredentials() {
|
|
12
|
+
const bypassId = process.env.__VINEXT_PREVIEW_MODE_ID;
|
|
13
|
+
const encryptionKey = decodeKey(process.env.__VINEXT_PREVIEW_MODE_ENCRYPTION_KEY);
|
|
14
|
+
const signingKey = decodeKey(process.env.__VINEXT_PREVIEW_MODE_SIGNING_KEY);
|
|
15
|
+
if (bypassId && encryptionKey && signingKey) return {
|
|
16
|
+
bypassId,
|
|
17
|
+
encryptionKey,
|
|
18
|
+
signingKey
|
|
19
|
+
};
|
|
20
|
+
if (!devCredentials) devCredentials = {
|
|
21
|
+
bypassId: randomBytes(16).toString("hex"),
|
|
22
|
+
encryptionKey: randomBytes(32),
|
|
23
|
+
signingKey: randomBytes(32)
|
|
24
|
+
};
|
|
25
|
+
return devCredentials;
|
|
26
|
+
}
|
|
27
|
+
function getPagesPreviewModeId() {
|
|
28
|
+
return getPagesPreviewCredentials().bypassId;
|
|
29
|
+
}
|
|
30
|
+
function serializeCookie(name, value, options = {}) {
|
|
31
|
+
const parts = [
|
|
32
|
+
`${name}=${encodeURIComponent(value)}`,
|
|
33
|
+
"HttpOnly",
|
|
34
|
+
`Path=${options.path ?? "/"}`,
|
|
35
|
+
process.env.NODE_ENV !== "development" ? "SameSite=None" : "SameSite=Lax"
|
|
36
|
+
];
|
|
37
|
+
if (process.env.NODE_ENV !== "development") parts.push("Secure");
|
|
38
|
+
if (options.maxAge !== void 0) parts.push(`Max-Age=${Math.trunc(options.maxAge)}`);
|
|
39
|
+
return parts.join("; ");
|
|
40
|
+
}
|
|
41
|
+
function serializeClearedCookie(name, options = {}) {
|
|
42
|
+
return [
|
|
43
|
+
`${name}=`,
|
|
44
|
+
"Expires=Thu, 01 Jan 1970 00:00:00 GMT",
|
|
45
|
+
"HttpOnly",
|
|
46
|
+
`Path=${options.path ?? "/"}`,
|
|
47
|
+
process.env.NODE_ENV !== "development" ? "SameSite=None" : "SameSite=Lax",
|
|
48
|
+
...process.env.NODE_ENV !== "development" ? ["Secure"] : []
|
|
49
|
+
].join("; ");
|
|
50
|
+
}
|
|
51
|
+
function normalizeSetCookie(value) {
|
|
52
|
+
if (value === void 0) return [];
|
|
53
|
+
return Array.isArray(value) ? value.map(String) : [String(value)];
|
|
54
|
+
}
|
|
55
|
+
function encodePayload(data, maxAge) {
|
|
56
|
+
const iv = randomBytes(12);
|
|
57
|
+
const credentials = getPagesPreviewCredentials();
|
|
58
|
+
const cipher = createCipheriv("aes-256-gcm", credentials.encryptionKey, iv);
|
|
59
|
+
const plaintext = JSON.stringify({
|
|
60
|
+
data,
|
|
61
|
+
...maxAge === void 0 ? {} : { expiresAt: Date.now() + maxAge * 1e3 }
|
|
62
|
+
});
|
|
63
|
+
const encryptedToken = [
|
|
64
|
+
iv,
|
|
65
|
+
Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]),
|
|
66
|
+
cipher.getAuthTag()
|
|
67
|
+
].map((part) => part.toString("base64url")).join(".");
|
|
68
|
+
return `${encryptedToken}.${createHmac("sha256", credentials.signingKey).update(encryptedToken).digest("base64url")}`;
|
|
69
|
+
}
|
|
70
|
+
function decodePayload(payload) {
|
|
71
|
+
try {
|
|
72
|
+
const [ivValue, encryptedValue, tagValue, signatureValue, ...extra] = payload.split(".");
|
|
73
|
+
if (!ivValue || !encryptedValue || !tagValue || !signatureValue || extra.length > 0) return false;
|
|
74
|
+
const encryptedToken = `${ivValue}.${encryptedValue}.${tagValue}`;
|
|
75
|
+
const credentials = getPagesPreviewCredentials();
|
|
76
|
+
const expected = createHmac("sha256", credentials.signingKey).update(encryptedToken).digest();
|
|
77
|
+
const signature = Buffer.from(signatureValue, "base64url");
|
|
78
|
+
if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) return false;
|
|
79
|
+
const decipher = createDecipheriv("aes-256-gcm", credentials.encryptionKey, Buffer.from(ivValue, "base64url"));
|
|
80
|
+
decipher.setAuthTag(Buffer.from(tagValue, "base64url"));
|
|
81
|
+
const decoded = Buffer.concat([decipher.update(Buffer.from(encryptedValue, "base64url")), decipher.final()]).toString("utf8");
|
|
82
|
+
const value = JSON.parse(decoded);
|
|
83
|
+
if (typeof value !== "object" || value === null || !("data" in value)) return false;
|
|
84
|
+
const expiresAt = "expiresAt" in value ? value.expiresAt : void 0;
|
|
85
|
+
if (typeof expiresAt === "number" && Date.now() >= expiresAt) return false;
|
|
86
|
+
const data = value.data;
|
|
87
|
+
return typeof data === "object" && data !== null ? data : String(data);
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function getPagesPreviewState(cookieHeader, options = {}) {
|
|
93
|
+
if (options.isOnDemandRevalidate) return {
|
|
94
|
+
data: false,
|
|
95
|
+
shouldClear: false
|
|
96
|
+
};
|
|
97
|
+
const cookies = parseCookieHeader(Array.isArray(cookieHeader) ? cookieHeader.join("; ") : cookieHeader);
|
|
98
|
+
const bypass = cookies.__prerender_bypass;
|
|
99
|
+
const payload = cookies.__next_preview_data;
|
|
100
|
+
if (!bypass && !payload) return {
|
|
101
|
+
data: false,
|
|
102
|
+
shouldClear: false
|
|
103
|
+
};
|
|
104
|
+
if (!bypass || bypass !== getPagesPreviewCredentials().bypassId) return {
|
|
105
|
+
data: false,
|
|
106
|
+
shouldClear: true
|
|
107
|
+
};
|
|
108
|
+
if (!payload) return {
|
|
109
|
+
data: {},
|
|
110
|
+
shouldClear: false
|
|
111
|
+
};
|
|
112
|
+
const data = decodePayload(payload);
|
|
113
|
+
return {
|
|
114
|
+
data,
|
|
115
|
+
shouldClear: data === false
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function setPagesDraftMode(response, enabled) {
|
|
119
|
+
const cookie = enabled ? serializeCookie("__prerender_bypass", getPagesPreviewModeId()) : serializeClearedCookie("__prerender_bypass");
|
|
120
|
+
response.setHeader("Set-Cookie", [...normalizeSetCookie(response.getHeader("Set-Cookie")), cookie]);
|
|
121
|
+
}
|
|
122
|
+
function setPagesPreviewData(response, data, options = {}) {
|
|
123
|
+
const payload = encodePayload(data, options.maxAge);
|
|
124
|
+
if (payload.length > 2048) throw new Error("Preview data is limited to 2KB currently, reduce how much data you are storing as preview data to continue");
|
|
125
|
+
response.setHeader("Set-Cookie", [
|
|
126
|
+
...normalizeSetCookie(response.getHeader("Set-Cookie")),
|
|
127
|
+
serializeCookie("__prerender_bypass", getPagesPreviewModeId(), options),
|
|
128
|
+
serializeCookie("__next_preview_data", payload, options)
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
function clearPagesPreviewData(response, options = {}) {
|
|
132
|
+
if (pagesPreviewCookiesCleared in response) return;
|
|
133
|
+
response.setHeader("Set-Cookie", [
|
|
134
|
+
...normalizeSetCookie(response.getHeader("Set-Cookie")),
|
|
135
|
+
serializeClearedCookie("__prerender_bypass", options),
|
|
136
|
+
serializeClearedCookie("__next_preview_data", options)
|
|
137
|
+
]);
|
|
138
|
+
Object.defineProperty(response, pagesPreviewCookiesCleared, {
|
|
139
|
+
value: true,
|
|
140
|
+
enumerable: false
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function appendPagesPreviewClearCookies(headers) {
|
|
144
|
+
const cookies = headers.getSetCookie();
|
|
145
|
+
const hasExpiredCookie = (name) => cookies.some((cookie) => {
|
|
146
|
+
const [cookieValue, ...attributes] = cookie.split(";").map((part) => part.trim());
|
|
147
|
+
if (!cookieValue?.startsWith(`${name}=`)) return false;
|
|
148
|
+
let expiresAtEpoch = false;
|
|
149
|
+
let path;
|
|
150
|
+
let hasDomain = false;
|
|
151
|
+
for (const attribute of attributes) {
|
|
152
|
+
const separator = attribute.indexOf("=");
|
|
153
|
+
const attributeName = (separator === -1 ? attribute : attribute.slice(0, separator)).trim().toLowerCase();
|
|
154
|
+
const attributeValue = separator === -1 ? "" : attribute.slice(separator + 1).trim();
|
|
155
|
+
if (attributeName === "expires") expiresAtEpoch = Date.parse(attributeValue) === 0;
|
|
156
|
+
if (attributeName === "path") path = attributeValue;
|
|
157
|
+
if (attributeName === "domain") hasDomain = true;
|
|
158
|
+
}
|
|
159
|
+
return expiresAtEpoch && path === "/" && !hasDomain;
|
|
160
|
+
});
|
|
161
|
+
if (!hasExpiredCookie("__prerender_bypass")) headers.append("Set-Cookie", serializeClearedCookie("__prerender_bypass"));
|
|
162
|
+
if (!hasExpiredCookie("__next_preview_data")) headers.append("Set-Cookie", serializeClearedCookie("__next_preview_data"));
|
|
163
|
+
}
|
|
164
|
+
//#endregion
|
|
165
|
+
export { PAGES_PREVIEW_CACHE_CONTROL, appendPagesPreviewClearCookies, clearPagesPreviewData, getPagesPreviewModeId, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData };
|
|
@@ -7,9 +7,9 @@ import { PagesPageModule } from "./pages-page-data.js";
|
|
|
7
7
|
*
|
|
8
8
|
* The initial `router.isReady` value for the `next/navigation` compat hooks is
|
|
9
9
|
* derived from the page/_app data-fetching exports plus the configured-rewrites
|
|
10
|
-
* flag
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* flag. The client recomputes readiness from those flags and its live URL,
|
|
11
|
+
* matching the Pages Router constructor; server-only readiness remains in the
|
|
12
|
+
* request context. See `getPagesNavigationIsReadyFromSerializedState` in
|
|
13
13
|
* `shims/router.ts`.
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
@@ -18,7 +18,7 @@ import { PagesPageModule } from "./pages-page-data.js";
|
|
|
18
18
|
* The field names/types are projected from the canonical `VinextNextData` so
|
|
19
19
|
* this stays in lockstep with the `__NEXT_DATA__` shape it feeds into.
|
|
20
20
|
*/
|
|
21
|
-
type PagesReadinessNextData = Pick<VinextNextData, "gssp" | "gsp" | "gip" | "appGip" | "autoExport"> & {
|
|
21
|
+
type PagesReadinessNextData = Pick<VinextNextData, "gssp" | "gsp" | "gip" | "appGip" | "autoExport" | "nextExport"> & {
|
|
22
22
|
__vinext: Pick<NonNullable<VinextNextData["__vinext"]>, "hasRewrites">;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
@@ -29,6 +29,7 @@ declare function buildPagesReadinessNextData(options: {
|
|
|
29
29
|
pageModule: PagesPageModule;
|
|
30
30
|
appComponent: {
|
|
31
31
|
getInitialProps?: unknown;
|
|
32
|
+
origGetInitialProps?: unknown;
|
|
32
33
|
} | null | undefined;
|
|
33
34
|
hasRewrites: boolean;
|
|
34
35
|
}): PagesReadinessNextData;
|
|
@@ -7,13 +7,15 @@ function buildPagesReadinessNextData(options) {
|
|
|
7
7
|
const hasPageGssp = typeof options.pageModule.getServerSideProps === "function";
|
|
8
8
|
const hasPageGsp = typeof options.pageModule.getStaticProps === "function";
|
|
9
9
|
const hasPageGip = typeof options.pageModule.default?.getInitialProps === "function";
|
|
10
|
-
const hasAppGip = typeof options.appComponent?.getInitialProps === "function";
|
|
10
|
+
const hasAppGip = typeof options.appComponent?.getInitialProps === "function" && options.appComponent.getInitialProps !== options.appComponent.origGetInitialProps;
|
|
11
|
+
const autoExport = !hasPageGssp && !hasPageGsp && !hasPageGip && !hasAppGip;
|
|
11
12
|
return {
|
|
12
13
|
gssp: hasPageGssp,
|
|
13
14
|
gsp: hasPageGsp ? true : void 0,
|
|
14
15
|
gip: hasPageGip,
|
|
15
16
|
appGip: hasAppGip,
|
|
16
|
-
autoExport
|
|
17
|
+
autoExport,
|
|
18
|
+
nextExport: autoExport ? true : void 0,
|
|
17
19
|
__vinext: { hasRewrites: options.hasRewrites }
|
|
18
20
|
};
|
|
19
21
|
}
|
|
@@ -44,6 +44,7 @@ type PagesPipelineDeps = {
|
|
|
44
44
|
hasMiddleware: boolean;
|
|
45
45
|
ctx?: unknown;
|
|
46
46
|
rawSearch?: string;
|
|
47
|
+
configMatchPathname?: string;
|
|
47
48
|
matchPageRoute?: ((pathname: string, request: Request) => PageRouteMatch | null) | null;
|
|
48
49
|
runMiddleware?: ((request: Request, ctx: unknown, opts: {
|
|
49
50
|
isDataRequest: boolean;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { addBasePathToPathname, hasBasePath } from "../utils/base-path.js";
|
|
2
2
|
import { patternToNextFormat } from "../routing/route-validation.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { requestContextFromRequest } from "../config/request-context.js";
|
|
4
|
+
import { isExternalUrl } from "../utils/external-url.js";
|
|
5
|
+
import { applyMiddlewareRequestHeaders, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
6
|
+
import { cloneRequestWithUrl, normalizeTrailingSlash } from "./request-pipeline.js";
|
|
5
7
|
import { mergeRewriteQuery } from "../utils/query.js";
|
|
6
8
|
import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
|
|
7
9
|
import { buildMiddlewarePrefetchSkipResponse } from "./pages-data-route.js";
|
|
10
|
+
import { applyConfigHeadersToHeaderRecord } from "./config-headers.js";
|
|
8
11
|
import { mergeHeaders } from "./worker-utils.js";
|
|
9
12
|
//#region src/server/pages-request-pipeline.ts
|
|
10
13
|
async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset) {
|
|
@@ -53,6 +56,7 @@ async function runPagesRequest(request, deps) {
|
|
|
53
56
|
const url = new URL(request.url);
|
|
54
57
|
let pathname = url.pathname;
|
|
55
58
|
const search = url.search;
|
|
59
|
+
const requestConfigPathname = deps.configMatchPathname ?? pathname;
|
|
56
60
|
const basePathState = {
|
|
57
61
|
basePath,
|
|
58
62
|
hadBasePath
|
|
@@ -66,9 +70,9 @@ async function runPagesRequest(request, deps) {
|
|
|
66
70
|
}
|
|
67
71
|
const reqCtx = requestContextFromRequest(request);
|
|
68
72
|
const requestHostname = i18nConfig ? url.hostname : "";
|
|
69
|
-
const
|
|
73
|
+
const requestConfigMatchPathname = i18nConfig ? normalizeDefaultLocalePathname(requestConfigPathname, i18nConfig, { hostname: requestHostname }) : requestConfigPathname;
|
|
70
74
|
if (configRedirects.length) {
|
|
71
|
-
const redirect = matchRedirect(
|
|
75
|
+
const redirect = matchRedirect(requestConfigMatchPathname, configRedirects, reqCtx, basePathState);
|
|
72
76
|
if (redirect) {
|
|
73
77
|
const location = preserveRedirectDestinationQuery(sanitizeDestination(basePath && hadBasePath && !isExternalUrl(redirect.destination) && !hasBasePath(redirect.destination, basePath) ? basePath + redirect.destination : redirect.destination), deps.rawSearch ?? search);
|
|
74
78
|
return {
|
|
@@ -82,6 +86,7 @@ async function runPagesRequest(request, deps) {
|
|
|
82
86
|
}
|
|
83
87
|
const originalResolvedUrl = pathname + search;
|
|
84
88
|
let resolvedUrl = originalResolvedUrl;
|
|
89
|
+
let resolvedPathnameIsRequestPathname = true;
|
|
85
90
|
const middlewareHeaders = {};
|
|
86
91
|
let middlewareStatus;
|
|
87
92
|
const serveFilesystemRoute = async (requestPathname, phase) => {
|
|
@@ -131,7 +136,10 @@ async function runPagesRequest(request, deps) {
|
|
|
131
136
|
else if (existing) middlewareHeaders[key] = [existing, value];
|
|
132
137
|
else middlewareHeaders[key] = [value];
|
|
133
138
|
} else middlewareHeaders[key] = value;
|
|
134
|
-
if (result.rewriteUrl)
|
|
139
|
+
if (result.rewriteUrl) {
|
|
140
|
+
resolvedUrl = result.rewriteUrl;
|
|
141
|
+
resolvedPathnameIsRequestPathname = false;
|
|
142
|
+
}
|
|
135
143
|
middlewareStatus = result.status ?? result.rewriteStatus;
|
|
136
144
|
}
|
|
137
145
|
const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, request, { preserveCredentialHeaders: isExternalUrl(resolvedUrl) });
|
|
@@ -143,6 +151,7 @@ async function runPagesRequest(request, deps) {
|
|
|
143
151
|
});
|
|
144
152
|
let resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
145
153
|
const matchResolvedPathname = (p) => i18nConfig ? normalizeDefaultLocalePathname(p, i18nConfig, { hostname: requestHostname }) : p;
|
|
154
|
+
const configSourcePathname = () => resolvedPathnameIsRequestPathname ? requestConfigMatchPathname : matchResolvedPathname(resolvedPathname);
|
|
146
155
|
const matchedPathnameForRoute = (routePattern) => {
|
|
147
156
|
const matchedPathname = routePattern ? patternToNextFormat(routePattern) : resolvedPathname;
|
|
148
157
|
if (!i18nConfig) return matchedPathname;
|
|
@@ -161,7 +170,7 @@ async function runPagesRequest(request, deps) {
|
|
|
161
170
|
};
|
|
162
171
|
if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
|
|
163
172
|
configHeaders,
|
|
164
|
-
pathname:
|
|
173
|
+
pathname: requestConfigMatchPathname,
|
|
165
174
|
requestContext: reqCtx,
|
|
166
175
|
basePathState
|
|
167
176
|
});
|
|
@@ -173,7 +182,7 @@ async function runPagesRequest(request, deps) {
|
|
|
173
182
|
if (directFilesystemResult) return directFilesystemResult;
|
|
174
183
|
let configRewriteFired = false;
|
|
175
184
|
for (const rewrite of configRewrites.beforeFiles ?? []) {
|
|
176
|
-
const rewritten = matchRewrite(
|
|
185
|
+
const rewritten = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), basePathState);
|
|
177
186
|
if (rewritten) {
|
|
178
187
|
if (isExternalUrl(rewritten)) return {
|
|
179
188
|
type: "response",
|
|
@@ -181,6 +190,7 @@ async function runPagesRequest(request, deps) {
|
|
|
181
190
|
};
|
|
182
191
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
183
192
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
193
|
+
resolvedPathnameIsRequestPathname = false;
|
|
184
194
|
configRewriteFired = true;
|
|
185
195
|
}
|
|
186
196
|
}
|
|
@@ -227,7 +237,7 @@ async function runPagesRequest(request, deps) {
|
|
|
227
237
|
let pageMatch = !isOutsideBasePathUnclaimed() && deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
|
|
228
238
|
let resolvedPathnameChanged = false;
|
|
229
239
|
if (!pageMatch || pageMatch.route.isDynamic) for (const rewrite of configRewrites.afterFiles ?? []) {
|
|
230
|
-
const rewritten = matchRewrite(
|
|
240
|
+
const rewritten = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), basePathState);
|
|
231
241
|
if (rewritten) {
|
|
232
242
|
if (isExternalUrl(rewritten)) return {
|
|
233
243
|
type: "response",
|
|
@@ -235,6 +245,7 @@ async function runPagesRequest(request, deps) {
|
|
|
235
245
|
};
|
|
236
246
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
237
247
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
248
|
+
resolvedPathnameIsRequestPathname = false;
|
|
238
249
|
configRewriteFired = true;
|
|
239
250
|
resolvedPathnameChanged = true;
|
|
240
251
|
const afterFilesFilesystemResult = await serveFilesystemRoute(resolvedPathname, "afterFiles");
|
|
@@ -253,7 +264,7 @@ async function runPagesRequest(request, deps) {
|
|
|
253
264
|
if (typeof deps.renderPage === "function") {
|
|
254
265
|
let renderPageMatch = pageMatch;
|
|
255
266
|
if ((isOutsideBasePathUnclaimed() || isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
256
|
-
const fallbackRewrite = matchRewrite(
|
|
267
|
+
const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), basePathState);
|
|
257
268
|
if (!fallbackRewrite) continue;
|
|
258
269
|
if (isExternalUrl(fallbackRewrite)) return {
|
|
259
270
|
type: "response",
|
|
@@ -261,6 +272,7 @@ async function runPagesRequest(request, deps) {
|
|
|
261
272
|
};
|
|
262
273
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
263
274
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
275
|
+
resolvedPathnameIsRequestPathname = false;
|
|
264
276
|
configRewriteFired = true;
|
|
265
277
|
const fallbackFilesystemResult = await serveFilesystemRoute(resolvedPathname, "fallback");
|
|
266
278
|
if (fallbackFilesystemResult) return fallbackFilesystemResult;
|
|
@@ -281,7 +293,7 @@ async function runPagesRequest(request, deps) {
|
|
|
281
293
|
let response = await deps.renderPage(request, resolvedUrl, initialRenderOptions, stagedHeaders);
|
|
282
294
|
let matchedFallbackRewrite = false;
|
|
283
295
|
if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
284
|
-
const fallbackRewrite = matchRewrite(
|
|
296
|
+
const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), basePathState);
|
|
285
297
|
if (!fallbackRewrite) continue;
|
|
286
298
|
if (isExternalUrl(fallbackRewrite)) return {
|
|
287
299
|
type: "response",
|
|
@@ -289,6 +301,7 @@ async function runPagesRequest(request, deps) {
|
|
|
289
301
|
};
|
|
290
302
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
291
303
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
304
|
+
resolvedPathnameIsRequestPathname = false;
|
|
292
305
|
configRewriteFired = true;
|
|
293
306
|
const fallbackFilesystemResult = await serveFilesystemRoute(resolvedPathname, "fallback");
|
|
294
307
|
if (fallbackFilesystemResult) return fallbackFilesystemResult;
|
|
@@ -325,7 +338,7 @@ async function runPagesRequest(request, deps) {
|
|
|
325
338
|
}
|
|
326
339
|
let devPageMatch = isOutsideBasePathUnclaimed() ? null : resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch;
|
|
327
340
|
if (!devPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
328
|
-
const fallbackRewrite = matchRewrite(
|
|
341
|
+
const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), basePathState);
|
|
329
342
|
if (!fallbackRewrite) continue;
|
|
330
343
|
if (isExternalUrl(fallbackRewrite)) return {
|
|
331
344
|
type: "response",
|
|
@@ -333,6 +346,7 @@ async function runPagesRequest(request, deps) {
|
|
|
333
346
|
};
|
|
334
347
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
335
348
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
349
|
+
resolvedPathnameIsRequestPathname = false;
|
|
336
350
|
configRewriteFired = true;
|
|
337
351
|
const fallbackFilesystemResult = await serveFilesystemRoute(resolvedPathname, "fallback");
|
|
338
352
|
if (fallbackFilesystemResult) return fallbackFilesystemResult;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
1
2
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
2
3
|
import { notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
3
4
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
@@ -52,6 +53,11 @@ async function handleRequest(request, env, ctx) {
|
|
|
52
53
|
try {
|
|
53
54
|
let pathname = new URL(request.url).pathname;
|
|
54
55
|
if (isOpenRedirectShaped(pathname)) return new Response("This page could not be found", { status: 404 });
|
|
56
|
+
try {
|
|
57
|
+
normalizePathnameForRouteMatchStrict(pathname);
|
|
58
|
+
} catch {
|
|
59
|
+
return new Response("Bad Request", { status: 400 });
|
|
60
|
+
}
|
|
55
61
|
const missingBuildAsset = isNextStaticPath(pathname, basePath, assetPathPrefix);
|
|
56
62
|
request = cloneRequestWithHeaders(request, filterInternalHeaders(request.headers));
|
|
57
63
|
const hadBasePath = !basePath || hasBasePath(pathname, basePath);
|
|
@@ -58,11 +58,11 @@ function decodedPrerenderRouteParamEquals(prerenderValue, matchedValue) {
|
|
|
58
58
|
if (prerenderValue.length !== matchedValue.length) return false;
|
|
59
59
|
return prerenderValue.every((item, index) => {
|
|
60
60
|
const decoded = decodePrerenderRouteParam(item);
|
|
61
|
-
return decoded !== null && decoded === matchedValue[index];
|
|
61
|
+
return item === matchedValue[index] || decoded !== null && decoded === matchedValue[index];
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
const decoded = decodePrerenderRouteParam(prerenderValue);
|
|
65
|
-
return decoded !== null && decoded === matchedValue;
|
|
65
|
+
return prerenderValue === matchedValue || decoded !== null && decoded === matchedValue;
|
|
66
66
|
}
|
|
67
67
|
function prerenderRouteParamsPayloadMatchesRoute(payload, routePattern, params) {
|
|
68
68
|
return matchPrerenderRouteParamsPayload(payload, routePattern, params)?.kind === "exact";
|
|
@@ -101,10 +101,7 @@ declare function tryServeStatic(req: IncomingMessage, res: ServerResponse, clien
|
|
|
101
101
|
* Convert a Node.js IncomingMessage to a Web Request object.
|
|
102
102
|
*
|
|
103
103
|
* When `urlOverride` is provided, it is used as the path + query string
|
|
104
|
-
* instead of `req.url`.
|
|
105
|
-
* caller has already decoded and normalized the pathname (e.g. the App
|
|
106
|
-
* Router prod server normalizes before static-asset lookup, and can pass
|
|
107
|
-
* the result here so the downstream RSC handler doesn't re-normalize).
|
|
104
|
+
* instead of `req.url`.
|
|
108
105
|
*/
|
|
109
106
|
declare function nodeToWebRequest(req: IncomingMessage, urlOverride?: string, prerenderSecret?: string): Request;
|
|
110
107
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
1
2
|
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
2
3
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
3
4
|
import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
@@ -5,9 +6,9 @@ import { VINEXT_STATIC_FILE_HEADER } from "./headers.js";
|
|
|
5
6
|
import { normalizePath } from "./normalize-path.js";
|
|
6
7
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
7
8
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
8
|
-
import { filterInternalHeaders } from "./request-pipeline.js";
|
|
9
|
+
import { canonicalizeRequestPathname, filterInternalHeaders } from "./request-pipeline.js";
|
|
9
10
|
import { isUnknownRecord } from "../utils/record.js";
|
|
10
|
-
import { buildNextDataNotFoundResponse, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname } from "./pages-data-route.js";
|
|
11
|
+
import { buildNextDataNotFoundResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, urlParserCreatesPagesDataPath } from "./pages-data-route.js";
|
|
11
12
|
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
12
13
|
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
13
14
|
import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
@@ -23,8 +24,7 @@ import { readPrerenderSecret } from "../build/server-manifest.js";
|
|
|
23
24
|
import { seedMemoryCacheFromPrerender } from "./seed-cache.js";
|
|
24
25
|
import { negotiateEncoding, parseAcceptedEncodings, selectContentEncoding } from "./accept-encoding.js";
|
|
25
26
|
import fs from "node:fs";
|
|
26
|
-
import
|
|
27
|
-
import fs$1 from "node:fs/promises";
|
|
27
|
+
import fsp from "node:fs/promises";
|
|
28
28
|
import { pathToFileURL } from "node:url";
|
|
29
29
|
import { Readable, pipeline } from "node:stream";
|
|
30
30
|
import zlib from "node:zlib";
|
|
@@ -159,7 +159,7 @@ function readNodeStream(req) {
|
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
/** Content types that benefit from compression. */
|
|
162
|
-
const COMPRESSIBLE_TYPES = new Set([
|
|
162
|
+
const COMPRESSIBLE_TYPES = /* @__PURE__ */ new Set([
|
|
163
163
|
"text/html",
|
|
164
164
|
"text/css",
|
|
165
165
|
"text/plain",
|
|
@@ -237,13 +237,13 @@ function nodeHeadersToWebHeaders(headersRecord) {
|
|
|
237
237
|
for (const [key, value] of Object.entries(headersRecord)) appendWebHeader(headers, key, value);
|
|
238
238
|
return headers;
|
|
239
239
|
}
|
|
240
|
-
const NO_BODY_RESPONSE_STATUSES = new Set([
|
|
240
|
+
const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
|
|
241
241
|
204,
|
|
242
242
|
205,
|
|
243
243
|
304
|
|
244
244
|
]);
|
|
245
|
-
const OMIT_BODY_HEADERS = new Set(["content-length", "content-type"]);
|
|
246
|
-
const OMIT_STATIC_RESPONSE_HEADERS = new Set([
|
|
245
|
+
const OMIT_BODY_HEADERS = /* @__PURE__ */ new Set(["content-length", "content-type"]);
|
|
246
|
+
const OMIT_STATIC_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
|
|
247
247
|
VINEXT_STATIC_FILE_HEADER,
|
|
248
248
|
"content-encoding",
|
|
249
249
|
"content-length",
|
|
@@ -542,7 +542,7 @@ async function resolveStaticFile(staticFile) {
|
|
|
542
542
|
}
|
|
543
543
|
async function statIfFile(filePath) {
|
|
544
544
|
try {
|
|
545
|
-
const stat = await
|
|
545
|
+
const stat = await fsp.stat(filePath);
|
|
546
546
|
return stat.isFile() ? {
|
|
547
547
|
size: stat.size,
|
|
548
548
|
mtimeMs: stat.mtimeMs
|
|
@@ -555,10 +555,7 @@ async function statIfFile(filePath) {
|
|
|
555
555
|
* Convert a Node.js IncomingMessage to a Web Request object.
|
|
556
556
|
*
|
|
557
557
|
* When `urlOverride` is provided, it is used as the path + query string
|
|
558
|
-
* instead of `req.url`.
|
|
559
|
-
* caller has already decoded and normalized the pathname (e.g. the App
|
|
560
|
-
* Router prod server normalizes before static-asset lookup, and can pass
|
|
561
|
-
* the result here so the downstream RSC handler doesn't re-normalize).
|
|
558
|
+
* instead of `req.url`.
|
|
562
559
|
*/
|
|
563
560
|
function nodeToWebRequest(req, urlOverride, prerenderSecret) {
|
|
564
561
|
const origin = `${resolveRequestProtocol(req)}://${resolveRequestHost(req, "localhost")}`;
|
|
@@ -873,8 +870,14 @@ async function startAppRouterServer(options) {
|
|
|
873
870
|
return;
|
|
874
871
|
}
|
|
875
872
|
try {
|
|
876
|
-
const
|
|
877
|
-
const response = await rscHandler(
|
|
873
|
+
const request = nodeToWebRequest(req, rawUrl, prerenderSecret);
|
|
874
|
+
const response = await rscHandler(request);
|
|
875
|
+
if (missingBuildAsset && response.status === 404) {
|
|
876
|
+
cancelResponseBody(response);
|
|
877
|
+
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
878
|
+
res.end("Not Found");
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
878
881
|
const staticFileSignal = response.headers.get(VINEXT_STATIC_FILE_HEADER);
|
|
879
882
|
if (staticFileSignal) {
|
|
880
883
|
let staticFilePath = "/";
|
|
@@ -890,12 +893,6 @@ async function startAppRouterServer(options) {
|
|
|
890
893
|
await sendWebResponse(notFoundResponse({ headers: toWebHeaders(staticResponseHeaders) }), req, res, compress);
|
|
891
894
|
return;
|
|
892
895
|
}
|
|
893
|
-
if (missingBuildAsset && response.status === 404) {
|
|
894
|
-
cancelResponseBody(response);
|
|
895
|
-
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
896
|
-
res.end("Not Found");
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
896
|
await sendWebResponse(response, req, res, compress);
|
|
900
897
|
} catch (e) {
|
|
901
898
|
console.error("[vinext] Server error:", e);
|
|
@@ -986,8 +983,9 @@ async function startPagesRouterServer(options) {
|
|
|
986
983
|
res.end("This page could not be found");
|
|
987
984
|
return;
|
|
988
985
|
}
|
|
989
|
-
const rawPagesPathname = rawPagesPathnameBeforeNormalize.replaceAll("\\", "/");
|
|
986
|
+
const rawPagesPathname = canonicalizeRequestPathname(rawPagesPathnameBeforeNormalize.replaceAll("\\", "/"));
|
|
990
987
|
const rawQs = rawUrl.includes("?") ? rawUrl.slice(rawUrl.indexOf("?")) : "";
|
|
988
|
+
let requestPathname = normalizePath(rawPagesPathname);
|
|
991
989
|
let pathname;
|
|
992
990
|
try {
|
|
993
991
|
pathname = normalizePath(normalizePathnameForRouteMatchStrict(rawPagesPathname));
|
|
@@ -996,7 +994,7 @@ async function startPagesRouterServer(options) {
|
|
|
996
994
|
res.end("Bad Request");
|
|
997
995
|
return;
|
|
998
996
|
}
|
|
999
|
-
let url =
|
|
997
|
+
let url = requestPathname + rawQs;
|
|
1000
998
|
if (pathname === "/__vinext/prerender/pages-static-paths") {
|
|
1001
999
|
const secret = req.headers[VINEXT_PRERENDER_SECRET_HEADER];
|
|
1002
1000
|
if (!prerenderSecret || secret !== prerenderSecret) {
|
|
@@ -1057,18 +1055,31 @@ async function startPagesRouterServer(options) {
|
|
|
1057
1055
|
return;
|
|
1058
1056
|
}
|
|
1059
1057
|
try {
|
|
1060
|
-
const hadBasePath = !basePath || hasBasePath(
|
|
1058
|
+
const hadBasePath = !basePath || hasBasePath(requestPathname, basePath);
|
|
1059
|
+
let configMatchPathname = stripBasePath(requestPathname, basePath);
|
|
1061
1060
|
{
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1061
|
+
const strippedPathname = stripBasePath(pathname, basePath);
|
|
1062
|
+
const strippedRequestPathname = stripBasePath(requestPathname, basePath);
|
|
1063
|
+
pathname = strippedPathname;
|
|
1064
|
+
if (strippedRequestPathname !== requestPathname) {
|
|
1065
|
+
requestPathname = strippedRequestPathname;
|
|
1066
|
+
url = requestPathname + rawQs;
|
|
1066
1067
|
}
|
|
1067
1068
|
}
|
|
1069
|
+
if (urlParserCreatesPagesDataPath(pathname)) {
|
|
1070
|
+
res.writeHead(404);
|
|
1071
|
+
res.end("This page could not be found");
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
requestPathname = encodeUrlParserIgnoredCharacters(requestPathname);
|
|
1075
|
+
{
|
|
1076
|
+
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
1077
|
+
url = requestPathname + qs;
|
|
1078
|
+
}
|
|
1068
1079
|
let isDataReq = false;
|
|
1069
1080
|
const originalRenderUrl = url;
|
|
1070
|
-
if (isNextDataPathname(
|
|
1071
|
-
const dataMatch = pagesBuildId ? parseNextDataPathname(
|
|
1081
|
+
if (isNextDataPathname(requestPathname)) {
|
|
1082
|
+
const dataMatch = pagesBuildId ? parseNextDataPathname(requestPathname, pagesBuildId) : null;
|
|
1072
1083
|
if (!dataMatch) {
|
|
1073
1084
|
await sendWebResponse(buildNextDataNotFoundResponse(), req, res, compress);
|
|
1074
1085
|
return;
|
|
@@ -1077,7 +1088,9 @@ async function startPagesRouterServer(options) {
|
|
|
1077
1088
|
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
1078
1089
|
const pagePathname = normalizeNextDataPagePathname(dataMatch.pagePathname, hasMiddleware && trailingSlash);
|
|
1079
1090
|
url = pagePathname + qs;
|
|
1091
|
+
requestPathname = pagePathname;
|
|
1080
1092
|
pathname = pagePathname;
|
|
1093
|
+
configMatchPathname = pagePathname;
|
|
1081
1094
|
}
|
|
1082
1095
|
const protocol = resolveRequestProtocol(req);
|
|
1083
1096
|
const hostHeader = resolveRequestHost(req, `${host}:${port}`);
|
|
@@ -1104,6 +1117,7 @@ async function startPagesRouterServer(options) {
|
|
|
1104
1117
|
hasMiddleware,
|
|
1105
1118
|
ctx: void 0,
|
|
1106
1119
|
rawSearch: rawQs,
|
|
1120
|
+
configMatchPathname,
|
|
1107
1121
|
matchPageRoute: matchPageRoute ?? null,
|
|
1108
1122
|
runMiddleware: typeof runMiddleware === "function" ? wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath) : null,
|
|
1109
1123
|
renderPage: typeof renderPage === "function" ? (request, resolvedUrl, options, stagedHeaders) => renderPage(request, resolvedUrl, ssrManifest, void 0, stagedHeaders, {
|