vinext 1.2.0 → 1.3.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 +13 -10
- package/dist/build/client-build-config.d.ts +64 -3
- package/dist/build/client-build-config.js +131 -4
- package/dist/build/client-reference-groups.d.ts +163 -0
- package/dist/build/client-reference-groups.js +534 -0
- package/dist/build/module-dependency-cache.d.ts +31 -0
- package/dist/build/module-dependency-cache.js +51 -1
- package/dist/build/next-client-runtime-manifests.d.ts +10 -1
- package/dist/build/next-client-runtime-manifests.js +19 -4
- package/dist/build/nitro-public-files.d.ts +24 -0
- package/dist/build/nitro-public-files.js +60 -0
- package/dist/build/output-root-externals.d.ts +21 -0
- package/dist/build/output-root-externals.js +40 -0
- package/dist/build/pages-client-assets-module.js +1 -1
- package/dist/build/prerender-paths.js +6 -3
- package/dist/build/prerender.js +1 -1
- package/dist/build/server-actions-encryption-key.d.ts +23 -0
- package/dist/build/server-actions-encryption-key.js +101 -0
- package/dist/build/ssr-manifest.d.ts +3 -0
- package/dist/build/ssr-manifest.js +10 -1
- package/dist/check.js +5 -6
- package/dist/cli-dev-config.js +3 -3
- package/dist/cli.js +1 -1
- package/dist/client/client-rewrite-params.d.ts +9 -0
- package/dist/client/client-rewrite-params.js +20 -0
- package/dist/client/dev-error-overlay.js +2 -1
- package/dist/client/navigation-runtime.d.ts +25 -2
- package/dist/client/navigation-runtime.js +42 -11
- package/dist/client/vinext-next-data.d.ts +0 -1
- package/dist/config/config-matchers.d.ts +15 -40
- package/dist/config/config-matchers.js +195 -262
- package/dist/config/config-source.d.ts +34 -0
- package/dist/config/config-source.js +141 -0
- package/dist/config/header-params.d.ts +29 -0
- package/dist/config/header-params.js +106 -0
- package/dist/config/next-config.d.ts +7 -5
- package/dist/config/next-config.js +120 -7
- package/dist/entries/app-browser-entry.d.ts +14 -1
- package/dist/entries/app-browser-entry.js +26 -36
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +92 -57
- package/dist/entries/app-rsc-manifest.d.ts +10 -0
- package/dist/entries/app-rsc-manifest.js +20 -1
- package/dist/entries/app-ssr-entry.d.ts +4 -1
- package/dist/entries/app-ssr-entry.js +9 -2
- package/dist/entries/pages-client-entry.d.ts +1 -0
- package/dist/entries/pages-client-entry.js +6 -6
- package/dist/entries/pages-server-entry.js +17 -14
- package/dist/index.d.ts +11 -0
- package/dist/index.js +350 -175
- package/dist/init.d.ts +1 -1
- package/dist/init.js +103 -6
- package/dist/plugins/ast-utils.d.ts +53 -2
- package/dist/plugins/ast-utils.js +90 -2
- package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
- package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
- package/dist/plugins/commonjs-esm-facade.js +2 -2
- package/dist/plugins/css-module-imports.js +13 -20
- package/dist/plugins/dynamic-preload-metadata.js +2 -3
- package/dist/plugins/extensionless-dynamic-import.js +2 -3
- package/dist/plugins/fonts.d.ts +1 -1
- package/dist/plugins/fonts.js +3 -3
- package/dist/plugins/ignore-dynamic-requests.js +2 -3
- package/dist/plugins/import-meta-url.js +3 -4
- package/dist/plugins/instrumentation-client.js +3 -2
- package/dist/plugins/middleware-export-validation.js +2 -3
- package/dist/plugins/og-harfbuzz.js +2 -3
- package/dist/plugins/optimize-imports.d.ts +25 -2
- package/dist/plugins/optimize-imports.js +109 -24
- package/dist/plugins/pages-node-externals.js +2 -3
- package/dist/plugins/remove-console.js +2 -18
- package/dist/plugins/require-condition-resolution.js +3 -3
- package/dist/plugins/require-context.js +2 -3
- package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
- package/dist/plugins/rsc-client-reference-loaders.js +336 -18
- package/dist/plugins/strip-server-exports.js +3 -4
- package/dist/plugins/styled-jsx.js +2 -3
- package/dist/plugins/use-cache-callable.d.ts +26 -2
- package/dist/plugins/use-cache-callable.js +101 -36
- package/dist/plugins/worker-image-imports.d.ts +1 -0
- package/dist/plugins/worker-image-imports.js +31 -34
- package/dist/plugins/worker-use-server.js +38 -14
- package/dist/routing/app-route-graph.d.ts +1 -1
- package/dist/routing/browser-route-manifest.d.ts +43 -0
- package/dist/routing/browser-route-manifest.js +195 -0
- package/dist/routing/hashed-route-patterns.d.ts +4 -0
- package/dist/routing/hashed-route-patterns.js +22 -0
- package/dist/routing/optimistic-route-trie.d.ts +27 -0
- package/dist/routing/optimistic-route-trie.js +102 -0
- package/dist/routing/route-validation.d.ts +6 -1
- package/dist/routing/route-validation.js +26 -10
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-action-forwarding.d.ts +8 -0
- package/dist/server/app-action-forwarding.js +17 -3
- package/dist/server/app-browser-entry.js +149 -62
- package/dist/server/app-browser-error.d.ts +3 -1
- package/dist/server/app-browser-error.js +7 -2
- package/dist/server/app-browser-interception-context.d.ts +2 -2
- package/dist/server/app-browser-interception-context.js +1 -1
- package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
- package/dist/server/app-browser-mpa-navigation.js +6 -5
- package/dist/server/app-browser-navigation-controller.d.ts +17 -6
- package/dist/server/app-browser-navigation-controller.js +88 -26
- package/dist/server/app-browser-prefetch-response.js +2 -2
- package/dist/server/app-browser-state.d.ts +2 -2
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-supplemental-refresh.js +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +4 -4
- package/dist/server/app-client-reference-preloader.d.ts +23 -0
- package/dist/server/app-client-reference-preloader.js +30 -7
- package/dist/server/app-fallback-renderer.js +2 -1
- package/dist/server/app-middleware.d.ts +6 -0
- package/dist/server/app-middleware.js +8 -10
- package/dist/server/app-optimistic-routing.d.ts +8 -10
- package/dist/server/app-optimistic-routing.js +4 -95
- package/dist/server/app-page-boundary-render.js +8 -1
- package/dist/server/app-page-cache-render.js +1 -0
- package/dist/server/app-page-dispatch.js +3 -1
- package/dist/server/app-page-render.js +4 -2
- package/dist/server/app-page-rsc-render-status.d.ts +1 -0
- package/dist/server/app-page-rsc-render-status.js +1 -0
- package/dist/server/app-page-search-params-observation.d.ts +1 -4
- package/dist/server/app-page-search-params-observation.js +8 -10
- package/dist/server/app-page-stream.d.ts +7 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +12 -8
- package/dist/server/app-prerender-endpoints.js +1 -1
- package/dist/server/app-prerender-static-params.js +3 -2
- package/dist/server/app-render-abort-error.d.ts +19 -0
- package/dist/server/app-render-abort-error.js +31 -1
- package/dist/server/app-render-dependency.js +42 -2
- package/dist/server/app-request-stage-independent-entry.js +7 -7
- package/dist/server/app-response-stage-entry.js +5 -5
- package/dist/server/app-route-handler-dispatch.js +3 -1
- package/dist/server/app-route-handler-execution.d.ts +2 -0
- package/dist/server/app-route-handler-execution.js +9 -2
- package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
- package/dist/server/app-route-handler-middleware-context.js +3 -3
- package/dist/server/app-route-handler-response.d.ts +2 -1
- package/dist/server/app-route-handler-response.js +2 -2
- package/dist/server/app-route-handler-runtime.d.ts +2 -0
- package/dist/server/app-route-handler-runtime.js +21 -4
- package/dist/server/app-route-module-loader.js +7 -6
- package/dist/server/app-route-tree.d.ts +20 -0
- package/dist/server/app-route-tree.js +18 -0
- package/dist/server/app-router-entry.js +7 -7
- package/dist/server/app-rsc-cache-busting.d.ts +16 -0
- package/dist/server/app-rsc-cache-busting.js +29 -12
- package/dist/server/app-rsc-combined-handler.js +8 -1
- package/dist/server/app-rsc-errors.d.ts +7 -0
- package/dist/server/app-rsc-errors.js +9 -2
- package/dist/server/app-rsc-handler.d.ts +4 -1
- package/dist/server/app-rsc-handler.js +151 -135
- package/dist/server/app-rsc-request-normalization.js +3 -3
- package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
- package/dist/server/app-rsc-response-finalizer.js +4 -1
- package/dist/server/app-rsc-response-stage.js +5 -3
- package/dist/server/app-rsc-route-matching.d.ts +1 -0
- package/dist/server/app-rsc-route-matching.js +1 -1
- package/dist/server/app-server-action-execution.d.ts +23 -6
- package/dist/server/app-server-action-execution.js +51 -57
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +21 -11
- package/dist/server/app-ssr-stream.d.ts +7 -0
- package/dist/server/app-ssr-stream.js +13 -1
- package/dist/server/app-visited-response-cache.js +2 -2
- package/dist/server/config-headers.js +13 -4
- package/dist/server/defer-until-stream-consumed.d.ts +2 -1
- package/dist/server/defer-until-stream-consumed.js +3 -1
- package/dist/server/dev-server.js +1 -1
- package/dist/server/image-optimization.js +1 -0
- package/dist/server/isolate-shared-promise.d.ts +10 -0
- package/dist/server/isolate-shared-promise.js +33 -0
- package/dist/server/isr-cache.js +3 -2
- package/dist/server/metadata-route-response.js +2 -2
- package/dist/server/middleware-matcher-pattern.d.ts +0 -1
- package/dist/server/middleware-matcher-pattern.js +11 -140
- package/dist/server/middleware-matcher.js +5 -6
- package/dist/server/middleware-response-headers.d.ts +31 -0
- package/dist/server/middleware-response-headers.js +57 -1
- package/dist/server/middleware-runtime.js +30 -17
- package/dist/server/navigation-planner.d.ts +2 -2
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/nitro-public-files-plugin.d.ts +38 -0
- package/dist/server/nitro-public-files-plugin.js +106 -0
- package/dist/server/nitro-public-files.d.ts +21 -0
- package/dist/server/nitro-public-files.js +39 -0
- package/dist/server/open-redirect.d.ts +11 -4
- package/dist/server/open-redirect.js +11 -4
- package/dist/server/pages-api-route.js +2 -2
- package/dist/server/pages-asset-tags.d.ts +5 -0
- package/dist/server/pages-asset-tags.js +9 -2
- package/dist/server/pages-client-assets.d.ts +4 -1
- package/dist/server/pages-data-route.js +2 -1
- package/dist/server/pages-i18n.d.ts +18 -0
- package/dist/server/pages-i18n.js +18 -2
- package/dist/server/pages-node-compat.d.ts +5 -3
- package/dist/server/pages-node-compat.js +35 -16
- package/dist/server/pages-page-data.js +1 -1
- package/dist/server/pages-page-handler.js +1 -1
- package/dist/server/pages-page-response.js +1 -1
- package/dist/server/pages-request-pipeline.d.ts +6 -1
- package/dist/server/pages-request-pipeline.js +35 -39
- package/dist/server/pages-request-stage-entry.js +20 -10
- package/dist/server/pages-response-stage-entry.js +1 -1
- package/dist/server/pages-revalidate.js +3 -2
- package/dist/server/pages-router-entry.js +2 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +74 -36
- package/dist/server/proxy-trust.d.ts +6 -0
- package/dist/server/proxy-trust.js +12 -6
- package/dist/server/request-pipeline.d.ts +5 -0
- package/dist/server/request-pipeline.js +12 -1
- package/dist/server/rsc-stream-hints.d.ts +1 -1
- package/dist/server/rsc-stream-hints.js +21 -3
- package/dist/server/server-reference-loader.js +10 -1
- package/dist/server/static-file-cache.js +15 -3
- package/dist/server/worker-image-optimization.js +19 -6
- package/dist/server/worker-utils.js +1 -1
- package/dist/shims/cache-handler.js +3 -2
- package/dist/shims/cache-request-state.d.ts +40 -3
- package/dist/shims/cache-request-state.js +70 -5
- package/dist/shims/cache-runtime.js +47 -19
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +17 -8
- package/dist/shims/cdn-purge-routes.d.ts +24 -0
- package/dist/shims/cdn-purge-routes.js +77 -0
- package/dist/shims/dynamic.js +17 -4
- package/dist/shims/form.js +8 -3
- package/dist/shims/head.js +1 -1
- package/dist/shims/headers.js +2 -2
- package/dist/shims/image-props.d.ts +93 -0
- package/dist/shims/image-props.js +323 -0
- package/dist/shims/image.d.ts +4 -18
- package/dist/shims/image.js +4 -319
- package/dist/shims/internal/headers-state.d.ts +7 -0
- package/dist/shims/internal/headers-state.js +14 -2
- package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
- package/dist/shims/internal/hybrid-client-route-owner-direct.js +32 -15
- package/dist/shims/internal/hybrid-client-route-owner.js +9 -8
- package/dist/shims/link-prefetch.js +5 -4
- package/dist/shims/link.js +7 -5
- package/dist/shims/navigation.d.ts +1 -1
- package/dist/shims/navigation.js +21 -10
- package/dist/shims/og.js +35 -10
- package/dist/shims/request-context.d.ts +13 -0
- package/dist/shims/router.js +28 -52
- package/dist/shims/server.d.ts +42 -8
- package/dist/shims/server.js +99 -15
- package/dist/shims/thenable-params.d.ts +6 -1
- package/dist/shims/thenable-params.js +11 -2
- package/dist/shims/unified-request-context.d.ts +5 -0
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/url-utils.d.ts +7 -0
- package/dist/shims/url-utils.js +12 -3
- package/dist/utils/asset-prefix.d.ts +7 -0
- package/dist/utils/asset-prefix.js +10 -1
- package/dist/utils/client-build-manifest.js +12 -5
- package/dist/utils/client-runtime-metadata.d.ts +1 -0
- package/dist/utils/client-runtime-metadata.js +15 -2
- package/dist/utils/domain-locale.js +1 -1
- package/dist/utils/lazy-chunks.d.ts +4 -0
- package/dist/utils/manifest-paths.d.ts +14 -0
- package/dist/utils/manifest-paths.js +22 -1
- package/dist/utils/path-to-regexp.d.ts +21 -0
- package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
- package/dist/utils/plugin-react-version.d.ts +15 -0
- package/dist/utils/plugin-react-version.js +64 -0
- package/dist/utils/plugin-rsc-version.d.ts +2 -0
- package/dist/utils/plugin-rsc-version.js +28 -2
- package/dist/utils/public-routes.d.ts +2 -0
- package/dist/utils/public-routes.js +18 -7
- package/dist/utils/react-version.d.ts +7 -0
- package/dist/utils/react-version.js +39 -16
- package/package.json +6 -6
- package/dist/build/nitro-route-rules.d.ts +0 -47
- package/dist/build/nitro-route-rules.js +0 -79
- package/dist/plugins/cache-flight-codec.d.ts +0 -19
- package/dist/plugins/cache-flight-codec.js +0 -68
- package/dist/server/middleware-path-to-regexp.d.ts +0 -13
- package/dist/utils/regex-safety.d.ts +0 -17
- package/dist/utils/regex-safety.js +0 -789
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { isNextStaticPath } from "../utils/asset-prefix.js";
|
|
2
|
-
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
3
1
|
import { VINEXT_PRERENDER_SPECIAL_ERROR_HEADER } from "./headers.js";
|
|
4
|
-
import { normalizePath } from "./normalize-path.js";
|
|
5
2
|
import { readStaticFileSignal, readStaticFileSignalRequestHeaders } from "./static-file-signal.js";
|
|
6
3
|
import { attachRequestCfMetadata, cloneRequestWithUrl } from "./request-pipeline.js";
|
|
4
|
+
import { isNextStaticPath } from "../utils/asset-prefix.js";
|
|
7
5
|
import { handleConfiguredImageOptimization, invalidImageSourceResponse, isImageSourceBodyStatus } from "./image-optimization.js";
|
|
8
6
|
import { createStaticAssetRequest, mergeHeaders } from "./worker-utils.js";
|
|
9
7
|
import { resolveClientBuildFile } from "./client-build-files.js";
|
|
@@ -28,19 +26,34 @@ function cancelResponseBody(response) {
|
|
|
28
26
|
body.cancel().catch(() => {});
|
|
29
27
|
}
|
|
30
28
|
/**
|
|
29
|
+
* Return the pathname of the `_next/static` file a source's decoded pathname
|
|
30
|
+
* names, or null. Next.js matches the decoded pathname against its
|
|
31
|
+
* `.next/static` files literally, so a `.`, `..` or empty segment names no
|
|
32
|
+
* file. The asset binding decodes each segment once, so each segment is
|
|
33
|
+
* encoded once from the name checked here. Parsing the decoded pathname as a
|
|
34
|
+
* URL again would resolve a segment that decoded to `%2E%2E` as `..`, outside
|
|
35
|
+
* `_next/static`.
|
|
36
|
+
*/
|
|
37
|
+
function resolveNextStaticFile(decodedPathname, options) {
|
|
38
|
+
if (!isNextStaticPath(decodedPathname, options.basePath, options.assetPathPrefix)) return null;
|
|
39
|
+
const segments = decodedPathname.split("/").slice(1);
|
|
40
|
+
if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) return null;
|
|
41
|
+
return "/" + segments.map(encodeURIComponent).join("/");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
31
44
|
* Fetch a local image source. Build output is fetched from the asset binding,
|
|
32
45
|
* which serves it before the Worker and its middleware. Any other source is
|
|
33
46
|
* served only when the application pipeline selects a public file for it.
|
|
34
47
|
*/
|
|
35
48
|
async function fetchWorkerImageSource(imageUrl, request, options) {
|
|
36
49
|
const sourceUrl = new URL(imageUrl, request.url);
|
|
37
|
-
let
|
|
50
|
+
let decodedPathname;
|
|
38
51
|
try {
|
|
39
|
-
|
|
52
|
+
decodedPathname = decodeURIComponent(sourceUrl.pathname);
|
|
40
53
|
} catch {
|
|
41
54
|
return invalidImageSourceResponse();
|
|
42
55
|
}
|
|
43
|
-
const buildAssetPath =
|
|
56
|
+
const buildAssetPath = resolveNextStaticFile(decodedPathname, options) ?? resolveClientBuildFile(sourceUrl.pathname, options.basePath, options.clientBuildFiles);
|
|
44
57
|
if (buildAssetPath !== null) return options.assets.fetch(new Request(new URL(buildAssetPath, request.url)));
|
|
45
58
|
const sourceResponse = await options.fetchPublicFile(attachRequestCfMetadata(new Request(sourceUrl, { signal: request.signal }), request));
|
|
46
59
|
if (sourceResponse && isImageSourceBodyStatus(sourceResponse.status)) return sourceResponse;
|
|
@@ -108,7 +108,7 @@ async function resolveStaticAssetSignal(signalResponse, options) {
|
|
|
108
108
|
* overrides, so a removed `Range` or replaced validator reaches the asset fetch.
|
|
109
109
|
*/
|
|
110
110
|
function createStaticAssetRequest(assetPath, sourceRequest, headers = null) {
|
|
111
|
-
const assetUrl = new URL(assetPath, sourceRequest.url);
|
|
111
|
+
const assetUrl = new URL(assetPath.replace(/[?#]/g, (character) => encodeURIComponent(character)), sourceRequest.url);
|
|
112
112
|
if (sourceRequest.method === "GET" || sourceRequest.method === "HEAD") return headers ? new Request(new Request(assetUrl, sourceRequest), { headers }) : new Request(assetUrl, sourceRequest);
|
|
113
113
|
return new Request(assetUrl, {
|
|
114
114
|
method: sourceRequest.method,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { shareIsolatePromise } from "../server/isolate-shared-promise.js";
|
|
1
2
|
import { readCacheControlNumberField, readCacheControlRevalidateField } from "../utils/cache-control-metadata.js";
|
|
2
3
|
//#region src/shims/cache-handler.ts
|
|
3
4
|
var NoOpCacheHandler = class {
|
|
@@ -167,7 +168,7 @@ var LazyDataCacheHandler = class {
|
|
|
167
168
|
this.load = load;
|
|
168
169
|
}
|
|
169
170
|
resolve() {
|
|
170
|
-
return this.resolved ??= this.load().then(() => {
|
|
171
|
+
return this.resolved ??= shareIsolatePromise(this.load().then(() => {
|
|
171
172
|
const registered = globalHandlers[HANDLER_KEY];
|
|
172
173
|
if (registered && registered !== this) {
|
|
173
174
|
this.loadedHandler = registered;
|
|
@@ -179,7 +180,7 @@ var LazyDataCacheHandler = class {
|
|
|
179
180
|
delete globalHandlers[LAZY_HANDLER_KEY];
|
|
180
181
|
this.loadedHandler = fallback;
|
|
181
182
|
return fallback;
|
|
182
|
-
});
|
|
183
|
+
}));
|
|
183
184
|
}
|
|
184
185
|
async get(key, ctx) {
|
|
185
186
|
return (await this.resolve()).get(key, ctx);
|
|
@@ -23,9 +23,19 @@ export type UnstableCacheObservation = Readonly<{
|
|
|
23
23
|
export type CacheLifeSink = {
|
|
24
24
|
cacheLife: CacheLifeConfig | null;
|
|
25
25
|
};
|
|
26
|
+
type TagInvalidationDurations = {
|
|
27
|
+
expire?: number;
|
|
28
|
+
} | undefined;
|
|
29
|
+
/** A CDN purge waiting for the request boundary, after its data-cache invalidation. */
|
|
30
|
+
export type PendingCdnTagInvalidation = Readonly<{
|
|
31
|
+
tag: string;
|
|
32
|
+
durations: TagInvalidationDurations;
|
|
33
|
+
dataInvalidation: Promise<void>;
|
|
34
|
+
}>;
|
|
26
35
|
export type CacheState = {
|
|
27
36
|
actionRevalidationKind: ActionRevalidationKind;
|
|
28
37
|
cacheLifeSink: CacheLifeSink | null;
|
|
38
|
+
pendingCdnTagInvalidations: PendingCdnTagInvalidation[];
|
|
29
39
|
pendingRevalidatedTags: Set<string>;
|
|
30
40
|
pendingRevalidations: Set<Promise<void>>;
|
|
31
41
|
requestScopedCacheLife: CacheLifeConfig | null;
|
|
@@ -56,9 +66,36 @@ export declare function _hasPendingRevalidatedTag(tags: readonly string[]): bool
|
|
|
56
66
|
*/
|
|
57
67
|
export declare function _queuePendingRevalidation(promise: Promise<void>): boolean;
|
|
58
68
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
69
|
+
* Defer the CDN purge for `tag` to the current Server Action or Route Handler
|
|
70
|
+
* boundary, so the request sends one adapter call per cacheLife profile like
|
|
71
|
+
* Next.js' `executeRevalidates`. Edge purges are rate limited (Workers Cache
|
|
72
|
+
* allows 5 requests a minute per account), so per-call purges run out fast.
|
|
73
|
+
*
|
|
74
|
+
* Only those two phases defer: their executors always drain before the
|
|
75
|
+
* request finishes. Once the response has closed, `after()` callbacks run
|
|
76
|
+
* past the last drain, so they purge immediately too. Everywhere else returns
|
|
77
|
+
* false and the caller purges immediately.
|
|
78
|
+
*
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
export declare function _queuePendingCdnTagInvalidation(tag: string, durations: TagInvalidationDurations, dataInvalidation: Promise<void>): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Ask the CDN adapter to invalidate `tags`, logging rather than rethrowing a
|
|
84
|
+
* failure. The data cache is already invalidated by then, so a failed edge
|
|
85
|
+
* purge leaves edge-cached responses stale until they expire, and failing the
|
|
86
|
+
* request would not change that. It would only report a committed Server
|
|
87
|
+
* Action write as a failure.
|
|
88
|
+
*
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
export declare function _revalidateCdnTags(tags: string | string[], durations?: {
|
|
92
|
+
expire?: number;
|
|
93
|
+
}): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Await and clear every cache invalidation queued in the current request,
|
|
96
|
+
* then send the deferred CDN purges in batches. Clearing before awaiting also
|
|
97
|
+
* lets a later drain observe work enqueued by an async continuation while
|
|
98
|
+
* this batch is settling.
|
|
62
99
|
*
|
|
63
100
|
* @internal
|
|
64
101
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getOrCreateAls } from "./internal/als-registry.js";
|
|
2
2
|
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
3
|
+
import { getCdnCacheAdapter } from "./cdn-cache.js";
|
|
3
4
|
import { getHeadersAccessPhase } from "./internal/headers-state.js";
|
|
4
5
|
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
5
6
|
//#region src/shims/cache-request-state.ts
|
|
@@ -48,6 +49,7 @@ const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
|
|
|
48
49
|
const fallbackState = globalState[FALLBACK_KEY] ??= {
|
|
49
50
|
actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
|
|
50
51
|
cacheLifeSink: null,
|
|
52
|
+
pendingCdnTagInvalidations: [],
|
|
51
53
|
pendingRevalidatedTags: /* @__PURE__ */ new Set(),
|
|
52
54
|
pendingRevalidations: /* @__PURE__ */ new Set(),
|
|
53
55
|
requestScopedCacheLife: null,
|
|
@@ -69,6 +71,7 @@ function _runWithCacheState(fn) {
|
|
|
69
71
|
const state = {
|
|
70
72
|
actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
|
|
71
73
|
cacheLifeSink: null,
|
|
74
|
+
pendingCdnTagInvalidations: [],
|
|
72
75
|
pendingRevalidatedTags: /* @__PURE__ */ new Set(),
|
|
73
76
|
pendingRevalidations: /* @__PURE__ */ new Set(),
|
|
74
77
|
requestScopedCacheLife: null,
|
|
@@ -128,9 +131,69 @@ function _queuePendingRevalidation(promise) {
|
|
|
128
131
|
return true;
|
|
129
132
|
}
|
|
130
133
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
+
* Defer the CDN purge for `tag` to the current Server Action or Route Handler
|
|
135
|
+
* boundary, so the request sends one adapter call per cacheLife profile like
|
|
136
|
+
* Next.js' `executeRevalidates`. Edge purges are rate limited (Workers Cache
|
|
137
|
+
* allows 5 requests a minute per account), so per-call purges run out fast.
|
|
138
|
+
*
|
|
139
|
+
* Only those two phases defer: their executors always drain before the
|
|
140
|
+
* request finishes. Once the response has closed, `after()` callbacks run
|
|
141
|
+
* past the last drain, so they purge immediately too. Everywhere else returns
|
|
142
|
+
* false and the caller purges immediately.
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
function _queuePendingCdnTagInvalidation(tag, durations, dataInvalidation) {
|
|
147
|
+
const phase = getHeadersAccessPhase();
|
|
148
|
+
if (phase !== "action" && phase !== "route-handler") return false;
|
|
149
|
+
if (isInsideUnifiedScope() && getRequestContext().afterContext.responseClosed) return false;
|
|
150
|
+
getCacheState().pendingCdnTagInvalidations.push({
|
|
151
|
+
tag,
|
|
152
|
+
durations,
|
|
153
|
+
dataInvalidation
|
|
154
|
+
});
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Ask the CDN adapter to invalidate `tags`, logging rather than rethrowing a
|
|
159
|
+
* failure. The data cache is already invalidated by then, so a failed edge
|
|
160
|
+
* purge leaves edge-cached responses stale until they expire, and failing the
|
|
161
|
+
* request would not change that. It would only report a committed Server
|
|
162
|
+
* Action write as a failure.
|
|
163
|
+
*
|
|
164
|
+
* @internal
|
|
165
|
+
*/
|
|
166
|
+
async function _revalidateCdnTags(tags, durations) {
|
|
167
|
+
try {
|
|
168
|
+
await getCdnCacheAdapter().revalidateTag(tags, durations);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error("[vinext] CDN cache invalidation failed; edge-cached responses may stay stale until they expire:", error);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function flushCdnTagInvalidations(invalidations) {
|
|
174
|
+
if (invalidations.length === 0) return;
|
|
175
|
+
const settled = await Promise.allSettled(invalidations.map(({ dataInvalidation }) => dataInvalidation));
|
|
176
|
+
const batches = /* @__PURE__ */ new Map();
|
|
177
|
+
invalidations.forEach(({ tag, durations }, index) => {
|
|
178
|
+
if (settled[index].status === "rejected") return;
|
|
179
|
+
const key = durations === void 0 ? "" : JSON.stringify(durations);
|
|
180
|
+
let batch = batches.get(key);
|
|
181
|
+
if (!batch) {
|
|
182
|
+
batch = {
|
|
183
|
+
durations,
|
|
184
|
+
tags: /* @__PURE__ */ new Set()
|
|
185
|
+
};
|
|
186
|
+
batches.set(key, batch);
|
|
187
|
+
}
|
|
188
|
+
batch.tags.add(tag);
|
|
189
|
+
});
|
|
190
|
+
await Promise.all([...batches.values()].map(({ durations, tags }) => _revalidateCdnTags([...tags], durations)));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Await and clear every cache invalidation queued in the current request,
|
|
194
|
+
* then send the deferred CDN purges in batches. Clearing before awaiting also
|
|
195
|
+
* lets a later drain observe work enqueued by an async continuation while
|
|
196
|
+
* this batch is settling.
|
|
134
197
|
*
|
|
135
198
|
* @internal
|
|
136
199
|
*/
|
|
@@ -138,14 +201,16 @@ async function _drainPendingRevalidations() {
|
|
|
138
201
|
const state = getCacheState();
|
|
139
202
|
let didReject = false;
|
|
140
203
|
let firstRejection;
|
|
141
|
-
while (state.pendingRevalidations.size > 0) {
|
|
204
|
+
while (state.pendingRevalidations.size > 0 || state.pendingCdnTagInvalidations.length > 0) {
|
|
142
205
|
const pending = [...state.pendingRevalidations];
|
|
143
206
|
state.pendingRevalidations.clear();
|
|
207
|
+
const cdnInvalidations = state.pendingCdnTagInvalidations.splice(0);
|
|
144
208
|
const results = await Promise.allSettled(pending);
|
|
145
209
|
for (const result of results) if (result.status === "rejected" && !didReject) {
|
|
146
210
|
didReject = true;
|
|
147
211
|
firstRejection = result.reason;
|
|
148
212
|
}
|
|
213
|
+
await flushCdnTagInvalidations(cdnInvalidations);
|
|
149
214
|
}
|
|
150
215
|
if (didReject) throw firstRejection;
|
|
151
216
|
}
|
|
@@ -220,4 +285,4 @@ function shouldServeStaleUnstableCacheEntry() {
|
|
|
220
285
|
return getCacheState().unstableCacheRevalidation === "background";
|
|
221
286
|
}
|
|
222
287
|
//#endregion
|
|
223
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry };
|
|
288
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry };
|
|
@@ -3,17 +3,19 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
|
|
|
3
3
|
import { VINEXT_RSC_MARKER_HEADER } from "../server/headers.js";
|
|
4
4
|
import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
|
|
5
5
|
import { isRouteCacheabilityProbe, recordRouteCacheabilityProbeBailout } from "./cacheability-classification.js";
|
|
6
|
+
import { shareIsolatePromise } from "../server/isolate-shared-promise.js";
|
|
6
7
|
import { getDataCacheHandler } from "./cache-handler.js";
|
|
7
8
|
import { addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache-state.js";
|
|
8
9
|
import { suppressHangingPromiseAbortRejections } from "./internal/make-hanging-promise.js";
|
|
9
10
|
import { createPprFallbackShellSuspensePromise, trackPprFallbackShellCacheTask } from "./ppr-fallback-shell.js";
|
|
10
|
-
import { markDynamicUsage,
|
|
11
|
+
import { createUseCacheAccessError, markDynamicUsage, recordInvalidDynamicUsageError } from "./internal/headers-state.js";
|
|
11
12
|
import { isDraftModeEnabled } from "./headers.js";
|
|
12
13
|
import { _registerCacheContextAccessor } from "./internal/cache-context-accessor.js";
|
|
13
14
|
import { _hasPendingRevalidatedTag, _setRequestScopedCacheLife, cacheLifeProfiles, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
14
15
|
import "./fetch-cache.js";
|
|
15
16
|
import { hasUseCacheLayoutMarker, hasUseCachePageMarker, isUseCacheFunctionReference, withoutUseCacheSegmentMarker } from "./internal/app-page-props-cache-key.js";
|
|
16
|
-
import {
|
|
17
|
+
import { isWellKnownProperty } from "./internal/thenable-well-known-properties.js";
|
|
18
|
+
import { getFallbackParamsSnapshot, restoreThenableParams } from "./thenable-params.js";
|
|
17
19
|
import { getCurrentRootParams } from "./root-params.js";
|
|
18
20
|
import { flightArgumentsKey, restoreFlightReply, snapshotFlightReply } from "./cache-flight-arguments.js";
|
|
19
21
|
import { cache } from "react";
|
|
@@ -132,7 +134,7 @@ function buildUseCacheKey(id, keySeed, argsKey) {
|
|
|
132
134
|
}
|
|
133
135
|
let _rscModule;
|
|
134
136
|
function getRscModule() {
|
|
135
|
-
return _rscModule ??= import("@vitejs/plugin-rsc/react/rsc");
|
|
137
|
+
return _rscModule ??= shareIsolatePromise(import("@vitejs/plugin-rsc/react/rsc"));
|
|
136
138
|
}
|
|
137
139
|
/** Collect a ReadableStream<Uint8Array> into a single Uint8Array. */
|
|
138
140
|
async function collectStream(stream) {
|
|
@@ -365,9 +367,9 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
365
367
|
...props,
|
|
366
368
|
params: restoreThenableParams(await props.params, outerParams)
|
|
367
369
|
});
|
|
368
|
-
if (pagePropsIndex !== void 0) callArgs = withErroringPageSearchParams(callArgs, pagePropsIndex);
|
|
369
370
|
}
|
|
370
|
-
|
|
371
|
+
const callFn = segmentPropsIndex !== -1 && pagePropsIndex !== void 0 ? withErroringPageSearchParams(fn, pagePropsIndex) : fn;
|
|
372
|
+
if (fallbackParams) return (await executeWithContext(callFn, callArgs, cacheVariant, rsc)).result;
|
|
371
373
|
if (cacheVariant === "private") {
|
|
372
374
|
const privateCache = _getPrivateState()._privateCache;
|
|
373
375
|
const privateHit = privateCache.get(cacheKey);
|
|
@@ -375,11 +377,11 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
375
377
|
if (privateHit.serialized) return rsc.createFromReadableStream(uint8ToStream(base64ToUint8(privateHit.serialized.body)), {}, { preserveServerReferences: true });
|
|
376
378
|
return privateHit.result;
|
|
377
379
|
}
|
|
378
|
-
const execution = await executeWithContext(
|
|
380
|
+
const execution = await executeWithContext(callFn, callArgs, cacheVariant, rsc);
|
|
379
381
|
if (execution.cacheable) privateCache.set(cacheKey, execution);
|
|
380
382
|
return execution.result;
|
|
381
383
|
}
|
|
382
|
-
if (isDev || isDraftModeEnabled()) return (await executeWithContext(
|
|
384
|
+
if (isDev || isDraftModeEnabled()) return (await executeWithContext(callFn, callArgs, cacheVariant, rsc)).result;
|
|
383
385
|
const handler = getDataCacheHandler();
|
|
384
386
|
const rootParams = getCurrentRootParams();
|
|
385
387
|
const knownRootParamNames = knownRootParamsByFunctionId.get(id);
|
|
@@ -409,7 +411,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
409
411
|
}
|
|
410
412
|
}
|
|
411
413
|
const generate = async (propagate) => {
|
|
412
|
-
const { result, ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(
|
|
414
|
+
const { result, ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(callFn, callArgs, cacheVariant, (value) => serializeCacheResult(value, rsc));
|
|
413
415
|
const rootParamNames = ctx.readRootParamNames && ctx.readRootParamNames.size > 0 ? addKnownRootParamNames(id, ctx.readRootParamNames) : knownRootParamsByFunctionId.get(id);
|
|
414
416
|
if (propagate) {
|
|
415
417
|
recordRequestScopedCacheLife(effectiveLife);
|
|
@@ -631,18 +633,44 @@ function toReplayablePageArgs(args, index) {
|
|
|
631
633
|
return replaceArgument(args, index, pageProps);
|
|
632
634
|
}
|
|
633
635
|
/**
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
* `makeErroringSearchParamsForUseCache`, instead of `undefined`.
|
|
636
|
+
* Run `fn` with an erroring `searchParams` in the page props at `index` when
|
|
637
|
+
* they have none (they are omitted from a public page cache's arguments, and
|
|
638
|
+
* from a Response Store replay of them), instead of `undefined`.
|
|
638
639
|
*/
|
|
639
|
-
function withErroringPageSearchParams(
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
...
|
|
644
|
-
|
|
645
|
-
|
|
640
|
+
function withErroringPageSearchParams(fn, index) {
|
|
641
|
+
return (...args) => {
|
|
642
|
+
const props = args[index];
|
|
643
|
+
if (!isPagePropsObject(props) || "searchParams" in props) return fn(...args);
|
|
644
|
+
return fn(...replaceArgument(args, index, {
|
|
645
|
+
...props,
|
|
646
|
+
searchParams: makeErroringPageSearchParams()
|
|
647
|
+
}));
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function isNextWellKnownProperty(prop) {
|
|
651
|
+
return prop !== "value" && prop !== "error" && isWellKnownProperty(prop);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Ported from Next.js's `makeErroringSearchParamsForUseCache`
|
|
655
|
+
* (server/request/search-params.ts): reading `then` or a param throws, and
|
|
656
|
+
* everything else reads the underlying promise, with methods bound to it.
|
|
657
|
+
*/
|
|
658
|
+
function makeErroringPageSearchParams() {
|
|
659
|
+
const cacheContext = cacheContextStorage.getStore() ?? null;
|
|
660
|
+
const requestContext = isInsideUnifiedScope() ? getRequestContext() : null;
|
|
661
|
+
const promise = Promise.resolve({});
|
|
662
|
+
return new Proxy(promise, { get(target, prop, receiver) {
|
|
663
|
+
if (!Object.hasOwn(target, prop) && typeof prop === "string" && (prop === "then" || !isNextWellKnownProperty(prop))) {
|
|
664
|
+
const error = createUseCacheAccessError("searchParams");
|
|
665
|
+
if (cacheContext) cacheContext.invalidDynamicUsageError ??= error;
|
|
666
|
+
const activeCacheContext = cacheContextStorage.getStore();
|
|
667
|
+
if (activeCacheContext && activeCacheContext !== cacheContext) activeCacheContext.invalidDynamicUsageError ??= error;
|
|
668
|
+
if (requestContext) recordInvalidDynamicUsageError(requestContext, error);
|
|
669
|
+
throw error;
|
|
670
|
+
}
|
|
671
|
+
const value = Reflect.get(target, prop, receiver);
|
|
672
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
673
|
+
} });
|
|
646
674
|
}
|
|
647
675
|
//#endregion
|
|
648
676
|
export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isUseCacheFunction, memoizeInCacheScope, registerCachedFunction, replayCachedFunction, runWithPrivateCache };
|
package/dist/shims/cache.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExecutionContextLike, getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
|
|
2
2
|
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
3
|
-
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheLifeSink, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
3
|
+
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheLifeSink, CacheState, PendingCdnTagInvalidation, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
4
4
|
import { CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
|
|
5
5
|
//#region src/shims/cache.d.ts
|
|
6
6
|
/**
|
|
@@ -142,4 +142,4 @@ type UnstableCacheOptions = {
|
|
|
142
142
|
*/
|
|
143
143
|
export declare function unstable_cache<T extends (...args: any[]) => Promise<any>>(fn: T, keyParts?: string[], options?: UnstableCacheOptions): T;
|
|
144
144
|
//#endregion
|
|
145
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig, CacheLifeSink, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, recordUnstableCacheObservation, registerDataCacheHandler, registerLazyDataCacheHandler, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
|
|
145
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig, CacheLifeSink, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, PendingCdnTagInvalidation, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, recordUnstableCacheObservation, registerDataCacheHandler, registerLazyDataCacheHandler, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
|
package/dist/shims/cache.js
CHANGED
|
@@ -3,7 +3,6 @@ import { getRequestContext, isInsideUnifiedScope } from "./unified-request-conte
|
|
|
3
3
|
import { getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
|
|
4
4
|
import { isInsideWorkStoreScope } from "./internal/work-store-scope.js";
|
|
5
5
|
import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
|
|
6
|
-
import { getCdnCacheAdapter } from "./cdn-cache.js";
|
|
7
6
|
import { isStagedCacheabilityProbeActive } from "./cacheability-classification.js";
|
|
8
7
|
import { MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
|
|
9
8
|
import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
|
|
@@ -13,7 +12,8 @@ import { makeHangingPromise } from "./internal/make-hanging-promise.js";
|
|
|
13
12
|
import { getHeadersAccessPhase, markDynamicUsage } from "./internal/headers-state.js";
|
|
14
13
|
import { isDraftModeEnabled } from "./headers.js";
|
|
15
14
|
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
16
|
-
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
15
|
+
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
16
|
+
import { isPathKnownNotEdgeCached } from "./cdn-purge-routes.js";
|
|
17
17
|
//#region src/shims/cache.ts
|
|
18
18
|
/**
|
|
19
19
|
* next/cache shim
|
|
@@ -69,7 +69,7 @@ function revalidateTag(tag, profile) {
|
|
|
69
69
|
if (!profile || !durations || durations.expire === 0) markActionRevalidation(1);
|
|
70
70
|
const encodedTag = encodeCacheTag(tag);
|
|
71
71
|
_markPendingRevalidatedTag(encodedTag);
|
|
72
|
-
return
|
|
72
|
+
return scheduleTagInvalidation(encodedTag, durations);
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Invalidate one already-encoded tag across both cache layers.
|
|
@@ -79,10 +79,18 @@ function revalidateTag(tag, profile) {
|
|
|
79
79
|
* default CDN adapter), THEN ask the CDN adapter to purge its edge (a no-op for
|
|
80
80
|
* the default adapter). Purging the edge before the store is invalidated would
|
|
81
81
|
* let the edge re-fetch and re-cache stale data.
|
|
82
|
+
*
|
|
83
|
+
* The data cache is invalidated right away, so reads later in the same action
|
|
84
|
+
* see it. Inside a Server Action or Route Handler the purge waits for the
|
|
85
|
+
* request boundary, which sends one batched adapter call per profile.
|
|
82
86
|
*/
|
|
83
|
-
|
|
87
|
+
function scheduleTagInvalidation(encoded, durations) {
|
|
88
|
+
const dataInvalidation = invalidateDataCacheTag(encoded, durations);
|
|
89
|
+
if (_queuePendingCdnTagInvalidation(encoded, durations, dataInvalidation)) return scheduleRevalidation(dataInvalidation);
|
|
90
|
+
return scheduleRevalidation(dataInvalidation.then(() => _revalidateCdnTags(encoded, durations)));
|
|
91
|
+
}
|
|
92
|
+
async function invalidateDataCacheTag(encoded, durations) {
|
|
84
93
|
await getDataCacheHandler().revalidateTag(encoded, durations);
|
|
85
|
-
await getCdnCacheAdapter().revalidateTag(encoded, durations);
|
|
86
94
|
}
|
|
87
95
|
/**
|
|
88
96
|
* Revalidate cached data associated with a specific path.
|
|
@@ -109,7 +117,8 @@ function revalidatePath(path, type) {
|
|
|
109
117
|
const tag = type ? `_N_T_${stem}/${type}` : `_N_T_${stem || "/"}`;
|
|
110
118
|
const encodedTag = encodeCacheTag(tag);
|
|
111
119
|
_markPendingRevalidatedTag(encodedTag);
|
|
112
|
-
return scheduleRevalidation(
|
|
120
|
+
if (isPathKnownNotEdgeCached(stem || "/")) return scheduleRevalidation(invalidateDataCacheTag(encodedTag));
|
|
121
|
+
return scheduleTagInvalidation(encodedTag);
|
|
113
122
|
}
|
|
114
123
|
/**
|
|
115
124
|
* No-op shim for API compatibility.
|
|
@@ -140,7 +149,7 @@ function updateTag(tag) {
|
|
|
140
149
|
markActionRevalidation(1);
|
|
141
150
|
const encodedTag = encodeCacheTag(tag);
|
|
142
151
|
_markPendingRevalidatedTag(encodedTag);
|
|
143
|
-
return
|
|
152
|
+
return scheduleTagInvalidation(encodedTag);
|
|
144
153
|
}
|
|
145
154
|
/**
|
|
146
155
|
* Opt out of static rendering and indicate a particular component should not be cached.
|
|
@@ -464,4 +473,4 @@ function unstable_cache(fn, keyParts, options) {
|
|
|
464
473
|
return cachedFn;
|
|
465
474
|
}
|
|
466
475
|
//#endregion
|
|
467
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
|
|
476
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/shims/cdn-purge-routes.d.ts
|
|
2
|
+
type CdnPurgeRoute = {
|
|
3
|
+
patternParts: readonly string[];
|
|
4
|
+
routeSegments: readonly string[];
|
|
5
|
+
};
|
|
6
|
+
type CdnPurgeRoutes = {
|
|
7
|
+
metadataRoutes: readonly (Omit<CdnPurgeRoute, "patternParts"> & {
|
|
8
|
+
patternParts: readonly string[] | null;
|
|
9
|
+
servedUrl: string;
|
|
10
|
+
})[];
|
|
11
|
+
routes: readonly (CdnPurgeRoute & {
|
|
12
|
+
forceDynamic?: boolean;
|
|
13
|
+
})[];
|
|
14
|
+
};
|
|
15
|
+
/** Register the App Router's routes. Apps with a Pages Router never register. */
|
|
16
|
+
export declare function registerCdnPurgeRoutes(routes: CdnPurgeRoutes): void;
|
|
17
|
+
/**
|
|
18
|
+
* Whether no edge-cacheable response can carry the implicit tags of
|
|
19
|
+
* `revalidatePath(path)`, for any `type`. Paths that need encoding, the
|
|
20
|
+
* `/index` alias, and paths ending in a derived tag suffix (`/docs/page` is
|
|
21
|
+
* also the `/docs` page tag) always purge.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isPathKnownNotEdgeCached(path: string): boolean;
|
|
24
|
+
//#endregion
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { matchRoutePatternPrefix, routePatternParts } from "../routing/route-pattern.js";
|
|
2
|
+
//#region src/shims/cdn-purge-routes.ts
|
|
3
|
+
/**
|
|
4
|
+
* Build-time route facts that let `revalidatePath()` skip a CDN purge no
|
|
5
|
+
* edge-cached response could match.
|
|
6
|
+
*
|
|
7
|
+
* Edge purges are rate limited (Workers Cache allows 5 a minute per account),
|
|
8
|
+
* and a `dynamic = "force-dynamic"` App route never stores a response the
|
|
9
|
+
* edge can serve. The check is conservative: it only skips a path when at
|
|
10
|
+
* least one App route could serve it and every such route is force-dynamic.
|
|
11
|
+
* The data cache is always invalidated.
|
|
12
|
+
*/
|
|
13
|
+
const CDN_PURGE_ROUTES_KEY = Symbol.for("vinext.cdnPurgeRoutes");
|
|
14
|
+
const globals = globalThis;
|
|
15
|
+
const DERIVED_TAG_SUFFIXES = /* @__PURE__ */ new Set([
|
|
16
|
+
"layout",
|
|
17
|
+
"page",
|
|
18
|
+
"route"
|
|
19
|
+
]);
|
|
20
|
+
/** Register the App Router's routes. Apps with a Pages Router never register. */
|
|
21
|
+
function registerCdnPurgeRoutes(routes) {
|
|
22
|
+
globals[CDN_PURGE_ROUTES_KEY] = routes;
|
|
23
|
+
}
|
|
24
|
+
/** Whether some URL matched by `patternParts` starts with `pathParts`. */
|
|
25
|
+
function canServeUnder(pathParts, patternParts) {
|
|
26
|
+
const last = patternParts.at(-1) ?? "";
|
|
27
|
+
const endsInCatchAll = last.startsWith(":") && (last.endsWith("+") || last.endsWith("*"));
|
|
28
|
+
if (patternParts.length < pathParts.length && !endsInCatchAll) return false;
|
|
29
|
+
return matchRoutePatternPrefix(pathParts, patternParts.slice(0, pathParts.length));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Whether a response from `route` could carry a `revalidatePath(path)` tag.
|
|
33
|
+
* Implicit tags use either the URL (`/blog/a`) or the route's segments
|
|
34
|
+
* (`/(site)/blog/[slug]`), so check both as prefixes.
|
|
35
|
+
*/
|
|
36
|
+
function couldCarryPathTag(pathParts, route) {
|
|
37
|
+
return canServeUnder(pathParts, route.patternParts) || canServeUnder(pathParts, routePatternParts(route.routeSegments.join("/")));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether a metadata route, or a child it generates (`/icon/small` from
|
|
41
|
+
* `generateImageMetadata`, `/sitemap/0.xml` from `generateSitemaps`), could
|
|
42
|
+
* carry a `revalidatePath(path)` tag.
|
|
43
|
+
*/
|
|
44
|
+
function metadataCouldCarryPathTag(pathParts, route) {
|
|
45
|
+
const patternParts = route.patternParts ?? routePatternParts(route.servedUrl);
|
|
46
|
+
const childParts = [
|
|
47
|
+
...patternParts.slice(0, -1),
|
|
48
|
+
(patternParts.at(-1) ?? "").replace(/\.[^.]*$/, ""),
|
|
49
|
+
":children*"
|
|
50
|
+
];
|
|
51
|
+
return couldCarryPathTag(pathParts, {
|
|
52
|
+
patternParts,
|
|
53
|
+
routeSegments: route.routeSegments
|
|
54
|
+
}) || canServeUnder(pathParts, childParts);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether no edge-cacheable response can carry the implicit tags of
|
|
58
|
+
* `revalidatePath(path)`, for any `type`. Paths that need encoding, the
|
|
59
|
+
* `/index` alias, and paths ending in a derived tag suffix (`/docs/page` is
|
|
60
|
+
* also the `/docs` page tag) always purge.
|
|
61
|
+
*/
|
|
62
|
+
function isPathKnownNotEdgeCached(path) {
|
|
63
|
+
const registered = globals[CDN_PURGE_ROUTES_KEY];
|
|
64
|
+
if (!registered || path === "/index" || /[^\x21-\x7e]|%/.test(path)) return false;
|
|
65
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
66
|
+
if (DERIVED_TAG_SUFFIXES.has(pathParts.at(-1) ?? "")) return false;
|
|
67
|
+
if (registered.metadataRoutes.some((route) => metadataCouldCarryPathTag(pathParts, route))) return false;
|
|
68
|
+
let matched = false;
|
|
69
|
+
for (const route of registered.routes) {
|
|
70
|
+
if (!couldCarryPathTag(pathParts, route)) continue;
|
|
71
|
+
if (route.forceDynamic !== true) return false;
|
|
72
|
+
matched = true;
|
|
73
|
+
}
|
|
74
|
+
return matched;
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
export { isPathKnownNotEdgeCached, registerCdnPurgeRoutes };
|
package/dist/shims/dynamic.js
CHANGED
|
@@ -52,13 +52,26 @@ function normalizeDynamicOptions(dynamicInput, options) {
|
|
|
52
52
|
...options
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
function createLazyComponent(loader) {
|
|
56
|
-
return React.lazy(async () => {
|
|
55
|
+
function createLazyComponent(loader, share = (load) => load) {
|
|
56
|
+
return React.lazy(() => share((async () => {
|
|
57
57
|
const mod = await loader();
|
|
58
58
|
if (hasDefaultExport(mod)) return mod;
|
|
59
59
|
return { default: mod };
|
|
60
|
-
});
|
|
60
|
+
})()));
|
|
61
61
|
}
|
|
62
|
+
const SHARE_ISOLATE_PROMISE_KEY = Symbol.for("vinext.shareIsolatePromise");
|
|
63
|
+
/**
|
|
64
|
+
* The server React.lazy is created once per dynamic() call, so every request
|
|
65
|
+
* in the isolate renders the same load. On Workers, the request that starts it
|
|
66
|
+
* owns its I/O; if that request is canceled first, the load never settles and
|
|
67
|
+
* every later render of the component hangs. The server installs
|
|
68
|
+
* `shareIsolatePromise` on a global symbol, which keeps the starting request
|
|
69
|
+
* alive until the load settles, without this shim importing request state.
|
|
70
|
+
*/
|
|
71
|
+
const shareServerLoad = (load) => {
|
|
72
|
+
const share = globalThis[SHARE_ISOLATE_PROMISE_KEY];
|
|
73
|
+
return share ? share(load) : load;
|
|
74
|
+
};
|
|
62
75
|
function useRetryableLazyComponent(loader, initialLazyComponent) {
|
|
63
76
|
const [LazyComponent, setLazyComponent] = React.useState(() => initialLazyComponent);
|
|
64
77
|
const [retryKey, setRetryKey] = React.useState(0);
|
|
@@ -218,7 +231,7 @@ function dynamic(dynamicInput, options) {
|
|
|
218
231
|
AsyncServerDynamic.displayName = "DynamicAsyncServer";
|
|
219
232
|
return AsyncServerDynamic;
|
|
220
233
|
}
|
|
221
|
-
const LazyServer = createLazyComponent(loader);
|
|
234
|
+
const LazyServer = createLazyComponent(loader, shareServerLoad);
|
|
222
235
|
const ServerDynamic = (props) => {
|
|
223
236
|
const isAppRouterTree = useIsAppRouterTree();
|
|
224
237
|
const fallback = LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps()) : null;
|