vinext 0.1.2 → 0.1.3
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/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +2 -1
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.js +73 -14
- package/dist/config/next-config.d.ts +46 -4
- package/dist/config/next-config.js +147 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +180 -99
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -5
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +53 -8
- package/dist/entries/pages-server-entry.js +41 -5
- package/dist/index.js +200 -62
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/optimize-imports.d.ts +2 -1
- package/dist/plugins/optimize-imports.js +11 -9
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/routing/app-route-graph.d.ts +2 -1
- package/dist/routing/app-route-graph.js +44 -14
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +22 -1
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +167 -90
- package/dist/server/app-browser-error.d.ts +10 -6
- package/dist/server/app-browser-error.js +43 -8
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +4 -2
- package/dist/server/app-browser-navigation-controller.js +23 -2
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -0
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-optimistic-routing.js +2 -2
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +27 -14
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +62 -1
- package/dist/server/app-page-dispatch.d.ts +26 -0
- package/dist/server/app-page-dispatch.js +149 -92
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +5 -2
- package/dist/server/app-page-execution.d.ts +6 -1
- package/dist/server/app-page-execution.js +21 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +12 -1
- package/dist/server/app-page-render.js +42 -4
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +2 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +14 -5
- package/dist/server/app-page-stream.d.ts +15 -3
- package/dist/server/app-page-stream.js +11 -5
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +154 -54
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +42 -13
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +83 -10
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +244 -51
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/navigation-planner.d.ts +133 -30
- package/dist/server/navigation-planner.js +114 -0
- package/dist/server/navigation-trace.d.ts +8 -1
- package/dist/server/navigation-trace.js +8 -1
- package/dist/server/pages-api-route.d.ts +6 -0
- package/dist/server/pages-api-route.js +13 -2
- package/dist/server/pages-asset-tags.d.ts +2 -1
- package/dist/server/pages-asset-tags.js +6 -2
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +11 -2
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.js +2 -2
- package/dist/server/pages-page-data.d.ts +11 -2
- package/dist/server/pages-page-data.js +204 -33
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +59 -22
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +7 -4
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +73 -36
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.js +9 -3
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +3 -2
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.js +6 -4
- package/dist/shims/error-boundary.d.ts +2 -0
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +3 -2
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +45 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/headers.js +29 -4
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.js +8 -17
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +61 -31
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +419 -128
- package/dist/shims/server.d.ts +16 -1
- package/dist/shims/server.js +44 -12
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +7 -1
- package/dist/utils/path.js +9 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -201,6 +201,7 @@ function toWebHeaders(headersRecord) {
|
|
|
201
201
|
}
|
|
202
202
|
function appendWebHeader(headers, key, value) {
|
|
203
203
|
if (value === void 0) return;
|
|
204
|
+
if (key.startsWith(":")) return;
|
|
204
205
|
if (Array.isArray(value)) {
|
|
205
206
|
for (const item of value) headers.append(key, item);
|
|
206
207
|
return;
|
|
@@ -783,7 +784,7 @@ async function startAppRouterServer(options) {
|
|
|
783
784
|
}
|
|
784
785
|
}
|
|
785
786
|
if (isImageOptimizationPath(pathname)) {
|
|
786
|
-
const params = parseImageParams(new URL(rawUrl, "http://localhost"), [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES]);
|
|
787
|
+
const params = parseImageParams(new URL(rawUrl, "http://localhost"), [...imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], imageConfig?.qualities);
|
|
787
788
|
if (!params) {
|
|
788
789
|
res.writeHead(400);
|
|
789
790
|
res.end("Bad Request");
|
|
@@ -891,6 +892,7 @@ async function startPagesRouterServer(options) {
|
|
|
891
892
|
const pagesImageConfig = vinextConfig?.images ? {
|
|
892
893
|
dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
|
|
893
894
|
dangerouslyAllowLocalIP: vinextConfig.images.dangerouslyAllowLocalIP,
|
|
895
|
+
qualities: vinextConfig.images.qualities,
|
|
894
896
|
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
895
897
|
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy
|
|
896
898
|
} : void 0;
|
|
@@ -960,7 +962,7 @@ async function startPagesRouterServer(options) {
|
|
|
960
962
|
return;
|
|
961
963
|
}
|
|
962
964
|
if (isImageOptimizationPath(pathname) || isImageOptimizationPath(staticLookupPath)) {
|
|
963
|
-
const params = parseImageParams(new URL(rawUrl, "http://localhost"), allowedImageWidths);
|
|
965
|
+
const params = parseImageParams(new URL(rawUrl, "http://localhost"), allowedImageWidths, pagesImageConfig?.qualities);
|
|
964
966
|
if (!params) {
|
|
965
967
|
res.writeHead(400);
|
|
966
968
|
res.end("Bad Request");
|
|
@@ -991,6 +993,7 @@ async function startPagesRouterServer(options) {
|
|
|
991
993
|
}
|
|
992
994
|
}
|
|
993
995
|
let isDataReq = false;
|
|
996
|
+
const originalRenderUrl = url;
|
|
994
997
|
if (isNextDataPathname(pathname)) {
|
|
995
998
|
const dataMatch = pagesBuildId ? parseNextDataPathname(pathname, pagesBuildId) : null;
|
|
996
999
|
if (!dataMatch) {
|
|
@@ -1028,7 +1031,10 @@ async function startPagesRouterServer(options) {
|
|
|
1028
1031
|
rawSearch: rawQs,
|
|
1029
1032
|
matchPageRoute: matchPageRoute ?? null,
|
|
1030
1033
|
runMiddleware: typeof runMiddleware === "function" ? wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath) : null,
|
|
1031
|
-
renderPage: typeof renderPage === "function" ? (request, resolvedUrl, options, stagedHeaders) => renderPage(request, resolvedUrl, ssrManifest, void 0, stagedHeaders,
|
|
1034
|
+
renderPage: typeof renderPage === "function" ? (request, resolvedUrl, options, stagedHeaders) => renderPage(request, resolvedUrl, ssrManifest, void 0, stagedHeaders, {
|
|
1035
|
+
...options,
|
|
1036
|
+
originalUrl: originalRenderUrl
|
|
1037
|
+
}) : null,
|
|
1032
1038
|
handleApi: typeof handleApi === "function" ? (request, apiUrl) => handleApi(request, apiUrl, createNodeExecutionContext()) : null,
|
|
1033
1039
|
serveStaticFile: async (requestPathname, stagedHeaders) => {
|
|
1034
1040
|
if (requestPathname === "/" || requestPathname.startsWith("/api/") || requestPathname.startsWith(`/_next/static/`)) return false;
|
|
@@ -76,7 +76,8 @@ type ApplyConfigHeadersOptions = {
|
|
|
76
76
|
* (basePath: true) rule for backward compatibility — callers that need to
|
|
77
77
|
* support `basePath: false` headers must pass this in.
|
|
78
78
|
*/
|
|
79
|
-
basePathState?: BasePathMatchState;
|
|
79
|
+
basePathState?: BasePathMatchState; /** Existing framework-generated headers that matching config rules may replace. */
|
|
80
|
+
overwriteExisting?: ReadonlySet<string>;
|
|
80
81
|
};
|
|
81
82
|
type StaticFileSignalContext = {
|
|
82
83
|
headers: Headers | null;
|
|
@@ -157,19 +158,6 @@ declare function validateCsrfOrigin(request: Request, allowedOrigins?: string[])
|
|
|
157
158
|
*/
|
|
158
159
|
declare function validateServerActionPayload(body: string | FormData): Promise<Response | null>;
|
|
159
160
|
declare function isOriginAllowed(origin: string, allowed: string[]): boolean;
|
|
160
|
-
/**
|
|
161
|
-
* Validate an image optimization URL parameter.
|
|
162
|
-
*
|
|
163
|
-
* Ensures the URL is a relative path that doesn't escape the origin:
|
|
164
|
-
* - Must start with "/" but not "//"
|
|
165
|
-
* - Backslashes are normalized (browsers treat `\` as `/`)
|
|
166
|
-
* - Origin validation as defense-in-depth
|
|
167
|
-
*
|
|
168
|
-
* @param rawUrl - The raw `url` query parameter value
|
|
169
|
-
* @param requestUrl - The full request URL for origin comparison
|
|
170
|
-
* @returns An error Response if validation fails, or the normalized image URL
|
|
171
|
-
*/
|
|
172
|
-
declare function validateImageUrl(rawUrl: string | null, requestUrl: string): Response | string;
|
|
173
161
|
/**
|
|
174
162
|
* Strip internal `x-middleware-*` headers from a Headers object.
|
|
175
163
|
*
|
|
@@ -219,4 +207,4 @@ declare function cloneRequestWithHeaders(request: Request, headers: Headers): Re
|
|
|
219
207
|
*/
|
|
220
208
|
declare function cloneRequestWithUrl(request: Request, url: string): Request;
|
|
221
209
|
//#endregion
|
|
222
|
-
export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin,
|
|
210
|
+
export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
@@ -122,7 +122,7 @@ function applyConfigHeadersToResponse(responseHeaders, options) {
|
|
|
122
122
|
for (const header of matched) {
|
|
123
123
|
const lowerName = header.key.toLowerCase();
|
|
124
124
|
if (lowerName === "vary" || lowerName === "set-cookie") responseHeaders.append(header.key, header.value);
|
|
125
|
-
else if (!responseHeaders.has(lowerName)) responseHeaders.set(header.key, header.value);
|
|
125
|
+
else if (options.overwriteExisting?.has(lowerName) || !responseHeaders.has(lowerName)) responseHeaders.set(header.key, header.value);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
@@ -197,9 +197,10 @@ function normalizeTrailingSlash(pathname, basePath, trailingSlash, search) {
|
|
|
197
197
|
if (isOpenRedirectShaped(pathname)) return notFoundResponse();
|
|
198
198
|
const normalizedPathname = normalizeTrailingSlashPathname(pathname, trailingSlash);
|
|
199
199
|
if (normalizedPathname === null) return null;
|
|
200
|
+
const encodedPathname = normalizedPathname.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@/%]/gu, encodeURIComponent);
|
|
200
201
|
return new Response(null, {
|
|
201
202
|
status: 308,
|
|
202
|
-
headers: { Location: basePath +
|
|
203
|
+
headers: { Location: basePath + encodedPathname + search }
|
|
203
204
|
});
|
|
204
205
|
}
|
|
205
206
|
/**
|
|
@@ -246,45 +247,74 @@ function validateCsrfOrigin(request, allowedOrigins = []) {
|
|
|
246
247
|
* Regular user form fields are ignored entirely.
|
|
247
248
|
*/
|
|
248
249
|
async function validateServerActionPayload(body) {
|
|
249
|
-
const
|
|
250
|
+
const maxNumericFields = 4096;
|
|
251
|
+
const maxContainerReferences = 16384;
|
|
252
|
+
const maxContainerDepth = 1024;
|
|
253
|
+
const containerRefRe = /"\$([QWi])([0-9a-f]+)(?=[:"])/gi;
|
|
250
254
|
const fieldRefs = /* @__PURE__ */ new Map();
|
|
255
|
+
let referenceCount = 0;
|
|
256
|
+
const invalidPayloadResponse = () => new Response("Invalid server action payload", {
|
|
257
|
+
status: 400,
|
|
258
|
+
headers: { "Content-Type": "text/plain" }
|
|
259
|
+
});
|
|
251
260
|
const collectRefs = (fieldKey, text) => {
|
|
261
|
+
if (fieldRefs.has(fieldKey)) return true;
|
|
262
|
+
if (fieldRefs.size >= maxNumericFields) return false;
|
|
252
263
|
const refs = /* @__PURE__ */ new Set();
|
|
253
264
|
let match;
|
|
254
265
|
containerRefRe.lastIndex = 0;
|
|
255
|
-
while ((match = containerRefRe.exec(text)) !== null)
|
|
266
|
+
while ((match = containerRefRe.exec(text)) !== null) {
|
|
267
|
+
const previousSize = refs.size;
|
|
268
|
+
refs.add(String(Number.parseInt(match[2], 16)));
|
|
269
|
+
if (refs.size !== previousSize && ++referenceCount > maxContainerReferences) return false;
|
|
270
|
+
}
|
|
256
271
|
fieldRefs.set(fieldKey, refs);
|
|
272
|
+
return true;
|
|
257
273
|
};
|
|
258
|
-
if (typeof body === "string")
|
|
259
|
-
|
|
274
|
+
if (typeof body === "string") {
|
|
275
|
+
if (!collectRefs("0", body)) return invalidPayloadResponse();
|
|
276
|
+
} else for (const [key, value] of body.entries()) {
|
|
260
277
|
if (!/^\d+$/.test(key)) continue;
|
|
261
278
|
if (typeof value === "string") {
|
|
262
|
-
collectRefs(key, value);
|
|
279
|
+
if (!collectRefs(key, value)) return invalidPayloadResponse();
|
|
263
280
|
continue;
|
|
264
281
|
}
|
|
265
|
-
if (typeof value?.text === "function")
|
|
282
|
+
if (typeof value?.text === "function") {
|
|
283
|
+
if (!collectRefs(key, await value.text())) return invalidPayloadResponse();
|
|
284
|
+
}
|
|
266
285
|
}
|
|
267
286
|
if (fieldRefs.size === 0) return null;
|
|
268
287
|
const knownFields = new Set(fieldRefs.keys());
|
|
269
|
-
for (const refs of fieldRefs.values()) for (const ref of refs) if (!knownFields.has(ref)) return
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
stack.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
for (const refs of fieldRefs.values()) for (const ref of refs) if (!knownFields.has(ref)) return invalidPayloadResponse();
|
|
289
|
+
const state = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const root of fieldRefs.keys()) {
|
|
291
|
+
if (state.has(root)) continue;
|
|
292
|
+
const stack = [{
|
|
293
|
+
node: root,
|
|
294
|
+
refs: [...fieldRefs.get(root) ?? []],
|
|
295
|
+
nextRef: 0
|
|
296
|
+
}];
|
|
297
|
+
state.set(root, "visiting");
|
|
298
|
+
while (stack.length > 0) {
|
|
299
|
+
if (stack.length > maxContainerDepth) return invalidPayloadResponse();
|
|
300
|
+
const frame = stack[stack.length - 1];
|
|
301
|
+
const ref = frame.refs[frame.nextRef++];
|
|
302
|
+
if (ref === void 0) {
|
|
303
|
+
state.set(frame.node, "visited");
|
|
304
|
+
stack.pop();
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const refState = state.get(ref);
|
|
308
|
+
if (refState === "visiting") return invalidPayloadResponse();
|
|
309
|
+
if (refState === "visited") continue;
|
|
310
|
+
state.set(ref, "visiting");
|
|
311
|
+
stack.push({
|
|
312
|
+
node: ref,
|
|
313
|
+
refs: [...fieldRefs.get(ref) ?? []],
|
|
314
|
+
nextRef: 0
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
288
318
|
return null;
|
|
289
319
|
}
|
|
290
320
|
/**
|
|
@@ -329,25 +359,6 @@ function isOriginAllowed(origin, allowed) {
|
|
|
329
359
|
return false;
|
|
330
360
|
}
|
|
331
361
|
/**
|
|
332
|
-
* Validate an image optimization URL parameter.
|
|
333
|
-
*
|
|
334
|
-
* Ensures the URL is a relative path that doesn't escape the origin:
|
|
335
|
-
* - Must start with "/" but not "//"
|
|
336
|
-
* - Backslashes are normalized (browsers treat `\` as `/`)
|
|
337
|
-
* - Origin validation as defense-in-depth
|
|
338
|
-
*
|
|
339
|
-
* @param rawUrl - The raw `url` query parameter value
|
|
340
|
-
* @param requestUrl - The full request URL for origin comparison
|
|
341
|
-
* @returns An error Response if validation fails, or the normalized image URL
|
|
342
|
-
*/
|
|
343
|
-
function validateImageUrl(rawUrl, requestUrl) {
|
|
344
|
-
const imgUrl = rawUrl?.replaceAll("\\", "/") ?? null;
|
|
345
|
-
if (!imgUrl || !imgUrl.startsWith("/") || imgUrl.startsWith("//")) return new Response(!rawUrl ? "Missing url parameter" : "Only relative URLs allowed", { status: 400 });
|
|
346
|
-
const url = new URL(requestUrl);
|
|
347
|
-
if (new URL(imgUrl, url.origin).origin !== url.origin) return new Response("Only relative URLs allowed", { status: 400 });
|
|
348
|
-
return imgUrl;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
362
|
* Strip internal `x-middleware-*` headers from a Headers object.
|
|
352
363
|
*
|
|
353
364
|
* Middleware uses `x-middleware-*` headers as internal signals (e.g.
|
|
@@ -465,4 +476,4 @@ function cloneRequestWithUrl(request, url) {
|
|
|
465
476
|
return cloned;
|
|
466
477
|
}
|
|
467
478
|
//#endregion
|
|
468
|
-
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin,
|
|
479
|
+
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
//#region src/server/rsc-stream-hints.d.ts
|
|
2
2
|
declare function normalizeReactFlightPreloadHints(stream: ReadableStream<Uint8Array>): ReadableStream<Uint8Array>;
|
|
3
3
|
type RscRawRenderer = (model: unknown, options?: unknown) => ReadableStream<Uint8Array>;
|
|
4
|
+
type RscRawPrerenderer = (model: unknown, options?: unknown) => Promise<{
|
|
5
|
+
prelude: ReadableStream<Uint8Array>;
|
|
6
|
+
}>;
|
|
4
7
|
declare function createRscRenderer(render: RscRawRenderer): RscRawRenderer;
|
|
8
|
+
declare function createRscPrerenderer(prerender: RscRawPrerenderer): RscRawPrerenderer;
|
|
5
9
|
//#endregion
|
|
6
|
-
export { createRscRenderer, normalizeReactFlightPreloadHints };
|
|
10
|
+
export { RscRawPrerenderer, RscRawRenderer, createRscPrerenderer, createRscRenderer, normalizeReactFlightPreloadHints };
|
|
@@ -32,5 +32,10 @@ function normalizeReactFlightPreloadHints(stream) {
|
|
|
32
32
|
function createRscRenderer(render) {
|
|
33
33
|
return (model, options) => normalizeReactFlightPreloadHints(render(model, options));
|
|
34
34
|
}
|
|
35
|
+
function createRscPrerenderer(prerender) {
|
|
36
|
+
return async (model, options) => {
|
|
37
|
+
return { prelude: normalizeReactFlightPreloadHints((await prerender(model, options)).prelude) };
|
|
38
|
+
};
|
|
39
|
+
}
|
|
35
40
|
//#endregion
|
|
36
|
-
export { createRscRenderer, normalizeReactFlightPreloadHints };
|
|
41
|
+
export { createRscPrerenderer, createRscRenderer, normalizeReactFlightPreloadHints };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { normalizePathnameForRouteMatch } from "../routing/utils.js";
|
|
2
|
-
import { normalizePath } from "./normalize-path.js";
|
|
3
1
|
import { isrCacheKey, isrSetPrerenderedAppPage } from "./isr-cache.js";
|
|
4
2
|
import { buildAppPageCacheTags } from "./app-page-cache.js";
|
|
5
3
|
import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
|
|
4
|
+
import { addPregeneratedConcretePath, clearPregeneratedConcretePaths, normalizePregeneratedPathname } from "./pregenerated-concrete-paths.js";
|
|
5
|
+
import { getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
//#region src/server/seed-cache.ts
|
|
@@ -46,26 +46,21 @@ import path from "node:path";
|
|
|
46
46
|
* @returns The number of routes seeded (0 if no manifest or no renderable routes).
|
|
47
47
|
*/
|
|
48
48
|
async function seedMemoryCacheFromPrerender(serverDir, options) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
54
|
-
} catch (err) {
|
|
55
|
-
console.warn("[vinext] Failed to parse vinext-prerender.json, skipping cache seeding:", err);
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
49
|
+
clearPregeneratedConcretePaths();
|
|
50
|
+
const manifest = readPrerenderManifest(path.join(serverDir, "vinext-prerender.json"));
|
|
51
|
+
if (!manifest) return 0;
|
|
58
52
|
const { buildId, routes } = manifest;
|
|
59
53
|
if (!buildId || !Array.isArray(routes)) return 0;
|
|
60
54
|
const trailingSlash = manifest.trailingSlash ?? false;
|
|
61
55
|
const prerenderDir = path.join(serverDir, "prerendered-routes");
|
|
62
56
|
const writeAppPageEntry = options?.writeAppPageEntry ?? createDefaultAppPageEntryWriter();
|
|
63
57
|
let seeded = 0;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
const appRoutes = getRenderedAppRoutes(routes);
|
|
59
|
+
for (const route of appRoutes) {
|
|
60
|
+
const concretePathname = route.path ?? route.route;
|
|
61
|
+
if (!isFallbackShellArtifactPath(concretePathname, route)) addPregeneratedConcretePath(route.route, concretePathname);
|
|
67
62
|
const artifactPathname = route.path ?? route.route;
|
|
68
|
-
const cachePathname =
|
|
63
|
+
const cachePathname = normalizePregeneratedPathname(artifactPathname);
|
|
69
64
|
const baseKey = isrCacheKey("app", cachePathname, buildId);
|
|
70
65
|
const htmlKey = options?.buildAppPageHtmlKey?.(cachePathname) ?? baseKey + ":html";
|
|
71
66
|
const rscKey = options?.buildAppPageRscKey?.(cachePathname) ?? baseKey + ":rsc";
|
|
@@ -79,9 +74,6 @@ async function seedMemoryCacheFromPrerender(serverDir, options) {
|
|
|
79
74
|
}
|
|
80
75
|
return seeded;
|
|
81
76
|
}
|
|
82
|
-
function normalizePrerenderCachePathname(pathname) {
|
|
83
|
-
return normalizePath(normalizePathnameForRouteMatch(pathname));
|
|
84
|
-
}
|
|
85
77
|
function createDefaultAppPageEntryWriter() {
|
|
86
78
|
return (key, data, metadata) => isrSetPrerenderedAppPage(key, data, metadata);
|
|
87
79
|
}
|
|
@@ -3,11 +3,13 @@ type AppRouterScrollIntent = Readonly<{
|
|
|
3
3
|
commitId: number | null;
|
|
4
4
|
hash: string | null;
|
|
5
5
|
id: number;
|
|
6
|
+
targetHoistedInHead: boolean;
|
|
6
7
|
}>;
|
|
7
8
|
declare function beginAppRouterScrollIntent(hash: string | null): AppRouterScrollIntent;
|
|
8
9
|
declare function clearAppRouterScrollIntent(): void;
|
|
9
10
|
declare function getPendingAppRouterScrollIntent(): AppRouterScrollIntent | null;
|
|
10
11
|
declare function claimAppRouterScrollIntentForCommit(expected: AppRouterScrollIntent | null | undefined, commitId: number): void;
|
|
12
|
+
declare function markAppRouterScrollIntentHeadHoisted(expected: AppRouterScrollIntent | null | undefined, commitId: number): void;
|
|
11
13
|
declare function consumeAppRouterScrollIntent(expected: AppRouterScrollIntent | null | undefined, commitId?: number): AppRouterScrollIntent | null;
|
|
12
14
|
//#endregion
|
|
13
|
-
export { AppRouterScrollIntent, beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent };
|
|
15
|
+
export { AppRouterScrollIntent, beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent, markAppRouterScrollIntentHeadHoisted };
|
|
@@ -14,7 +14,8 @@ function beginAppRouterScrollIntent(hash) {
|
|
|
14
14
|
const intent = {
|
|
15
15
|
commitId: null,
|
|
16
16
|
hash,
|
|
17
|
-
id: store.nextId
|
|
17
|
+
id: store.nextId,
|
|
18
|
+
targetHoistedInHead: false
|
|
18
19
|
};
|
|
19
20
|
store.pending = intent;
|
|
20
21
|
return intent;
|
|
@@ -35,6 +36,17 @@ function claimAppRouterScrollIntentForCommit(expected, commitId) {
|
|
|
35
36
|
commitId
|
|
36
37
|
};
|
|
37
38
|
}
|
|
39
|
+
function markAppRouterScrollIntentHeadHoisted(expected, commitId) {
|
|
40
|
+
const store = getScrollIntentStore();
|
|
41
|
+
const intent = store.pending;
|
|
42
|
+
if (expected === null || expected === void 0 || intent === null) return;
|
|
43
|
+
if (intent.id !== expected.id) return;
|
|
44
|
+
if (intent.commitId !== commitId) return;
|
|
45
|
+
store.pending = {
|
|
46
|
+
...intent,
|
|
47
|
+
targetHoistedInHead: true
|
|
48
|
+
};
|
|
49
|
+
}
|
|
38
50
|
function consumeAppRouterScrollIntent(expected, commitId) {
|
|
39
51
|
if (expected === null || expected === void 0) return null;
|
|
40
52
|
const store = getScrollIntentStore();
|
|
@@ -46,4 +58,4 @@ function consumeAppRouterScrollIntent(expected, commitId) {
|
|
|
46
58
|
return intent;
|
|
47
59
|
}
|
|
48
60
|
//#endregion
|
|
49
|
-
export { beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent };
|
|
61
|
+
export { beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent, markAppRouterScrollIntentHeadHoisted };
|
|
@@ -5,9 +5,12 @@ declare class AppRouterScrollTargetInner extends React$1.Component<{
|
|
|
5
5
|
children: React$1.ReactNode;
|
|
6
6
|
commitId: number | null;
|
|
7
7
|
}> {
|
|
8
|
+
scheduledCommitId: number | null;
|
|
9
|
+
schedulePotentialScroll: () => void;
|
|
8
10
|
handlePotentialScroll: () => void;
|
|
9
11
|
componentDidMount(): void;
|
|
10
12
|
componentDidUpdate(): void;
|
|
13
|
+
componentWillUnmount(): void;
|
|
11
14
|
render(): React$1.ReactNode;
|
|
12
15
|
}
|
|
13
16
|
declare function AppRouterScrollCommitProvider({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { decodeHashFragment } from "./hash-scroll.js";
|
|
3
|
-
import { consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent } from "./app-router-scroll-state.js";
|
|
3
|
+
import { consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent, markAppRouterScrollIntentHeadHoisted } from "./app-router-scroll-state.js";
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import * as ReactDOM from "react-dom";
|
|
@@ -46,8 +46,7 @@ function topOfElementInViewport(element, viewportHeight) {
|
|
|
46
46
|
function getHashFragmentDomNode(hash) {
|
|
47
47
|
const fragment = decodeHashFragment(hash.startsWith("#") ? hash.slice(1) : hash);
|
|
48
48
|
if (fragment === "top") return document.body;
|
|
49
|
-
|
|
50
|
-
return element instanceof HTMLElement ? element : null;
|
|
49
|
+
return document.getElementById(fragment) ?? document.getElementsByName(fragment)[0] ?? null;
|
|
51
50
|
}
|
|
52
51
|
function isInDocumentHead(node) {
|
|
53
52
|
const head = node.ownerDocument?.head;
|
|
@@ -55,7 +54,7 @@ function isInDocumentHead(node) {
|
|
|
55
54
|
}
|
|
56
55
|
function findNextScrollTarget(node) {
|
|
57
56
|
if (!(node instanceof Element)) return null;
|
|
58
|
-
if (isInDocumentHead(node)) return
|
|
57
|
+
if (isInDocumentHead(node)) return null;
|
|
59
58
|
let target = node;
|
|
60
59
|
while (!(target instanceof HTMLElement) || shouldSkipElement(target)) {
|
|
61
60
|
if (target.nextElementSibling === null) return null;
|
|
@@ -82,34 +81,45 @@ function scrollToElement(target, hash) {
|
|
|
82
81
|
});
|
|
83
82
|
}
|
|
84
83
|
var AppRouterScrollTargetInner = class extends React$1.Component {
|
|
84
|
+
scheduledCommitId = null;
|
|
85
|
+
schedulePotentialScroll = () => {
|
|
86
|
+
const commitId = this.props.commitId;
|
|
87
|
+
this.scheduledCommitId = commitId;
|
|
88
|
+
queueMicrotask(() => {
|
|
89
|
+
if (this.scheduledCommitId !== commitId) return;
|
|
90
|
+
this.handlePotentialScroll();
|
|
91
|
+
});
|
|
92
|
+
};
|
|
85
93
|
handlePotentialScroll = () => {
|
|
86
94
|
const intent = getPendingAppRouterScrollIntent();
|
|
87
95
|
if (intent === null) return;
|
|
88
96
|
if (this.props.commitId === null || intent.commitId !== this.props.commitId) return;
|
|
89
|
-
let
|
|
90
|
-
if (intent.hash !== null)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (next.kind === "document-top") {
|
|
97
|
-
if (consumeAppRouterScrollIntent(intent, this.props.commitId) === null) return;
|
|
98
|
-
document.documentElement.scrollTop = 0;
|
|
97
|
+
let node;
|
|
98
|
+
if (intent.hash !== null) node = getHashFragmentDomNode(intent.hash);
|
|
99
|
+
else node = null;
|
|
100
|
+
if (node === null) {
|
|
101
|
+
node = findDOMNode(this);
|
|
102
|
+
if (node !== null && isInDocumentHead(node)) {
|
|
103
|
+
markAppRouterScrollIntentHeadHoisted(intent, this.props.commitId);
|
|
99
104
|
return;
|
|
100
105
|
}
|
|
101
|
-
target = next.element;
|
|
102
106
|
}
|
|
107
|
+
const next = findNextScrollTarget(node);
|
|
108
|
+
if (next === null) return;
|
|
109
|
+
const target = next.element;
|
|
103
110
|
const consumed = consumeAppRouterScrollIntent(intent, this.props.commitId);
|
|
104
111
|
if (consumed === null) return;
|
|
105
112
|
scrollToElement(target, consumed.hash);
|
|
106
|
-
target.focus(
|
|
113
|
+
target.focus();
|
|
107
114
|
};
|
|
108
115
|
componentDidMount() {
|
|
109
|
-
this.
|
|
116
|
+
this.schedulePotentialScroll();
|
|
110
117
|
}
|
|
111
118
|
componentDidUpdate() {
|
|
112
|
-
this.
|
|
119
|
+
this.schedulePotentialScroll();
|
|
120
|
+
}
|
|
121
|
+
componentWillUnmount() {
|
|
122
|
+
this.scheduledCommitId = null;
|
|
113
123
|
}
|
|
114
124
|
render() {
|
|
115
125
|
return this.props.children;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getOrCreateAls } from "./internal/als-registry.js";
|
|
2
2
|
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
3
3
|
import { VINEXT_RSC_MARKER_HEADER } from "../server/headers.js";
|
|
4
|
+
import { trackPprFallbackShellCacheTask } from "./ppr-fallback-shell.js";
|
|
4
5
|
import { markDynamicUsage } from "./headers.js";
|
|
5
6
|
import { _registerCacheContextAccessor, _setRequestScopedCacheLife, cacheLifeProfiles, getDataCacheHandler } from "./cache.js";
|
|
6
7
|
import { addCollectedRequestTags, getCurrentFetchSoftTags } from "./fetch-cache.js";
|
|
@@ -243,7 +244,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
243
244
|
const cacheVariant = variant ?? "";
|
|
244
245
|
const omitAppPageSearchParamsFromFirstArg = options.appPageDefaultExport === true;
|
|
245
246
|
const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
|
|
246
|
-
const cachedFn =
|
|
247
|
+
const cachedFn = (...args) => trackPprFallbackShellCacheTask(async () => {
|
|
247
248
|
const rsc = await getRscModule();
|
|
248
249
|
const keySeed = getUseCacheKeySeed();
|
|
249
250
|
let cacheKey;
|
|
@@ -320,7 +321,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
320
321
|
});
|
|
321
322
|
} catch {}
|
|
322
323
|
return result;
|
|
323
|
-
};
|
|
324
|
+
}, cacheVariant);
|
|
324
325
|
Object.defineProperty(cachedFn, "length", {
|
|
325
326
|
value: fn.length,
|
|
326
327
|
configurable: true
|
package/dist/shims/cache.d.ts
CHANGED
package/dist/shims/cache.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { getOrCreateAls } from "./internal/als-registry.js";
|
|
2
2
|
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
3
3
|
import { getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
|
|
4
|
+
import { makeHangingPromise } from "./internal/make-hanging-promise.js";
|
|
4
5
|
import { getHeadersAccessPhase, markDynamicUsage } from "./headers.js";
|
|
5
6
|
import { fnv1a64 } from "../utils/hash.js";
|
|
6
7
|
import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
|
|
7
|
-
import { makeHangingPromise } from "./internal/make-hanging-promise.js";
|
|
8
8
|
import { readCacheControlNumberField } from "../utils/cache-control-metadata.js";
|
|
9
9
|
import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
|
|
10
10
|
import { getCdnCacheAdapter } from "./cdn-cache.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CacheHandlerValue, IncrementalCacheValue } from "./cache.js";
|
|
2
2
|
|
|
3
3
|
//#region src/shims/cdn-cache.d.ts
|
|
4
|
-
/** A map of response header name -> value the adapter wants applied. */
|
|
5
|
-
type CdnResponseHeaders = Record<string, string>;
|
|
4
|
+
/** A map of response header name -> value the adapter wants applied or removed. */
|
|
5
|
+
type CdnResponseHeaders = Record<string, string | null>;
|
|
6
6
|
type CdnCacheableHeaderInput = {
|
|
7
7
|
/**
|
|
8
8
|
* The cacheable `Cache-Control` value the framework computed for shared
|
|
@@ -50,9 +50,9 @@ type CdnCacheAdapter = {
|
|
|
50
50
|
*/
|
|
51
51
|
set(key: string, data: IncrementalCacheValue | null, ctx?: Record<string, unknown>): Promise<void>;
|
|
52
52
|
/**
|
|
53
|
-
* Build the response cache headers for a given
|
|
54
|
-
*
|
|
55
|
-
* `CDN-Cache-Control`)
|
|
53
|
+
* Build the response cache headers for a given policy. Returns a map so an
|
|
54
|
+
* adapter can emit more than one header (e.g. `Cache-Control` +
|
|
55
|
+
* `CDN-Cache-Control`) and remove stale adapter-owned headers with `null`.
|
|
56
56
|
*/
|
|
57
57
|
buildResponseHeaders(input: CdnCacheableHeaderInput): CdnResponseHeaders;
|
|
58
58
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
|
|
2
3
|
import { useScriptNonce } from "./script-nonce-context.js";
|
|
3
4
|
import React from "react";
|
|
4
5
|
import * as ReactDOM from "react-dom";
|
|
@@ -51,8 +52,9 @@ function DynamicPreloadChunks(props) {
|
|
|
51
52
|
if (files.length === 0) return null;
|
|
52
53
|
const stylesheets = [];
|
|
53
54
|
for (const file of files) {
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
55
|
+
const assetHref = dynamicPreloadHref(file);
|
|
56
|
+
if (assetHref.endsWith(".css")) {
|
|
57
|
+
const href = appendAssetDeploymentIdQuery(assetHref);
|
|
56
58
|
stylesheets.push(React.createElement("link", {
|
|
57
59
|
key: href,
|
|
58
60
|
rel: "stylesheet",
|
|
@@ -62,13 +64,13 @@ function DynamicPreloadChunks(props) {
|
|
|
62
64
|
}));
|
|
63
65
|
continue;
|
|
64
66
|
}
|
|
65
|
-
if (
|
|
67
|
+
if (assetHref.endsWith(".js") && typeof ReactDOM.preload === "function") {
|
|
66
68
|
const preloadOptions = {
|
|
67
69
|
as: "script",
|
|
68
70
|
fetchPriority: "low",
|
|
69
71
|
nonce
|
|
70
72
|
};
|
|
71
|
-
ReactDOM.preload(
|
|
73
|
+
ReactDOM.preload(assetHref, preloadOptions);
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
return stylesheets.length > 0 ? React.createElement(React.Fragment, null, ...stylesheets) : null;
|
|
@@ -17,6 +17,7 @@ type RedirectBoundaryState = {
|
|
|
17
17
|
redirectType: "push" | "replace" | null;
|
|
18
18
|
};
|
|
19
19
|
type ErrorBoundaryInnerProps = {
|
|
20
|
+
isImplicitRootErrorBoundary?: boolean;
|
|
20
21
|
pathname: string | null;
|
|
21
22
|
} & ErrorBoundaryProps;
|
|
22
23
|
type ErrorBoundaryState = {
|
|
@@ -131,6 +132,7 @@ declare function UnauthorizedBoundary({
|
|
|
131
132
|
resetKey
|
|
132
133
|
}: UnauthorizedBoundaryProps): React.JSX.Element;
|
|
133
134
|
type DevRecoveryBoundaryProps = {
|
|
135
|
+
isImplicitRootErrorBoundary?: boolean;
|
|
134
136
|
resetKey: number;
|
|
135
137
|
onCatch?: (resetKey: number) => void;
|
|
136
138
|
children?: React.ReactNode;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { handleAppNavigationFailure } from "../client/app-nav-failure-handler.js";
|
|
2
3
|
import { decodeRedirectError, isRedirectError, usePathname, useRouter } from "./navigation.js";
|
|
4
|
+
import DefaultGlobalError from "./default-global-error.js";
|
|
3
5
|
import { VINEXT_DEV_ERROR_RECOVERY_EVENT } from "../utils/dev-error-recovery-event.js";
|
|
4
6
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
5
7
|
import React from "react";
|
|
@@ -98,6 +100,10 @@ var ErrorBoundaryInner = class extends React.Component {
|
|
|
98
100
|
}
|
|
99
101
|
static getDerivedStateFromProps(props, state) {
|
|
100
102
|
const nextResetState = readBoundaryResetState(props);
|
|
103
|
+
if (state.error && handleAppNavigationFailure(state.error.thrownValue)) return {
|
|
104
|
+
error: null,
|
|
105
|
+
...nextResetState
|
|
106
|
+
};
|
|
101
107
|
if (state.error && shouldResetBoundary(nextResetState, state)) return {
|
|
102
108
|
error: null,
|
|
103
109
|
...nextResetState
|
|
@@ -150,6 +156,7 @@ function GlobalErrorBoundary({ fallback, children }) {
|
|
|
150
156
|
return /* @__PURE__ */ jsx(ErrorBoundaryInner, {
|
|
151
157
|
pathname: usePathname(),
|
|
152
158
|
fallback,
|
|
159
|
+
isImplicitRootErrorBoundary: fallback === DefaultGlobalError,
|
|
153
160
|
children
|
|
154
161
|
});
|
|
155
162
|
}
|
package/dist/shims/error.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AppRouterContext } from "./internal/app-router-context.js";
|
|
2
2
|
import { RouterContext } from "./internal/router-context.js";
|
|
3
|
-
import { isNextRouterError
|
|
3
|
+
import { isNextRouterError } from "./navigation.js";
|
|
4
|
+
import { useUntrackedPathname } from "./internal/navigation-untracked.js";
|
|
4
5
|
import React from "react";
|
|
5
6
|
//#region src/shims/error.tsx
|
|
6
7
|
/**
|
|
@@ -104,7 +105,7 @@ function unstable_catchError(fallback) {
|
|
|
104
105
|
Fallback.displayName = fallback.name || "CatchErrorFallback";
|
|
105
106
|
function CatchErrorBoundary(allProps) {
|
|
106
107
|
const { children, ...rest } = allProps;
|
|
107
|
-
const pathname =
|
|
108
|
+
const pathname = useUntrackedPathname();
|
|
108
109
|
const isPagesRouter = React.useContext(RouterContext) !== null;
|
|
109
110
|
const forwardedProps = rest;
|
|
110
111
|
return React.createElement(_CatchError, {
|