vinext 1.3.1 → 1.4.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 +25 -22
- package/THIRD_PARTY_LICENSES.md +47 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -2
- package/dist/build/prerender.js +4 -3
- package/dist/build/report.d.ts +0 -14
- package/dist/build/report.js +1 -51
- package/dist/check.js +4 -7
- package/dist/cli.js +3 -0
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +20 -4
- package/dist/client/navigation-runtime.d.ts +13 -1
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +2 -0
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +52 -2
- package/dist/config/next-config.d.ts +25 -0
- package/dist/config/next-config.js +82 -4
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
- package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
- package/dist/entries/app-rsc-entry.js +17 -49
- package/dist/entries/app-rsc-manifest.js +3 -4
- package/dist/entries/app-ssr-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +36 -9
- package/dist/index.js +112 -90
- package/dist/init-cloudflare.d.ts +1 -3
- package/dist/init-cloudflare.js +10 -48
- package/dist/init-platform.d.ts +2 -0
- package/dist/init-platform.js +4 -0
- package/dist/plugins/extensionless-dynamic-import.js +6 -2
- package/dist/plugins/next-intl-catalog.d.ts +12 -0
- package/dist/plugins/next-intl-catalog.js +85 -0
- package/dist/plugins/pages-node-externals.d.ts +1 -0
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/plugins/use-cache-callable.d.ts +1 -1
- package/dist/plugins/use-cache-callable.js +136 -94
- package/dist/routing/app-route-graph.d.ts +6 -0
- package/dist/routing/app-route-graph.js +9 -1
- package/dist/server/api-handler.js +21 -5
- package/dist/server/app-bfcache-identity.js +1 -1
- package/dist/server/app-browser-entry.js +86 -66
- package/dist/server/app-browser-history-controller.d.ts +5 -4
- package/dist/server/app-browser-history-controller.js +93 -15
- package/dist/server/app-browser-navigation-controller.d.ts +2 -2
- package/dist/server/app-browser-navigation-controller.js +1 -2
- package/dist/server/app-browser-rsc-redirect.js +7 -7
- package/dist/server/app-browser-server-action-client.d.ts +2 -0
- package/dist/server/app-browser-server-action-client.js +5 -4
- package/dist/server/app-browser-state.d.ts +2 -4
- package/dist/server/app-browser-state.js +9 -4
- package/dist/server/app-browser-supplemental-refresh.js +16 -1
- package/dist/server/app-browser-visible-commit.d.ts +1 -1
- package/dist/server/app-browser-visible-commit.js +4 -14
- package/dist/server/app-elements-wire.d.ts +6 -38
- package/dist/server/app-elements-wire.js +4 -41
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-history-state.d.ts +2 -2
- package/dist/server/app-history-state.js +5 -2
- package/dist/server/app-mounted-layouts.d.ts +21 -0
- package/dist/server/app-mounted-layouts.js +67 -0
- package/dist/server/app-optimistic-routing.d.ts +19 -1
- package/dist/server/app-optimistic-routing.js +43 -4
- package/dist/server/app-page-boundary-render.js +10 -14
- package/dist/server/app-page-boundary.js +2 -2
- package/dist/server/app-page-cache-finalizer.d.ts +12 -1
- package/dist/server/app-page-cache-finalizer.js +70 -29
- package/dist/server/app-page-cache.d.ts +13 -1
- package/dist/server/app-page-cache.js +31 -9
- package/dist/server/app-page-dispatch.d.ts +5 -11
- package/dist/server/app-page-dispatch.js +84 -155
- package/dist/server/app-page-element-builder.d.ts +2 -2
- package/dist/server/app-page-element-builder.js +13 -12
- package/dist/server/app-page-execution.d.ts +17 -52
- package/dist/server/app-page-execution.js +102 -95
- package/dist/server/app-page-head.d.ts +13 -0
- package/dist/server/app-page-head.js +44 -16
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
- package/dist/server/app-page-layout-gate.d.ts +35 -0
- package/dist/server/app-page-layout-gate.js +50 -0
- package/dist/server/app-page-params.d.ts +0 -1
- package/dist/server/app-page-params.js +1 -14
- package/dist/server/app-page-probe.d.ts +3 -21
- package/dist/server/app-page-probe.js +4 -37
- package/dist/server/app-page-render.d.ts +2 -13
- package/dist/server/app-page-render.js +103 -234
- package/dist/server/app-page-request.d.ts +1 -3
- package/dist/server/app-page-request.js +1 -1
- package/dist/server/app-page-response.js +3 -3
- package/dist/server/app-page-route-wiring.d.ts +13 -6
- package/dist/server/app-page-route-wiring.js +86 -63
- package/dist/server/app-page-rsc-render-status.d.ts +27 -1
- package/dist/server/app-page-rsc-render-status.js +121 -13
- package/dist/server/app-page-stream.d.ts +12 -8
- package/dist/server/app-page-stream.js +4 -3
- package/dist/server/app-pages-bridge.d.ts +4 -0
- package/dist/server/app-pages-bridge.js +7 -3
- package/dist/server/app-render-dependency.d.ts +11 -4
- package/dist/server/app-render-dependency.js +86 -38
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-route-handler-cache.js +2 -2
- package/dist/server/app-route-handler-dispatch.js +14 -9
- package/dist/server/app-route-handler-execution.js +11 -5
- package/dist/server/app-route-handler-policy.d.ts +1 -1
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +28 -11
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +12 -12
- package/dist/server/app-rsc-cache-busting.js +31 -72
- package/dist/server/app-rsc-error-handler.d.ts +2 -1
- package/dist/server/app-rsc-error-handler.js +10 -2
- package/dist/server/app-rsc-errors.d.ts +8 -0
- package/dist/server/app-rsc-errors.js +11 -1
- package/dist/server/app-rsc-handler.d.ts +5 -5
- package/dist/server/app-rsc-handler.js +80 -83
- package/dist/server/app-rsc-request-normalization.d.ts +10 -16
- package/dist/server/app-rsc-request-normalization.js +12 -18
- package/dist/server/app-rsc-response-finalizer.js +2 -2
- package/dist/server/app-rsc-response-stage.js +9 -15
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +15 -8
- package/dist/server/app-ssr-entry.d.ts +8 -0
- package/dist/server/app-ssr-entry.js +22 -16
- package/dist/server/app-ssr-stream.js +1 -1
- package/dist/server/app-visited-response-cache.d.ts +36 -1
- package/dist/server/app-visited-response-cache.js +46 -5
- package/dist/server/app-worker-stages.d.ts +37 -6
- package/dist/server/app-worker-stages.js +81 -9
- package/dist/server/artifact-compatibility.d.ts +0 -1
- package/dist/server/artifact-compatibility.js +1 -10
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cache-proof.d.ts +1 -115
- package/dist/server/cache-proof.js +1 -544
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/cacheability-request.js +13 -8
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +6 -4
- package/dist/server/headers.d.ts +6 -3
- package/dist/server/headers.js +9 -5
- package/dist/server/image-optimization.d.ts +5 -0
- package/dist/server/image-optimization.js +6 -1
- package/dist/server/isr-cache.d.ts +8 -2
- package/dist/server/isr-cache.js +30 -2
- package/dist/server/metadata-route-response.js +32 -15
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +57 -12
- package/dist/server/multi-stage.js +13 -1
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/pages-api-route.js +28 -19
- package/dist/server/pages-media-type.d.ts +21 -1
- package/dist/server/pages-media-type.js +69 -5
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +54 -27
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +28 -26
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-pipeline.d.ts +8 -0
- package/dist/server/pages-request-pipeline.js +2 -2
- package/dist/server/pages-request-stage-entry.js +36 -14
- package/dist/server/pages-response-stage-entry.js +9 -3
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +47 -9
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +15 -4
- package/dist/server/request-pipeline.js +43 -15
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/shared-cache-identity.d.ts +23 -0
- package/dist/server/shared-cache-identity.js +36 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/server/worker-stages.d.ts +16 -3
- package/dist/server/worker-stages.js +23 -4
- package/dist/shims/cache-handler.js +2 -2
- package/dist/shims/cache-request-state.d.ts +23 -26
- package/dist/shims/cache-request-state.js +22 -57
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +94 -48
- package/dist/shims/cache.d.ts +16 -10
- package/dist/shims/cache.js +47 -36
- package/dist/shims/cacheability-classification.d.ts +2 -0
- package/dist/shims/cdn-cache.d.ts +22 -5
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/client-page-root.js +2 -2
- package/dist/shims/dynamic.js +9 -6
- package/dist/shims/error-boundary.js +2 -2
- package/dist/shims/fetch-cache-state.d.ts +5 -1
- package/dist/shims/fetch-cache-state.js +1 -3
- package/dist/shims/fetch-cache.d.ts +2 -1
- package/dist/shims/fetch-cache.js +39 -25
- package/dist/shims/form.js +2 -2
- package/dist/shims/headers.d.ts +10 -24
- package/dist/shims/headers.js +22 -70
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/internal/navigation-untracked.js +1 -1
- package/dist/shims/link.js +8 -11
- package/dist/shims/metadata.d.ts +23 -21
- package/dist/shims/metadata.js +62 -24
- package/dist/shims/navigation-server.js +1 -1
- package/dist/shims/navigation.d.ts +74 -7
- package/dist/shims/navigation.js +184 -31
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/request-state-types.d.ts +3 -2
- package/dist/shims/slot.d.ts +16 -0
- package/dist/shims/slot.js +44 -9
- package/dist/shims/unified-request-context.d.ts +7 -1
- package/dist/shims/unified-request-context.js +3 -3
- package/dist/utils/cache-control-metadata.d.ts +5 -0
- package/dist/utils/cache-control-metadata.js +9 -1
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/dist/utils/project.d.ts +2 -2
- package/dist/utils/project.js +3 -16
- package/dist/utils/regex.d.ts +5 -0
- package/dist/utils/regex.js +11 -1
- package/dist/utils/text-stream.d.ts +10 -5
- package/dist/utils/text-stream.js +6 -6
- package/package.json +2 -1
- package/dist/build/layout-classification-types.d.ts +0 -60
- package/dist/build/layout-classification-types.js +0 -1
- package/dist/build/layout-classification.d.ts +0 -62
- package/dist/build/layout-classification.js +0 -98
- package/dist/build/route-classification-injector.d.ts +0 -33
- package/dist/build/route-classification-injector.js +0 -59
- package/dist/build/route-classification-manifest.d.ts +0 -54
- package/dist/build/route-classification-manifest.js +0 -143
- package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
- package/dist/server/app-browser-client-reuse-manifest.js +0 -101
- package/dist/server/app-layout-param-observation.d.ts +0 -42
- package/dist/server/app-layout-param-observation.js +0 -168
- package/dist/server/client-reuse-manifest.d.ts +0 -103
- package/dist/server/client-reuse-manifest.js +0 -209
- package/dist/server/skip-cache-proof.d.ts +0 -60
- package/dist/server/skip-cache-proof.js +0 -168
- package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
- package/dist/server/static-layout-client-reuse-proof.js +0 -33
- package/dist/utils/sorted-array.d.ts +0 -8
- package/dist/utils/sorted-array.js +0 -20
|
@@ -9,6 +9,26 @@ export declare class PagesBodyParseError extends Error {
|
|
|
9
9
|
readonly statusCode: number;
|
|
10
10
|
constructor(message: string, statusCode: number);
|
|
11
11
|
}
|
|
12
|
-
export declare function getMediaType(contentType: string | null | undefined): string;
|
|
13
12
|
export declare function isJsonMediaType(mediaType: string): boolean;
|
|
13
|
+
/** A `TextDecoder`-shaped decoder for one request body. */
|
|
14
|
+
export type PagesBodyDecoder = {
|
|
15
|
+
decode(input?: Uint8Array, options?: {
|
|
16
|
+
stream?: boolean;
|
|
17
|
+
}): string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the media type and body decoder for a Pages API request, matching
|
|
21
|
+
* Next.js `parseBody()`: a malformed Content-Type is treated as `text/plain`,
|
|
22
|
+
* the body is decoded with its `charset` (UTF-8 by default), and a charset that
|
|
23
|
+
* can't be decoded is rejected with `400 Invalid body`.
|
|
24
|
+
*
|
|
25
|
+
* Next.js decodes through raw-body with iconv-lite 0.4, which vinext bundles
|
|
26
|
+
* at the same version. It is loaded only for non-UTF-8 charsets: `TextDecoder`
|
|
27
|
+
* decodes UTF-8 identically, BOM stripping included, and keeps iconv-lite's
|
|
28
|
+
* encoding tables out of the startup path.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createPagesBodyDecoder(contentType: string | null | undefined): Promise<{
|
|
31
|
+
mediaType: string;
|
|
32
|
+
decoder: PagesBodyDecoder;
|
|
33
|
+
}>;
|
|
14
34
|
//#endregion
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { __toESM } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
1
3
|
//#region src/server/pages-media-type.ts
|
|
2
4
|
/**
|
|
3
5
|
* Shared media-type helpers and body-parse error for Pages API routes.
|
|
@@ -13,12 +15,74 @@ var PagesBodyParseError = class extends Error {
|
|
|
13
15
|
this.name = "PagesBodyParseError";
|
|
14
16
|
}
|
|
15
17
|
};
|
|
16
|
-
function getMediaType(contentType) {
|
|
17
|
-
const [type] = (contentType ?? "text/plain").split(";");
|
|
18
|
-
return type?.trim().toLowerCase() || "text/plain";
|
|
19
|
-
}
|
|
20
18
|
function isJsonMediaType(mediaType) {
|
|
21
19
|
return mediaType === "application/json" || mediaType === "application/ld+json";
|
|
22
20
|
}
|
|
21
|
+
const TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
22
|
+
const PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
|
|
23
|
+
const QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
|
|
24
|
+
function parseContentType(header) {
|
|
25
|
+
let index = header.indexOf(";");
|
|
26
|
+
const type = (index === -1 ? header : header.slice(0, index)).trim();
|
|
27
|
+
if (!TYPE_REGEXP.test(type)) return null;
|
|
28
|
+
let charset;
|
|
29
|
+
if (index !== -1) {
|
|
30
|
+
const paramRegexp = new RegExp(PARAM_REGEXP);
|
|
31
|
+
paramRegexp.lastIndex = index;
|
|
32
|
+
let match;
|
|
33
|
+
while (match = paramRegexp.exec(header)) {
|
|
34
|
+
if (match.index !== index) return null;
|
|
35
|
+
index += match[0].length;
|
|
36
|
+
if (match[1].toLowerCase() !== "charset") continue;
|
|
37
|
+
const value = match[2];
|
|
38
|
+
charset = value.startsWith("\"") ? value.slice(1, -1).replace(QESC_REGEXP, "$1") : value;
|
|
39
|
+
}
|
|
40
|
+
if (index !== header.length) return null;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
mediaType: type.toLowerCase(),
|
|
44
|
+
charset
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function iconvBodyDecoder(decoder) {
|
|
48
|
+
return { decode(input, options) {
|
|
49
|
+
let text = input ? decoder.write(Buffer.from(input.buffer, input.byteOffset, input.byteLength)) : "";
|
|
50
|
+
if (!options?.stream) text += decoder.end() || "";
|
|
51
|
+
return text;
|
|
52
|
+
} };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the media type and body decoder for a Pages API request, matching
|
|
56
|
+
* Next.js `parseBody()`: a malformed Content-Type is treated as `text/plain`,
|
|
57
|
+
* the body is decoded with its `charset` (UTF-8 by default), and a charset that
|
|
58
|
+
* can't be decoded is rejected with `400 Invalid body`.
|
|
59
|
+
*
|
|
60
|
+
* Next.js decodes through raw-body with iconv-lite 0.4, which vinext bundles
|
|
61
|
+
* at the same version. It is loaded only for non-UTF-8 charsets: `TextDecoder`
|
|
62
|
+
* decodes UTF-8 identically, BOM stripping included, and keeps iconv-lite's
|
|
63
|
+
* encoding tables out of the startup path.
|
|
64
|
+
*/
|
|
65
|
+
async function createPagesBodyDecoder(contentType) {
|
|
66
|
+
const parsed = contentType && parseContentType(contentType) || {
|
|
67
|
+
mediaType: "text/plain",
|
|
68
|
+
charset: void 0
|
|
69
|
+
};
|
|
70
|
+
const charset = parsed.charset || "utf-8";
|
|
71
|
+
if (charset.toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "") === "utf8") return {
|
|
72
|
+
mediaType: parsed.mediaType,
|
|
73
|
+
decoder: new TextDecoder()
|
|
74
|
+
};
|
|
75
|
+
const iconv = (await import("../deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1))).default;
|
|
76
|
+
let decoder;
|
|
77
|
+
try {
|
|
78
|
+
decoder = iconv.getDecoder(charset);
|
|
79
|
+
} catch {
|
|
80
|
+
throw new PagesBodyParseError("Invalid body", 400);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
mediaType: parsed.mediaType,
|
|
84
|
+
decoder: iconvBodyDecoder(decoder)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
23
87
|
//#endregion
|
|
24
|
-
export { PagesBodyParseError,
|
|
88
|
+
export { PagesBodyParseError, createPagesBodyDecoder, isJsonMediaType };
|
|
@@ -7,7 +7,7 @@ export type PagesRequestQuery = Record<string, string | string[]>;
|
|
|
7
7
|
export type PagesReqResRequest = Readable & {
|
|
8
8
|
method: string;
|
|
9
9
|
url: string;
|
|
10
|
-
headers: Record<string, string>;
|
|
10
|
+
headers: Record<string, string | string[] | undefined>;
|
|
11
11
|
query: PagesRequestQuery;
|
|
12
12
|
body: unknown;
|
|
13
13
|
cookies: Record<string, string>;
|
|
@@ -2,11 +2,11 @@ import { parseCookieHeader } from "../utils/parse-cookie.js";
|
|
|
2
2
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
3
3
|
import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
|
|
4
4
|
import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
|
|
5
|
-
import { PagesBodyParseError,
|
|
5
|
+
import { PagesBodyParseError, createPagesBodyDecoder, isJsonMediaType } from "./pages-media-type.js";
|
|
6
6
|
import { performOnDemandRevalidate } from "./pages-revalidate.js";
|
|
7
7
|
import { clearPagesPreviewData, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData } from "./pages-preview.js";
|
|
8
8
|
import { decode } from "node:querystring";
|
|
9
|
-
import { Readable, Writable } from "node:stream";
|
|
9
|
+
import { Readable, Stream, Writable } from "node:stream";
|
|
10
10
|
//#region src/server/pages-node-compat.ts
|
|
11
11
|
const MAX_PAGES_API_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;
|
|
12
12
|
const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -26,11 +26,17 @@ function validateAppendedHeader(name, value) {
|
|
|
26
26
|
if (INVALID_HEADER_VALUE_CHAR_PATTERN.test(String(item))) throw createNodeTypeError("ERR_INVALID_CHAR", `Invalid character in header content ["${name}"]`);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
/** The decoded body, or undefined when the request carried no body bytes. */
|
|
30
|
+
async function readPagesRequestBodyWithLimit(request, maxBytes, decoder) {
|
|
31
|
+
if (!request.body) return;
|
|
32
|
+
let byteLength = 0;
|
|
33
|
+
const text = await readStreamAsTextWithLimit(request.body, maxBytes, () => {
|
|
32
34
|
throw new PagesBodyParseError("Request body too large", 413);
|
|
33
|
-
})
|
|
35
|
+
}, { decode(input, options) {
|
|
36
|
+
byteLength += input?.byteLength ?? 0;
|
|
37
|
+
return decoder.decode(input, options);
|
|
38
|
+
} });
|
|
39
|
+
return byteLength > 0 ? text : void 0;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
42
|
* Read and parse a Pages Router API request body for the Workers/prod path.
|
|
@@ -43,16 +49,16 @@ async function readPagesRequestBodyWithLimit(request, maxBytes) {
|
|
|
43
49
|
* @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
|
|
44
50
|
*/
|
|
45
51
|
async function parsePagesApiBody(request, maxBytes = MAX_PAGES_API_BODY_SIZE) {
|
|
52
|
+
const { mediaType, decoder } = await createPagesBodyDecoder(request.headers.get("content-type"));
|
|
46
53
|
if (Number.parseInt(request.headers.get("content-length") || "0", 10) > maxBytes) throw new PagesBodyParseError("Request body too large", 413);
|
|
47
|
-
let rawBody
|
|
54
|
+
let rawBody;
|
|
48
55
|
try {
|
|
49
|
-
rawBody = await readPagesRequestBodyWithLimit(request, maxBytes);
|
|
56
|
+
rawBody = await readPagesRequestBodyWithLimit(request, maxBytes, decoder);
|
|
50
57
|
} catch (err) {
|
|
51
58
|
if (err instanceof PagesBodyParseError) throw err;
|
|
52
59
|
throw new PagesBodyParseError("Request body too large", 413);
|
|
53
60
|
}
|
|
54
|
-
|
|
55
|
-
if (!rawBody) return isJsonMediaType(mediaType) ? {} : mediaType === "application/x-www-form-urlencoded" ? decode(rawBody) : void 0;
|
|
61
|
+
if (!rawBody) return isJsonMediaType(mediaType) ? {} : mediaType === "application/x-www-form-urlencoded" ? decode("") : rawBody;
|
|
56
62
|
if (isJsonMediaType(mediaType)) try {
|
|
57
63
|
return JSON.parse(rawBody);
|
|
58
64
|
} catch {
|
|
@@ -61,24 +67,34 @@ async function parsePagesApiBody(request, maxBytes = MAX_PAGES_API_BODY_SIZE) {
|
|
|
61
67
|
if (mediaType === "application/x-www-form-urlencoded") return decode(rawBody);
|
|
62
68
|
return rawBody;
|
|
63
69
|
}
|
|
64
|
-
async function* requestBodyChunks(request) {
|
|
65
|
-
if (!request.body || request.bodyUsed) return;
|
|
66
|
-
const reader = request.body.getReader();
|
|
67
|
-
try {
|
|
68
|
-
for (;;) {
|
|
69
|
-
const { value, done } = await reader.read();
|
|
70
|
-
if (done) return;
|
|
71
|
-
yield Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
72
|
-
}
|
|
73
|
-
} finally {
|
|
74
|
-
try {
|
|
75
|
-
await reader.cancel();
|
|
76
|
-
} catch {}
|
|
77
|
-
reader.releaseLock();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
70
|
function createRequestReadable(request) {
|
|
81
|
-
|
|
71
|
+
const body = request.bodyUsed ? null : request.body;
|
|
72
|
+
let reader;
|
|
73
|
+
return new Readable({
|
|
74
|
+
read() {
|
|
75
|
+
if (!body) {
|
|
76
|
+
this.push(null);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
reader ??= body.getReader();
|
|
80
|
+
reader.read().then(({ value, done }) => {
|
|
81
|
+
if (this.destroyed) return;
|
|
82
|
+
if (done) {
|
|
83
|
+
this.push(null);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.push(Buffer.from(value.buffer, value.byteOffset, value.byteLength));
|
|
87
|
+
}, (error) => this.destroy(error));
|
|
88
|
+
},
|
|
89
|
+
destroy(error, callback) {
|
|
90
|
+
const cancelled = reader ? reader.cancel(error ?? void 0) : body?.cancel(error ?? void 0);
|
|
91
|
+
if (!cancelled) {
|
|
92
|
+
callback(error);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
cancelled.then(() => callback(error), () => callback(error));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
82
98
|
}
|
|
83
99
|
function parsePagesRequestCookies(cookieHeader) {
|
|
84
100
|
return parseCookieHeader(Array.isArray(cookieHeader) ? cookieHeader.join("; ") : cookieHeader);
|
|
@@ -189,6 +205,15 @@ var PagesResponseStream = class extends Writable {
|
|
|
189
205
|
this.end(JSON.stringify(data));
|
|
190
206
|
}
|
|
191
207
|
send(data) {
|
|
208
|
+
if (NO_BODY_RESPONSE_STATUSES.has(this.resStatusCode)) {
|
|
209
|
+
this.end();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (data instanceof Stream) {
|
|
213
|
+
if (!this.resHeaders["content-type"]) this.resHeaders["content-type"] = "application/octet-stream";
|
|
214
|
+
data.pipe(this);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
192
217
|
if (Buffer.isBuffer(data)) {
|
|
193
218
|
if (!this.resHeaders["content-type"]) this.resHeaders["content-type"] = "application/octet-stream";
|
|
194
219
|
this.resHeaders["content-length"] = String(data.length);
|
|
@@ -342,6 +367,8 @@ function isVinextStreamedApiResponse(response) {
|
|
|
342
367
|
function createPagesReqRes(options) {
|
|
343
368
|
const headersObj = {};
|
|
344
369
|
for (const [key, value] of options.request.headers) headersObj[key.toLowerCase()] = value;
|
|
370
|
+
const setCookies = options.request.headers.getSetCookie();
|
|
371
|
+
if (setCookies.length > 1) headersObj["set-cookie"] = setCookies;
|
|
345
372
|
const req = Object.assign(createRequestReadable(options.request), {
|
|
346
373
|
method: options.request.method,
|
|
347
374
|
url: options.url,
|
|
@@ -13,7 +13,7 @@ import { normalizeStaticPathname } from "../routing/route-pattern.js";
|
|
|
13
13
|
import { buildCacheStateHeaders } from "./cache-headers.js";
|
|
14
14
|
import { pagesPathCacheTag } from "./pages-cache-tag.js";
|
|
15
15
|
import { isPageNotModified } from "./http-conditional.js";
|
|
16
|
-
import { generatePagesETag, isPagesStreamingBot, rendersPagesNotModified } from "./pages-page-response.js";
|
|
16
|
+
import { applyPagesPrerenderRevalidateHeader, generatePagesETag, isPagesStreamingBot, rendersPagesNotModified } from "./pages-page-response.js";
|
|
17
17
|
import { createPagesGetInitialPropsRouter, hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
|
|
18
18
|
import { isSerializableProps } from "./pages-serializable-props.js";
|
|
19
19
|
import { tracePagesData, tracePagesDocument } from "./pages-execution-tracing.js";
|
|
@@ -130,6 +130,7 @@ function applyPagesTerminalMissHeaders(response, revalidateSeconds, isrCachePath
|
|
|
130
130
|
tags: [pagesPathCacheTag(isrCachePathname)]
|
|
131
131
|
});
|
|
132
132
|
for (const [name, value] of Object.entries(buildCacheStateHeaders("MISS"))) response.headers.set(name, value);
|
|
133
|
+
applyPagesPrerenderRevalidateHeader(response.headers, revalidateSeconds);
|
|
133
134
|
return response;
|
|
134
135
|
}
|
|
135
136
|
function applyCachedPagesRepresentationHeaders(response, cacheState, entry, options) {
|
|
@@ -8,13 +8,14 @@ import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
|
8
8
|
import { extractLocaleFromUrl, resolvePagesI18nRequest } from "./pages-i18n.js";
|
|
9
9
|
import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
|
|
10
10
|
import { reportRequestError } from "./instrumentation.js";
|
|
11
|
+
import { logRequestError } from "./request-error-log.js";
|
|
11
12
|
import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
|
|
12
13
|
import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, markRouteCacheabilityExplicitResponsePolicy, markRouteCacheabilityFinalResponseUncacheable, recordRouteCacheability } from "../shims/cacheability-classification.js";
|
|
13
14
|
import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, hasExplicitNonCacheableResponsePolicy, isCdnResponsePolicyHeader, shouldUseNextDeployCacheControl } from "./cache-control.js";
|
|
14
15
|
import { buildMissIsrCacheControl } from "./isr-decision.js";
|
|
15
16
|
import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
|
|
16
|
-
import {
|
|
17
|
-
import { ensureFetchPatch } from "../shims/fetch-cache.js";
|
|
17
|
+
import { coalesceOnDemandResponse, isrGet, isrSet, pagesIsrCacheKey, triggerBackgroundRegeneration } from "./isr-cache.js";
|
|
18
|
+
import { ensureFetchPatch, setCurrentFetchDraftMode } from "../shims/fetch-cache.js";
|
|
18
19
|
import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
|
|
19
20
|
import { getScriptNonceFromHeaderSources } from "./csp.js";
|
|
20
21
|
import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
|
|
@@ -22,7 +23,7 @@ import { buildPagesReadinessNextData } from "./pages-readiness.js";
|
|
|
22
23
|
import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
|
|
23
24
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
24
25
|
import { pagesPathCacheTag } from "./pages-cache-tag.js";
|
|
25
|
-
import { renderPagesPageResponse } from "./pages-page-response.js";
|
|
26
|
+
import { applyPagesPrerenderRevalidateHeader, renderPagesPageResponse } from "./pages-page-response.js";
|
|
26
27
|
import { hasPagesGetInitialProps } from "./pages-get-initial-props.js";
|
|
27
28
|
import { traceFindPageComponents, tracePagesDocumentStream } from "./pages-execution-tracing.js";
|
|
28
29
|
import { mergePagesNotFoundSourceHeaders, resolvePagesPageData, resolvePagesStatusPageRenderPath, setPagesResponseHeader } from "./pages-page-data.js";
|
|
@@ -244,10 +245,12 @@ function createPagesPageHandler(opts) {
|
|
|
244
245
|
hasRewrites
|
|
245
246
|
});
|
|
246
247
|
const isCacheabilityProbe = isRouteCacheabilityProbe();
|
|
247
|
-
|
|
248
|
+
const isTopLevelPageRoute = !isRouteMissErrorRender && options?.__forcedRoute === void 0;
|
|
249
|
+
const isInitialPropsRender = isTopLevelPageRoute && !isStaticPropsRoute && pagesReadiness.gssp !== true && (pagesReadiness.gip === true || pagesReadiness.appGip === true);
|
|
250
|
+
if (isTopLevelPageRoute) {
|
|
248
251
|
beginRouteCacheability("pages-page", route.pattern);
|
|
249
252
|
if (isRouteCacheabilityIdentityProbe()) return new Response(null, { status: 204 });
|
|
250
|
-
if (pagesReadiness.gssp !== true &&
|
|
253
|
+
if (pagesReadiness.gssp !== true && !isInitialPropsRender && !isStaticPropsRoute) recordRouteCacheability({
|
|
251
254
|
cacheable: true,
|
|
252
255
|
cacheControl: STATIC_CACHE_CONTROL
|
|
253
256
|
});
|
|
@@ -258,23 +261,10 @@ function createPagesPageHandler(opts) {
|
|
|
258
261
|
const isStaticPropsRender = isStaticPropsRoute && typeof pageModule.getServerSideProps !== "function";
|
|
259
262
|
if (!options?.__skipOnDemandCoalesce && !options?.__forcedRoute && !cacheIdentityDiverges && isStaticPropsRoute && isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"))) {
|
|
260
263
|
const cacheKey = pageIsrCacheKey("pages", routeUrl.split("?")[0]);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}, initialResponseHeaders);
|
|
266
|
-
return {
|
|
267
|
-
body: request.method === "HEAD" || response.status === 204 || response.status === 304 ? null : new Uint8Array(await response.arrayBuffer()),
|
|
268
|
-
headers: [...response.headers.entries()],
|
|
269
|
-
status: response.status,
|
|
270
|
-
statusText: response.statusText
|
|
271
|
-
};
|
|
272
|
-
});
|
|
273
|
-
return new Response(snapshot.body?.slice() ?? null, {
|
|
274
|
-
headers: snapshot.headers,
|
|
275
|
-
status: snapshot.status,
|
|
276
|
-
statusText: snapshot.statusText
|
|
277
|
-
});
|
|
264
|
+
return coalesceOnDemandResponse(cacheKey, request.method, () => renderPage(request, url, manifest, middlewareHeaders, {
|
|
265
|
+
...options,
|
|
266
|
+
__skipOnDemandCoalesce: true
|
|
267
|
+
}, initialResponseHeaders));
|
|
278
268
|
}
|
|
279
269
|
const routePattern = patternToNextFormat(route.pattern);
|
|
280
270
|
const renderStatusCode = renderStatusCodeOverride ?? (routePattern === "/404" ? 404 : void 0);
|
|
@@ -283,7 +273,10 @@ function createPagesPageHandler(opts) {
|
|
|
283
273
|
const renderRouteUrl = isStaticPropsRender && isStatusPageIdentity ? resolvePagesStatusPageRenderPath(statusPagePathname, vinextConfig.trailingSlash, originalRequestUrl.pathname) : isStaticPropsRender ? routeUrl.split("?")[0] : routeUrl;
|
|
284
274
|
const routerAsPathSource = isStaticPropsRender ? renderRouteUrl : renderAsPath ?? renderRouteUrl;
|
|
285
275
|
const routerAsPath = i18nConfig ? extractLocaleFromUrl(routerAsPathSource, i18nConfig, locale).url : routerAsPathSource;
|
|
286
|
-
const uCtx = createRequestContext({
|
|
276
|
+
const uCtx = createRequestContext({
|
|
277
|
+
executionContext: getRequestExecutionContext(),
|
|
278
|
+
isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER))
|
|
279
|
+
});
|
|
287
280
|
let pageReqRes = null;
|
|
288
281
|
const pageResponseSent = () => pageReqRes?.res.headersSent === true;
|
|
289
282
|
const sendsEarly = isStaticPropsRoute && !isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"));
|
|
@@ -292,7 +285,7 @@ function createPagesPageHandler(opts) {
|
|
|
292
285
|
resolveSentResponse = resolve;
|
|
293
286
|
});
|
|
294
287
|
const reportSsrError = async (e) => {
|
|
295
|
-
|
|
288
|
+
logRequestError("[vinext] SSR error:", e);
|
|
296
289
|
await reportRequestError(e, {
|
|
297
290
|
path: url,
|
|
298
291
|
method: request.method,
|
|
@@ -322,6 +315,7 @@ function createPagesPageHandler(opts) {
|
|
|
322
315
|
shouldClear: false
|
|
323
316
|
};
|
|
324
317
|
const previewData = preview.data;
|
|
318
|
+
setCurrentFetchDraftMode(previewData !== false);
|
|
325
319
|
const pagesNextData = {
|
|
326
320
|
...pagesReadiness,
|
|
327
321
|
...previewData === false ? {} : { isPreview: true }
|
|
@@ -444,6 +438,7 @@ function createPagesPageHandler(opts) {
|
|
|
444
438
|
clientTraceMetadata: shouldEmitPagesClientTraceMetadata(pageModule, AppComponent) ? vinextConfig.clientTraceMetadata : void 0,
|
|
445
439
|
documentReqRes: render.documentReqRes,
|
|
446
440
|
gsspRes: render.gsspRes,
|
|
441
|
+
isInitialPropsRender,
|
|
447
442
|
isrCacheKey: pageIsrCacheKey,
|
|
448
443
|
isrCachePathname,
|
|
449
444
|
expireSeconds: render.expireSeconds,
|
|
@@ -594,6 +589,7 @@ function createPagesPageHandler(opts) {
|
|
|
594
589
|
notFoundResponse = stripPagesNotFoundFramingHeaders(notFoundResponse);
|
|
595
590
|
if (isOnDemandRevalidate) notFoundResponse = withPagesCacheState(notFoundResponse, "REVALIDATED", isrCachePathname);
|
|
596
591
|
else if (pageDataResult.cacheState) notFoundResponse = withPagesCacheState(notFoundResponse, pageDataResult.cacheState);
|
|
592
|
+
if (pageDataResult.revalidateSeconds !== void 0) applyPagesPrerenderRevalidateHeader(notFoundResponse.headers, pageDataResult.revalidateSeconds);
|
|
597
593
|
return finalizePagesPreviewResponse(withBrowserPolicy(notFoundResponse), preview);
|
|
598
594
|
}
|
|
599
595
|
if (pageDataResult.kind === "response") {
|
|
@@ -623,6 +619,7 @@ function createPagesPageHandler(opts) {
|
|
|
623
619
|
});
|
|
624
620
|
if (isDataReq) {
|
|
625
621
|
const headers = new Headers();
|
|
622
|
+
let resHasCacheControl = false;
|
|
626
623
|
if (gsspRes && typeof gsspRes.getHeaders === "function") {
|
|
627
624
|
const gsspHeaders = gsspRes.getHeaders();
|
|
628
625
|
for (const k of Object.keys(gsspHeaders)) {
|
|
@@ -631,10 +628,15 @@ function createPagesPageHandler(opts) {
|
|
|
631
628
|
if (k.toLowerCase() === "set-cookie" && Array.isArray(v)) for (const cookie of v) headers.append(k, String(cookie));
|
|
632
629
|
else headers.set(k, Array.isArray(v) ? v.join(", ") : String(v));
|
|
633
630
|
}
|
|
631
|
+
resHasCacheControl = headers.has("Cache-Control");
|
|
632
|
+
} else if (isInitialPropsRender && documentReqRes) {
|
|
633
|
+
const resHeaders = documentReqRes.res.getHeaders();
|
|
634
|
+
for (const [name, value] of Object.entries(resHeaders)) if (isCdnResponsePolicyHeader(name)) setPagesResponseHeader(headers, name, value);
|
|
635
|
+
resHasCacheControl = Boolean(resHeaders["cache-control"]);
|
|
634
636
|
}
|
|
635
637
|
if (hasCdnResponsePolicy(headers)) markRouteCacheabilityExplicitResponsePolicy();
|
|
636
|
-
if (gsspRes) {
|
|
637
|
-
if (!
|
|
638
|
+
if (gsspRes || isInitialPropsRender) {
|
|
639
|
+
if (!resHasCacheControl) headers.set("Cache-Control", NEVER_CACHE_CONTROL);
|
|
638
640
|
} else if (isStaticPropsRoute) {
|
|
639
641
|
if (isrRevalidateSeconds !== null) applyCdnResponseHeaders(headers, {
|
|
640
642
|
cacheControl: buildMissIsrCacheControl(isrRevalidateSeconds, vinextConfig.expireTime),
|
|
@@ -17,6 +17,13 @@ export declare function generatePagesETag(payload: string): string;
|
|
|
17
17
|
* A page whose status carries no body has nothing to store.
|
|
18
18
|
*/
|
|
19
19
|
export declare function rendersPagesNotModified(status: number): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Hand the revalidate getStaticProps returned to build/prerender.ts, which
|
|
22
|
+
* records it in vinext-prerender.json like Next.js's `initialRevalidateSeconds`.
|
|
23
|
+
* The CDN adapter may rewrite Cache-Control, so the build cannot read it there.
|
|
24
|
+
* Only build-time renders carry this header.
|
|
25
|
+
*/
|
|
26
|
+
export declare function applyPagesPrerenderRevalidateHeader(headers: Headers, revalidateSeconds: number | false): void;
|
|
20
27
|
type PagesFontPreload = {
|
|
21
28
|
href: string;
|
|
22
29
|
type: string;
|
|
@@ -79,6 +86,8 @@ type RenderPagesPageResponseOptions = {
|
|
|
79
86
|
setDocumentInitialHead?: ((head: ReactNode[]) => void) | undefined;
|
|
80
87
|
documentReqRes?: PagesDocumentReqRes | null;
|
|
81
88
|
gsspRes: PagesGsspResponse | null;
|
|
89
|
+
/** A page or custom `_app` getInitialProps render; rendered per request like gSSP. */
|
|
90
|
+
isInitialPropsRender?: boolean;
|
|
82
91
|
isrCacheKey: (router: string, pathname: string) => string;
|
|
83
92
|
/** Filesystem-route identity used for ISR persistence and cache tags. */
|
|
84
93
|
isrCachePathname?: string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { isBotUserAgent } from "../utils/html-limited-bots.js";
|
|
2
|
-
import { NEXTJS_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
|
|
2
|
+
import { NEXTJS_CACHE_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
|
|
3
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
4
|
import { reportRequestError } from "./instrumentation.js";
|
|
5
|
+
import { logRequestError } from "./request-error-log.js";
|
|
5
6
|
import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
|
|
6
7
|
import { markRouteCacheabilityExplicitResponsePolicy } from "../shims/cacheability-classification.js";
|
|
7
8
|
import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, shouldUseNextDeployCacheControl } from "./cache-control.js";
|
|
@@ -17,6 +18,7 @@ import { spliceDocumentHeadClose, spliceDocumentHeadOpen, spliceDocumentScripts,
|
|
|
17
18
|
import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
|
|
18
19
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
19
20
|
import { pagesPathCacheTag } from "./pages-cache-tag.js";
|
|
21
|
+
import { applyPrerenderCacheLifeHeader } from "./prerender-cache-life-header.js";
|
|
20
22
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
21
23
|
import { loadUserDocumentInitialProps, runDocumentRenderPage } from "./pages-document-initial-props.js";
|
|
22
24
|
import { callDocumentGetInitialProps } from "./document-initial-head.js";
|
|
@@ -42,6 +44,17 @@ function generatePagesETag(payload) {
|
|
|
42
44
|
function rendersPagesNotModified(status) {
|
|
43
45
|
return status === 204 || status === 205 || status === 304 || getCdnCacheAdapter().deferNotModifiedResponse?.() !== true;
|
|
44
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Hand the revalidate getStaticProps returned to build/prerender.ts, which
|
|
49
|
+
* records it in vinext-prerender.json like Next.js's `initialRevalidateSeconds`.
|
|
50
|
+
* The CDN adapter may rewrite Cache-Control, so the build cannot read it there.
|
|
51
|
+
* Only build-time renders carry this header.
|
|
52
|
+
*/
|
|
53
|
+
function applyPagesPrerenderRevalidateHeader(headers, revalidateSeconds) {
|
|
54
|
+
if (typeof process === "undefined" || process.env?.VINEXT_PRERENDER !== "1") return;
|
|
55
|
+
headers.delete(VINEXT_PRERENDER_CACHE_LIFE_HEADER);
|
|
56
|
+
if (typeof revalidateSeconds === "number") applyPrerenderCacheLifeHeader(headers, { revalidate: revalidateSeconds });
|
|
57
|
+
}
|
|
45
58
|
function buildPagesFontHeadHtml(fontLinks, fontPreloads, fontStyles, scriptNonce) {
|
|
46
59
|
let html = "";
|
|
47
60
|
const nonceAttr = createNonceAttribute(scriptNonce);
|
|
@@ -121,7 +134,7 @@ async function buildPagesCompositeStream(bodyStream, shellPrefix, shellSuffix) {
|
|
|
121
134
|
} });
|
|
122
135
|
}
|
|
123
136
|
async function reportPagesIsrCacheWriteError(error, cacheKey, routePattern) {
|
|
124
|
-
|
|
137
|
+
logRequestError(`[vinext] Pages ISR cache write failed for ${cacheKey}:`, error);
|
|
125
138
|
try {
|
|
126
139
|
await reportRequestError(error, {
|
|
127
140
|
path: cacheKey,
|
|
@@ -284,12 +297,13 @@ async function renderPagesPageResponse(options) {
|
|
|
284
297
|
cacheControl: buildMissIsrCacheControl(options.isrRevalidateSeconds, options.expireSeconds),
|
|
285
298
|
tags: [pathTag]
|
|
286
299
|
});
|
|
300
|
+
applyPagesPrerenderRevalidateHeader(responseHeaders, options.isrRevalidateSeconds);
|
|
287
301
|
if (options.isOnDemandRevalidate) {
|
|
288
302
|
responseHeaders.set(NEXTJS_CACHE_HEADER, "REVALIDATED");
|
|
289
303
|
responseHeaders.set(VINEXT_REVALIDATED_CACHE_TAG_HEADER, encodeURIComponent(pathTag));
|
|
290
304
|
} else setCacheStateHeaders(responseHeaders, "MISS");
|
|
291
305
|
} else if (options.isStaticPropsRoute && shouldUseNextDeployCacheControl()) responseHeaders.set("Cache-Control", BROWSER_REVALIDATE_CACHE_CONTROL);
|
|
292
|
-
else if (options.gsspRes && !userSetCacheControl) responseHeaders.set("Cache-Control", NEVER_CACHE_CONTROL);
|
|
306
|
+
else if ((options.gsspRes || options.isInitialPropsRender || options.isFallback) && !userSetCacheControl) responseHeaders.set("Cache-Control", NEVER_CACHE_CONTROL);
|
|
293
307
|
if (options.fontLinkHeader) responseHeaders.set("Link", options.fontLinkHeader);
|
|
294
308
|
if (options.userAgent && isPagesStreamingBot(options.userAgent)) {
|
|
295
309
|
const fullHtml = await readStreamAsText(compositeStream);
|
|
@@ -314,4 +328,4 @@ async function renderPagesPageResponse(options) {
|
|
|
314
328
|
}), { __vinextStreamedHtmlResponse: true });
|
|
315
329
|
}
|
|
316
330
|
//#endregion
|
|
317
|
-
export { buildPagesNextDataScript, generatePagesETag, isPagesStreamingBot, renderPagesPageResponse, rendersPagesNotModified };
|
|
331
|
+
export { applyPagesPrerenderRevalidateHeader, buildPagesNextDataScript, generatePagesETag, isPagesStreamingBot, renderPagesPageResponse, rendersPagesNotModified };
|
|
@@ -84,6 +84,14 @@ export type PagesPipelineDeps = {
|
|
|
84
84
|
dataNotFoundResponse?: Response | null;
|
|
85
85
|
renderPage?: ((request: Request, resolvedUrl: string, options?: PagesRenderOptions, stagedHeaders?: Headers) => Promise<Response>) | null;
|
|
86
86
|
handleApi?: ((request: Request, apiUrl: string, ctx: unknown, stagedHeaders: Headers) => Promise<Response>) | null;
|
|
87
|
+
/**
|
|
88
|
+
* `handleApi` installs the staged headers on the handler's `res` before user
|
|
89
|
+
* code runs, as Next.js does, so its response already reflects any header the
|
|
90
|
+
* handler replaced and only middleware's status is applied here.
|
|
91
|
+
* Workers leaves this unset: its response stage strips the inherited cookies
|
|
92
|
+
* so they are not stored, and this merge adds them back.
|
|
93
|
+
*/
|
|
94
|
+
handleApiAppliesStagedHeaders?: boolean;
|
|
87
95
|
/**
|
|
88
96
|
* Optional override for proxying external rewrite destinations.
|
|
89
97
|
* When supplied, the pipeline calls this instead of proxyExternalRequest(currentRequest, url).
|
|
@@ -14,8 +14,8 @@ import { buildMiddlewarePrefetchSkipResponse } from "./pages-data-route.js";
|
|
|
14
14
|
import { markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
|
|
15
15
|
import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
|
|
16
16
|
import { mergeRewriteQuery } from "../utils/query.js";
|
|
17
|
-
import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
|
|
18
17
|
import { setFrameworkRequestRoute } from "./request-tracing.js";
|
|
18
|
+
import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
|
|
19
19
|
import { applyConfigHeadersToHeaderRecord } from "./config-headers.js";
|
|
20
20
|
import { finalizeMissingStaticAssetResponse, mergeHeaders } from "./worker-utils.js";
|
|
21
21
|
//#region src/server/pages-request-pipeline.ts
|
|
@@ -310,7 +310,7 @@ async function runPagesRequest(request, deps) {
|
|
|
310
310
|
apiRequest = cloneRequestWithUrl(request, apiRequestUrl.toString());
|
|
311
311
|
}
|
|
312
312
|
const response = await deps.handleApi(apiRequest, apiLookupUrl, deps.ctx ?? null, headersFromRecord(middlewareHeaders));
|
|
313
|
-
const merged = mergeHeaders(response, middlewareHeaders, middlewareStatus);
|
|
313
|
+
const merged = mergeHeaders(response, deps.handleApiAppliesStagedHeaders ? {} : middlewareHeaders, middlewareStatus);
|
|
314
314
|
if (merged !== response) merged.__vinextStreamedApiResponse = response.__vinextStreamedApiResponse;
|
|
315
315
|
return {
|
|
316
316
|
type: "response",
|