vinext 1.0.0-beta.0 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -2
- package/dist/build/assets-ignore.js +1 -1
- package/dist/build/clean-output.js +1 -1
- package/dist/build/client-build-config.js +7 -4
- package/dist/build/css-url-assets.js +3 -3
- package/dist/build/google-fonts/fallback-metrics.js +1 -1
- package/dist/build/google-fonts/font-metadata.js +1 -1
- package/dist/build/inject-pregenerated-paths.js +1 -1
- package/dist/build/inline-css.js +2 -5
- package/dist/build/module-dependency-cache.d.ts +4 -0
- package/dist/build/module-dependency-cache.js +13 -0
- package/dist/build/next-client-runtime-manifests.js +1 -1
- package/dist/build/pages-client-assets-module.js +1 -1
- package/dist/build/precompress.js +7 -7
- package/dist/build/prerender-paths.d.ts +2 -2
- package/dist/build/prerender-paths.js +10 -15
- package/dist/build/prerender-server-pool.js +2 -2
- package/dist/build/prerender.js +1 -1
- package/dist/build/preview-credentials.d.ts +11 -0
- package/dist/build/preview-credentials.js +19 -0
- package/dist/build/report.d.ts +8 -4
- package/dist/build/report.js +14 -6
- package/dist/build/run-prerender.d.ts +2 -11
- package/dist/build/run-prerender.js +2 -10
- package/dist/build/server-manifest.js +1 -1
- package/dist/build/ssr-manifest.d.ts +4 -0
- package/dist/build/ssr-manifest.js +10 -6
- package/dist/build/standalone.js +37 -37
- package/dist/cache/cache-adapters-virtual.d.ts +1 -17
- package/dist/cache/cache-adapters-virtual.js +20 -11
- package/dist/check.d.ts +0 -16
- package/dist/check.js +27 -36
- package/dist/cli.js +61 -55
- package/dist/client/instrumentation-client-inject.js +1 -1
- package/dist/client/pages-router-link-navigation.js +1 -1
- package/dist/config/config-matchers.d.ts +13 -37
- package/dist/config/config-matchers.js +33 -123
- package/dist/config/dotenv.js +1 -1
- package/dist/config/next-config.d.ts +7 -3
- package/dist/config/next-config.js +84 -15
- package/dist/config/prerender.d.ts +2 -2
- package/dist/config/prerender.js +7 -15
- package/dist/config/request-context.d.ts +14 -0
- package/dist/config/request-context.js +26 -0
- package/dist/config/server-external-packages.js +1 -1
- package/dist/config/tsconfig-paths.js +2 -2
- package/dist/{node_modules/.pnpm/am-i-vibing@0.5.0/node_modules → deps/.pnpm/am-i-vibing@0.5.0/deps}/am-i-vibing/dist/detector-1yx2Hoe0.js +2 -2
- package/dist/deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js +50 -0
- package/dist/entries/app-rsc-entry.js +39 -14
- package/dist/entries/app-rsc-manifest.js +21 -4
- package/dist/entries/pages-client-entry.js +6 -5
- package/dist/entries/pages-server-entry.js +18 -28
- package/dist/entries/runtime-entry-module.js +2 -2
- package/dist/index.js +314 -230
- package/dist/init-cloudflare.js +1 -1
- package/dist/init-platform.js +1 -1
- package/dist/init.d.ts +6 -4
- package/dist/init.js +25 -27
- package/dist/plugins/ast-utils.js +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +7 -7
- package/dist/plugins/extensionless-dynamic-import.js +1 -1
- package/dist/plugins/fonts.js +3 -3
- package/dist/plugins/ignore-dynamic-requests.js +13 -8
- package/dist/plugins/import-meta-url.js +16 -17
- package/dist/plugins/middleware-export-validation.js +1 -1
- package/dist/plugins/middleware-server-only.js +2 -2
- package/dist/plugins/og-asset-ownership.js +7 -6
- package/dist/plugins/og-assets.js +5 -6
- package/dist/plugins/optimize-imports.js +12 -13
- package/dist/plugins/postcss.js +1 -1
- package/dist/plugins/remove-console.js +1 -1
- package/dist/plugins/require-context.js +1 -1
- package/dist/plugins/sass.js +2 -2
- package/dist/plugins/server-externals-manifest.js +1 -1
- package/dist/plugins/strip-server-exports.js +1 -1
- package/dist/plugins/styled-jsx.js +3 -2
- package/dist/plugins/typeof-window.js +1 -1
- package/dist/routing/app-route-graph.d.ts +16 -15
- package/dist/routing/app-route-graph.js +86 -88
- package/dist/routing/app-router.d.ts +0 -5
- package/dist/routing/app-router.js +12 -11
- package/dist/routing/file-matcher.d.ts +13 -28
- package/dist/routing/file-matcher.js +31 -44
- package/dist/routing/pages-router.js +26 -32
- package/dist/routing/route-matching.d.ts +14 -1
- package/dist/routing/route-matching.js +13 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +7 -4
- package/dist/routing/route-trie.d.ts +5 -1
- package/dist/routing/route-trie.js +5 -2
- package/dist/server/api-handler.js +41 -33
- package/dist/server/app-browser-entry.js +18 -11
- package/dist/server/app-browser-history-controller.d.ts +1 -1
- package/dist/server/app-browser-history-controller.js +3 -3
- package/dist/server/app-browser-navigation-controller.js +4 -2
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-elements-wire.d.ts +2 -1
- package/dist/server/app-fallback-renderer.d.ts +11 -0
- package/dist/server/app-fallback-renderer.js +16 -2
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +26 -2
- package/dist/server/app-page-boundary-render.js +190 -55
- package/dist/server/app-page-cache-finalizer.d.ts +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-dispatch.d.ts +12 -2
- package/dist/server/app-page-dispatch.js +37 -51
- package/dist/server/app-page-element-builder.d.ts +8 -2
- package/dist/server/app-page-element-builder.js +112 -27
- package/dist/server/app-page-execution.d.ts +3 -1
- package/dist/server/app-page-execution.js +31 -39
- package/dist/server/app-page-head.d.ts +54 -2
- package/dist/server/app-page-head.js +164 -78
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +106 -0
- package/dist/server/app-page-render.d.ts +2 -2
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-request.d.ts +12 -0
- package/dist/server/app-page-request.js +134 -14
- package/dist/server/app-page-route-wiring.d.ts +9 -0
- package/dist/server/app-page-route-wiring.js +44 -4
- package/dist/server/app-post-middleware-context.d.ts +1 -1
- package/dist/server/app-post-middleware-context.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +31 -17
- package/dist/server/app-route-handler-execution.d.ts +6 -1
- package/dist/server/app-route-handler-execution.js +41 -15
- package/dist/server/app-route-handler-policy.d.ts +2 -0
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-module-loader.d.ts +3 -1
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-route-tree-prefetch.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +1 -1
- package/dist/server/app-rsc-cache-busting.js +1 -1
- package/dist/server/app-rsc-errors.d.ts +1 -1
- package/dist/server/app-rsc-errors.js +12 -2
- package/dist/server/app-rsc-handler.d.ts +10 -5
- package/dist/server/app-rsc-handler.js +51 -23
- package/dist/server/app-rsc-redirect-flight.d.ts +66 -0
- package/dist/server/app-rsc-redirect-flight.js +71 -0
- package/dist/server/app-rsc-request-normalization.d.ts +3 -2
- package/dist/server/app-rsc-request-normalization.js +8 -2
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
- package/dist/server/app-rsc-response-finalizer.js +5 -11
- package/dist/server/app-rsc-route-matching.d.ts +20 -0
- package/dist/server/app-rsc-route-matching.js +87 -11
- package/dist/server/app-segment-config.js +15 -5
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +8 -6
- package/dist/server/app-ssr-entry.js +4 -1
- package/dist/server/app-ssr-stream.d.ts +2 -7
- package/dist/server/app-ssr-stream.js +5 -10
- package/dist/server/cache-proof.js +1 -1
- package/dist/server/config-headers.d.ts +24 -0
- package/dist/server/config-headers.js +52 -0
- package/dist/server/default-global-error-module.d.ts +3 -1
- package/dist/server/default-not-found-module.d.ts +3 -1
- package/dist/server/dev-initial-server-error.d.ts +1 -1
- package/dist/server/dev-lockfile.js +2 -3
- package/dist/server/dev-route-files.js +1 -1
- package/dist/server/dev-server.js +281 -173
- package/dist/server/dev-stack-sourcemap.js +4 -3
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/image-optimization.js +2 -2
- package/dist/server/implicit-tags.js +2 -1
- package/dist/server/instrumentation.js +2 -2
- package/dist/server/isr-cache.d.ts +1 -1
- package/dist/server/isr-cache.js +1 -1
- package/dist/server/metadata-routes.js +4 -4
- package/dist/server/middleware-matcher-pattern.d.ts +22 -0
- package/dist/server/middleware-matcher-pattern.js +219 -0
- package/dist/server/middleware-matcher.d.ts +2 -7
- package/dist/server/middleware-matcher.js +13 -60
- package/dist/server/middleware-path-to-regexp.d.ts +14 -0
- package/dist/server/middleware-path-to-regexp.js +228 -0
- package/dist/server/middleware-response-headers.js +1 -1
- package/dist/server/middleware-runtime.js +5 -4
- package/dist/server/middleware.d.ts +2 -1
- package/dist/server/middleware.js +3 -2
- package/dist/server/navigation-planner.d.ts +2 -0
- package/dist/server/navigation-planner.js +8 -2
- package/dist/server/next-error-digest.d.ts +9 -24
- package/dist/server/next-error-digest.js +23 -15
- package/dist/server/operation-token.js +1 -1
- package/dist/server/pages-body-parser-config.js +2 -1
- package/dist/server/pages-data-route.d.ts +11 -1
- package/dist/server/pages-data-route.js +16 -1
- package/dist/server/pages-dev-hydration.d.ts +14 -0
- package/dist/server/pages-dev-hydration.js +83 -0
- package/dist/server/pages-dev-module-url.js +2 -2
- package/dist/server/pages-get-initial-props.d.ts +15 -2
- package/dist/server/pages-get-initial-props.js +16 -6
- package/dist/server/pages-node-compat.d.ts +13 -6
- package/dist/server/pages-node-compat.js +44 -45
- package/dist/server/pages-page-data.d.ts +4 -2
- package/dist/server/pages-page-data.js +20 -10
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +74 -43
- package/dist/server/pages-page-response.d.ts +2 -2
- package/dist/server/pages-page-response.js +1 -1
- package/dist/server/pages-preview.d.ts +26 -0
- package/dist/server/pages-preview.js +165 -0
- package/dist/server/pages-readiness.d.ts +5 -4
- package/dist/server/pages-readiness.js +4 -2
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +25 -11
- package/dist/server/pages-router-entry.js +6 -0
- package/dist/server/prerender-route-params.js +2 -2
- package/dist/server/prod-server.d.ts +1 -4
- package/dist/server/prod-server.js +44 -30
- package/dist/server/request-pipeline.d.ts +15 -29
- package/dist/server/request-pipeline.js +25 -60
- package/dist/server/rsc-stream-hints.js +122 -18
- package/dist/server/seed-cache.js +1 -1
- package/dist/server/socket-error-backstop.js +1 -1
- package/dist/server/static-file-cache.js +7 -8
- package/dist/server/worker-utils.js +1 -1
- package/dist/shims/app.d.ts +1 -1
- package/dist/shims/cache-request-state.d.ts +27 -1
- package/dist/shims/cache-request-state.js +60 -1
- package/dist/shims/cache-runtime.d.ts +12 -1
- package/dist/shims/cache-runtime.js +22 -7
- package/dist/shims/cache.d.ts +5 -5
- package/dist/shims/cache.js +28 -11
- package/dist/shims/constants.js +1 -1
- package/dist/shims/document.d.ts +42 -83
- package/dist/shims/document.js +62 -53
- package/dist/shims/dynamic.d.ts +5 -25
- package/dist/shims/dynamic.js +29 -8
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error.d.ts +22 -6
- package/dist/shims/error.js +53 -15
- package/dist/shims/fetch-cache.js +13 -4
- package/dist/shims/font-google-base.d.ts +11 -4
- package/dist/shims/font-local.d.ts +10 -3
- package/dist/shims/font-utils.js +1 -1
- package/dist/shims/form.d.ts +1 -1
- package/dist/shims/head.d.ts +13 -2
- package/dist/shims/head.js +6 -6
- package/dist/shims/headers.d.ts +28 -31
- package/dist/shims/headers.js +115 -53
- package/dist/shims/image.d.ts +27 -37
- package/dist/shims/image.js +21 -14
- package/dist/shims/internal/cookie-serialize.d.ts +3 -1
- package/dist/shims/internal/cookie-serialize.js +3 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +5 -3
- package/dist/shims/internal/utils.d.ts +3 -3
- package/dist/shims/layout-segment-context.d.ts +1 -1
- package/dist/shims/legacy-image.d.ts +3 -37
- package/dist/shims/legacy-image.js +6 -16
- package/dist/shims/link.d.ts +16 -21
- package/dist/shims/link.js +25 -13
- package/dist/shims/navigation-context-state.d.ts +1 -1
- package/dist/shims/navigation-errors.d.ts +2 -1
- package/dist/shims/navigation-errors.js +9 -13
- package/dist/shims/navigation.d.ts +8 -4
- package/dist/shims/navigation.js +29 -18
- package/dist/shims/next-shims-augmentations.d.ts +1 -0
- package/dist/shims/next-shims-public.d.ts +1 -0
- package/dist/shims/public-shim-map.json.js +103 -0
- package/dist/shims/readonly-url-search-params.d.ts +3 -3
- package/dist/shims/readonly-url-search-params.js +3 -3
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router.d.ts +57 -22
- package/dist/shims/router.js +178 -46
- package/dist/shims/script.d.ts +6 -10
- package/dist/shims/script.js +7 -4
- package/dist/shims/server.d.ts +45 -22
- package/dist/shims/server.js +46 -7
- package/dist/shims/slot.d.ts +1 -1
- package/dist/shims/thenable-params.js +1 -1
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/url-safety.d.ts +1 -1
- package/dist/shims/url-safety.js +2 -2
- package/dist/typegen.d.ts +8 -2
- package/dist/typegen.js +84 -25
- package/dist/utils/client-build-manifest.js +2 -2
- package/dist/utils/client-entry-manifest.js +1 -1
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/commonjs-loader.js +3 -3
- package/dist/utils/domain-locale.d.ts +2 -2
- package/dist/utils/external-url.d.ts +5 -0
- package/dist/utils/external-url.js +7 -0
- package/dist/utils/mdx-scan.js +1 -1
- package/dist/utils/path.d.ts +1 -13
- package/dist/utils/path.js +1 -15
- package/dist/utils/plugin-options.d.ts +4 -0
- package/dist/utils/plugin-options.js +8 -0
- package/dist/utils/project.d.ts +0 -6
- package/dist/utils/project.js +2 -8
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.js +1 -1
- package/dist/utils/redirect-digest.d.ts +9 -0
- package/dist/utils/redirect-digest.js +25 -0
- package/dist/utils/regex-safety.d.ts +8 -0
- package/dist/utils/regex-safety.js +737 -0
- package/dist/utils/vinext-root.js +1 -1
- package/dist/utils/vite-version.d.ts +5 -2
- package/dist/utils/vite-version.js +43 -17
- package/package.json +16 -4
- /package/dist/build/google-fonts/{fallback-metrics-data.js → fallback-metrics-data.json.js} +0 -0
- /package/dist/build/google-fonts/{font-data.js → font-data.json.js} +0 -0
- /package/dist/{node_modules/.pnpm/process-ancestry@0.1.0/node_modules → deps/.pnpm/process-ancestry@0.1.0/deps}/process-ancestry/dist/index.js +0 -0
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import { NextHeader } from "../config/next-config.js";
|
|
2
|
-
import { BasePathMatchState, RequestContext } from "../config/config-matchers.js";
|
|
3
1
|
import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS } from "./headers.js";
|
|
4
|
-
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
5
2
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
3
|
+
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
6
4
|
|
|
7
5
|
//#region src/server/request-pipeline.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Apply the URL Standard's pathname canonicalization without decoding and
|
|
8
|
+
* re-encoding ordinary percent escapes.
|
|
9
|
+
*
|
|
10
|
+
* In particular, WHATWG URLs remove literal and percent-encoded dot segments
|
|
11
|
+
* (`/%2e/about` becomes `/about`) while preserving unrelated spellings such
|
|
12
|
+
* as `/%61bout`, `%2F`, `%5C`, and `%252F` byte-for-byte. Node request adapters
|
|
13
|
+
* must do this before comparing raw route/config/basePath identity so those
|
|
14
|
+
* comparisons agree with the `Request` that userland eventually receives.
|
|
15
|
+
*/
|
|
16
|
+
declare function canonicalizeRequestPathname(pathname: string): string;
|
|
17
|
+
/** Canonicalize only the pathname portion while preserving the raw query. */
|
|
18
|
+
declare function canonicalizeRequestUrlPathname(url: string): string;
|
|
8
19
|
/**
|
|
9
20
|
* Shared request pipeline utilities.
|
|
10
21
|
*
|
|
@@ -44,18 +55,6 @@ import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
|
44
55
|
*/
|
|
45
56
|
declare function guardProtocolRelativeUrl(rawPathname: string): Response | null;
|
|
46
57
|
type HeaderRecord = Record<string, string | string[]>;
|
|
47
|
-
type ApplyConfigHeadersOptions = {
|
|
48
|
-
configHeaders: NextHeader[];
|
|
49
|
-
pathname: string;
|
|
50
|
-
requestContext: RequestContext;
|
|
51
|
-
/**
|
|
52
|
-
* basePath gating state. When omitted, every rule is treated as a default
|
|
53
|
-
* (basePath: true) rule for backward compatibility — callers that need to
|
|
54
|
-
* support `basePath: false` headers must pass this in.
|
|
55
|
-
*/
|
|
56
|
-
basePathState?: BasePathMatchState; /** Existing framework-generated headers that matching config rules may replace. */
|
|
57
|
-
overwriteExisting?: ReadonlySet<string>;
|
|
58
|
-
};
|
|
59
58
|
type StaticFileSignalContext = {
|
|
60
59
|
headers: Headers | null;
|
|
61
60
|
status: number | null;
|
|
@@ -67,19 +66,6 @@ type ResolvePublicFileRouteOptions = {
|
|
|
67
66
|
publicFiles: ReadonlySet<string>;
|
|
68
67
|
request: Request;
|
|
69
68
|
};
|
|
70
|
-
/**
|
|
71
|
-
* Apply matched next.config.js headers to a Web Headers object.
|
|
72
|
-
*
|
|
73
|
-
* Next.js evaluates config header match conditions against the original
|
|
74
|
-
* request snapshot. Middleware response headers still win for the same
|
|
75
|
-
* response key, while multi-value headers are additive.
|
|
76
|
-
*/
|
|
77
|
-
declare function applyConfigHeadersToResponse(responseHeaders: Headers, options: ApplyConfigHeadersOptions): void;
|
|
78
|
-
/**
|
|
79
|
-
* Apply matched next.config.js headers to the early response header record used
|
|
80
|
-
* by Node and Worker Pages Router pipelines before a concrete response exists.
|
|
81
|
-
*/
|
|
82
|
-
declare function applyConfigHeadersToHeaderRecord(headers: HeaderRecord, options: ApplyConfigHeadersOptions): void;
|
|
83
69
|
declare function createStaticFileSignal(pathname: string, context: StaticFileSignalContext): Response;
|
|
84
70
|
/**
|
|
85
71
|
* Resolve the public/ filesystem-route slot in the Next.js routing order.
|
|
@@ -184,4 +170,4 @@ declare function cloneRequestWithHeaders(request: Request, headers: Headers): Re
|
|
|
184
170
|
*/
|
|
185
171
|
declare function cloneRequestWithUrl(request: Request, url: string): Request;
|
|
186
172
|
//#endregion
|
|
187
|
-
export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS,
|
|
173
|
+
export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
import { hasBasePath, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
|
|
2
2
|
import "../utils/protocol-headers.js";
|
|
3
3
|
import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, VINEXT_STATIC_FILE_HEADER } from "./headers.js";
|
|
4
|
-
import { matchHeaders } from "../config/config-matchers.js";
|
|
5
4
|
import { forbiddenResponse, notFoundResponse } from "./http-error-responses.js";
|
|
6
5
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
7
6
|
//#region src/server/request-pipeline.ts
|
|
7
|
+
const PATHNAME_CANONICALIZATION_BASE = new URL("http://vinext.invalid/");
|
|
8
|
+
/**
|
|
9
|
+
* Apply the URL Standard's pathname canonicalization without decoding and
|
|
10
|
+
* re-encoding ordinary percent escapes.
|
|
11
|
+
*
|
|
12
|
+
* In particular, WHATWG URLs remove literal and percent-encoded dot segments
|
|
13
|
+
* (`/%2e/about` becomes `/about`) while preserving unrelated spellings such
|
|
14
|
+
* as `/%61bout`, `%2F`, `%5C`, and `%252F` byte-for-byte. Node request adapters
|
|
15
|
+
* must do this before comparing raw route/config/basePath identity so those
|
|
16
|
+
* comparisons agree with the `Request` that userland eventually receives.
|
|
17
|
+
*/
|
|
18
|
+
function canonicalizeRequestPathname(pathname) {
|
|
19
|
+
const url = new URL(PATHNAME_CANONICALIZATION_BASE);
|
|
20
|
+
url.pathname = pathname;
|
|
21
|
+
return url.pathname;
|
|
22
|
+
}
|
|
23
|
+
/** Canonicalize only the pathname portion while preserving the raw query. */
|
|
24
|
+
function canonicalizeRequestUrlPathname(url) {
|
|
25
|
+
const queryIndex = url.indexOf("?");
|
|
26
|
+
const pathname = queryIndex === -1 ? url : url.slice(0, queryIndex);
|
|
27
|
+
const search = queryIndex === -1 ? "" : url.slice(queryIndex);
|
|
28
|
+
return canonicalizeRequestPathname(pathname) + search;
|
|
29
|
+
}
|
|
8
30
|
/**
|
|
9
31
|
* Shared request pipeline utilities.
|
|
10
32
|
*
|
|
@@ -50,63 +72,6 @@ const FILE_LIKE_PATHNAME_RE = /\.[^/]+\/?$/;
|
|
|
50
72
|
function isWellKnownPathname(pathname) {
|
|
51
73
|
return pathname === "/.well-known" || pathname.startsWith("/.well-known/");
|
|
52
74
|
}
|
|
53
|
-
function findHeaderRecordKey(headers, lowerName) {
|
|
54
|
-
for (const key of Object.keys(headers)) if (key.toLowerCase() === lowerName) return key;
|
|
55
|
-
}
|
|
56
|
-
function appendHeaderRecord(headers, lowerName, value) {
|
|
57
|
-
const key = findHeaderRecordKey(headers, lowerName) ?? lowerName;
|
|
58
|
-
const existing = headers[key];
|
|
59
|
-
if (existing === void 0) {
|
|
60
|
-
headers[key] = value;
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (Array.isArray(existing)) {
|
|
64
|
-
existing.push(value);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
headers[key] = [existing, value];
|
|
68
|
-
}
|
|
69
|
-
function appendVaryHeaderRecord(headers, value) {
|
|
70
|
-
const key = findHeaderRecordKey(headers, "vary") ?? "vary";
|
|
71
|
-
const existing = headers[key];
|
|
72
|
-
if (existing === void 0) {
|
|
73
|
-
headers[key] = value;
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (Array.isArray(existing)) {
|
|
77
|
-
existing.push(value);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
headers[key] = existing + ", " + value;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Apply matched next.config.js headers to a Web Headers object.
|
|
84
|
-
*
|
|
85
|
-
* Next.js evaluates config header match conditions against the original
|
|
86
|
-
* request snapshot. Middleware response headers still win for the same
|
|
87
|
-
* response key, while multi-value headers are additive.
|
|
88
|
-
*/
|
|
89
|
-
function applyConfigHeadersToResponse(responseHeaders, options) {
|
|
90
|
-
const matched = matchHeaders(options.pathname, options.configHeaders, options.requestContext, options.basePathState);
|
|
91
|
-
for (const header of matched) {
|
|
92
|
-
const lowerName = header.key.toLowerCase();
|
|
93
|
-
if (lowerName === "vary" || lowerName === "set-cookie") responseHeaders.append(header.key, header.value);
|
|
94
|
-
else if (options.overwriteExisting?.has(lowerName) || !responseHeaders.has(lowerName)) responseHeaders.set(header.key, header.value);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Apply matched next.config.js headers to the early response header record used
|
|
99
|
-
* by Node and Worker Pages Router pipelines before a concrete response exists.
|
|
100
|
-
*/
|
|
101
|
-
function applyConfigHeadersToHeaderRecord(headers, options) {
|
|
102
|
-
const matched = matchHeaders(options.pathname, options.configHeaders, options.requestContext, options.basePathState);
|
|
103
|
-
for (const header of matched) {
|
|
104
|
-
const lowerName = header.key.toLowerCase();
|
|
105
|
-
if (lowerName === "set-cookie") appendHeaderRecord(headers, lowerName, header.value);
|
|
106
|
-
else if (lowerName === "vary") appendVaryHeaderRecord(headers, header.value);
|
|
107
|
-
else if (findHeaderRecordKey(headers, lowerName) === void 0) headers[lowerName] = header.value;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
75
|
function createStaticFileSignal(pathname, context) {
|
|
111
76
|
const headers = new Headers({ [VINEXT_STATIC_FILE_HEADER]: encodeURIComponent(pathname) });
|
|
112
77
|
if (context.headers) for (const [key, value] of context.headers) headers.append(key, value);
|
|
@@ -341,7 +306,7 @@ function processMiddlewareHeaders(headers) {
|
|
|
341
306
|
for (const key of headers.keys()) if (key.startsWith("x-middleware-") && key !== "x-middleware-cache") keysToDelete.push(key);
|
|
342
307
|
for (const key of keysToDelete) headers.delete(key);
|
|
343
308
|
}
|
|
344
|
-
const STRIPPED_INTERNAL_HEADERS = new Set([...INTERNAL_HEADERS, ...VINEXT_INTERNAL_HEADERS]);
|
|
309
|
+
const STRIPPED_INTERNAL_HEADERS = /* @__PURE__ */ new Set([...INTERNAL_HEADERS, ...VINEXT_INTERNAL_HEADERS]);
|
|
345
310
|
/**
|
|
346
311
|
* Strip internal headers from an inbound request so they cannot be forged by
|
|
347
312
|
* an external attacker to influence routing or impersonate internal state.
|
|
@@ -445,4 +410,4 @@ function cloneRequestWithUrl(request, url) {
|
|
|
445
410
|
return cloned;
|
|
446
411
|
}
|
|
447
412
|
//#endregion
|
|
448
|
-
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS,
|
|
413
|
+
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
@@ -1,31 +1,135 @@
|
|
|
1
1
|
//#region src/server/rsc-stream-hints.ts
|
|
2
|
-
const REACT_FLIGHT_STYLESHEET_PRELOAD_HINT =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
const REACT_FLIGHT_STYLESHEET_PRELOAD_HINT = /^([0-9a-f]*:HL\[.*?),"stylesheet"(\]|,)/;
|
|
3
|
+
const STYLESHEET_TO_STYLE_JSON_PADDING = " ".repeat(5);
|
|
4
|
+
const LENGTH_PREFIXED_ROW_TAGS = /* @__PURE__ */ new Set([
|
|
5
|
+
"T",
|
|
6
|
+
"A",
|
|
7
|
+
"O",
|
|
8
|
+
"o",
|
|
9
|
+
"b",
|
|
10
|
+
"U",
|
|
11
|
+
"S",
|
|
12
|
+
"s",
|
|
13
|
+
"L",
|
|
14
|
+
"l",
|
|
15
|
+
"G",
|
|
16
|
+
"g",
|
|
17
|
+
"M",
|
|
18
|
+
"m",
|
|
19
|
+
"V"
|
|
20
|
+
]);
|
|
21
|
+
const NEWLINE_PREFIXED_ROW_TAGS = /* @__PURE__ */ new Set([
|
|
22
|
+
"I",
|
|
23
|
+
"H",
|
|
24
|
+
"E",
|
|
25
|
+
"N",
|
|
26
|
+
"D",
|
|
27
|
+
"J",
|
|
28
|
+
"W",
|
|
29
|
+
"R",
|
|
30
|
+
"r",
|
|
31
|
+
"X",
|
|
32
|
+
"x",
|
|
33
|
+
"C",
|
|
34
|
+
"P",
|
|
35
|
+
"#"
|
|
36
|
+
]);
|
|
37
|
+
const decoder = new TextDecoder();
|
|
38
|
+
const encoder = new TextEncoder();
|
|
39
|
+
/** Rewrite only a complete React Flight stylesheet hint row. */
|
|
8
40
|
function normalizeReactFlightHintLine(line) {
|
|
9
|
-
|
|
41
|
+
const text = decoder.decode(line);
|
|
42
|
+
const normalized = text.replace(REACT_FLIGHT_STYLESHEET_PRELOAD_HINT, `$1,"style"${STYLESHEET_TO_STYLE_JSON_PADDING}$2`);
|
|
43
|
+
if (normalized === text) return line;
|
|
44
|
+
const normalizedBytes = encoder.encode(normalized);
|
|
45
|
+
return normalizedBytes.byteLength === line.byteLength ? normalizedBytes : line;
|
|
46
|
+
}
|
|
47
|
+
function concatBytes(first, second) {
|
|
48
|
+
if (first.byteLength === 0) return second;
|
|
49
|
+
const combined = new Uint8Array(first.byteLength + second.byteLength);
|
|
50
|
+
combined.set(first);
|
|
51
|
+
combined.set(second, first.byteLength);
|
|
52
|
+
return combined;
|
|
53
|
+
}
|
|
54
|
+
function indexOfByte(bytes, byte, from = 0) {
|
|
55
|
+
for (let index = from; index < bytes.byteLength; index++) if (bytes[index] === byte) return index;
|
|
56
|
+
return -1;
|
|
57
|
+
}
|
|
58
|
+
function parseHexBytes(bytes, start, end) {
|
|
59
|
+
if (start === end) return null;
|
|
60
|
+
let value = 0;
|
|
61
|
+
for (let index = start; index < end; index++) {
|
|
62
|
+
const byte = bytes[index];
|
|
63
|
+
const digit = byte >= 48 && byte <= 57 ? byte - 48 : byte >= 97 && byte <= 102 ? byte - 87 : -1;
|
|
64
|
+
if (digit === -1) return null;
|
|
65
|
+
value = value * 16 + digit;
|
|
66
|
+
if (!Number.isSafeInteger(value)) return null;
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
function isUntaggedJsonRowStart(byte) {
|
|
71
|
+
return byte === 34 || byte === 45 || byte >= 48 && byte <= 57 || byte === 91 || byte === 102 || byte === 110 || byte === 116 || byte === 123;
|
|
10
72
|
}
|
|
11
73
|
function normalizeReactFlightPreloadHints(stream) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let
|
|
74
|
+
let carry = /* @__PURE__ */ new Uint8Array();
|
|
75
|
+
let rawBytesRemaining = 0;
|
|
76
|
+
let passThrough = false;
|
|
15
77
|
return stream.pipeThrough(new TransformStream({
|
|
16
78
|
transform(chunk, controller) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (lastNewline === -1) {
|
|
20
|
-
carry = text;
|
|
79
|
+
if (passThrough) {
|
|
80
|
+
controller.enqueue(chunk);
|
|
21
81
|
return;
|
|
22
82
|
}
|
|
23
|
-
|
|
24
|
-
|
|
83
|
+
let bytes = concatBytes(carry, chunk);
|
|
84
|
+
carry = /* @__PURE__ */ new Uint8Array();
|
|
85
|
+
while (bytes.byteLength > 0) {
|
|
86
|
+
if (rawBytesRemaining > 0) {
|
|
87
|
+
const length = Math.min(rawBytesRemaining, bytes.byteLength);
|
|
88
|
+
controller.enqueue(bytes.slice(0, length));
|
|
89
|
+
rawBytesRemaining -= length;
|
|
90
|
+
bytes = bytes.subarray(length);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const colon = indexOfByte(bytes, 58);
|
|
94
|
+
if (colon === -1 || colon + 1 === bytes.byteLength) {
|
|
95
|
+
carry = bytes.slice();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const tag = String.fromCharCode(bytes[colon + 1]);
|
|
99
|
+
if (LENGTH_PREFIXED_ROW_TAGS.has(tag)) {
|
|
100
|
+
const comma = indexOfByte(bytes, 44, colon + 2);
|
|
101
|
+
if (comma === -1) {
|
|
102
|
+
carry = bytes.slice();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const length = parseHexBytes(bytes, colon + 2, comma);
|
|
106
|
+
if (length != null) {
|
|
107
|
+
controller.enqueue(bytes.slice(0, comma + 1));
|
|
108
|
+
rawBytesRemaining = length;
|
|
109
|
+
bytes = bytes.subarray(comma + 1);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
passThrough = true;
|
|
113
|
+
controller.enqueue(bytes);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const tagByte = bytes[colon + 1];
|
|
117
|
+
if (!NEWLINE_PREFIXED_ROW_TAGS.has(tag) && !isUntaggedJsonRowStart(tagByte)) {
|
|
118
|
+
passThrough = true;
|
|
119
|
+
controller.enqueue(bytes);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const newline = indexOfByte(bytes, 10);
|
|
123
|
+
if (newline === -1) {
|
|
124
|
+
carry = bytes.slice();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
controller.enqueue(normalizeReactFlightHintLine(bytes.slice(0, newline + 1)));
|
|
128
|
+
bytes = bytes.subarray(newline + 1);
|
|
129
|
+
}
|
|
25
130
|
},
|
|
26
131
|
flush(controller) {
|
|
27
|
-
|
|
28
|
-
if (text) controller.enqueue(encoder.encode(normalizeReactFlightHintLine(text)));
|
|
132
|
+
if (carry.byteLength > 0) controller.enqueue(rawBytesRemaining > 0 ? carry : normalizeReactFlightHintLine(carry));
|
|
29
133
|
}
|
|
30
134
|
}));
|
|
31
135
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
1
2
|
import { isrCacheKey, isrSetPrerenderedAppPage } from "./isr-cache.js";
|
|
2
3
|
import { getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
|
|
3
4
|
import { buildAppPageCacheTags } from "./app-page-cache.js";
|
|
4
5
|
import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
|
|
5
6
|
import { addPregeneratedConcretePath, clearPregeneratedConcretePaths, normalizePregeneratedPathname } from "./pregenerated-concrete-paths.js";
|
|
6
7
|
import fs from "node:fs";
|
|
7
|
-
import path from "node:path";
|
|
8
8
|
//#region src/server/seed-cache.ts
|
|
9
9
|
/**
|
|
10
10
|
* Seed the memory cache from pre-rendered build output.
|
|
@@ -90,7 +90,7 @@ function peerDisconnectCode(err) {
|
|
|
90
90
|
const code = err?.code;
|
|
91
91
|
return code === "ECONNRESET" || code === "EPIPE" || code === "ECONNABORTED" ? code : void 0;
|
|
92
92
|
}
|
|
93
|
-
const STATIC_ASSET_IMPORT_EXTENSIONS = new Set([
|
|
93
|
+
const STATIC_ASSET_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
94
94
|
".css",
|
|
95
95
|
".scss",
|
|
96
96
|
".sass",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { ASSET_PREFIX_URL_DIR } from "../utils/asset-prefix.js";
|
|
3
|
-
import
|
|
4
|
-
import fs from "node:fs/promises";
|
|
3
|
+
import fsp from "node:fs/promises";
|
|
5
4
|
//#region src/server/static-file-cache.ts
|
|
6
5
|
/**
|
|
7
6
|
* Startup metadata cache for static file serving.
|
|
@@ -137,7 +136,7 @@ var StaticFileCache = class StaticFileCache {
|
|
|
137
136
|
}
|
|
138
137
|
}
|
|
139
138
|
for (let i = 0; i < toBuffer.length; i += 64) await Promise.all(toBuffer.slice(i, i + 64).map(async (v) => {
|
|
140
|
-
v.buffer = await
|
|
139
|
+
v.buffer = await fsp.readFile(v.path);
|
|
141
140
|
}));
|
|
142
141
|
return new StaticFileCache(entries);
|
|
143
142
|
}
|
|
@@ -170,7 +169,7 @@ function etagFromFilenameHash(relativePath, ext) {
|
|
|
170
169
|
const suffix = basename.slice(lastDash + 1);
|
|
171
170
|
if (suffix.length >= 6 && suffix.length <= 12 && /^[A-Za-z0-9_-]+$/.test(suffix)) return `W/"${suffix}"`;
|
|
172
171
|
}
|
|
173
|
-
const normalizedPath =
|
|
172
|
+
const normalizedPath = toSlash(relativePath);
|
|
174
173
|
const managedMediaSegment = `${ASSET_PREFIX_URL_DIR}/media/`;
|
|
175
174
|
if (normalizedPath.startsWith(managedMediaSegment) || normalizedPath.includes(`/${managedMediaSegment}`)) {
|
|
176
175
|
const lastDot = basename.lastIndexOf(".");
|
|
@@ -204,7 +203,7 @@ const STAT_BATCH_SIZE = 64;
|
|
|
204
203
|
async function* walkFilesWithStats(dir, base = dir) {
|
|
205
204
|
let entries;
|
|
206
205
|
try {
|
|
207
|
-
entries = await
|
|
206
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
208
207
|
} catch {
|
|
209
208
|
return;
|
|
210
209
|
}
|
|
@@ -216,9 +215,9 @@ async function* walkFilesWithStats(dir, base = dir) {
|
|
|
216
215
|
}
|
|
217
216
|
for (let i = 0; i < files.length; i += STAT_BATCH_SIZE) {
|
|
218
217
|
const batch = files.slice(i, i + STAT_BATCH_SIZE);
|
|
219
|
-
const stats = await Promise.all(batch.map((f) =>
|
|
218
|
+
const stats = await Promise.all(batch.map((f) => fsp.stat(f)));
|
|
220
219
|
for (let j = 0; j < batch.length; j++) yield {
|
|
221
|
-
relativePath:
|
|
220
|
+
relativePath: path.relative(base, batch[j]),
|
|
222
221
|
fullPath: batch[j],
|
|
223
222
|
stat: {
|
|
224
223
|
size: stats[j].size,
|
|
@@ -14,7 +14,7 @@ import { notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
|
14
14
|
* are preserved). Uses getSetCookie() to preserve multiple Set-Cookie values.
|
|
15
15
|
* Keep this in sync with prod-server.ts.
|
|
16
16
|
*/
|
|
17
|
-
const NO_BODY_RESPONSE_STATUSES = new Set([
|
|
17
|
+
const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
|
|
18
18
|
204,
|
|
19
19
|
205,
|
|
20
20
|
304
|
package/dist/shims/app.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ declare function appGetInitialProps({
|
|
|
36
36
|
declare class App<P = any, CP = any, S = any> extends React.Component<P & AppProps<CP>, S> {
|
|
37
37
|
static origGetInitialProps: typeof appGetInitialProps;
|
|
38
38
|
static getInitialProps: typeof appGetInitialProps;
|
|
39
|
-
render(): React.
|
|
39
|
+
render(): React.ReactElement;
|
|
40
40
|
}
|
|
41
41
|
//#endregion
|
|
42
42
|
export { AppContext, AppInitialProps, AppProps, App as default };
|
|
@@ -26,6 +26,8 @@ type UnstableCacheObservation = Readonly<{
|
|
|
26
26
|
}>;
|
|
27
27
|
type CacheState = {
|
|
28
28
|
actionRevalidationKind: ActionRevalidationKind;
|
|
29
|
+
pendingRevalidatedTags: Set<string>;
|
|
30
|
+
pendingRevalidations: Set<Promise<void>>;
|
|
29
31
|
requestScopedCacheLife: CacheLifeConfig | null;
|
|
30
32
|
unstableCacheObservations: Map<string, UnstableCacheObservation>;
|
|
31
33
|
unstableCacheRevalidation: UnstableCacheRevalidationMode;
|
|
@@ -37,6 +39,30 @@ declare function _runWithCacheState<T>(fn: () => T | Promise<T>): T | Promise<T>
|
|
|
37
39
|
declare function _initRequestScopedCacheState(): void;
|
|
38
40
|
declare function markActionRevalidation(kind: ActionRevalidationKind): void;
|
|
39
41
|
declare function getAndClearActionRevalidationKind(): ActionRevalidationKind;
|
|
42
|
+
/** @internal */
|
|
43
|
+
declare function _markPendingRevalidatedTag(tag: string): void;
|
|
44
|
+
/** @internal */
|
|
45
|
+
declare function _hasPendingRevalidatedTag(tags: readonly string[]): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Record a cache invalidation that must finish before the current action or
|
|
48
|
+
* route-handler request is finalized. The public revalidation APIs remain
|
|
49
|
+
* synchronous, matching Next.js, while the request boundary owns the await.
|
|
50
|
+
*
|
|
51
|
+
* Returns false outside a request-like phase so standalone calls can retain
|
|
52
|
+
* their historical background-work behavior without accumulating promises in
|
|
53
|
+
* the process-global fallback state.
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
declare function _queuePendingRevalidation(promise: Promise<void>): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Await and clear every cache invalidation queued in the current request.
|
|
60
|
+
* Clearing before awaiting also lets a later drain observe work enqueued by
|
|
61
|
+
* an async continuation while this batch is settling.
|
|
62
|
+
*
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
declare function _drainPendingRevalidations(): Promise<void>;
|
|
40
66
|
declare function _setRequestScopedCacheLife(config: CacheLifeConfig): void;
|
|
41
67
|
declare function _peekRequestScopedCacheLife(): CacheLifeConfig | null;
|
|
42
68
|
declare function _consumeRequestScopedCacheLife(): CacheLifeConfig | null;
|
|
@@ -44,4 +70,4 @@ declare function recordUnstableCacheObservation(observation: UnstableCacheObserv
|
|
|
44
70
|
declare function _peekUnstableCacheObservations(): UnstableCacheObservation[];
|
|
45
71
|
declare function shouldServeStaleUnstableCacheEntry(): boolean;
|
|
46
72
|
//#endregion
|
|
47
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _consumeRequestScopedCacheLife, _initRequestScopedCacheState, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
|
|
73
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
|
|
@@ -53,6 +53,8 @@ const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
|
|
|
53
53
|
const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
|
|
54
54
|
const fallbackState = globalState[FALLBACK_KEY] ??= {
|
|
55
55
|
actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
|
|
56
|
+
pendingRevalidatedTags: /* @__PURE__ */ new Set(),
|
|
57
|
+
pendingRevalidations: /* @__PURE__ */ new Set(),
|
|
56
58
|
requestScopedCacheLife: null,
|
|
57
59
|
unstableCacheObservations: /* @__PURE__ */ new Map(),
|
|
58
60
|
unstableCacheRevalidation: "foreground"
|
|
@@ -70,6 +72,8 @@ function _runWithCacheState(fn) {
|
|
|
70
72
|
}, fn);
|
|
71
73
|
const state = {
|
|
72
74
|
actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
|
|
75
|
+
pendingRevalidatedTags: /* @__PURE__ */ new Set(),
|
|
76
|
+
pendingRevalidations: /* @__PURE__ */ new Set(),
|
|
73
77
|
requestScopedCacheLife: null,
|
|
74
78
|
unstableCacheObservations: /* @__PURE__ */ new Map(),
|
|
75
79
|
unstableCacheRevalidation: "foreground"
|
|
@@ -93,6 +97,61 @@ function getAndClearActionRevalidationKind() {
|
|
|
93
97
|
state.actionRevalidationKind = ACTION_DID_NOT_REVALIDATE;
|
|
94
98
|
return kind;
|
|
95
99
|
}
|
|
100
|
+
function hasRequestScopedCacheState() {
|
|
101
|
+
if (isInsideUnifiedScope() || cacheAls.getStore() !== void 0) return true;
|
|
102
|
+
const phase = getHeadersAccessPhase();
|
|
103
|
+
return phase === "action" || phase === "route-handler";
|
|
104
|
+
}
|
|
105
|
+
/** @internal */
|
|
106
|
+
function _markPendingRevalidatedTag(tag) {
|
|
107
|
+
if (!hasRequestScopedCacheState()) return;
|
|
108
|
+
getCacheState().pendingRevalidatedTags.add(tag);
|
|
109
|
+
}
|
|
110
|
+
/** @internal */
|
|
111
|
+
function _hasPendingRevalidatedTag(tags) {
|
|
112
|
+
if (!hasRequestScopedCacheState()) return false;
|
|
113
|
+
const pendingTags = getCacheState().pendingRevalidatedTags;
|
|
114
|
+
return tags.some((tag) => pendingTags.has(tag));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Record a cache invalidation that must finish before the current action or
|
|
118
|
+
* route-handler request is finalized. The public revalidation APIs remain
|
|
119
|
+
* synchronous, matching Next.js, while the request boundary owns the await.
|
|
120
|
+
*
|
|
121
|
+
* Returns false outside a request-like phase so standalone calls can retain
|
|
122
|
+
* their historical background-work behavior without accumulating promises in
|
|
123
|
+
* the process-global fallback state.
|
|
124
|
+
*
|
|
125
|
+
* @internal
|
|
126
|
+
*/
|
|
127
|
+
function _queuePendingRevalidation(promise) {
|
|
128
|
+
if (!hasRequestScopedCacheState()) return false;
|
|
129
|
+
getCacheState().pendingRevalidations.add(promise);
|
|
130
|
+
promise.catch(() => {});
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Await and clear every cache invalidation queued in the current request.
|
|
135
|
+
* Clearing before awaiting also lets a later drain observe work enqueued by
|
|
136
|
+
* an async continuation while this batch is settling.
|
|
137
|
+
*
|
|
138
|
+
* @internal
|
|
139
|
+
*/
|
|
140
|
+
async function _drainPendingRevalidations() {
|
|
141
|
+
const state = getCacheState();
|
|
142
|
+
let didReject = false;
|
|
143
|
+
let firstRejection;
|
|
144
|
+
while (state.pendingRevalidations.size > 0) {
|
|
145
|
+
const pending = [...state.pendingRevalidations];
|
|
146
|
+
state.pendingRevalidations.clear();
|
|
147
|
+
const results = await Promise.allSettled(pending);
|
|
148
|
+
for (const result of results) if (result.status === "rejected" && !didReject) {
|
|
149
|
+
didReject = true;
|
|
150
|
+
firstRejection = result.reason;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (didReject) throw firstRejection;
|
|
154
|
+
}
|
|
96
155
|
function _setRequestScopedCacheLife(config) {
|
|
97
156
|
const state = getCacheState();
|
|
98
157
|
if (state.requestScopedCacheLife === null) {
|
|
@@ -123,4 +182,4 @@ function shouldServeStaleUnstableCacheEntry() {
|
|
|
123
182
|
return getCacheState().unstableCacheRevalidation === "background";
|
|
124
183
|
}
|
|
125
184
|
//#endregion
|
|
126
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _consumeRequestScopedCacheLife, _initRequestScopedCacheState, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
|
|
185
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
|
|
@@ -35,6 +35,17 @@ declare const cacheContextStorage: import("node:async_hooks").AsyncLocalStorage<
|
|
|
35
35
|
* Get the current cache context. Returns null if not inside a "use cache" function.
|
|
36
36
|
*/
|
|
37
37
|
declare function getCacheContext(): CacheContext | null;
|
|
38
|
+
/**
|
|
39
|
+
* Build the shared-cache key for a "use cache" function from its build-scoped
|
|
40
|
+
* identity and serialized arguments.
|
|
41
|
+
*
|
|
42
|
+
* This is a logical handler key, not a storage key. Backend-specific adapters
|
|
43
|
+
* are responsible for mapping it to their physical key constraints after
|
|
44
|
+
* applying any storage prefixes.
|
|
45
|
+
*
|
|
46
|
+
* Exported for testing.
|
|
47
|
+
*/
|
|
48
|
+
declare function buildUseCacheKey(id: string, keySeed: string | undefined, argsKey?: string): string;
|
|
38
49
|
/**
|
|
39
50
|
* Convert an encodeReply result (string | FormData) to a cache key string.
|
|
40
51
|
* For FormData (binary args), produces a deterministic SHA-256 hash over
|
|
@@ -80,4 +91,4 @@ type RegisterCachedFunctionOptions = {
|
|
|
80
91
|
*/
|
|
81
92
|
declare function registerCachedFunction<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, id: string, variant?: string, options?: RegisterCachedFunctionOptions): (...args: TArgs) => Promise<TResult>;
|
|
82
93
|
//#endregion
|
|
83
|
-
export { CacheContext, NestedDynamicUseCacheError, PrivateCacheState, cacheContextStorage, clearPrivateCache, getCacheContext, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
|
|
94
|
+
export { CacheContext, NestedDynamicUseCacheError, PrivateCacheState, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
|
|
@@ -4,7 +4,7 @@ import { VINEXT_RSC_MARKER_HEADER } from "../server/headers.js";
|
|
|
4
4
|
import { getDataCacheHandler } from "./cache-handler.js";
|
|
5
5
|
import { trackPprFallbackShellCacheTask } from "./ppr-fallback-shell.js";
|
|
6
6
|
import { markDynamicUsage } from "./headers.js";
|
|
7
|
-
import { _registerCacheContextAccessor, _setRequestScopedCacheLife, cacheLifeProfiles } from "./cache-request-state.js";
|
|
7
|
+
import { _hasPendingRevalidatedTag, _registerCacheContextAccessor, _setRequestScopedCacheLife, cacheLifeProfiles } from "./cache-request-state.js";
|
|
8
8
|
import { addCollectedRequestTags, getCurrentFetchSoftTags } from "./fetch-cache.js";
|
|
9
9
|
import { isMarkedAppPagePropsObject, markAppPagePropsForUseCache } from "./internal/app-page-props-cache-key.js";
|
|
10
10
|
//#region src/shims/cache-runtime.ts
|
|
@@ -102,6 +102,16 @@ function getUseCacheBuildIdDefine() {
|
|
|
102
102
|
function getUseCacheKeySeed() {
|
|
103
103
|
return getUseCacheDeploymentIdDefine() || getUseCacheBuildIdDefine();
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Build the shared-cache key for a "use cache" function from its build-scoped
|
|
107
|
+
* identity and serialized arguments.
|
|
108
|
+
*
|
|
109
|
+
* This is a logical handler key, not a storage key. Backend-specific adapters
|
|
110
|
+
* are responsible for mapping it to their physical key constraints after
|
|
111
|
+
* applying any storage prefixes.
|
|
112
|
+
*
|
|
113
|
+
* Exported for testing.
|
|
114
|
+
*/
|
|
105
115
|
function buildUseCacheKey(id, keySeed, argsKey) {
|
|
106
116
|
const scopedId = keySeed ? `build:${encodeURIComponent(keySeed)}:${id}` : id;
|
|
107
117
|
return argsKey === void 0 ? `use-cache:${scopedId}` : `use-cache:${scopedId}:${argsKey}`;
|
|
@@ -263,11 +273,16 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
263
273
|
if (isDev) return executeWithContext(fn, args, cacheVariant);
|
|
264
274
|
const handler = getDataCacheHandler();
|
|
265
275
|
const softTags = getCurrentFetchSoftTags();
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
276
|
+
let existing = null;
|
|
277
|
+
if (!_hasPendingRevalidatedTag(softTags)) try {
|
|
278
|
+
existing = await handler.get(cacheKey, {
|
|
279
|
+
kind: "FETCH",
|
|
280
|
+
softTags
|
|
281
|
+
});
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error("[vinext] use cache: handler.get failed; treating as a cache miss:", error);
|
|
284
|
+
}
|
|
285
|
+
if (existing?.value && existing.value.kind === "FETCH" && existing.cacheState !== "stale" && !_hasPendingRevalidatedTag([...existing.value.tags ?? [], ...softTags])) try {
|
|
271
286
|
propagateCacheTagsToRequest(existing.value.tags);
|
|
272
287
|
if (rsc && existing.value.data.headers["x-vinext-rsc"] === "1") {
|
|
273
288
|
const stream = uint8ToStream(base64ToUint8(existing.value.data.body));
|
|
@@ -449,4 +464,4 @@ function stableStringify(value, seen) {
|
|
|
449
464
|
return JSON.stringify(value);
|
|
450
465
|
}
|
|
451
466
|
//#endregion
|
|
452
|
-
export { NestedDynamicUseCacheError, cacheContextStorage, clearPrivateCache, getCacheContext, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
|
|
467
|
+
export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
|