vinext 1.1.0 → 1.2.1
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 +22 -10
- package/dist/build/client-build-config.d.ts +10 -0
- package/dist/build/client-build-config.js +18 -2
- package/dist/build/output-root-externals.d.ts +21 -0
- package/dist/build/output-root-externals.js +40 -0
- package/dist/build/pages-client-assets-module.d.ts +8 -0
- package/dist/build/pages-client-assets-module.js +21 -1
- package/dist/build/prerender-paths.js +6 -4
- package/dist/build/prerender.js +1 -1
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/ssr-manifest.d.ts +2 -0
- package/dist/build/ssr-manifest.js +6 -2
- package/dist/check.js +12 -12
- package/dist/cli-dev-config.js +3 -3
- package/dist/cli.js +3 -2
- package/dist/client/client-redirect-matcher.d.ts +14 -0
- package/dist/client/client-redirect-matcher.js +37 -0
- package/dist/client/client-redirects.d.ts +27 -0
- package/dist/client/client-redirects.js +28 -0
- package/dist/client/client-rewrites.d.ts +2 -1
- package/dist/client/client-rewrites.js +1 -1
- package/dist/config/config-matchers.d.ts +26 -11
- package/dist/config/config-matchers.js +90 -88
- package/dist/config/destination-params.d.ts +47 -0
- package/dist/config/destination-params.js +116 -0
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +3 -0
- package/dist/entries/app-rsc-entry.d.ts +4 -0
- package/dist/entries/app-rsc-entry.js +20 -6
- package/dist/entries/pages-client-entry.js +3 -1
- package/dist/entries/pages-server-entry.js +13 -37
- package/dist/index.d.ts +3 -1
- package/dist/index.js +246 -136
- package/dist/init-cloudflare.d.ts +9 -0
- package/dist/init-cloudflare.js +107 -31
- package/dist/init-platform.d.ts +4 -0
- package/dist/init-platform.js +27 -2
- package/dist/init.d.ts +2 -1
- package/dist/init.js +153 -9
- package/dist/plugins/ast-scope.d.ts +7 -0
- package/dist/plugins/ast-scope.js +59 -3
- package/dist/plugins/ast-utils.d.ts +53 -2
- package/dist/plugins/ast-utils.js +90 -2
- package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
- package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
- package/dist/plugins/commonjs-esm-facade.js +2 -2
- package/dist/plugins/css-module-imports.js +13 -20
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +11 -11
- package/dist/plugins/extensionless-dynamic-import.js +2 -3
- package/dist/plugins/fonts.d.ts +1 -1
- package/dist/plugins/fonts.js +3 -3
- package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +5 -7
- package/dist/plugins/import-meta-url.js +3 -4
- package/dist/plugins/instrumentation-client.js +3 -2
- package/dist/plugins/middleware-export-validation.js +2 -3
- package/dist/plugins/middleware-server-only.d.ts +5 -4
- package/dist/plugins/middleware-server-only.js +8 -5
- package/dist/plugins/og-harfbuzz.js +2 -3
- package/dist/plugins/optimize-imports.js +3 -4
- package/dist/plugins/pages-node-externals.js +3 -4
- package/dist/plugins/remove-console.js +2 -18
- package/dist/plugins/require-condition-resolution.js +3 -3
- package/dist/plugins/require-context.js +2 -3
- package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
- package/dist/plugins/rsc-scan-glob-imports.js +50 -0
- package/dist/plugins/strip-server-exports.js +265 -102
- package/dist/plugins/styled-jsx.js +2 -3
- package/dist/plugins/transform-result.d.ts +9 -5
- package/dist/plugins/transitive-externals.js +1 -1
- package/dist/plugins/typeof-window.d.ts +2 -2
- package/dist/plugins/use-cache-callable.d.ts +21 -2
- package/dist/plugins/use-cache-callable.js +84 -35
- package/dist/plugins/worker-image-imports.js +30 -33
- package/dist/plugins/worker-server-only-imports.d.ts +20 -0
- package/dist/plugins/worker-server-only-imports.js +31 -0
- package/dist/plugins/worker-use-server.d.ts +25 -0
- package/dist/plugins/worker-use-server.js +153 -0
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +3 -2
- package/dist/server/app-action-forwarding.js +2 -2
- package/dist/server/app-browser-action-result.d.ts +1 -1
- package/dist/server/app-browser-action-result.js +9 -2
- package/dist/server/app-browser-entry.js +3 -3
- package/dist/server/app-browser-interception-context.js +1 -1
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-prefetch-response.js +2 -2
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-supplemental-refresh.js +1 -1
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +17 -2
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +3 -1
- package/dist/server/app-page-dispatch.js +5 -4
- package/dist/server/app-page-ppr-runtime.js +1 -1
- package/dist/server/app-page-render-observation.js +1 -1
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-request.js +53 -15
- package/dist/server/app-page-route-wiring.js +2 -2
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +3 -4
- package/dist/server/app-prerender-endpoints.js +9 -6
- package/dist/server/app-render-abort-error.d.ts +19 -0
- package/dist/server/app-render-abort-error.js +31 -1
- package/dist/server/app-request-stage-dispatch.js +6 -2
- package/dist/server/app-request-stage-independent-entry.js +29 -9
- package/dist/server/app-response-stage-entry.js +11 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +5 -2
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +46 -25
- package/dist/server/app-router-entry.js +29 -10
- package/dist/server/app-rsc-cache-busting.d.ts +16 -0
- package/dist/server/app-rsc-cache-busting.js +30 -13
- package/dist/server/app-rsc-errors.js +20 -16
- package/dist/server/app-rsc-handler.d.ts +7 -0
- package/dist/server/app-rsc-handler.js +89 -39
- package/dist/server/app-rsc-request-normalization.js +3 -3
- package/dist/server/app-rsc-response-stage.js +5 -3
- package/dist/server/app-segment-config.d.ts +2 -1
- package/dist/server/app-server-action-execution.d.ts +2 -1
- package/dist/server/app-server-action-execution.js +62 -23
- package/dist/server/app-ssr-entry.js +7 -5
- package/dist/server/app-visited-response-cache.js +2 -2
- package/dist/server/app-worker-stages.d.ts +5 -0
- package/dist/server/app-worker-stages.js +1 -1
- package/dist/server/cacheability-request.js +2 -2
- package/dist/server/client-build-files.d.ts +16 -0
- package/dist/server/client-build-files.js +36 -0
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/config-headers.js +1 -1
- package/dist/server/defer-until-stream-consumed.d.ts +2 -1
- package/dist/server/defer-until-stream-consumed.js +3 -1
- package/dist/server/dev-server.js +39 -28
- package/dist/server/dev-stack-sourcemap.js +18 -23
- package/dist/server/document-initial-head.d.ts +0 -11
- package/dist/server/document-initial-head.js +1 -1
- package/dist/server/forwarded-middleware-context.d.ts +5 -0
- package/dist/server/forwarded-middleware-context.js +22 -0
- package/dist/server/headers.d.ts +4 -1
- package/dist/server/headers.js +4 -1
- package/dist/server/http-conditional.d.ts +11 -0
- package/dist/server/http-conditional.js +10 -1
- package/dist/server/http-error-responses.d.ts +1 -1
- package/dist/server/image-optimization.d.ts +38 -0
- package/dist/server/image-optimization.js +94 -4
- package/dist/server/isr-cache.d.ts +10 -0
- package/dist/server/isr-cache.js +41 -6
- package/dist/server/metadata-route-response.js +11 -10
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-path-to-regexp.js +1 -1
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +38 -25
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +3 -1
- package/dist/server/multi-stage.d.ts +11 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/open-redirect.d.ts +11 -4
- package/dist/server/open-redirect.js +11 -4
- package/dist/server/pages-api-route.d.ts +3 -2
- package/dist/server/pages-api-route.js +6 -5
- package/dist/server/pages-cache-tag.d.ts +12 -0
- package/dist/server/pages-cache-tag.js +19 -0
- package/dist/server/pages-client-assets.d.ts +2 -0
- package/dist/server/pages-data-route.d.ts +10 -0
- package/dist/server/pages-data-route.js +21 -3
- package/dist/server/pages-document-asset-props.d.ts +5 -1
- package/dist/server/pages-document-asset-props.js +13 -5
- package/dist/server/pages-document-splice.d.ts +19 -0
- package/dist/server/pages-document-splice.js +55 -0
- package/dist/server/pages-i18n.d.ts +12 -1
- package/dist/server/pages-i18n.js +18 -4
- package/dist/server/pages-node-compat.d.ts +16 -5
- package/dist/server/pages-node-compat.js +20 -12
- package/dist/server/pages-page-data.d.ts +32 -24
- package/dist/server/pages-page-data.js +51 -121
- package/dist/server/pages-page-handler.d.ts +0 -6
- package/dist/server/pages-page-handler.js +189 -127
- package/dist/server/pages-page-response.d.ts +12 -6
- package/dist/server/pages-page-response.js +42 -35
- package/dist/server/pages-request-pipeline.d.ts +10 -2
- package/dist/server/pages-request-pipeline.js +41 -22
- package/dist/server/pages-request-stage-entry.d.ts +6 -0
- package/dist/server/pages-request-stage-entry.js +75 -16
- package/dist/server/pages-response-stage-entry.js +4 -0
- package/dist/server/pages-revalidate.js +3 -3
- package/dist/server/pages-router-entry.js +5 -4
- package/dist/server/prerender-manifest.d.ts +3 -3
- package/dist/server/prerender-manifest.js +4 -3
- package/dist/server/prerender-work-unit-setup.js +4 -0
- package/dist/server/prod-server.d.ts +12 -0
- package/dist/server/prod-server.js +204 -74
- package/dist/server/proper-error.d.ts +4 -0
- package/dist/server/proper-error.js +31 -0
- package/dist/server/request-pipeline.d.ts +4 -1
- package/dist/server/request-pipeline.js +3 -2
- package/dist/server/revalidation-request.d.ts +1 -0
- package/dist/server/revalidation-request.js +1 -1
- package/dist/server/rsc-stream-hints.d.ts +1 -1
- package/dist/server/rsc-stream-hints.js +52 -5
- package/dist/server/seed-cache.d.ts +1 -0
- package/dist/server/seed-cache.js +5 -4
- package/dist/server/server-reference-loader.d.ts +4 -0
- package/dist/server/server-reference-loader.js +29 -0
- package/dist/server/socket-error-backstop.d.ts +9 -1
- package/dist/server/socket-error-backstop.js +46 -17
- package/dist/server/static-file-signal.d.ts +15 -4
- package/dist/server/static-file-signal.js +46 -12
- package/dist/server/worker-image-optimization.d.ts +34 -0
- package/dist/server/worker-image-optimization.js +99 -0
- package/dist/server/worker-stages.d.ts +1 -1
- package/dist/server/worker-stages.js +2 -2
- package/dist/server/worker-utils.d.ts +8 -3
- package/dist/server/worker-utils.js +12 -7
- package/dist/shims/app-router-scroll.js +4 -1
- package/dist/shims/app-router-tree-context.d.ts +5 -0
- package/dist/shims/app-router-tree-context.js +27 -0
- package/dist/shims/cache-callable-runtime.d.ts +4 -2
- package/dist/shims/cache-callable-runtime.js +21 -12
- package/dist/shims/cache-handler.js +1 -9
- package/dist/shims/cache-runtime.d.ts +6 -1
- package/dist/shims/cache-runtime.js +2 -1
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +40 -13
- package/dist/shims/cdn-cache.d.ts +8 -0
- package/dist/shims/cdn-cache.js +17 -1
- package/dist/shims/disable-smooth-scroll.d.ts +3 -0
- package/dist/shims/disable-smooth-scroll.js +36 -0
- package/dist/shims/document-placeholders.d.ts +19 -0
- package/dist/shims/document-placeholders.js +45 -0
- package/dist/shims/document.js +21 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
- package/dist/shims/dynamic-preload-chunks.js +13 -9
- package/dist/shims/dynamic.d.ts +1 -1
- package/dist/shims/dynamic.js +60 -8
- package/dist/shims/fetch-cache-state.d.ts +66 -0
- package/dist/shims/fetch-cache-state.js +92 -0
- package/dist/shims/fetch-cache.d.ts +3 -67
- package/dist/shims/fetch-cache.js +160 -125
- package/dist/shims/head.d.ts +10 -6
- package/dist/shims/head.js +16 -14
- package/dist/shims/headers.js +2 -2
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/hybrid-client-route-owner-direct.js +1 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +1 -0
- package/dist/shims/internal/work-store-scope.d.ts +5 -0
- package/dist/shims/internal/work-store-scope.js +24 -0
- package/dist/shims/link-prefetch.js +5 -4
- package/dist/shims/link.js +2 -2
- package/dist/shims/navigation.js +34 -9
- package/dist/shims/request-context.d.ts +2 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/router.js +21 -32
- package/dist/shims/server.d.ts +27 -4
- package/dist/shims/server.js +65 -9
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/url-utils.d.ts +9 -0
- package/dist/shims/url-utils.js +15 -4
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/domain-locale.js +1 -1
- package/dist/utils/hash.d.ts +7 -0
- package/dist/utils/hash.js +11 -1
- package/dist/utils/package-name.d.ts +6 -0
- package/dist/utils/package-name.js +12 -1
- package/dist/utils/plugin-rsc-version.d.ts +6 -0
- package/dist/utils/plugin-rsc-version.js +41 -0
- package/dist/utils/prerender-output-paths.js +15 -4
- package/dist/utils/public-file-path.d.ts +10 -2
- package/dist/utils/public-file-path.js +13 -9
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.d.ts +10 -0
- package/dist/utils/react-version.js +39 -16
- package/package.json +11 -7
- package/dist/build/nitro-route-rules.d.ts +0 -47
- package/dist/build/nitro-route-rules.js +0 -79
- package/dist/plugins/cache-flight-codec.d.ts +0 -19
- package/dist/plugins/cache-flight-codec.js +0 -68
|
@@ -77,7 +77,7 @@ function isMiddlewareModule(value) {
|
|
|
77
77
|
* @param request - The incoming Request object
|
|
78
78
|
* @returns Middleware result describing what action to take
|
|
79
79
|
*/
|
|
80
|
-
async function runMiddleware(runner, middlewarePath, request, i18nConfig, basePath, trailingSlash, isDataRequest, normalizedPathname) {
|
|
80
|
+
async function runMiddleware(runner, middlewarePath, request, i18nConfig, basePath, trailingSlash, isDataRequest, normalizedPathname, isStaleDataRequest, skipTrailingSlashRedirect) {
|
|
81
81
|
const mod = await runner.import(middlewarePath);
|
|
82
82
|
if (!isMiddlewareModule(mod)) throw new Error(`Middleware module "${middlewarePath}" did not evaluate to an object.`);
|
|
83
83
|
return runGeneratedMiddleware({
|
|
@@ -87,10 +87,12 @@ async function runMiddleware(runner, middlewarePath, request, i18nConfig, basePa
|
|
|
87
87
|
i18nConfig,
|
|
88
88
|
includeErrorDetails: process.env.NODE_ENV !== "production",
|
|
89
89
|
isDataRequest,
|
|
90
|
+
isStaleDataRequest,
|
|
90
91
|
isProxy: isProxyFile(middlewarePath),
|
|
91
92
|
module: mod,
|
|
92
93
|
normalizedPathname,
|
|
93
94
|
request,
|
|
95
|
+
skipTrailingSlashRedirect,
|
|
94
96
|
trailingSlash
|
|
95
97
|
});
|
|
96
98
|
}
|
|
@@ -29,6 +29,17 @@ export type VinextResponseStageDispatchOptions = {
|
|
|
29
29
|
* partition its lookup or stored entry by it.
|
|
30
30
|
*/
|
|
31
31
|
renderWholeDocument?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Regenerate an entry the adapter already stores for this build. Set only
|
|
34
|
+
* from a platform-invoked regeneration callback or a platform cache's
|
|
35
|
+
* conditional revalidation of a stored entry, never from anything a client
|
|
36
|
+
* can send: core then treats the path as admitted and skips
|
|
37
|
+
* request-time admission work such as a Pages `getStaticPaths()` call, as
|
|
38
|
+
* Next.js regenerates a generated path without consulting it. It is not a
|
|
39
|
+
* cache selector: a transport must not partition its lookup or stored entry
|
|
40
|
+
* by it.
|
|
41
|
+
*/
|
|
42
|
+
regeneratesStoredEntry?: boolean;
|
|
32
43
|
/**
|
|
33
44
|
* Query-free identity of a shared App page GET/HEAD dispatch, supplied only
|
|
34
45
|
* to adapters that declare `responseStageCacheIdentity: "query-free"` and
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
2
1
|
import { stripBasePath } from "../utils/base-path.js";
|
|
2
|
+
import { splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
3
3
|
import { matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternWithOptionalDynamicSegments } from "../routing/route-pattern.js";
|
|
4
4
|
import { AppElementsWire, compareAppElementsSlotIds } from "./app-elements-wire.js";
|
|
5
5
|
import "./app-elements.js";
|
|
@@ -1,17 +1,4 @@
|
|
|
1
1
|
//#region src/server/normalize-path.d.ts
|
|
2
|
-
export declare function escapePathDelimiters(segment: string, escapeEncoded?: boolean): string;
|
|
3
|
-
/**
|
|
4
|
-
* Decode a URL pathname segment-by-segment, preserving encoded path delimiters.
|
|
5
|
-
* Non-ASCII characters (e.g. %C3%A9 -> e) are decoded, but structural characters
|
|
6
|
-
* like %2F (/) %23 (#) %3F (?) %5C (\) are re-encoded after decoding.
|
|
7
|
-
*
|
|
8
|
-
* This prevents encoded slashes from changing the path structure (e.g.
|
|
9
|
-
* /admin%2Fpanel stays as a single segment, not /admin/panel).
|
|
10
|
-
*
|
|
11
|
-
* Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts
|
|
12
|
-
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts
|
|
13
|
-
*/
|
|
14
|
-
export declare function decodePathParams(pathname: string): string;
|
|
15
2
|
export declare function isInterceptionMatchedUrlPath(value: string): boolean;
|
|
16
3
|
/**
|
|
17
4
|
* Path normalization utility for request handling.
|
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
//#region src/server/normalize-path.ts
|
|
2
|
-
/**
|
|
3
|
-
* Re-encode path delimiter characters that were decoded by decodeURIComponent.
|
|
4
|
-
* After decoding a URL segment, characters like / # ? \ need to be re-encoded
|
|
5
|
-
* so they don't change the path structure.
|
|
6
|
-
*
|
|
7
|
-
* Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts
|
|
8
|
-
* https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts
|
|
9
|
-
*/
|
|
10
|
-
const PATH_DELIMITERS_RE = /([/#?])/gi;
|
|
11
|
-
const PATH_DELIMITERS_ENCODED_RE = /([/#?]|%(2f|23|3f|5c))/gi;
|
|
12
|
-
function escapePathDelimiters(segment, escapeEncoded) {
|
|
13
|
-
return segment.replace(escapeEncoded ? PATH_DELIMITERS_ENCODED_RE : PATH_DELIMITERS_RE, (char) => encodeURIComponent(char));
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Decode a URL pathname segment-by-segment, preserving encoded path delimiters.
|
|
17
|
-
* Non-ASCII characters (e.g. %C3%A9 -> e) are decoded, but structural characters
|
|
18
|
-
* like %2F (/) %23 (#) %3F (?) %5C (\) are re-encoded after decoding.
|
|
19
|
-
*
|
|
20
|
-
* This prevents encoded slashes from changing the path structure (e.g.
|
|
21
|
-
* /admin%2Fpanel stays as a single segment, not /admin/panel).
|
|
22
|
-
*
|
|
23
|
-
* Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts
|
|
24
|
-
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts
|
|
25
|
-
*/
|
|
26
|
-
function decodePathParams(pathname) {
|
|
27
|
-
return pathname.split("/").map((seg) => {
|
|
28
|
-
try {
|
|
29
|
-
return escapePathDelimiters(decodeURIComponent(seg), true);
|
|
30
|
-
} catch {
|
|
31
|
-
return seg;
|
|
32
|
-
}
|
|
33
|
-
}).join("/");
|
|
34
|
-
}
|
|
35
2
|
function isInterceptionMatchedUrlPath(value) {
|
|
36
3
|
return value.startsWith("/") && !value.startsWith("//") && !value.includes("?") && !value.includes("#") && !value.includes("\\") && !value.includes("\0");
|
|
37
4
|
}
|
|
@@ -67,4 +34,4 @@ function normalizePath(pathname) {
|
|
|
67
34
|
return "/" + resolved.join("/");
|
|
68
35
|
}
|
|
69
36
|
//#endregion
|
|
70
|
-
export {
|
|
37
|
+
export { isInterceptionMatchedUrlPath, normalizePath };
|
|
@@ -11,7 +11,7 @@ export declare function isOpenRedirectShaped(rawPathname: string): boolean;
|
|
|
11
11
|
/**
|
|
12
12
|
* What a request entry answers for a raw path containing a backslash or a
|
|
13
13
|
* repeated slash: Next.js's 308, or a 404 when the collapsed path would still
|
|
14
|
-
* be open-redirect shaped.
|
|
14
|
+
* be open-redirect shaped or the raw target is not origin-form.
|
|
15
15
|
*/
|
|
16
16
|
export type RepeatedSlashRedirect = {
|
|
17
17
|
status: 308;
|
|
@@ -33,17 +33,24 @@ export type RepeatedSlashRedirect = {
|
|
|
33
33
|
* `//evil.com` → `/evil.com`. Percent-encoded `%2F`/`%5C` are not touched and
|
|
34
34
|
* keep falling through to `isOpenRedirectShaped` (404), as in Next.js.
|
|
35
35
|
*
|
|
36
|
-
* The Location is always same-origin.
|
|
37
|
-
* (`GET http://host//x`) are left alone. A collapsed path that still starts
|
|
36
|
+
* The Location is always same-origin. A collapsed path that still starts
|
|
38
37
|
* with an encoded slash or backslash (`//%2Fevil.com`, `/.//%2Fevil.com`) is
|
|
39
38
|
* never echoed into a Location or routed: it gets a 404 instead.
|
|
40
39
|
*
|
|
40
|
+
* A raw Node request target that is not origin-form (`GET http://evil.example/x`,
|
|
41
|
+
* which Node's parser accepts, or `OPTIONS *`) also gets a 404. Next.js never
|
|
42
|
+
* routes these either: it 308s absolute-form targets to their own URL (the
|
|
43
|
+
* `//` after the scheme trips the same check) and 500s `OPTIONS *`. Routing
|
|
44
|
+
* them would let the request line choose the origin of `request.url` that
|
|
45
|
+
* middleware and handlers see, bypassing the Host trust policy. Request-based
|
|
46
|
+
* entries always pass a pathname.
|
|
47
|
+
*
|
|
41
48
|
* @param rawUrl - The raw request target: pathname plus optional `?query`
|
|
42
49
|
*/
|
|
43
50
|
export declare function getRepeatedSlashRedirect(rawUrl: string): RepeatedSlashRedirect | null;
|
|
44
51
|
/**
|
|
45
52
|
* Build the Response for a raw request path containing a backslash or a
|
|
46
|
-
* repeated slash. See `getRepeatedSlashRedirect`.
|
|
53
|
+
* repeated slash, or a non-origin-form target. See `getRepeatedSlashRedirect`.
|
|
47
54
|
*/
|
|
48
55
|
export declare function repeatedSlashRedirectResponse(rawUrl: string): Response | null;
|
|
49
56
|
/**
|
|
@@ -34,15 +34,22 @@ const REDIRECT_LOCATION_BASE = "http://vinext.invalid";
|
|
|
34
34
|
* `//evil.com` → `/evil.com`. Percent-encoded `%2F`/`%5C` are not touched and
|
|
35
35
|
* keep falling through to `isOpenRedirectShaped` (404), as in Next.js.
|
|
36
36
|
*
|
|
37
|
-
* The Location is always same-origin.
|
|
38
|
-
* (`GET http://host//x`) are left alone. A collapsed path that still starts
|
|
37
|
+
* The Location is always same-origin. A collapsed path that still starts
|
|
39
38
|
* with an encoded slash or backslash (`//%2Fevil.com`, `/.//%2Fevil.com`) is
|
|
40
39
|
* never echoed into a Location or routed: it gets a 404 instead.
|
|
41
40
|
*
|
|
41
|
+
* A raw Node request target that is not origin-form (`GET http://evil.example/x`,
|
|
42
|
+
* which Node's parser accepts, or `OPTIONS *`) also gets a 404. Next.js never
|
|
43
|
+
* routes these either: it 308s absolute-form targets to their own URL (the
|
|
44
|
+
* `//` after the scheme trips the same check) and 500s `OPTIONS *`. Routing
|
|
45
|
+
* them would let the request line choose the origin of `request.url` that
|
|
46
|
+
* middleware and handlers see, bypassing the Host trust policy. Request-based
|
|
47
|
+
* entries always pass a pathname.
|
|
48
|
+
*
|
|
42
49
|
* @param rawUrl - The raw request target: pathname plus optional `?query`
|
|
43
50
|
*/
|
|
44
51
|
function getRepeatedSlashRedirect(rawUrl) {
|
|
45
|
-
if (!rawUrl.startsWith("/")) return
|
|
52
|
+
if (!rawUrl.startsWith("/")) return { status: 404 };
|
|
46
53
|
const urlParts = rawUrl.split("?");
|
|
47
54
|
const pathname = urlParts[0];
|
|
48
55
|
if (!REPEATED_SLASH_OR_BACKSLASH_RE.test(pathname)) return null;
|
|
@@ -62,7 +69,7 @@ function repeatedSlashRedirectHeaders(location) {
|
|
|
62
69
|
}
|
|
63
70
|
/**
|
|
64
71
|
* Build the Response for a raw request path containing a backslash or a
|
|
65
|
-
* repeated slash. See `getRepeatedSlashRedirect`.
|
|
72
|
+
* repeated slash, or a non-origin-form target. See `getRepeatedSlashRedirect`.
|
|
66
73
|
*/
|
|
67
74
|
function repeatedSlashRedirectResponse(rawUrl) {
|
|
68
75
|
const redirect = getRepeatedSlashRedirect(rawUrl);
|
|
@@ -2,7 +2,7 @@ import { NextI18nConfig } from "../config/next-config.js";
|
|
|
2
2
|
import { Route } from "../routing/pages-router.js";
|
|
3
3
|
import { ExecutionContextLike } from "../shims/request-context.js";
|
|
4
4
|
import { EdgeApiExecutionRuntime } from "./edge-api-runtime.js";
|
|
5
|
-
import {
|
|
5
|
+
import { PagesApiReqResResponse, PagesReqResRequest, PagesRequestQuery } from "./pages-node-compat.js";
|
|
6
6
|
//#region src/server/pages-api-route.d.ts
|
|
7
7
|
type PagesApiRouteConfig = {
|
|
8
8
|
runtime?: string;
|
|
@@ -36,7 +36,7 @@ type PagesApiRouteConfig = {
|
|
|
36
36
|
externalResolver?: boolean;
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
|
-
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res:
|
|
39
|
+
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesApiReqResResponse) => unknown;
|
|
40
40
|
type PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;
|
|
41
41
|
type PagesApiRouteModule = {
|
|
42
42
|
/**
|
|
@@ -80,6 +80,7 @@ type HandlePagesApiRouteOptions = {
|
|
|
80
80
|
allowedRevalidateHeaderKeys?: readonly string[];
|
|
81
81
|
i18n?: NextI18nConfig | null;
|
|
82
82
|
trailingSlash?: boolean;
|
|
83
|
+
skipTrailingSlashRedirect?: boolean;
|
|
83
84
|
};
|
|
84
85
|
trustedRevalidateOrigin?: string;
|
|
85
86
|
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import { internalServerErrorResponse } from "./http-error-responses.js";
|
|
2
|
+
import { cloneRequestWithUrl } from "./request-pipeline.js";
|
|
1
3
|
import { getRequestExecutionContext, runWithExecutionContext } from "../shims/request-context.js";
|
|
2
4
|
import "./server-globals.js";
|
|
3
5
|
import { NextRequest } from "../shims/server.js";
|
|
4
|
-
import { internalServerErrorResponse } from "./http-error-responses.js";
|
|
5
|
-
import { cloneRequestWithUrl } from "./request-pipeline.js";
|
|
6
6
|
import { markRouteCacheabilityExplicitResponsePolicy } from "../shims/cacheability-classification.js";
|
|
7
7
|
import { hasCdnResponsePolicy } from "./cache-control.js";
|
|
8
8
|
import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
|
|
9
9
|
import { tracePagesApiHandler } from "./pages-execution-tracing.js";
|
|
10
10
|
import { resolveBodyParserConfig } from "./pages-body-parser-config.js";
|
|
11
11
|
import { PagesBodyParseError } from "./pages-media-type.js";
|
|
12
|
-
import {
|
|
12
|
+
import { createPagesApiReqRes, markVinextStreamedApiResponse, parsePagesApiBody } from "./pages-node-compat.js";
|
|
13
13
|
import { finalizeEdgeApiResponse, isEdgeApiRuntime } from "./edge-api-runtime.js";
|
|
14
14
|
//#region src/server/pages-api-route.ts
|
|
15
15
|
function resolveModuleRuntime(module) {
|
|
@@ -47,7 +47,8 @@ async function _handlePagesApiRoute(options) {
|
|
|
47
47
|
const nextRequest = new NextRequest(createEdgeApiRequest(options.request, options.url, params), options.nextConfig ? { nextConfig: {
|
|
48
48
|
basePath: options.nextConfig.basePath,
|
|
49
49
|
i18n: options.nextConfig.i18n ?? void 0,
|
|
50
|
-
trailingSlash: options.nextConfig.trailingSlash
|
|
50
|
+
trailingSlash: options.nextConfig.trailingSlash,
|
|
51
|
+
skipTrailingSlashRedirect: options.nextConfig.skipTrailingSlashRedirect
|
|
51
52
|
} } : void 0);
|
|
52
53
|
const response = await tracePagesApiHandler(route.pattern, () => handler(nextRequest));
|
|
53
54
|
if (response instanceof Response) {
|
|
@@ -70,7 +71,7 @@ async function _handlePagesApiRoute(options) {
|
|
|
70
71
|
const query = buildPagesApiQuery(options.url, params);
|
|
71
72
|
const bodyParserConfig = resolveBodyParserConfig(route.module.config);
|
|
72
73
|
const body = bodyParserConfig.enabled ? await parsePagesApiBody(options.request, bodyParserConfig.sizeLimit) : void 0;
|
|
73
|
-
const { req, res, responsePromise } =
|
|
74
|
+
const { req, res, responsePromise } = createPagesApiReqRes({
|
|
74
75
|
allowedRevalidateHeaderKeys: options.nextConfig?.allowedRevalidateHeaderKeys,
|
|
75
76
|
body,
|
|
76
77
|
initialResponseHeaders: options.initialResponseHeaders,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/server/pages-cache-tag.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build the edge path tag for a Pages ISR pathname.
|
|
4
|
+
*
|
|
5
|
+
* Every spelling of one pathname shares a single ISR entry, because
|
|
6
|
+
* `pagesIsrCacheKey()` decodes each segment first. The tag must use that same
|
|
7
|
+
* decoded identity. Otherwise `/users/%40alice` is stored at the edge under its
|
|
8
|
+
* own tag, and `res.revalidate("/users/@alice")` or
|
|
9
|
+
* `revalidatePath("/users/@alice")` never purges it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pagesPathCacheTag(isrPathname: string): string;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { normalizePathnameForRouteMatch } from "../routing/utils.js";
|
|
2
|
+
import { encodeCacheTag } from "../utils/encode-cache-tag.js";
|
|
3
|
+
//#region src/server/pages-cache-tag.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build the edge path tag for a Pages ISR pathname.
|
|
6
|
+
*
|
|
7
|
+
* Every spelling of one pathname shares a single ISR entry, because
|
|
8
|
+
* `pagesIsrCacheKey()` decodes each segment first. The tag must use that same
|
|
9
|
+
* decoded identity. Otherwise `/users/%40alice` is stored at the edge under its
|
|
10
|
+
* own tag, and `res.revalidate("/users/@alice")` or
|
|
11
|
+
* `revalidatePath("/users/@alice")` never purges it.
|
|
12
|
+
*/
|
|
13
|
+
function pagesPathCacheTag(isrPathname) {
|
|
14
|
+
const pathname = normalizePathnameForRouteMatch(isrPathname);
|
|
15
|
+
const stem = pathname.endsWith("/") ? pathname.slice(0, -1) : pathname;
|
|
16
|
+
return encodeCacheTag(`_N_T_${stem || "/"}`);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { pagesPathCacheTag };
|
|
@@ -14,6 +14,8 @@ export type PagesClientAssets = {
|
|
|
14
14
|
dynamicPreloads?: Record<string, string[]>;
|
|
15
15
|
/** next.config crossOrigin, defaulting to anonymous for Vite's CORS-fetched assets. */
|
|
16
16
|
crossOrigin?: AssetCrossOrigin;
|
|
17
|
+
/** Client bundle files outside `_next/static`, as URL pathnames. */
|
|
18
|
+
clientBuildFiles?: string[];
|
|
17
19
|
};
|
|
18
20
|
export declare function setPagesClientAssets(assets: PagesClientAssets | undefined): void;
|
|
19
21
|
export declare function getPagesClientAssets(): PagesClientAssets;
|
|
@@ -61,6 +61,16 @@ export declare function encodeUrlParserIgnoredCharacters(pathname: string): stri
|
|
|
61
61
|
* `/_next/data/<buildId>/about` → null (missing .json suffix)
|
|
62
62
|
*/
|
|
63
63
|
export declare function parseNextDataPathname(pathname: string, buildId: string): NextDataMatch | null;
|
|
64
|
+
/**
|
|
65
|
+
* The page pathname a `_next/data` URL addresses, whatever its buildId. Next.js
|
|
66
|
+
* compiles every middleware matcher with an optional `/_next/data/<buildId>`
|
|
67
|
+
* prefix and `.json` suffix, so a matcher written for `/admin` also guards that
|
|
68
|
+
* page's data URL, even one with a stale buildId. Middleware matching uses this
|
|
69
|
+
* when the request reaches middleware with its raw data URL
|
|
70
|
+
* (`skipProxyUrlNormalize`).
|
|
71
|
+
* https://github.com/vercel/next.js/blob/v16.2.7/packages/next/src/build/analysis/get-page-static-info.ts
|
|
72
|
+
*/
|
|
73
|
+
export declare function nextDataMiddlewareMatchPathname(pathname: string): string | null;
|
|
64
74
|
export declare function normalizeNextDataPagePathname(pagePathname: string, trailingSlash?: boolean): string;
|
|
65
75
|
/**
|
|
66
76
|
* Next.js only applies `trailingSlash` while normalizing a data URL for
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MIDDLEWARE_SKIP_HEADER } from "../utils/protocol-headers.js";
|
|
2
2
|
import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
|
|
4
|
+
import { cloneRequestWithUrl } from "./request-pipeline.js";
|
|
4
5
|
//#region src/server/pages-data-route.ts
|
|
5
6
|
/**
|
|
6
7
|
* Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
|
|
@@ -67,7 +68,24 @@ function parseNextDataPathname(pathname, buildId) {
|
|
|
67
68
|
if (!isNextDataPathname(pathname)) return null;
|
|
68
69
|
const expectedPrefix = `${NEXT_DATA_PREFIX}${buildId}/`;
|
|
69
70
|
if (!pathname.startsWith(expectedPrefix)) return null;
|
|
70
|
-
|
|
71
|
+
return pageFromNextDataRest(pathname.slice(expectedPrefix.length, -5));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The page pathname a `_next/data` URL addresses, whatever its buildId. Next.js
|
|
75
|
+
* compiles every middleware matcher with an optional `/_next/data/<buildId>`
|
|
76
|
+
* prefix and `.json` suffix, so a matcher written for `/admin` also guards that
|
|
77
|
+
* page's data URL, even one with a stale buildId. Middleware matching uses this
|
|
78
|
+
* when the request reaches middleware with its raw data URL
|
|
79
|
+
* (`skipProxyUrlNormalize`).
|
|
80
|
+
* https://github.com/vercel/next.js/blob/v16.2.7/packages/next/src/build/analysis/get-page-static-info.ts
|
|
81
|
+
*/
|
|
82
|
+
function nextDataMiddlewareMatchPathname(pathname) {
|
|
83
|
+
if (!isNextDataPathname(pathname)) return null;
|
|
84
|
+
const buildIdEnd = pathname.indexOf("/", 12);
|
|
85
|
+
if (buildIdEnd <= 12) return null;
|
|
86
|
+
return pageFromNextDataRest(pathname.slice(buildIdEnd + 1, -5))?.pagePathname ?? null;
|
|
87
|
+
}
|
|
88
|
+
function pageFromNextDataRest(rest) {
|
|
71
89
|
if (rest.length === 0) return null;
|
|
72
90
|
if (rest === "index") return { pagePathname: "/" };
|
|
73
91
|
if (rest.endsWith("/index")) return { pagePathname: `/${rest.slice(0, -6)}` };
|
|
@@ -174,11 +192,11 @@ function normalizePagesDataRequest(request, buildId, basePath = "", trailingSlas
|
|
|
174
192
|
normalizedUrl.pathname = hadBasePath ? addBasePathToPathname(pagePathname, basePath) : pagePathname;
|
|
175
193
|
return {
|
|
176
194
|
isDataReq: true,
|
|
177
|
-
request:
|
|
195
|
+
request: cloneRequestWithUrl(request, normalizedUrl.href),
|
|
178
196
|
normalizedPathname: pagePathname,
|
|
179
197
|
search: reqUrl.search,
|
|
180
198
|
notFoundResponse: null
|
|
181
199
|
};
|
|
182
200
|
}
|
|
183
201
|
//#endregion
|
|
184
|
-
export { buildMiddlewarePrefetchSkipResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, normalizePagesDataRequest, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath };
|
|
202
|
+
export { buildMiddlewarePrefetchSkipResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, nextDataMiddlewareMatchPathname, normalizeNextDataPagePathname, normalizePagesDataRequest, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath };
|
|
@@ -10,7 +10,11 @@ type ApplyDocumentAssetPropsOptions = {
|
|
|
10
10
|
protectedAssetMarker?: string;
|
|
11
11
|
scriptOwner?: "head" | "next-script";
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Read and strip the nonce and crossOrigin props that `<Head>` and
|
|
15
|
+
* `<NextScript />` recorded on their tags, found by this render's token.
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractDocumentAssetProps(html: string, token: string): {
|
|
14
18
|
html: string;
|
|
15
19
|
props: DocumentAssetProps;
|
|
16
20
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { escapeRegExp } from "../utils/regex.js";
|
|
1
2
|
import { escapeHtmlAttr } from "./html.js";
|
|
3
|
+
import { getDocumentHeadOpenMarker, getDocumentScriptsPlaceholder } from "../shims/document-placeholders.js";
|
|
2
4
|
//#region src/server/pages-document-asset-props.ts
|
|
3
5
|
const HEAD_NONCE_ATTR = "data-vinext-head-nonce";
|
|
4
6
|
const HEAD_CROSS_ORIGIN_ATTR = "data-vinext-head-cross-origin";
|
|
@@ -11,9 +13,15 @@ function readAttribute(tag, name) {
|
|
|
11
13
|
function removeAttributes(tag, names) {
|
|
12
14
|
return tag.replace(new RegExp(`\\s(?:${names.join("|")})="[^"]*"`, "g"), "");
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Read and strip the nonce and crossOrigin props that `<Head>` and
|
|
18
|
+
* `<NextScript />` recorded on their tags, found by this render's token.
|
|
19
|
+
*/
|
|
20
|
+
function extractDocumentAssetProps(html, token) {
|
|
21
|
+
const headTagPattern = new RegExp(`<head\\b[^>]*${escapeRegExp(getDocumentHeadOpenMarker(token))}[^>]*>`, "i");
|
|
22
|
+
const nextScriptTagPattern = new RegExp(`<span\\b[^>]*>(?=${escapeRegExp(getDocumentScriptsPlaceholder(token))})`, "i");
|
|
23
|
+
const headTag = html.match(headTagPattern)?.[0];
|
|
24
|
+
const nextScriptTag = html.match(nextScriptTagPattern)?.[0];
|
|
17
25
|
const props = {
|
|
18
26
|
headNonce: readAttribute(headTag, HEAD_NONCE_ATTR),
|
|
19
27
|
headCrossOrigin: readAttribute(headTag, HEAD_CROSS_ORIGIN_ATTR),
|
|
@@ -21,14 +29,14 @@ function extractDocumentAssetProps(html) {
|
|
|
21
29
|
scriptCrossOrigin: readAttribute(nextScriptTag, SCRIPT_CROSS_ORIGIN_ATTR)
|
|
22
30
|
};
|
|
23
31
|
return {
|
|
24
|
-
html: html.replace(
|
|
32
|
+
html: html.replace(headTagPattern, (tag) => removeAttributes(tag, [HEAD_NONCE_ATTR, HEAD_CROSS_ORIGIN_ATTR])).replace(nextScriptTagPattern, (tag) => removeAttributes(tag, [SCRIPT_NONCE_ATTR, SCRIPT_CROSS_ORIGIN_ATTR])),
|
|
25
33
|
props
|
|
26
34
|
};
|
|
27
35
|
}
|
|
28
36
|
function addAttribute(tag, name, value, replaceExisting = false) {
|
|
29
37
|
if (value === void 0) return tag;
|
|
30
38
|
const attributePattern = new RegExp(`\\s${name}(?:="[^"]*")?`, "i");
|
|
31
|
-
if (attributePattern.test(tag)) return replaceExisting ? tag.replace(attributePattern, ` ${name}="${escapeHtmlAttr(value)}"`) : tag;
|
|
39
|
+
if (attributePattern.test(tag)) return replaceExisting ? tag.replace(attributePattern, () => ` ${name}="${escapeHtmlAttr(value)}"`) : tag;
|
|
32
40
|
if (!tag.endsWith(">")) return tag;
|
|
33
41
|
const selfClosing = tag.endsWith("/>");
|
|
34
42
|
const closingStart = selfClosing ? tag.length - 2 : tag.length - 1;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/server/pages-document-splice.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Drop `<Head>`'s marker attribute and insert `insertion` right after its
|
|
4
|
+
* opening tag. Dev HTML transforms may add attributes after the marker.
|
|
5
|
+
*/
|
|
6
|
+
export declare function spliceDocumentHeadOpen(html: string, token: string, insertion: string): string;
|
|
7
|
+
/** Insert `insertion` right before `<Head>`'s closing tag. */
|
|
8
|
+
export declare function spliceDocumentHeadClose(html: string, token: string, insertion: string): string;
|
|
9
|
+
/** Put the generated hydration scripts where `<NextScript />` rendered. */
|
|
10
|
+
export declare function spliceDocumentScripts(html: string, token: string, scripts: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Split the Document where `<Main />` rendered. Like Next.js, a Document
|
|
13
|
+
* without `<Main />` gets the page body after its own markup.
|
|
14
|
+
*/
|
|
15
|
+
export declare function splitDocumentAtMain(html: string, token: string): {
|
|
16
|
+
prefix: string;
|
|
17
|
+
suffix: string;
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getDocumentHeadCloseMarker, getDocumentHeadOpenMarker, getDocumentMainPlaceholder, getDocumentScriptsPlaceholder } from "../shims/document-placeholders.js";
|
|
2
|
+
//#region src/server/pages-document-splice.ts
|
|
3
|
+
/**
|
|
4
|
+
* Splices framework output into a serialized custom Pages Router Document.
|
|
5
|
+
*
|
|
6
|
+
* `<Head>`, `<Main />` and `<NextScript />` mark their splice points with the
|
|
7
|
+
* per-render token from `vinext/shims/document-placeholders`, so nothing the
|
|
8
|
+
* Document renders can be taken for one. Each edit slices at a located index
|
|
9
|
+
* instead of calling `String#replace`, so inserted HTML is never parsed for
|
|
10
|
+
* `$&`-style replacement patterns. Like Next.js, a Document that leaves out
|
|
11
|
+
* one of those components gets nothing inserted for it.
|
|
12
|
+
*/
|
|
13
|
+
function spliceMarker(html, marker, insertion) {
|
|
14
|
+
const index = html.indexOf(marker);
|
|
15
|
+
if (index === -1) return html;
|
|
16
|
+
return html.slice(0, index) + insertion + html.slice(index + marker.length);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Drop `<Head>`'s marker attribute and insert `insertion` right after its
|
|
20
|
+
* opening tag. Dev HTML transforms may add attributes after the marker.
|
|
21
|
+
*/
|
|
22
|
+
function spliceDocumentHeadOpen(html, token, insertion) {
|
|
23
|
+
const marker = getDocumentHeadOpenMarker(token);
|
|
24
|
+
const index = html.indexOf(marker);
|
|
25
|
+
if (index === -1) return html;
|
|
26
|
+
const tagEnd = html.indexOf(">", index + marker.length) + 1;
|
|
27
|
+
if (tagEnd === 0) return html;
|
|
28
|
+
return html.slice(0, index) + html.slice(index + marker.length, tagEnd) + insertion + html.slice(tagEnd);
|
|
29
|
+
}
|
|
30
|
+
/** Insert `insertion` right before `<Head>`'s closing tag. */
|
|
31
|
+
function spliceDocumentHeadClose(html, token, insertion) {
|
|
32
|
+
return spliceMarker(html, getDocumentHeadCloseMarker(token), insertion);
|
|
33
|
+
}
|
|
34
|
+
/** Put the generated hydration scripts where `<NextScript />` rendered. */
|
|
35
|
+
function spliceDocumentScripts(html, token, scripts) {
|
|
36
|
+
return spliceMarker(html, getDocumentScriptsPlaceholder(token), scripts);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Split the Document where `<Main />` rendered. Like Next.js, a Document
|
|
40
|
+
* without `<Main />` gets the page body after its own markup.
|
|
41
|
+
*/
|
|
42
|
+
function splitDocumentAtMain(html, token) {
|
|
43
|
+
const placeholder = getDocumentMainPlaceholder(token);
|
|
44
|
+
const index = html.indexOf(placeholder);
|
|
45
|
+
if (index === -1) return {
|
|
46
|
+
prefix: html,
|
|
47
|
+
suffix: ""
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
prefix: html.slice(0, index),
|
|
51
|
+
suffix: html.slice(index + placeholder.length)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { spliceDocumentHeadClose, spliceDocumentHeadOpen, spliceDocumentScripts, splitDocumentAtMain };
|
|
@@ -24,6 +24,15 @@ type PagesI18nRequestInfo = {
|
|
|
24
24
|
domainLocale?: DomainLocale;
|
|
25
25
|
redirectUrl?: string;
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Return the configured locale that the first pathname segment names, compared
|
|
29
|
+
* case-insensitively (`/EN/about` -> `"en"`), or `undefined` when there is none.
|
|
30
|
+
* The configured casing is returned, not the request's.
|
|
31
|
+
*
|
|
32
|
+
* Ported from Next.js: packages/next/src/shared/lib/i18n/normalize-locale-path.ts
|
|
33
|
+
* https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/normalize-locale-path.ts
|
|
34
|
+
*/
|
|
35
|
+
export declare function detectPathnameLocale(pathname: string, locales: readonly string[]): string | undefined;
|
|
27
36
|
/**
|
|
28
37
|
* Prepend the default locale prefix to a pathname when i18n is configured and
|
|
29
38
|
* the path does not already carry a locale prefix. Mirrors Next.js's
|
|
@@ -42,7 +51,9 @@ type PagesI18nRequestInfo = {
|
|
|
42
51
|
* - `/__vinext/*` (vinext-internal endpoints)
|
|
43
52
|
*
|
|
44
53
|
* Returns the input unchanged when i18n is not configured or when the path
|
|
45
|
-
* already starts with one of the configured locales
|
|
54
|
+
* already starts with one of the configured locales (compared
|
|
55
|
+
* case-insensitively, like Next.js's `normalizeLocalePath`, so `/EN/about`
|
|
56
|
+
* is left alone rather than becoming `/en/EN/about`). The host-based default
|
|
46
57
|
* locale (i18n.domains[].defaultLocale) is preferred over the global default
|
|
47
58
|
* when supplied, matching Next.js's `domainLocale.defaultLocale` branch.
|
|
48
59
|
*
|
|
@@ -9,6 +9,19 @@ function readHeader(headers, name) {
|
|
|
9
9
|
}
|
|
10
10
|
const normalizeHostname = normalizeDomainHostname;
|
|
11
11
|
/**
|
|
12
|
+
* Return the configured locale that the first pathname segment names, compared
|
|
13
|
+
* case-insensitively (`/EN/about` -> `"en"`), or `undefined` when there is none.
|
|
14
|
+
* The configured casing is returned, not the request's.
|
|
15
|
+
*
|
|
16
|
+
* Ported from Next.js: packages/next/src/shared/lib/i18n/normalize-locale-path.ts
|
|
17
|
+
* https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/normalize-locale-path.ts
|
|
18
|
+
*/
|
|
19
|
+
function detectPathnameLocale(pathname, locales) {
|
|
20
|
+
const segment = pathname.split("/", 2)[1]?.toLowerCase();
|
|
21
|
+
if (!segment) return void 0;
|
|
22
|
+
return locales.find((locale) => locale.toLowerCase() === segment);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
12
25
|
* Prepend the default locale prefix to a pathname when i18n is configured and
|
|
13
26
|
* the path does not already carry a locale prefix. Mirrors Next.js's
|
|
14
27
|
* server-side path normalisation in `resolve-routes.ts` (lines ~250-263):
|
|
@@ -26,7 +39,9 @@ const normalizeHostname = normalizeDomainHostname;
|
|
|
26
39
|
* - `/__vinext/*` (vinext-internal endpoints)
|
|
27
40
|
*
|
|
28
41
|
* Returns the input unchanged when i18n is not configured or when the path
|
|
29
|
-
* already starts with one of the configured locales
|
|
42
|
+
* already starts with one of the configured locales (compared
|
|
43
|
+
* case-insensitively, like Next.js's `normalizeLocalePath`, so `/EN/about`
|
|
44
|
+
* is left alone rather than becoming `/en/EN/about`). The host-based default
|
|
30
45
|
* locale (i18n.domains[].defaultLocale) is preferred over the global default
|
|
31
46
|
* when supplied, matching Next.js's `domainLocale.defaultLocale` branch.
|
|
32
47
|
*
|
|
@@ -42,8 +57,7 @@ const normalizeHostname = normalizeDomainHostname;
|
|
|
42
57
|
function normalizeDefaultLocalePathname(pathname, i18n, options = {}) {
|
|
43
58
|
if (!i18n) return pathname;
|
|
44
59
|
if (pathname.startsWith("/_next/") || pathname.startsWith("/__vinext/")) return pathname;
|
|
45
|
-
|
|
46
|
-
if (parts[1] && i18n.locales.includes(parts[1])) return pathname;
|
|
60
|
+
if (detectPathnameLocale(pathname, i18n.locales)) return pathname;
|
|
47
61
|
const defaultLocale = detectDomainLocale(i18n.domains, options.hostname ?? void 0)?.defaultLocale ?? i18n.defaultLocale;
|
|
48
62
|
if (pathname === "/") return `/${defaultLocale}`;
|
|
49
63
|
return `/${defaultLocale}${pathname}`;
|
|
@@ -229,4 +243,4 @@ function resolvePagesI18nRequest(url, i18nConfig, headers, hostname, basePath =
|
|
|
229
243
|
};
|
|
230
244
|
}
|
|
231
245
|
//#endregion
|
|
232
|
-
export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
|
|
246
|
+
export { detectDomainLocale, detectLocaleFromAcceptLanguage, detectPathnameLocale, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
|
|
@@ -29,7 +29,6 @@ export type PagesReqResResponse = Writable & {
|
|
|
29
29
|
send: (data: unknown) => void;
|
|
30
30
|
redirect: (statusOrUrl: number | string, url?: string) => PagesReqResResponse;
|
|
31
31
|
getHeaders: () => PagesReqResHeaders;
|
|
32
|
-
revalidate: (urlPath: string, opts?: RevalidateOptions) => Promise<void>;
|
|
33
32
|
setPreviewData: (data: object | string, options?: {
|
|
34
33
|
maxAge?: number;
|
|
35
34
|
path?: string;
|
|
@@ -41,6 +40,9 @@ export type PagesReqResResponse = Writable & {
|
|
|
41
40
|
enable?: boolean;
|
|
42
41
|
}) => PagesReqResResponse;
|
|
43
42
|
};
|
|
43
|
+
export type PagesApiReqResResponse = PagesReqResResponse & {
|
|
44
|
+
revalidate: (urlPath: string, opts?: RevalidateOptions) => Promise<void>;
|
|
45
|
+
};
|
|
44
46
|
type PagesRequestCookiesCarrier = {
|
|
45
47
|
headers: {
|
|
46
48
|
cookie?: string | string[] | null | undefined;
|
|
@@ -48,17 +50,19 @@ type PagesRequestCookiesCarrier = {
|
|
|
48
50
|
cookies?: unknown;
|
|
49
51
|
};
|
|
50
52
|
type CreatePagesReqResOptions = {
|
|
51
|
-
allowedRevalidateHeaderKeys?: readonly string[];
|
|
52
53
|
body: unknown;
|
|
53
54
|
initialResponseHeaders?: Headers;
|
|
54
55
|
query: PagesRequestQuery;
|
|
55
56
|
request: Request;
|
|
56
|
-
trustedRevalidateOrigin?: string;
|
|
57
57
|
url: string;
|
|
58
58
|
};
|
|
59
|
-
type
|
|
59
|
+
type CreatePagesApiReqResOptions = CreatePagesReqResOptions & {
|
|
60
|
+
allowedRevalidateHeaderKeys?: readonly string[];
|
|
61
|
+
trustedRevalidateOrigin?: string;
|
|
62
|
+
};
|
|
63
|
+
type CreatePagesReqResResult<Res extends PagesReqResResponse = PagesReqResResponse> = {
|
|
60
64
|
req: PagesReqResRequest;
|
|
61
|
-
res:
|
|
65
|
+
res: Res;
|
|
62
66
|
responsePromise: Promise<Response>;
|
|
63
67
|
};
|
|
64
68
|
/**
|
|
@@ -85,5 +89,12 @@ export declare function attachPagesPreviewApi(req: PagesReqResRequest, res: Page
|
|
|
85
89
|
export declare function markVinextStreamedApiResponse(response: Response): void;
|
|
86
90
|
export declare function isVinextStreamedApiResponse(response: Response): boolean;
|
|
87
91
|
export declare function createPagesReqRes(options: CreatePagesReqResOptions): CreatePagesReqResResult;
|
|
92
|
+
/**
|
|
93
|
+
* Create the req/res pair for a Pages API route. Only API responses get
|
|
94
|
+
* `res.revalidate()`: Next.js attaches it in apiResolver
|
|
95
|
+
* (`packages/next/src/server/api-utils/node/api-resolver.ts`), so a page's
|
|
96
|
+
* getServerSideProps `res` never carries the revalidation secret.
|
|
97
|
+
*/
|
|
98
|
+
export declare function createPagesApiReqRes(options: CreatePagesApiReqResOptions): CreatePagesReqResResult<PagesApiReqResResponse>;
|
|
88
99
|
//#endregion
|
|
89
100
|
export { PagesBodyParseError as PagesApiBodyParseError };
|