vinext 1.3.1 → 1.4.0
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 +5 -2
- package/THIRD_PARTY_LICENSES.md +47 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -2
- package/dist/build/prerender.js +1 -1
- package/dist/build/report.d.ts +0 -14
- package/dist/build/report.js +1 -51
- package/dist/check.js +1 -1
- package/dist/cli.js +3 -0
- package/dist/client/dev-error-overlay.js +1 -1
- package/dist/client/navigation-runtime.d.ts +13 -1
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/next-config.d.ts +19 -0
- package/dist/config/next-config.js +64 -1
- 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 -48
- 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 +33 -8
- package/dist/index.js +83 -70
- 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/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 +19 -4
- package/dist/server/app-bfcache-identity.js +1 -1
- package/dist/server/app-browser-entry.js +79 -63
- 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 +4 -4
- package/dist/server/app-browser-server-action-client.d.ts +2 -0
- package/dist/server/app-browser-server-action-client.js +4 -3
- 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 +2 -12
- 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 +42 -2
- package/dist/server/app-page-boundary-render.js +7 -6
- 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 -10
- package/dist/server/app-page-dispatch.js +84 -154
- package/dist/server/app-page-element-builder.d.ts +2 -2
- package/dist/server/app-page-element-builder.js +10 -9
- package/dist/server/app-page-execution.d.ts +17 -52
- package/dist/server/app-page-execution.js +99 -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 -12
- package/dist/server/app-page-render.js +89 -220
- 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 +67 -61
- 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 +2 -0
- package/dist/server/app-page-stream.js +2 -2
- 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-route-handler-cache.js +2 -2
- package/dist/server/app-route-handler-dispatch.js +14 -9
- package/dist/server/app-route-handler-execution.js +8 -3
- 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.js +17 -4
- package/dist/server/app-rsc-cache-busting.d.ts +2 -2
- package/dist/server/app-rsc-cache-busting.js +4 -4
- package/dist/server/app-rsc-error-handler.d.ts +2 -1
- package/dist/server/app-rsc-error-handler.js +9 -1
- package/dist/server/app-rsc-errors.d.ts +8 -0
- package/dist/server/app-rsc-errors.js +8 -1
- package/dist/server/app-rsc-handler.d.ts +5 -5
- package/dist/server/app-rsc-handler.js +30 -24
- package/dist/server/app-rsc-request-normalization.d.ts +0 -4
- package/dist/server/app-rsc-request-normalization.js +1 -4
- package/dist/server/app-rsc-response-finalizer.js +2 -2
- package/dist/server/app-rsc-response-stage.js +5 -3
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +7 -4
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +9 -8
- 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 +25 -3
- package/dist/server/app-worker-stages.js +45 -6
- package/dist/server/artifact-compatibility.d.ts +0 -1
- package/dist/server/artifact-compatibility.js +1 -10
- package/dist/server/cache-proof.d.ts +1 -115
- package/dist/server/cache-proof.js +1 -544
- package/dist/server/cacheability-request.js +13 -8
- package/dist/server/dev-server.js +4 -3
- package/dist/server/headers.d.ts +6 -3
- package/dist/server/headers.js +9 -5
- package/dist/server/isr-cache.d.ts +8 -2
- package/dist/server/isr-cache.js +26 -1
- package/dist/server/metadata-route-response.js +32 -15
- package/dist/server/multi-stage.d.ts +52 -11
- 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.js +52 -27
- package/dist/server/pages-page-handler.js +11 -20
- 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 +14 -12
- package/dist/server/pages-response-stage-entry.js +9 -3
- package/dist/server/prod-server.js +5 -1
- package/dist/server/request-pipeline.d.ts +6 -0
- package/dist/server/request-pipeline.js +21 -1
- package/dist/server/shared-cache-identity.d.ts +23 -0
- package/dist/server/shared-cache-identity.js +36 -0
- 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 +17 -20
- package/dist/shims/cache-request-state.js +16 -21
- package/dist/shims/cache-runtime.js +27 -11
- package/dist/shims/cache.d.ts +8 -7
- package/dist/shims/cache.js +17 -19
- package/dist/shims/cacheability-classification.d.ts +2 -0
- package/dist/shims/cdn-cache.d.ts +22 -5
- 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 +34 -24
- package/dist/shims/form.js +2 -2
- package/dist/shims/headers.d.ts +8 -23
- package/dist/shims/headers.js +17 -67
- package/dist/shims/internal/navigation-untracked.js +1 -1
- package/dist/shims/link.js +3 -1
- 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 +183 -29
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/request-state-types.d.ts +2 -2
- package/dist/shims/slot.d.ts +12 -0
- package/dist/shims/slot.js +37 -9
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +2 -3
- package/dist/utils/cache-control-metadata.d.ts +5 -0
- package/dist/utils/cache-control-metadata.js +9 -1
- 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
|
@@ -13,8 +13,8 @@ import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCachea
|
|
|
13
13
|
import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, hasExplicitNonCacheableResponsePolicy, isCdnResponsePolicyHeader, shouldUseNextDeployCacheControl } from "./cache-control.js";
|
|
14
14
|
import { buildMissIsrCacheControl } from "./isr-decision.js";
|
|
15
15
|
import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
|
|
16
|
-
import {
|
|
17
|
-
import { ensureFetchPatch } from "../shims/fetch-cache.js";
|
|
16
|
+
import { coalesceOnDemandResponse, isrGet, isrSet, pagesIsrCacheKey, triggerBackgroundRegeneration } from "./isr-cache.js";
|
|
17
|
+
import { ensureFetchPatch, setCurrentFetchDraftMode } from "../shims/fetch-cache.js";
|
|
18
18
|
import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
|
|
19
19
|
import { getScriptNonceFromHeaderSources } from "./csp.js";
|
|
20
20
|
import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
|
|
@@ -258,23 +258,10 @@ function createPagesPageHandler(opts) {
|
|
|
258
258
|
const isStaticPropsRender = isStaticPropsRoute && typeof pageModule.getServerSideProps !== "function";
|
|
259
259
|
if (!options?.__skipOnDemandCoalesce && !options?.__forcedRoute && !cacheIdentityDiverges && isStaticPropsRoute && isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"))) {
|
|
260
260
|
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
|
-
});
|
|
261
|
+
return coalesceOnDemandResponse(cacheKey, request.method, () => renderPage(request, url, manifest, middlewareHeaders, {
|
|
262
|
+
...options,
|
|
263
|
+
__skipOnDemandCoalesce: true
|
|
264
|
+
}, initialResponseHeaders));
|
|
278
265
|
}
|
|
279
266
|
const routePattern = patternToNextFormat(route.pattern);
|
|
280
267
|
const renderStatusCode = renderStatusCodeOverride ?? (routePattern === "/404" ? 404 : void 0);
|
|
@@ -283,7 +270,10 @@ function createPagesPageHandler(opts) {
|
|
|
283
270
|
const renderRouteUrl = isStaticPropsRender && isStatusPageIdentity ? resolvePagesStatusPageRenderPath(statusPagePathname, vinextConfig.trailingSlash, originalRequestUrl.pathname) : isStaticPropsRender ? routeUrl.split("?")[0] : routeUrl;
|
|
284
271
|
const routerAsPathSource = isStaticPropsRender ? renderRouteUrl : renderAsPath ?? renderRouteUrl;
|
|
285
272
|
const routerAsPath = i18nConfig ? extractLocaleFromUrl(routerAsPathSource, i18nConfig, locale).url : routerAsPathSource;
|
|
286
|
-
const uCtx = createRequestContext({
|
|
273
|
+
const uCtx = createRequestContext({
|
|
274
|
+
executionContext: getRequestExecutionContext(),
|
|
275
|
+
isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER))
|
|
276
|
+
});
|
|
287
277
|
let pageReqRes = null;
|
|
288
278
|
const pageResponseSent = () => pageReqRes?.res.headersSent === true;
|
|
289
279
|
const sendsEarly = isStaticPropsRoute && !isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"));
|
|
@@ -322,6 +312,7 @@ function createPagesPageHandler(opts) {
|
|
|
322
312
|
shouldClear: false
|
|
323
313
|
};
|
|
324
314
|
const previewData = preview.data;
|
|
315
|
+
setCurrentFetchDraftMode(previewData !== false);
|
|
325
316
|
const pagesNextData = {
|
|
326
317
|
...pagesReadiness,
|
|
327
318
|
...previewData === false ? {} : { isPreview: true }
|
|
@@ -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",
|
|
@@ -3,7 +3,7 @@ import { requestContextFromRequest } from "../config/request-context.js";
|
|
|
3
3
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
4
4
|
import { VINEXT_CACHEABILITY_PROBE_QUERY_PARAM, VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "./headers.js";
|
|
5
5
|
import { notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
6
|
-
import { attachRequestCfMetadata,
|
|
6
|
+
import { attachRequestCfMetadata, cloneRequestWithUrl, filterInternalHeaders, guardProtocolRelativeUrl, haveSameHeaders, withRequestHeaders } from "./request-pipeline.js";
|
|
7
7
|
import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
|
|
8
8
|
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
9
9
|
import { runWithExecutionContext } from "../shims/request-context.js";
|
|
@@ -22,7 +22,8 @@ import { resolveClientBuildFile } from "./client-build-files.js";
|
|
|
22
22
|
import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
|
|
23
23
|
import { createWorkerPrerenderDiscoveryContext, createWorkerPrerenderReadinessResponse, isWorkerPrerenderDiscoveryPath } from "./worker-prerender-discovery.js";
|
|
24
24
|
import { getPagesResponseStageCacheDisposition } from "./pages-response-stage.js";
|
|
25
|
-
import "./
|
|
25
|
+
import { adapterUsesSharedCacheIdentity, pagesCacheIdentityOrigin, pagesPageSharesAcrossHosts } from "./shared-cache-identity.js";
|
|
26
|
+
import { createSharedPagesPageCacheIdentity } from "./worker-stages.js";
|
|
26
27
|
import { consumePagesResponseStagePolicyOwner, prependResponseStageAdditiveHeaders, withResponseStageVary, withoutResponseStageVary } from "./response-stage-policy.js";
|
|
27
28
|
import * as configuredCdnCacheAdapters from "virtual:vinext-cdn-cache-adapter";
|
|
28
29
|
import { registerConfiguredImageOptimizer } from "virtual:vinext-image-adapters";
|
|
@@ -34,11 +35,6 @@ import * as pagesEntry from "virtual:vinext-pages-request-entry";
|
|
|
34
35
|
* The public pages-router-entry delegates here. Multi-stage hosts import the
|
|
35
36
|
* named request handler directly and provide their response-stage dispatcher.
|
|
36
37
|
*/
|
|
37
|
-
function haveSameHeaders(first, second) {
|
|
38
|
-
const firstEntries = [...first];
|
|
39
|
-
const secondEntries = [...second];
|
|
40
|
-
return firstEntries.length === secondEntries.length && firstEntries.every(([name, value], index) => name === secondEntries[index]?.[0] && value === secondEntries[index]?.[1]);
|
|
41
|
-
}
|
|
42
38
|
function captureOuterResponsePolicyHeaders(stagedHeaders, transportedPolicyHeaders) {
|
|
43
39
|
return captureCdnResponsePolicyOverrides(stagedHeaders, new Headers(transportedPolicyHeaders ?? []));
|
|
44
40
|
}
|
|
@@ -151,7 +147,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
|
|
|
151
147
|
const expectedWorkerVersion = request.headers.get(VINEXT_EXPECTED_WORKER_VERSION_HEADER);
|
|
152
148
|
if (expectedWorkerVersion) filteredHeaders.set(VINEXT_EXPECTED_WORKER_VERSION_HEADER, expectedWorkerVersion);
|
|
153
149
|
}
|
|
154
|
-
request =
|
|
150
|
+
request = withRequestHeaders(request, filteredHeaders);
|
|
155
151
|
const url = new URL(request.url);
|
|
156
152
|
let pathname = url.pathname;
|
|
157
153
|
if (ctx.isPrerenderPathDiscovery && isWorkerPrerenderDiscoveryPath(pathname)) return trackedDispatchResponseStage(request, {
|
|
@@ -162,7 +158,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
|
|
|
162
158
|
resolvedRoutePathname: pathname
|
|
163
159
|
},
|
|
164
160
|
kind: "pages-prerender-discovery",
|
|
165
|
-
protocolVersion:
|
|
161
|
+
protocolVersion: 6,
|
|
166
162
|
requestHost: url.host,
|
|
167
163
|
stagedHeaders: null
|
|
168
164
|
}, { cache: "bypass" }, env, ctx);
|
|
@@ -247,6 +243,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
|
|
|
247
243
|
stagedHeaders
|
|
248
244
|
});
|
|
249
245
|
const isSharedStaticPage = cache === "shared" && matchedPage?.route.dataKind === "static";
|
|
246
|
+
const sharedAcrossHosts = (cache === "shared" || probeMode !== null) && pagesPageSharesAcrossHosts(matchedPage?.route) && adapterUsesSharedCacheIdentity();
|
|
250
247
|
const transportedPolicyHeaders = isSharedStaticPage ? withoutResponseStageVary(responseStagePolicyHeaders) : withResponseStageVary(responseStagePolicyHeaders, stagedHeaders?.get("Vary"));
|
|
251
248
|
const responseStageProps = () => ({
|
|
252
249
|
buildId: pagesEntry.buildId,
|
|
@@ -257,17 +254,22 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
|
|
|
257
254
|
resolvedRoutePathname: new URL(resolvedUrl, req.url).pathname
|
|
258
255
|
},
|
|
259
256
|
kind: "pages-page",
|
|
260
|
-
protocolVersion:
|
|
257
|
+
protocolVersion: 6,
|
|
261
258
|
requestHost: new URL(req.url).host,
|
|
262
259
|
renderOptions: isDataReq ? {
|
|
263
260
|
...options,
|
|
264
261
|
originalUrl: originalRenderUrl
|
|
265
262
|
} : options ?? null,
|
|
266
263
|
resolvedUrl,
|
|
264
|
+
sharedAcrossHosts,
|
|
267
265
|
stagedHeaders: isSharedStaticPage ? null : [...stagedHeaders ?? new Headers()]
|
|
268
266
|
});
|
|
269
267
|
const isHeadRequest = req.method.toUpperCase() === "HEAD";
|
|
270
|
-
const
|
|
268
|
+
const props = responseStageProps();
|
|
269
|
+
const responsePromise = trackedDispatchResponseStage(stageRequest, props, cache === "shared" && sharedAcrossHosts ? {
|
|
270
|
+
cache,
|
|
271
|
+
cacheIdentity: createSharedPagesPageCacheIdentity(stageRequest, props, pagesCacheIdentityOrigin(stageRequest.url, i18nConfig))
|
|
272
|
+
} : { cache }, env, ctx).then((response) => {
|
|
271
273
|
const consumed = consumePagesResponseStagePolicyOwner(response);
|
|
272
274
|
if (cache === "shared") {
|
|
273
275
|
if (isSharedStaticPage && stagedHeaders) prependResponseStageAdditiveHeaders(consumed.response.headers, stagedHeaders);
|
|
@@ -297,7 +299,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
|
|
|
297
299
|
resolvedRoutePathname: new URL(apiUrl, req.url).pathname
|
|
298
300
|
},
|
|
299
301
|
kind: "pages-api",
|
|
300
|
-
protocolVersion:
|
|
302
|
+
protocolVersion: 6,
|
|
301
303
|
requestHost: new URL(req.url).host,
|
|
302
304
|
stagedHeaders: [...stagedHeaders]
|
|
303
305
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
|
|
2
2
|
import "../shims/unified-request-context.js";
|
|
3
3
|
import { runWithExecutionContext } from "../shims/request-context.js";
|
|
4
|
-
import { beginRouteCacheability } from "../shims/cacheability-classification.js";
|
|
4
|
+
import { beginRouteCacheability, markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
|
|
5
5
|
import { validateCdnRequest } from "./cache-control.js";
|
|
6
6
|
import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
|
|
7
7
|
import { createWorkerPrerenderReadinessResponse } from "./worker-prerender-discovery.js";
|
|
@@ -57,6 +57,12 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
|
|
|
57
57
|
...ctx,
|
|
58
58
|
isStoredEntryRegeneration: true
|
|
59
59
|
};
|
|
60
|
+
let runtimeDataKind;
|
|
61
|
+
const runtimeDataKindIsRequestTime = () => {
|
|
62
|
+
if (props.kind !== "pages-page") return false;
|
|
63
|
+
runtimeDataKind ??= pagesEntry.getRuntimePageDataKind(props.resolvedUrl, request);
|
|
64
|
+
return runtimeDataKind === "server" || runtimeDataKind === "initial";
|
|
65
|
+
};
|
|
60
66
|
const render = async (cacheabilityContext) => {
|
|
61
67
|
if (props.kind === "pages-prerender-discovery") {
|
|
62
68
|
const readinessResponse = createWorkerPrerenderReadinessResponse(cacheabilityContext, request);
|
|
@@ -77,6 +83,7 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
|
|
|
77
83
|
});
|
|
78
84
|
}
|
|
79
85
|
if (typeof pagesEntry.renderPage !== "function") return new Response("This page could not be found", { status: 404 });
|
|
86
|
+
if (props.sharedAcrossHosts && runtimeDataKindIsRequestTime()) runWithExecutionContext(cacheabilityContext, () => markRouteCacheabilityDynamic("getInitialProps render shares a cache entry across hosts"));
|
|
80
87
|
return stripStreamedHtmlContentLength(await pagesEntry.renderPage(request, props.resolvedUrl, null, cacheabilityContext, renderHeaders, props.renderOptions ?? void 0, initialResponseHeaders));
|
|
81
88
|
};
|
|
82
89
|
const handle = async (cacheabilityContext) => stripInheritedResponseStageCookies(await render(cacheabilityContext), renderHeaders);
|
|
@@ -94,9 +101,8 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
|
|
|
94
101
|
resolvedRoutePathname: props.cacheability.resolvedRoutePathname
|
|
95
102
|
}, handle);
|
|
96
103
|
if (props.kind !== "pages-page") return response;
|
|
97
|
-
const runtimeDataKind = pagesEntry.getRuntimePageDataKind(props.resolvedUrl, request);
|
|
98
104
|
const headers = new Headers(response.headers);
|
|
99
|
-
headers.set(PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER,
|
|
105
|
+
headers.set(PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER, runtimeDataKindIsRequestTime() ? "request-time" : "static");
|
|
100
106
|
return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
|
|
101
107
|
headers,
|
|
102
108
|
status: response.status,
|
|
@@ -1646,7 +1646,11 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1646
1646
|
...options,
|
|
1647
1647
|
originalUrl: originalRenderUrl
|
|
1648
1648
|
}, stagedHeaders?.has("Cache-Control") ? new Headers({ "Cache-Control": stagedHeaders.get("Cache-Control") }) : void 0) : null,
|
|
1649
|
-
handleApi: typeof handleApi === "function" ? (request, apiUrl
|
|
1649
|
+
handleApi: typeof handleApi === "function" ? (request, apiUrl, _ctx, stagedHeaders) => {
|
|
1650
|
+
stagedHeaders.delete("Content-Length");
|
|
1651
|
+
return handleApi(request, apiUrl, createNodeExecutionContext(), resolveTrustedNodeRevalidateOrigin(req, host, port), "node", stagedHeaders);
|
|
1652
|
+
} : null,
|
|
1653
|
+
handleApiAppliesStagedHeaders: true,
|
|
1650
1654
|
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl, _request, resolvedPathnameHasBasePath) => {
|
|
1651
1655
|
if (resolvedPathnameHasBasePath && isImageOptimizationPath(requestPathname)) {
|
|
1652
1656
|
for (const [name, value] of Object.entries(stagedHeaders)) res.setHeader(name, value);
|
|
@@ -181,6 +181,12 @@ export declare function attachRequestCfMetadata(target: Request, source: Request
|
|
|
181
181
|
* a RequestInit with best-effort metadata.
|
|
182
182
|
*/
|
|
183
183
|
export declare function cloneRequestWithHeaders(request: Request, headers: Headers): Request;
|
|
184
|
+
export declare function haveSameHeaders(first: Headers, second: Headers): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* `cloneRequestWithHeaders`, except that a native request whose headers
|
|
187
|
+
* already match is returned as is, so its body stays where it is.
|
|
188
|
+
*/
|
|
189
|
+
export declare function withRequestHeaders(request: Request, headers: Headers): Request;
|
|
184
190
|
/**
|
|
185
191
|
* Clone a Request while overriding the URL, preserving headers and metadata
|
|
186
192
|
* when possible.
|
|
@@ -407,6 +407,26 @@ function cloneRequestWithHeaders(request, headers) {
|
|
|
407
407
|
}
|
|
408
408
|
return attachRequestCfMetadata(cloned, request);
|
|
409
409
|
}
|
|
410
|
+
function haveSameHeaders(first, second) {
|
|
411
|
+
const firstEntries = [...first];
|
|
412
|
+
const secondEntries = [...second];
|
|
413
|
+
return firstEntries.length === secondEntries.length && firstEntries.every(([name, value], index) => name === secondEntries[index]?.[0] && value === secondEntries[index]?.[1]);
|
|
414
|
+
}
|
|
415
|
+
function isNativeRequest(request) {
|
|
416
|
+
try {
|
|
417
|
+
Reflect.get(Request.prototype, "url", request);
|
|
418
|
+
return true;
|
|
419
|
+
} catch {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* `cloneRequestWithHeaders`, except that a native request whose headers
|
|
425
|
+
* already match is returned as is, so its body stays where it is.
|
|
426
|
+
*/
|
|
427
|
+
function withRequestHeaders(request, headers) {
|
|
428
|
+
return isNativeRequest(request) && haveSameHeaders(headers, request.headers) ? request : cloneRequestWithHeaders(request, headers);
|
|
429
|
+
}
|
|
410
430
|
/**
|
|
411
431
|
* Clone a Request while overriding the URL, preserving headers and metadata
|
|
412
432
|
* when possible.
|
|
@@ -444,4 +464,4 @@ function cloneRequestWithUrl(request, url) {
|
|
|
444
464
|
return attachRequestCfMetadata(cloned, request);
|
|
445
465
|
}
|
|
446
466
|
//#endregion
|
|
447
|
-
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, attachRequestCfMetadata, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, dropEmptyMiddlewareSetCookie, filterInternalHeaders, getRepeatedSlashRedirect, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, sendRepeatedSlashRedirect, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
467
|
+
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, attachRequestCfMetadata, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, dropEmptyMiddlewareSetCookie, filterInternalHeaders, getRepeatedSlashRedirect, guardProtocolRelativeUrl, hasBasePath, haveSameHeaders, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, sendRepeatedSlashRedirect, stripBasePath, validateCsrfOrigin, validateServerActionPayload, withRequestHeaders };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NextI18nConfig } from "../config/next-config.js";
|
|
2
|
+
//#region src/server/shared-cache-identity.d.ts
|
|
3
|
+
/** The core cache identity the configured adapter keys shared dispatches by, if any. */
|
|
4
|
+
export declare function adapterSharedCacheIdentity(): "host-free" | "query-free" | null;
|
|
5
|
+
/** Whether the configured adapter keys shared dispatches by a core cache identity. */
|
|
6
|
+
export declare function adapterUsesSharedCacheIdentity(): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Whether a Pages page's response is one for every host, as Next.js serves a
|
|
9
|
+
* getStaticProps page and an automatically static page. A page without data
|
|
10
|
+
* functions is rendered per request when its getInitialProps or a custom
|
|
11
|
+
* _app's runs, and may read the host, so it keeps the host in its key.
|
|
12
|
+
*/
|
|
13
|
+
export declare function pagesPageSharesAcrossHosts(route: {
|
|
14
|
+
dataKind?: string;
|
|
15
|
+
runsInitialProps?: boolean;
|
|
16
|
+
} | null | undefined): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The origin a shared Pages page identity names. A static Pages render reads
|
|
19
|
+
* the host only to select a configured i18n domain, so the identity keeps that
|
|
20
|
+
* domain, as vinext's Pages ISR key does, and every other host shares one entry.
|
|
21
|
+
*/
|
|
22
|
+
export declare function pagesCacheIdentityOrigin(requestUrl: string, i18nConfig: NextI18nConfig | null | undefined): string;
|
|
23
|
+
//#endregion
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { detectDomainLocale, normalizeDomainHostname } from "../utils/domain-locale.js";
|
|
2
|
+
import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
|
|
3
|
+
import { VINEXT_CACHE_IDENTITY_ORIGIN } from "./multi-stage.js";
|
|
4
|
+
//#region src/server/shared-cache-identity.ts
|
|
5
|
+
/** The core cache identity the configured adapter keys shared dispatches by, if any. */
|
|
6
|
+
function adapterSharedCacheIdentity() {
|
|
7
|
+
const adapter = getCdnCacheAdapter();
|
|
8
|
+
if (adapter.requiresCompletedResponseAdmission !== true) return null;
|
|
9
|
+
return adapter.responseStageCacheIdentity ?? null;
|
|
10
|
+
}
|
|
11
|
+
/** Whether the configured adapter keys shared dispatches by a core cache identity. */
|
|
12
|
+
function adapterUsesSharedCacheIdentity() {
|
|
13
|
+
return adapterSharedCacheIdentity() !== null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether a Pages page's response is one for every host, as Next.js serves a
|
|
17
|
+
* getStaticProps page and an automatically static page. A page without data
|
|
18
|
+
* functions is rendered per request when its getInitialProps or a custom
|
|
19
|
+
* _app's runs, and may read the host, so it keeps the host in its key.
|
|
20
|
+
*/
|
|
21
|
+
function pagesPageSharesAcrossHosts(route) {
|
|
22
|
+
if (route?.dataKind === "static") return true;
|
|
23
|
+
return route?.dataKind === "none" && route.runsInitialProps !== true;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The origin a shared Pages page identity names. A static Pages render reads
|
|
27
|
+
* the host only to select a configured i18n domain, so the identity keeps that
|
|
28
|
+
* domain, as vinext's Pages ISR key does, and every other host shares one entry.
|
|
29
|
+
*/
|
|
30
|
+
function pagesCacheIdentityOrigin(requestUrl, i18nConfig) {
|
|
31
|
+
const domainLocale = detectDomainLocale(i18nConfig?.domains, new URL(requestUrl).hostname);
|
|
32
|
+
if (!domainLocale) return VINEXT_CACHE_IDENTITY_ORIGIN;
|
|
33
|
+
return `${domainLocale.http ? "http" : "https"}://${normalizeDomainHostname(domainLocale.domain)}`;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { adapterSharedCacheIdentity, adapterUsesSharedCacheIdentity, pagesCacheIdentityOrigin, pagesPageSharesAcrossHosts };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { VinextResponseStageCacheability, VinextResponseStageTransport } from "./multi-stage.js";
|
|
1
|
+
import { VinextResponseStageCacheability, VinextResponseStageDispatchOptions, VinextResponseStageTransport } from "./multi-stage.js";
|
|
2
2
|
import { PagesRenderOptions } from "./pages-request-pipeline.js";
|
|
3
3
|
//#region src/server/worker-stages.d.ts
|
|
4
|
-
export declare const PAGES_RESPONSE_STAGE_PROTOCOL_VERSION =
|
|
4
|
+
export declare const PAGES_RESPONSE_STAGE_PROTOCOL_VERSION = 6;
|
|
5
5
|
export declare const PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER = "x-vinext-pages-response-stage-policy-owner";
|
|
6
6
|
export type PagesResponseStagePolicyOwner = "request-time" | "static";
|
|
7
7
|
type PagesResponseStageEnvelope = {
|
|
@@ -14,10 +14,16 @@ type PagesResponseStageEnvelope = {
|
|
|
14
14
|
stagedHeaders: Array<[string, string]> | null;
|
|
15
15
|
};
|
|
16
16
|
/** Serializable Pages page render delegated to a cacheable Worker stage. */
|
|
17
|
-
type PagesPageResponseStageProps = PagesResponseStageEnvelope & {
|
|
17
|
+
export type PagesPageResponseStageProps = PagesResponseStageEnvelope & {
|
|
18
18
|
kind: "pages-page";
|
|
19
19
|
renderOptions: PagesRenderOptions | null;
|
|
20
20
|
resolvedUrl: string;
|
|
21
|
+
/**
|
|
22
|
+
* The shared cache entry answers every host, as Next.js keys a static page
|
|
23
|
+
* by its path, so a getInitialProps render of a page without
|
|
24
|
+
* getStaticProps, which reads the request, is not stored.
|
|
25
|
+
*/
|
|
26
|
+
sharedAcrossHosts: boolean;
|
|
21
27
|
};
|
|
22
28
|
/** Serializable Pages API dispatch delegated to a cacheable Worker stage. */
|
|
23
29
|
type PagesApiResponseStageProps = PagesResponseStageEnvelope & {
|
|
@@ -39,6 +45,13 @@ export type WorkerResponseStageProps = PagesApiResponseStageProps | PagesPageRes
|
|
|
39
45
|
* response as Next.js.
|
|
40
46
|
*/
|
|
41
47
|
export type DispatchWorkerResponseStage = VinextResponseStageTransport<WorkerResponseStageProps>;
|
|
48
|
+
type PagesPageResponseStageCacheIdentity = NonNullable<VinextResponseStageDispatchOptions["cacheIdentity"]>;
|
|
49
|
+
/**
|
|
50
|
+
* Build the cache identity of a shared Pages page dispatch: the dispatched
|
|
51
|
+
* request and props under `origin`, so every host that names it shares one
|
|
52
|
+
* entry.
|
|
53
|
+
*/
|
|
54
|
+
export declare function createSharedPagesPageCacheIdentity(request: Request, props: PagesPageResponseStageProps, origin: string): PagesPageResponseStageCacheIdentity;
|
|
42
55
|
export declare function isPagesResponseStageProps(value: unknown): value is WorkerResponseStageProps;
|
|
43
56
|
//#endregion
|
|
44
57
|
export {};
|
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
import { withCacheIdentityOrigin } from "./multi-stage.js";
|
|
1
2
|
//#region src/server/worker-stages.ts
|
|
2
|
-
const PAGES_RESPONSE_STAGE_PROTOCOL_VERSION =
|
|
3
|
+
const PAGES_RESPONSE_STAGE_PROTOCOL_VERSION = 6;
|
|
3
4
|
const PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER = "x-vinext-pages-response-stage-policy-owner";
|
|
5
|
+
/**
|
|
6
|
+
* Build the cache identity of a shared Pages page dispatch: the dispatched
|
|
7
|
+
* request and props under `origin`, so every host that names it shares one
|
|
8
|
+
* entry.
|
|
9
|
+
*/
|
|
10
|
+
function createSharedPagesPageCacheIdentity(request, props, origin) {
|
|
11
|
+
return {
|
|
12
|
+
props: {
|
|
13
|
+
...props,
|
|
14
|
+
requestHost: new URL(origin).host
|
|
15
|
+
},
|
|
16
|
+
regenerateFromDispatch: true,
|
|
17
|
+
request: new Request(withCacheIdentityOrigin(request.url, origin), {
|
|
18
|
+
headers: new Headers(request.headers),
|
|
19
|
+
method: request.method
|
|
20
|
+
})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
4
23
|
function isSerializedHeaders(value) {
|
|
5
24
|
return Array.isArray(value) && value.every((entry) => Array.isArray(entry) && entry.length === 2 && typeof entry[0] === "string" && typeof entry[1] === "string");
|
|
6
25
|
}
|
|
@@ -12,14 +31,14 @@ function isResponseStageCacheability(value) {
|
|
|
12
31
|
function isPagesResponseStageProps(value) {
|
|
13
32
|
if (!value || typeof value !== "object") return false;
|
|
14
33
|
const props = value;
|
|
15
|
-
if (props.protocolVersion !==
|
|
34
|
+
if (props.protocolVersion !== 6 || props.buildId !== null && typeof props.buildId !== "string" || !isResponseStageCacheability(props.cacheability) || typeof props.requestHost !== "string" || props.requestHost.length === 0 || props.stagedHeaders !== null && !isSerializedHeaders(props.stagedHeaders)) return false;
|
|
16
35
|
if (props.kind === "pages-api") return typeof props.apiUrl === "string";
|
|
17
36
|
if (props.kind === "pages-prerender-discovery") return true;
|
|
18
|
-
if (props.kind !== "pages-page" || typeof props.resolvedUrl !== "string") return false;
|
|
37
|
+
if (props.kind !== "pages-page" || typeof props.resolvedUrl !== "string" || typeof props.sharedAcrossHosts !== "boolean") return false;
|
|
19
38
|
if (props.renderOptions === null) return true;
|
|
20
39
|
if (!props.renderOptions || typeof props.renderOptions !== "object") return false;
|
|
21
40
|
const options = props.renderOptions;
|
|
22
41
|
return (options.isDataReq === void 0 || typeof options.isDataReq === "boolean") && (options.renderErrorPageOnMiss === void 0 || typeof options.renderErrorPageOnMiss === "boolean") && (options.originalUrl === void 0 || typeof options.originalUrl === "string");
|
|
23
42
|
}
|
|
24
43
|
//#endregion
|
|
25
|
-
export { PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER, PAGES_RESPONSE_STAGE_PROTOCOL_VERSION, isPagesResponseStageProps };
|
|
44
|
+
export { PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER, PAGES_RESPONSE_STAGE_PROTOCOL_VERSION, createSharedPagesPageCacheIdentity, isPagesResponseStageProps };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { shareIsolatePromise } from "../server/isolate-shared-promise.js";
|
|
2
|
-
import { readCacheControlNumberField, readCacheControlRevalidateField } from "../utils/cache-control-metadata.js";
|
|
2
|
+
import { readCacheControlNumberField, readCacheControlRevalidateField, readCacheTimestamp } from "../utils/cache-control-metadata.js";
|
|
3
3
|
//#region src/shims/cache-handler.ts
|
|
4
4
|
var NoOpCacheHandler = class {
|
|
5
5
|
async get(_key, _ctx) {
|
|
@@ -122,7 +122,7 @@ var MemoryCacheHandler = class {
|
|
|
122
122
|
if (data && "revalidate" in data && typeof data.revalidate === "number") effectiveRevalidate = data.revalidate;
|
|
123
123
|
else if (data && "revalidate" in data && data.revalidate === false) effectiveRevalidate ??= false;
|
|
124
124
|
if (effectiveRevalidate === 0) return;
|
|
125
|
-
const now = Date.now();
|
|
125
|
+
const now = readCacheTimestamp(ctx, Date.now());
|
|
126
126
|
const revalidateAt = typeof effectiveRevalidate === "number" && effectiveRevalidate > 0 ? now + effectiveRevalidate * 1e3 : null;
|
|
127
127
|
const expireAt = typeof effectiveExpire === "number" && effectiveExpire > 0 ? now + effectiveExpire * 1e3 : null;
|
|
128
128
|
const cacheControl = typeof effectiveRevalidate === "number" || effectiveRevalidate === false ? {
|
|
@@ -8,21 +8,6 @@ export type CacheLifeConfig = {
|
|
|
8
8
|
export declare const cacheLifeProfiles: Record<string, CacheLifeConfig>;
|
|
9
9
|
export type UnstableCacheRevalidationMode = "foreground" | "background";
|
|
10
10
|
export type ActionRevalidationKind = 0 | 1 | 2;
|
|
11
|
-
export type UnstableCacheObservation = Readonly<{
|
|
12
|
-
kind: "unstable_cache";
|
|
13
|
-
keyHash: string;
|
|
14
|
-
revalidate: number | false | null;
|
|
15
|
-
tagCount: number;
|
|
16
|
-
tagHash: string | null;
|
|
17
|
-
}>;
|
|
18
|
-
/**
|
|
19
|
-
* Collects the cacheLife claims made anywhere below the scope that installed
|
|
20
|
-
* it, including nested scopes that reset `requestScopedCacheLife`. Shallow
|
|
21
|
-
* scope clones share it by reference.
|
|
22
|
-
*/
|
|
23
|
-
export type CacheLifeSink = {
|
|
24
|
-
cacheLife: CacheLifeConfig | null;
|
|
25
|
-
};
|
|
26
11
|
type TagInvalidationDurations = {
|
|
27
12
|
expire?: number;
|
|
28
13
|
} | undefined;
|
|
@@ -34,12 +19,17 @@ export type PendingCdnTagInvalidation = Readonly<{
|
|
|
34
19
|
}>;
|
|
35
20
|
export type CacheState = {
|
|
36
21
|
actionRevalidationKind: ActionRevalidationKind;
|
|
37
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The request is an authorized on-demand revalidation (`res.revalidate()`).
|
|
24
|
+
* Like Next.js's `workStore.isOnDemandRevalidate`, the data caches then skip
|
|
25
|
+
* their reads but still execute and store fresh results. Set once when the
|
|
26
|
+
* request context is created; nested scopes inherit it.
|
|
27
|
+
*/
|
|
28
|
+
isOnDemandRevalidate: boolean;
|
|
38
29
|
pendingCdnTagInvalidations: PendingCdnTagInvalidation[];
|
|
39
30
|
pendingRevalidatedTags: Set<string>;
|
|
40
31
|
pendingRevalidations: Set<Promise<void>>;
|
|
41
32
|
requestScopedCacheLife: CacheLifeConfig | null;
|
|
42
|
-
unstableCacheObservations: Map<string, UnstableCacheObservation>;
|
|
43
33
|
unstableCacheRevalidation: UnstableCacheRevalidationMode;
|
|
44
34
|
};
|
|
45
35
|
export declare const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
|
|
@@ -47,6 +37,15 @@ export declare const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
|
|
|
47
37
|
export declare function _runWithCacheState<T>(fn: () => Promise<T>): Promise<T>;
|
|
48
38
|
export declare function _runWithCacheState<T>(fn: () => T | Promise<T>): T | Promise<T>;
|
|
49
39
|
export declare function _initRequestScopedCacheState(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the current request is an authorized on-demand revalidation, so the
|
|
42
|
+
* data caches must skip their reads (not their writes). Mirrors Next.js's
|
|
43
|
+
* `workStore.isOnDemandRevalidate` checks in use-cache-wrapper, patch-fetch
|
|
44
|
+
* and unstable-cache.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function _isOnDemandRevalidate(): boolean;
|
|
50
49
|
export declare function markActionRevalidation(kind: ActionRevalidationKind): void;
|
|
51
50
|
export declare function getAndClearActionRevalidationKind(): ActionRevalidationKind;
|
|
52
51
|
/** @internal */
|
|
@@ -114,11 +113,9 @@ export declare function _captureRequestScopedCacheLifeAccessors(): {
|
|
|
114
113
|
consume: () => CacheLifeConfig | null;
|
|
115
114
|
peek: () => CacheLifeConfig | null;
|
|
116
115
|
};
|
|
117
|
-
export declare function recordUnstableCacheObservation(observation: UnstableCacheObservation): void;
|
|
118
|
-
export declare function _peekUnstableCacheObservations(): UnstableCacheObservation[];
|
|
119
116
|
/**
|
|
120
117
|
* Run `fn` with the request's cache settings, including its revalidation mode,
|
|
121
|
-
* but its own record of cache lives
|
|
118
|
+
* but its own record of cache lives, so work
|
|
122
119
|
* done on the request's behalf after the fact leaves the request untouched.
|
|
123
120
|
*/
|
|
124
121
|
export declare function runWithDetachedCacheObservations<T>(fn: () => Promise<T>): Promise<T>;
|
|
@@ -48,12 +48,11 @@ const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
|
|
|
48
48
|
const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
|
|
49
49
|
const fallbackState = globalState[FALLBACK_KEY] ??= {
|
|
50
50
|
actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
|
|
51
|
-
|
|
51
|
+
isOnDemandRevalidate: false,
|
|
52
52
|
pendingCdnTagInvalidations: [],
|
|
53
53
|
pendingRevalidatedTags: /* @__PURE__ */ new Set(),
|
|
54
54
|
pendingRevalidations: /* @__PURE__ */ new Set(),
|
|
55
55
|
requestScopedCacheLife: null,
|
|
56
|
-
unstableCacheObservations: /* @__PURE__ */ new Map(),
|
|
57
56
|
unstableCacheRevalidation: "foreground"
|
|
58
57
|
};
|
|
59
58
|
function getCacheState() {
|
|
@@ -63,19 +62,16 @@ function getCacheState() {
|
|
|
63
62
|
function _runWithCacheState(fn) {
|
|
64
63
|
if (isInsideUnifiedScope()) return runWithUnifiedStateMutation((context) => {
|
|
65
64
|
context.actionRevalidationKind = ACTION_DID_NOT_REVALIDATE;
|
|
66
|
-
context.cacheLifeSink = null;
|
|
67
65
|
context.requestScopedCacheLife = null;
|
|
68
|
-
context.unstableCacheObservations = /* @__PURE__ */ new Map();
|
|
69
66
|
context.unstableCacheRevalidation = "foreground";
|
|
70
67
|
}, fn);
|
|
71
68
|
const state = {
|
|
72
69
|
actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
|
|
73
|
-
|
|
70
|
+
isOnDemandRevalidate: false,
|
|
74
71
|
pendingCdnTagInvalidations: [],
|
|
75
72
|
pendingRevalidatedTags: /* @__PURE__ */ new Set(),
|
|
76
73
|
pendingRevalidations: /* @__PURE__ */ new Set(),
|
|
77
74
|
requestScopedCacheLife: null,
|
|
78
|
-
unstableCacheObservations: /* @__PURE__ */ new Map(),
|
|
79
75
|
unstableCacheRevalidation: "foreground"
|
|
80
76
|
};
|
|
81
77
|
return cacheAls.run(state, fn);
|
|
@@ -84,7 +80,17 @@ function _initRequestScopedCacheState() {
|
|
|
84
80
|
const state = getCacheState();
|
|
85
81
|
state.actionRevalidationKind = ACTION_DID_NOT_REVALIDATE;
|
|
86
82
|
state.requestScopedCacheLife = null;
|
|
87
|
-
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Whether the current request is an authorized on-demand revalidation, so the
|
|
86
|
+
* data caches must skip their reads (not their writes). Mirrors Next.js's
|
|
87
|
+
* `workStore.isOnDemandRevalidate` checks in use-cache-wrapper, patch-fetch
|
|
88
|
+
* and unstable-cache.
|
|
89
|
+
*
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
function _isOnDemandRevalidate() {
|
|
93
|
+
return getCacheState().isOnDemandRevalidate === true;
|
|
88
94
|
}
|
|
89
95
|
function markActionRevalidation(kind) {
|
|
90
96
|
if (getHeadersAccessPhase() !== "action") return;
|
|
@@ -224,7 +230,6 @@ function mergeCacheLife(current, config) {
|
|
|
224
230
|
function _setRequestScopedCacheLife(config) {
|
|
225
231
|
const state = getCacheState();
|
|
226
232
|
state.requestScopedCacheLife = mergeCacheLife(state.requestScopedCacheLife, config);
|
|
227
|
-
if (state.cacheLifeSink) state.cacheLifeSink.cacheLife = mergeCacheLife(state.cacheLifeSink.cacheLife, config);
|
|
228
233
|
}
|
|
229
234
|
function _peekRequestScopedCacheLife() {
|
|
230
235
|
const config = getCacheState().requestScopedCacheLife;
|
|
@@ -257,32 +262,22 @@ function _captureRequestScopedCacheLifeAccessors() {
|
|
|
257
262
|
}
|
|
258
263
|
};
|
|
259
264
|
}
|
|
260
|
-
function recordUnstableCacheObservation(observation) {
|
|
261
|
-
getCacheState().unstableCacheObservations.set(observation.keyHash, observation);
|
|
262
|
-
}
|
|
263
|
-
function _peekUnstableCacheObservations() {
|
|
264
|
-
return [...getCacheState().unstableCacheObservations.values()].sort((a, b) => a.keyHash.localeCompare(b.keyHash));
|
|
265
|
-
}
|
|
266
265
|
/**
|
|
267
266
|
* Run `fn` with the request's cache settings, including its revalidation mode,
|
|
268
|
-
* but its own record of cache lives
|
|
267
|
+
* but its own record of cache lives, so work
|
|
269
268
|
* done on the request's behalf after the fact leaves the request untouched.
|
|
270
269
|
*/
|
|
271
270
|
function runWithDetachedCacheObservations(fn) {
|
|
272
271
|
if (isInsideUnifiedScope()) return runWithUnifiedStateMutation((context) => {
|
|
273
|
-
context.cacheLifeSink = null;
|
|
274
272
|
context.requestScopedCacheLife = null;
|
|
275
|
-
context.unstableCacheObservations = /* @__PURE__ */ new Map();
|
|
276
273
|
}, fn);
|
|
277
274
|
return cacheAls.run({
|
|
278
275
|
...getCacheState(),
|
|
279
|
-
|
|
280
|
-
requestScopedCacheLife: null,
|
|
281
|
-
unstableCacheObservations: /* @__PURE__ */ new Map()
|
|
276
|
+
requestScopedCacheLife: null
|
|
282
277
|
}, fn);
|
|
283
278
|
}
|
|
284
279
|
function shouldServeStaleUnstableCacheEntry() {
|
|
285
280
|
return getCacheState().unstableCacheRevalidation === "background";
|
|
286
281
|
}
|
|
287
282
|
//#endregion
|
|
288
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife,
|
|
283
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _isOnDemandRevalidate, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry };
|