vinext 0.0.28 → 0.0.30
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/report.d.ts +117 -0
- package/dist/build/report.d.ts.map +1 -0
- package/dist/build/report.js +303 -0
- package/dist/build/report.js.map +1 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +11 -7
- package/dist/check.js.map +1 -1
- package/dist/cli.js +106 -9
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +58 -42
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +10 -0
- package/dist/cloudflare/tpr.d.ts.map +1 -1
- package/dist/cloudflare/tpr.js +36 -41
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/next-config.d.ts.map +1 -1
- package/dist/config/next-config.js +16 -0
- package/dist/config/next-config.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +1 -1
- package/dist/entries/app-rsc-entry.d.ts.map +1 -1
- package/dist/entries/app-rsc-entry.js +225 -186
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts.map +1 -1
- package/dist/entries/pages-server-entry.js +192 -91
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +121 -40
- package/dist/index.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -0
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +131 -104
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/pages-router.d.ts.map +1 -1
- package/dist/routing/pages-router.js +17 -57
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-trie.d.ts +57 -0
- package/dist/routing/route-trie.d.ts.map +1 -0
- package/dist/routing/route-trie.js +160 -0
- package/dist/routing/route-trie.js.map +1 -0
- package/dist/routing/route-validation.d.ts.map +1 -1
- package/dist/routing/route-validation.js +13 -1
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +19 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +47 -0
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts.map +1 -1
- package/dist/server/api-handler.js +28 -13
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-server.d.ts +2 -1
- package/dist/server/dev-server.d.ts.map +1 -1
- package/dist/server/dev-server.js +167 -115
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/image-optimization.d.ts.map +1 -1
- package/dist/server/image-optimization.js +24 -12
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/instrumentation.js +17 -8
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts.map +1 -1
- package/dist/server/isr-cache.js +8 -3
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-routes.js +56 -18
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts +10 -0
- package/dist/server/middleware-codegen.d.ts.map +1 -1
- package/dist/server/middleware-codegen.js +76 -4
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +52 -7
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +50 -0
- package/dist/server/pages-i18n.d.ts.map +1 -0
- package/dist/server/pages-i18n.js +152 -0
- package/dist/server/pages-i18n.js.map +1 -0
- package/dist/server/prod-server.d.ts +8 -2
- package/dist/server/prod-server.d.ts.map +1 -1
- package/dist/server/prod-server.js +60 -20
- package/dist/server/prod-server.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +3 -0
- package/dist/shims/cache-runtime.d.ts.map +1 -1
- package/dist/shims/cache-runtime.js +22 -5
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +3 -0
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +21 -12
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/constants.d.ts.map +1 -1
- package/dist/shims/constants.js +0 -1
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +14 -0
- package/dist/shims/fetch-cache.d.ts.map +1 -1
- package/dist/shims/fetch-cache.js +102 -37
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/head-state.d.ts +4 -0
- package/dist/shims/head-state.d.ts.map +1 -1
- package/dist/shims/head-state.js +14 -11
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +4 -2
- package/dist/shims/head.d.ts.map +1 -1
- package/dist/shims/head.js +162 -52
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +8 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/headers.js +23 -34
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.d.ts +27 -0
- package/dist/shims/i18n-context.d.ts.map +1 -0
- package/dist/shims/i18n-context.js +57 -0
- package/dist/shims/i18n-context.js.map +1 -0
- package/dist/shims/i18n-state.d.ts +20 -0
- package/dist/shims/i18n-state.d.ts.map +1 -0
- package/dist/shims/i18n-state.js +53 -0
- package/dist/shims/i18n-state.js.map +1 -0
- package/dist/shims/image.d.ts +2 -0
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/image.js +14 -6
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/internal/utils.d.ts.map +1 -1
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/link.d.ts.map +1 -1
- package/dist/shims/link.js +38 -54
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +78 -22
- package/dist/shims/metadata.d.ts.map +1 -1
- package/dist/shims/metadata.js +96 -28
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts +14 -0
- package/dist/shims/navigation-state.d.ts.map +1 -1
- package/dist/shims/navigation-state.js +33 -15
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +2 -0
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/shims/navigation.js +80 -51
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/request-context.d.ts.map +1 -1
- package/dist/shims/request-context.js +9 -0
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +11 -0
- package/dist/shims/request-state-types.d.ts.map +1 -0
- package/dist/shims/request-state-types.js +2 -0
- package/dist/shims/request-state-types.js.map +1 -0
- package/dist/shims/router-state.d.ts +11 -0
- package/dist/shims/router-state.d.ts.map +1 -1
- package/dist/shims/router-state.js +10 -8
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +4 -0
- package/dist/shims/router.d.ts.map +1 -1
- package/dist/shims/router.js +130 -40
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.d.ts +8 -1
- package/dist/shims/server.d.ts.map +1 -1
- package/dist/shims/server.js +52 -6
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +66 -0
- package/dist/shims/unified-request-context.d.ts.map +1 -0
- package/dist/shims/unified-request-context.js +116 -0
- package/dist/shims/unified-request-context.js.map +1 -0
- package/dist/shims/url-utils.d.ts +20 -6
- package/dist/shims/url-utils.d.ts.map +1 -1
- package/dist/shims/url-utils.js +79 -0
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +18 -0
- package/dist/utils/domain-locale.d.ts.map +1 -0
- package/dist/utils/domain-locale.js +64 -0
- package/dist/utils/domain-locale.js.map +1 -0
- package/package.json +2 -2
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { generateDevOriginCheckCode } from "../server/dev-origin-check.js";
|
|
13
|
-
import {
|
|
13
|
+
import { generateMiddlewareMatcherCode, generateNormalizePathCode, generateSafeRegExpCode, generateRouteMatchNormalizationCode, } from "../server/middleware-codegen.js";
|
|
14
14
|
import { isProxyFile } from "../server/middleware.js";
|
|
15
15
|
// Pre-computed absolute paths for generated-code imports. The virtual RSC
|
|
16
16
|
// entry can't use relative imports (it has no real file location), so we
|
|
@@ -18,6 +18,29 @@ import { isProxyFile } from "../server/middleware.js";
|
|
|
18
18
|
const configMatchersPath = fileURLToPath(new URL("../config/config-matchers.js", import.meta.url)).replace(/\\/g, "/");
|
|
19
19
|
const requestPipelinePath = fileURLToPath(new URL("../server/request-pipeline.js", import.meta.url)).replace(/\\/g, "/");
|
|
20
20
|
const requestContextShimPath = fileURLToPath(new URL("../shims/request-context.js", import.meta.url)).replace(/\\/g, "/");
|
|
21
|
+
const routeTriePath = fileURLToPath(new URL("../routing/route-trie.js", import.meta.url)).replace(/\\/g, "/");
|
|
22
|
+
// Canonical order of HTTP method handlers supported by route.ts modules.
|
|
23
|
+
const ROUTE_HANDLER_HTTP_METHODS = ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"];
|
|
24
|
+
// Runtime helpers injected into the generated RSC entry so OPTIONS/Allow handling
|
|
25
|
+
// logic stays alongside the route handler pipeline.
|
|
26
|
+
const routeHandlerHelperCode = String.raw `
|
|
27
|
+
// Duplicated from the build-time constant above via JSON.stringify.
|
|
28
|
+
const ROUTE_HANDLER_HTTP_METHODS = ${JSON.stringify(ROUTE_HANDLER_HTTP_METHODS)};
|
|
29
|
+
|
|
30
|
+
function collectRouteHandlerMethods(handler) {
|
|
31
|
+
const methods = ROUTE_HANDLER_HTTP_METHODS.filter((method) => typeof handler[method] === "function");
|
|
32
|
+
if (methods.includes("GET") && !methods.includes("HEAD")) {
|
|
33
|
+
methods.push("HEAD");
|
|
34
|
+
}
|
|
35
|
+
return methods;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildRouteHandlerAllowHeader(exportedMethods) {
|
|
39
|
+
const allow = new Set(exportedMethods);
|
|
40
|
+
allow.add("OPTIONS");
|
|
41
|
+
return Array.from(allow).sort().join(", ");
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
21
44
|
/**
|
|
22
45
|
* Generate the virtual RSC entry module.
|
|
23
46
|
*
|
|
@@ -165,14 +188,37 @@ ${slotEntries.join(",\n")}
|
|
|
165
188
|
// For static metadata files, read the file content at code-generation time
|
|
166
189
|
// and embed it as base64. This ensures static metadata files work on runtimes
|
|
167
190
|
// without filesystem access (e.g., Cloudflare Workers).
|
|
191
|
+
//
|
|
192
|
+
// For metadata routes in dynamic segments (e.g., /blog/[slug]/opengraph-image),
|
|
193
|
+
// generate patternParts so the runtime can use matchPattern() instead of strict
|
|
194
|
+
// equality — the same matching used for intercept routes.
|
|
168
195
|
const metaRouteEntries = effectiveMetaRoutes.map((mr) => {
|
|
196
|
+
// Convert dynamic segments in servedUrl to matchPattern format.
|
|
197
|
+
// Keep in sync with routing/app-router.ts patternParts generation.
|
|
198
|
+
// [param] → :param
|
|
199
|
+
// [...param] → :param+
|
|
200
|
+
// [[...param]] → :param*
|
|
201
|
+
const patternParts = mr.isDynamic && mr.servedUrl.includes("[")
|
|
202
|
+
? JSON.stringify(mr.servedUrl
|
|
203
|
+
.split("/")
|
|
204
|
+
.filter(Boolean)
|
|
205
|
+
.map((seg) => {
|
|
206
|
+
if (seg.startsWith("[[...") && seg.endsWith("]]"))
|
|
207
|
+
return ":" + seg.slice(5, -2) + "*";
|
|
208
|
+
if (seg.startsWith("[...") && seg.endsWith("]"))
|
|
209
|
+
return ":" + seg.slice(4, -1) + "+";
|
|
210
|
+
if (seg.startsWith("[") && seg.endsWith("]"))
|
|
211
|
+
return ":" + seg.slice(1, -1);
|
|
212
|
+
return seg;
|
|
213
|
+
}))
|
|
214
|
+
: null;
|
|
169
215
|
if (mr.isDynamic) {
|
|
170
216
|
return ` {
|
|
171
217
|
type: ${JSON.stringify(mr.type)},
|
|
172
218
|
isDynamic: true,
|
|
173
219
|
servedUrl: ${JSON.stringify(mr.servedUrl)},
|
|
174
220
|
contentType: ${JSON.stringify(mr.contentType)},
|
|
175
|
-
module: ${getImportVar(mr.filePath)}
|
|
221
|
+
module: ${getImportVar(mr.filePath)},${patternParts ? `\n patternParts: ${patternParts},` : ""}
|
|
176
222
|
}`;
|
|
177
223
|
}
|
|
178
224
|
// Static: read file and embed as base64
|
|
@@ -202,7 +248,7 @@ import {
|
|
|
202
248
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
203
249
|
import { createElement, Suspense, Fragment } from "react";
|
|
204
250
|
import { setNavigationContext as _setNavigationContextOrig, getNavigationContext as _getNavigationContext } from "next/navigation";
|
|
205
|
-
import { setHeadersContext, headersContextFromRequest, getDraftModeCookieHeader, getAndClearPendingCookies, consumeDynamicUsage, markDynamicUsage,
|
|
251
|
+
import { setHeadersContext, headersContextFromRequest, getDraftModeCookieHeader, getAndClearPendingCookies, consumeDynamicUsage, markDynamicUsage, applyMiddlewareRequestHeaders, getHeadersContext, setHeadersAccessPhase } from "next/headers";
|
|
206
252
|
import { NextRequest, NextFetchEvent } from "next/server";
|
|
207
253
|
import { ErrorBoundary, NotFoundBoundary } from "vinext/error-boundary";
|
|
208
254
|
import { LayoutSegmentProvider } from "vinext/layout-segment-context";
|
|
@@ -212,17 +258,19 @@ ${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(inst
|
|
|
212
258
|
${effectiveMetaRoutes.length > 0 ? `import { sitemapToXml, robotsToText, manifestToJson } from ${JSON.stringify(fileURLToPath(new URL("../server/metadata-routes.js", import.meta.url)).replace(/\\/g, "/"))};` : ""}
|
|
213
259
|
import { requestContextFromRequest, normalizeHost, matchRedirect, matchRewrite, matchHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination } from ${JSON.stringify(configMatchersPath)};
|
|
214
260
|
import { validateCsrfOrigin, validateImageUrl, guardProtocolRelativeUrl, hasBasePath, stripBasePath, normalizeTrailingSlash, processMiddlewareHeaders } from ${JSON.stringify(requestPipelinePath)};
|
|
215
|
-
import { _consumeRequestScopedCacheLife,
|
|
216
|
-
import {
|
|
217
|
-
import {
|
|
218
|
-
import {
|
|
261
|
+
import { _consumeRequestScopedCacheLife, getCacheHandler } from "next/cache";
|
|
262
|
+
import { getRequestExecutionContext as _getRequestExecutionContext } from ${JSON.stringify(requestContextShimPath)};
|
|
263
|
+
import { ensureFetchPatch as _ensureFetchPatch, getCollectedFetchTags } from "vinext/fetch-cache";
|
|
264
|
+
import { buildRouteTrie as _buildRouteTrie, trieMatch as _trieMatch } from ${JSON.stringify(routeTriePath)};
|
|
219
265
|
// Import server-only state module to register ALS-backed accessors.
|
|
220
|
-
import
|
|
266
|
+
import "vinext/navigation-state";
|
|
267
|
+
import { runWithRequestContext as _runWithUnifiedCtx, createRequestContext as _createUnifiedCtx } from "vinext/unified-request-context";
|
|
221
268
|
import { reportRequestError as _reportRequestError } from "vinext/instrumentation";
|
|
222
269
|
import { getSSRFontLinks as _getSSRFontLinks, getSSRFontStyles as _getSSRFontStylesGoogle, getSSRFontPreloads as _getSSRFontPreloadsGoogle } from "next/font/google";
|
|
223
270
|
import { getSSRFontStyles as _getSSRFontStylesLocal, getSSRFontPreloads as _getSSRFontPreloadsLocal } from "next/font/local";
|
|
224
271
|
function _getSSRFontStyles() { return [..._getSSRFontStylesGoogle(), ..._getSSRFontStylesLocal()]; }
|
|
225
272
|
function _getSSRFontPreloads() { return [..._getSSRFontPreloadsGoogle(), ..._getSSRFontPreloadsLocal()]; }
|
|
273
|
+
${routeHandlerHelperCode}
|
|
226
274
|
|
|
227
275
|
// ALS used to suppress the expected "Invalid hook call" dev warning when
|
|
228
276
|
// layout/page components are probed outside React's render cycle. Patching
|
|
@@ -484,9 +532,7 @@ function rscOnError(error, requestInfo, errorContext) {
|
|
|
484
532
|
error instanceof Error ? error : new Error(String(error)),
|
|
485
533
|
requestInfo,
|
|
486
534
|
errorContext,
|
|
487
|
-
)
|
|
488
|
-
console.error("[vinext] Failed to report render error:", reportErr);
|
|
489
|
-
});
|
|
535
|
+
);
|
|
490
536
|
}
|
|
491
537
|
|
|
492
538
|
// In production, generate a digest hash for non-navigation errors
|
|
@@ -552,6 +598,7 @@ async function __ensureInstrumentation() {
|
|
|
552
598
|
const routes = [
|
|
553
599
|
${routeEntries.join(",\n")}
|
|
554
600
|
];
|
|
601
|
+
const _routeTrie = _buildRouteTrie(routes);
|
|
555
602
|
|
|
556
603
|
const metadataRoutes = [
|
|
557
604
|
${metaRouteEntries.join(",\n")}
|
|
@@ -666,7 +713,7 @@ async function renderHTTPAccessFallbackPage(route, statusCode, isRscRequest, req
|
|
|
666
713
|
// that run during stream consumption to see null headers/navigation context and throw,
|
|
667
714
|
// resulting in missing provider context on the client (e.g. next-intl useTranslations fails
|
|
668
715
|
// with "context from NextIntlClientProvider was not found").
|
|
669
|
-
// Context is cleared naturally when the ALS scope from
|
|
716
|
+
// Context is cleared naturally when the ALS scope from runWithRequestContext unwinds.
|
|
670
717
|
return new Response(rscStream, {
|
|
671
718
|
status: statusCode,
|
|
672
719
|
headers: { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" },
|
|
@@ -816,7 +863,7 @@ async function renderErrorBoundaryPage(route, error, isRscRequest, request, matc
|
|
|
816
863
|
// that run during stream consumption to see null headers/navigation context and throw,
|
|
817
864
|
// resulting in missing provider context on the client (e.g. next-intl useTranslations fails
|
|
818
865
|
// with "context from NextIntlClientProvider was not found").
|
|
819
|
-
// Context is cleared naturally when the ALS scope from
|
|
866
|
+
// Context is cleared naturally when the ALS scope from runWithRequestContext unwinds.
|
|
820
867
|
return new Response(rscStream, {
|
|
821
868
|
status: 200,
|
|
822
869
|
headers: { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" },
|
|
@@ -844,20 +891,17 @@ async function renderErrorBoundaryPage(route, error, isRscRequest, request, matc
|
|
|
844
891
|
});
|
|
845
892
|
}
|
|
846
893
|
|
|
847
|
-
function matchRoute(url
|
|
894
|
+
function matchRoute(url) {
|
|
848
895
|
const pathname = url.split("?")[0];
|
|
849
896
|
let normalizedUrl = pathname === "/" ? "/" : pathname.replace(/\\/$/, "");
|
|
850
897
|
// NOTE: Do NOT decodeURIComponent here. The caller is responsible for decoding
|
|
851
898
|
// the pathname exactly once at the request entry point. Decoding again here
|
|
852
899
|
// would cause inconsistent path matching between middleware and routing.
|
|
853
900
|
const urlParts = normalizedUrl.split("/").filter(Boolean);
|
|
854
|
-
|
|
855
|
-
const params = matchPattern(urlParts, route.patternParts);
|
|
856
|
-
if (params !== null) return { route, params };
|
|
857
|
-
}
|
|
858
|
-
return null;
|
|
901
|
+
return _trieMatch(_routeTrie, urlParts);
|
|
859
902
|
}
|
|
860
903
|
|
|
904
|
+
// matchPattern is kept for findIntercept (linear scan over small interceptLookup array).
|
|
861
905
|
function matchPattern(urlParts, patternParts) {
|
|
862
906
|
const params = Object.create(null);
|
|
863
907
|
for (let i = 0; i < patternParts.length; i++) {
|
|
@@ -1233,6 +1277,7 @@ ${generateSafeRegExpCode("modern")}
|
|
|
1233
1277
|
|
|
1234
1278
|
// ── Path normalization ──────────────────────────────────────────────────
|
|
1235
1279
|
${generateNormalizePathCode("modern")}
|
|
1280
|
+
${generateRouteMatchNormalizationCode("modern")}
|
|
1236
1281
|
|
|
1237
1282
|
// ── Config pattern matching, redirects, rewrites, headers, CSRF validation,
|
|
1238
1283
|
// external URL proxy, cookie parsing, and request context are imported from
|
|
@@ -1336,60 +1381,50 @@ export default async function handler(request, ctx) {
|
|
|
1336
1381
|
await __ensureInstrumentation();
|
|
1337
1382
|
`
|
|
1338
1383
|
: ""}
|
|
1339
|
-
// Wrap the entire request in
|
|
1340
|
-
//
|
|
1341
|
-
//
|
|
1342
|
-
// streaming), preventing state leakage between concurrent requests on
|
|
1343
|
-
// Cloudflare Workers and other concurrent runtimes.
|
|
1344
|
-
//
|
|
1345
|
-
// runWithExecutionContext stores the Workers ExecutionContext (ctx) in ALS so
|
|
1346
|
-
// that KVCacheHandler._putInBackground can register background KV puts with
|
|
1347
|
-
// ctx.waitUntil() without needing ctx passed at construction time.
|
|
1384
|
+
// Wrap the entire request in a single unified ALS scope for per-request
|
|
1385
|
+
// isolation. All state modules (headers, navigation, cache, fetch-cache,
|
|
1386
|
+
// execution-context) read from this store via isInsideUnifiedScope().
|
|
1348
1387
|
const headersCtx = headersContextFromRequest(request);
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
)
|
|
1390
|
-
)
|
|
1391
|
-
);
|
|
1392
|
-
return ctx ? _runWithExecutionContext(ctx, _run) : _run();
|
|
1388
|
+
const __uCtx = _createUnifiedCtx({
|
|
1389
|
+
headersContext: headersCtx,
|
|
1390
|
+
executionContext: ctx ?? _getRequestExecutionContext() ?? null,
|
|
1391
|
+
});
|
|
1392
|
+
return _runWithUnifiedCtx(__uCtx, async () => {
|
|
1393
|
+
_ensureFetchPatch();
|
|
1394
|
+
const __reqCtx = requestContextFromRequest(request);
|
|
1395
|
+
// Per-request container for middleware state. Passed into
|
|
1396
|
+
// _handleRequest which fills in .headers and .status;
|
|
1397
|
+
// avoids module-level variables that race on Workers.
|
|
1398
|
+
const _mwCtx = { headers: null, status: null };
|
|
1399
|
+
const response = await _handleRequest(request, __reqCtx, _mwCtx);
|
|
1400
|
+
// Apply custom headers from next.config.js to non-redirect responses.
|
|
1401
|
+
// Skip redirects (3xx) because Response.redirect() creates immutable headers,
|
|
1402
|
+
// and Next.js doesn't apply custom headers to redirects anyway.
|
|
1403
|
+
if (response && response.headers && !(response.status >= 300 && response.status < 400)) {
|
|
1404
|
+
if (__configHeaders.length) {
|
|
1405
|
+
const url = new URL(request.url);
|
|
1406
|
+
let pathname;
|
|
1407
|
+
try { pathname = __normalizePath(__normalizePathnameForRouteMatch(url.pathname)); } catch { pathname = url.pathname; }
|
|
1408
|
+
${bp ? `if (pathname.startsWith(${JSON.stringify(bp)})) pathname = pathname.slice(${JSON.stringify(bp)}.length) || "/";` : ""}
|
|
1409
|
+
const extraHeaders = matchHeaders(pathname, __configHeaders, __reqCtx);
|
|
1410
|
+
for (const h of extraHeaders) {
|
|
1411
|
+
// Use append() for headers where multiple values must coexist
|
|
1412
|
+
// (Vary, Set-Cookie). Using set() on these would destroy
|
|
1413
|
+
// existing values like "Vary: RSC, Accept" which are critical
|
|
1414
|
+
// for correct CDN caching behavior.
|
|
1415
|
+
const lk = h.key.toLowerCase();
|
|
1416
|
+
if (lk === "vary" || lk === "set-cookie") {
|
|
1417
|
+
response.headers.append(h.key, h.value);
|
|
1418
|
+
} else if (!response.headers.has(lk)) {
|
|
1419
|
+
// Middleware headers take precedence: skip config keys already
|
|
1420
|
+
// set by middleware so middleware headers always win.
|
|
1421
|
+
response.headers.set(h.key, h.value);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
return response;
|
|
1427
|
+
});
|
|
1393
1428
|
}
|
|
1394
1429
|
|
|
1395
1430
|
async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
@@ -1413,11 +1448,11 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1413
1448
|
const __protoGuard = guardProtocolRelativeUrl(url.pathname);
|
|
1414
1449
|
if (__protoGuard) return __protoGuard;
|
|
1415
1450
|
|
|
1416
|
-
// Decode percent-encoding and normalize pathname to canonical form.
|
|
1417
|
-
//
|
|
1451
|
+
// Decode percent-encoding segment-wise and normalize pathname to canonical form.
|
|
1452
|
+
// This preserves encoded path delimiters like %2F within a single segment.
|
|
1418
1453
|
// __normalizePath collapses //foo///bar → /foo/bar, resolves . and .. segments.
|
|
1419
1454
|
let decodedUrlPathname;
|
|
1420
|
-
try { decodedUrlPathname =
|
|
1455
|
+
try { decodedUrlPathname = __normalizePathnameForRouteMatchStrict(url.pathname); } catch (e) {
|
|
1421
1456
|
return new Response("Bad Request", { status: 400 });
|
|
1422
1457
|
}
|
|
1423
1458
|
let pathname = __normalizePath(decodedUrlPathname);
|
|
@@ -1488,7 +1523,9 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1488
1523
|
const nextRequest = mwRequest instanceof NextRequest ? mwRequest : new NextRequest(mwRequest);
|
|
1489
1524
|
const mwFetchEvent = new NextFetchEvent({ page: cleanPathname });
|
|
1490
1525
|
const mwResponse = await middlewareFn(nextRequest, mwFetchEvent);
|
|
1491
|
-
mwFetchEvent.drainWaitUntil();
|
|
1526
|
+
const _mwWaitUntil = mwFetchEvent.drainWaitUntil();
|
|
1527
|
+
const _mwExecCtx = _getRequestExecutionContext();
|
|
1528
|
+
if (_mwExecCtx && typeof _mwExecCtx.waitUntil === "function") { _mwExecCtx.waitUntil(_mwWaitUntil); }
|
|
1492
1529
|
if (mwResponse) {
|
|
1493
1530
|
// Check for x-middleware-next (continue)
|
|
1494
1531
|
if (mwResponse.headers.get("x-middleware-next") === "1") {
|
|
@@ -1513,6 +1550,10 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1513
1550
|
if (rewriteUrl) {
|
|
1514
1551
|
const rewriteParsed = new URL(rewriteUrl, request.url);
|
|
1515
1552
|
cleanPathname = rewriteParsed.pathname;
|
|
1553
|
+
// Carry over query params from the rewrite URL so that
|
|
1554
|
+
// searchParams props, useSearchParams(), and navigation context
|
|
1555
|
+
// reflect the rewrite destination, not the original request.
|
|
1556
|
+
url.search = rewriteParsed.search;
|
|
1516
1557
|
// Capture custom status code from rewrite (e.g. NextResponse.rewrite(url, { status: 403 }))
|
|
1517
1558
|
if (mwResponse.status !== 200) {
|
|
1518
1559
|
_mwCtx.status = mwResponse.status;
|
|
@@ -1607,45 +1648,53 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1607
1648
|
// Skip — the base servedUrl is not served when generateSitemaps exists
|
|
1608
1649
|
continue;
|
|
1609
1650
|
}
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1651
|
+
// Match metadata route — use pattern matching for dynamic segments,
|
|
1652
|
+
// strict equality for static paths.
|
|
1653
|
+
var _metaParams = null;
|
|
1654
|
+
if (metaRoute.patternParts) {
|
|
1655
|
+
var _metaUrlParts = cleanPathname.split("/").filter(Boolean);
|
|
1656
|
+
_metaParams = matchPattern(_metaUrlParts, metaRoute.patternParts);
|
|
1657
|
+
if (!_metaParams) continue;
|
|
1658
|
+
} else if (cleanPathname !== metaRoute.servedUrl) {
|
|
1659
|
+
continue;
|
|
1660
|
+
}
|
|
1661
|
+
if (metaRoute.isDynamic) {
|
|
1662
|
+
// Dynamic metadata route — call the default export and serialize
|
|
1663
|
+
const metaFn = metaRoute.module.default;
|
|
1664
|
+
if (typeof metaFn === "function") {
|
|
1665
|
+
const result = await metaFn({ params: makeThenableParams(_metaParams || {}) });
|
|
1666
|
+
let body;
|
|
1667
|
+
// If it's already a Response (e.g., ImageResponse), return directly
|
|
1668
|
+
if (result instanceof Response) return result;
|
|
1669
|
+
// Serialize based on type
|
|
1670
|
+
if (metaRoute.type === "sitemap") body = sitemapToXml(result);
|
|
1671
|
+
else if (metaRoute.type === "robots") body = robotsToText(result);
|
|
1672
|
+
else if (metaRoute.type === "manifest") body = manifestToJson(result);
|
|
1673
|
+
else body = JSON.stringify(result);
|
|
1674
|
+
return new Response(body, {
|
|
1675
|
+
headers: { "Content-Type": metaRoute.contentType },
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
} else {
|
|
1679
|
+
// Static metadata file — decode from embedded base64 data
|
|
1680
|
+
try {
|
|
1681
|
+
const binary = atob(metaRoute.fileDataBase64);
|
|
1682
|
+
const bytes = new Uint8Array(binary.length);
|
|
1683
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1684
|
+
return new Response(bytes, {
|
|
1685
|
+
headers: {
|
|
1686
|
+
"Content-Type": metaRoute.contentType,
|
|
1687
|
+
"Cache-Control": "public, max-age=0, must-revalidate",
|
|
1688
|
+
},
|
|
1689
|
+
});
|
|
1690
|
+
} catch {
|
|
1691
|
+
return new Response("Not Found", { status: 404 });
|
|
1643
1692
|
}
|
|
1644
1693
|
}
|
|
1645
1694
|
}
|
|
1646
1695
|
|
|
1647
1696
|
// Set navigation context for Server Components.
|
|
1648
|
-
// Note: Headers context is already set by
|
|
1697
|
+
// Note: Headers context is already set by runWithRequestContext in the handler wrapper.
|
|
1649
1698
|
setNavigationContext({
|
|
1650
1699
|
pathname: cleanPathname,
|
|
1651
1700
|
searchParams: url.searchParams,
|
|
@@ -1758,7 +1807,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1758
1807
|
|
|
1759
1808
|
// After the action, re-render the current page so the client
|
|
1760
1809
|
// gets an updated React tree reflecting any mutations.
|
|
1761
|
-
const match = matchRoute(cleanPathname
|
|
1810
|
+
const match = matchRoute(cleanPathname);
|
|
1762
1811
|
let element;
|
|
1763
1812
|
if (match) {
|
|
1764
1813
|
const { route: actionRoute, params: actionParams } = match;
|
|
@@ -1785,7 +1834,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1785
1834
|
// Collect cookies set during the action synchronously (before stream is consumed).
|
|
1786
1835
|
// Do NOT clear headers/navigation context here — the RSC stream is consumed lazily
|
|
1787
1836
|
// by the client, and async server components that run during consumption need the
|
|
1788
|
-
// context to still be live. The AsyncLocalStorage scope from
|
|
1837
|
+
// context to still be live. The AsyncLocalStorage scope from runWithRequestContext
|
|
1789
1838
|
// handles cleanup naturally when all async continuations complete.
|
|
1790
1839
|
const actionPendingCookies = getAndClearPendingCookies();
|
|
1791
1840
|
const actionDraftCookie = getDraftModeCookieHeader();
|
|
@@ -1806,9 +1855,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1806
1855
|
err instanceof Error ? err : new Error(String(err)),
|
|
1807
1856
|
{ path: cleanPathname, method: request.method, headers: Object.fromEntries(request.headers.entries()) },
|
|
1808
1857
|
{ routerKind: "App Router", routePath: cleanPathname, routeType: "action" },
|
|
1809
|
-
)
|
|
1810
|
-
console.error("[vinext] Failed to report server action error:", reportErr);
|
|
1811
|
-
});
|
|
1858
|
+
);
|
|
1812
1859
|
setHeadersContext(null);
|
|
1813
1860
|
setNavigationContext(null);
|
|
1814
1861
|
return new Response(
|
|
@@ -1833,7 +1880,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1833
1880
|
}
|
|
1834
1881
|
}
|
|
1835
1882
|
|
|
1836
|
-
let match = matchRoute(cleanPathname
|
|
1883
|
+
let match = matchRoute(cleanPathname);
|
|
1837
1884
|
|
|
1838
1885
|
// ── Fallback rewrites from next.config.js (if no route matched) ───────
|
|
1839
1886
|
if (!match && __configRewrites.fallback && __configRewrites.fallback.length) {
|
|
@@ -1845,7 +1892,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1845
1892
|
return proxyExternalRequest(request, __fallbackRewritten);
|
|
1846
1893
|
}
|
|
1847
1894
|
cleanPathname = __fallbackRewritten;
|
|
1848
|
-
match = matchRoute(cleanPathname
|
|
1895
|
+
match = matchRoute(cleanPathname);
|
|
1849
1896
|
}
|
|
1850
1897
|
}
|
|
1851
1898
|
|
|
@@ -1872,15 +1919,15 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1872
1919
|
const handler = route.routeHandler;
|
|
1873
1920
|
const method = request.method.toUpperCase();
|
|
1874
1921
|
const revalidateSeconds = typeof handler.revalidate === "number" && handler.revalidate > 0 ? handler.revalidate : null;
|
|
1922
|
+
if (typeof handler["default"] === "function" && process.env.NODE_ENV === "development") {
|
|
1923
|
+
console.error(
|
|
1924
|
+
"[vinext] Detected default export in route handler " + route.pattern + ". Export a named export for each HTTP method instead.",
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1875
1927
|
|
|
1876
1928
|
// Collect exported HTTP methods for OPTIONS auto-response and Allow header
|
|
1877
|
-
const
|
|
1878
|
-
const
|
|
1879
|
-
// If GET is exported, HEAD is implicitly supported
|
|
1880
|
-
if (exportedMethods.includes("GET") && !exportedMethods.includes("HEAD")) {
|
|
1881
|
-
exportedMethods.push("HEAD");
|
|
1882
|
-
}
|
|
1883
|
-
const hasDefault = typeof handler["default"] === "function";
|
|
1929
|
+
const exportedMethods = collectRouteHandlerMethods(handler);
|
|
1930
|
+
const allowHeaderForOptions = buildRouteHandlerAllowHeader(exportedMethods);
|
|
1884
1931
|
|
|
1885
1932
|
// Route handlers need the same middleware header/status merge behavior as
|
|
1886
1933
|
// page responses. This keeps middleware response headers visible on API
|
|
@@ -1907,18 +1954,16 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1907
1954
|
|
|
1908
1955
|
// OPTIONS auto-implementation: respond with Allow header and 204
|
|
1909
1956
|
if (method === "OPTIONS" && typeof handler["OPTIONS"] !== "function") {
|
|
1910
|
-
const allowMethods = hasDefault ? HTTP_METHODS : exportedMethods;
|
|
1911
|
-
if (!allowMethods.includes("OPTIONS")) allowMethods.push("OPTIONS");
|
|
1912
1957
|
setHeadersContext(null);
|
|
1913
1958
|
setNavigationContext(null);
|
|
1914
1959
|
return attachRouteHandlerMiddlewareContext(new Response(null, {
|
|
1915
1960
|
status: 204,
|
|
1916
|
-
headers: { "Allow":
|
|
1961
|
+
headers: { "Allow": allowHeaderForOptions },
|
|
1917
1962
|
}));
|
|
1918
1963
|
}
|
|
1919
1964
|
|
|
1920
1965
|
// HEAD auto-implementation: run GET handler and strip body
|
|
1921
|
-
let handlerFn = handler[method]
|
|
1966
|
+
let handlerFn = handler[method];
|
|
1922
1967
|
let isAutoHead = false;
|
|
1923
1968
|
if (method === "HEAD" && typeof handler["HEAD"] !== "function" && typeof handler["GET"] === "function") {
|
|
1924
1969
|
handlerFn = handler["GET"];
|
|
@@ -2010,9 +2055,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2010
2055
|
err instanceof Error ? err : new Error(String(err)),
|
|
2011
2056
|
{ path: cleanPathname, method: request.method, headers: Object.fromEntries(request.headers.entries()) },
|
|
2012
2057
|
{ routerKind: "App Router", routePath: route.pattern, routeType: "route" },
|
|
2013
|
-
)
|
|
2014
|
-
console.error("[vinext] Failed to report route handler error:", reportErr);
|
|
2015
|
-
});
|
|
2058
|
+
);
|
|
2016
2059
|
return attachRouteHandlerMiddlewareContext(new Response(null, { status: 500 }));
|
|
2017
2060
|
} finally {
|
|
2018
2061
|
setHeadersAccessPhase(previousHeadersPhase);
|
|
@@ -2022,7 +2065,6 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2022
2065
|
setNavigationContext(null);
|
|
2023
2066
|
return attachRouteHandlerMiddlewareContext(new Response(null, {
|
|
2024
2067
|
status: 405,
|
|
2025
|
-
headers: { Allow: exportedMethods.join(", ") },
|
|
2026
2068
|
}));
|
|
2027
2069
|
}
|
|
2028
2070
|
|
|
@@ -2142,57 +2184,54 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2142
2184
|
// user request — to prevent user-specific cookies/auth headers from leaking
|
|
2143
2185
|
// into content that is cached and served to all subsequent users.
|
|
2144
2186
|
const __revalHeadCtx = { headers: new Headers(), cookies: new Map() };
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
)
|
|
2194
|
-
)
|
|
2195
|
-
);
|
|
2187
|
+
const __revalUCtx = _createUnifiedCtx({
|
|
2188
|
+
headersContext: __revalHeadCtx,
|
|
2189
|
+
executionContext: _getRequestExecutionContext(),
|
|
2190
|
+
});
|
|
2191
|
+
const __revalResult = await _runWithUnifiedCtx(__revalUCtx, async () => {
|
|
2192
|
+
_ensureFetchPatch();
|
|
2193
|
+
setNavigationContext({ pathname: cleanPathname, searchParams: url.searchParams, params });
|
|
2194
|
+
const __revalElement = await buildPageElement(route, params, undefined, url.searchParams);
|
|
2195
|
+
const __revalOnError = createRscOnErrorHandler(request, cleanPathname, route.pattern);
|
|
2196
|
+
const __revalRscStream = renderToReadableStream(__revalElement, { onError: __revalOnError });
|
|
2197
|
+
// Tee RSC stream: one for SSR, one to capture rscData
|
|
2198
|
+
const [__revalRscForSsr, __revalRscForCapture] = __revalRscStream.tee();
|
|
2199
|
+
// Capture rscData bytes in parallel with SSR
|
|
2200
|
+
const __rscDataPromise = (async () => {
|
|
2201
|
+
const __rscReader = __revalRscForCapture.getReader();
|
|
2202
|
+
const __rscChunks = [];
|
|
2203
|
+
let __rscTotal = 0;
|
|
2204
|
+
for (;;) {
|
|
2205
|
+
const { done, value } = await __rscReader.read();
|
|
2206
|
+
if (done) break;
|
|
2207
|
+
__rscChunks.push(value);
|
|
2208
|
+
__rscTotal += value.byteLength;
|
|
2209
|
+
}
|
|
2210
|
+
const __rscBuf = new Uint8Array(__rscTotal);
|
|
2211
|
+
let __rscOff = 0;
|
|
2212
|
+
for (const c of __rscChunks) { __rscBuf.set(c, __rscOff); __rscOff += c.byteLength; }
|
|
2213
|
+
return __rscBuf.buffer;
|
|
2214
|
+
})();
|
|
2215
|
+
const __revalFontData = { links: _getSSRFontLinks(), styles: _getSSRFontStyles(), preloads: _getSSRFontPreloads() };
|
|
2216
|
+
const __revalSsrEntry = await import.meta.viteRsc.loadModule("ssr", "index");
|
|
2217
|
+
const __revalHtmlStream = await __revalSsrEntry.handleSsr(__revalRscForSsr, _getNavigationContext(), __revalFontData);
|
|
2218
|
+
setHeadersContext(null);
|
|
2219
|
+
setNavigationContext(null);
|
|
2220
|
+
// Collect the full HTML string from the stream
|
|
2221
|
+
const __revalReader = __revalHtmlStream.getReader();
|
|
2222
|
+
const __revalDecoder = new TextDecoder();
|
|
2223
|
+
const __revalChunks = [];
|
|
2224
|
+
for (;;) {
|
|
2225
|
+
const { done, value } = await __revalReader.read();
|
|
2226
|
+
if (done) break;
|
|
2227
|
+
__revalChunks.push(__revalDecoder.decode(value, { stream: true }));
|
|
2228
|
+
}
|
|
2229
|
+
__revalChunks.push(__revalDecoder.decode());
|
|
2230
|
+
const __freshHtml = __revalChunks.join("");
|
|
2231
|
+
const __freshRscData = await __rscDataPromise;
|
|
2232
|
+
const __pageTags = __pageCacheTags(cleanPathname, getCollectedFetchTags());
|
|
2233
|
+
return { html: __freshHtml, rscData: __freshRscData, tags: __pageTags };
|
|
2234
|
+
});
|
|
2196
2235
|
// Write HTML and RSC to their own keys independently — no races
|
|
2197
2236
|
await Promise.all([
|
|
2198
2237
|
__isrSet(__isrHtmlKey(cleanPathname), { kind: "APP_PAGE", html: __revalResult.html, rscData: undefined, headers: undefined, postponed: undefined, status: 200 }, __revalSecs, __revalResult.tags),
|
|
@@ -2281,7 +2320,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2281
2320
|
const sourceRoute = routes[intercept.sourceRouteIndex];
|
|
2282
2321
|
if (sourceRoute && sourceRoute !== route) {
|
|
2283
2322
|
// Render the source route (e.g. /feed) with the intercepting page in the slot
|
|
2284
|
-
const sourceMatch = matchRoute(sourceRoute.pattern
|
|
2323
|
+
const sourceMatch = matchRoute(sourceRoute.pattern);
|
|
2285
2324
|
const sourceParams = sourceMatch ? sourceMatch.params : {};
|
|
2286
2325
|
setNavigationContext({
|
|
2287
2326
|
pathname: cleanPathname,
|
|
@@ -2301,7 +2340,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2301
2340
|
const interceptStream = renderToReadableStream(interceptElement, { onError: interceptOnError });
|
|
2302
2341
|
// Do NOT clear headers/navigation context here — the RSC stream is consumed lazily
|
|
2303
2342
|
// by the client, and async server components that run during consumption need the
|
|
2304
|
-
// context to still be live. The AsyncLocalStorage scope from
|
|
2343
|
+
// context to still be live. The AsyncLocalStorage scope from runWithRequestContext
|
|
2305
2344
|
// handles cleanup naturally when all async continuations complete.
|
|
2306
2345
|
return new Response(interceptStream, {
|
|
2307
2346
|
headers: { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" },
|
|
@@ -2536,7 +2575,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2536
2575
|
// NOTE: Do NOT clear headers/navigation context here!
|
|
2537
2576
|
// The RSC stream is consumed lazily - components render when chunks are read.
|
|
2538
2577
|
// If we clear context now, headers()/cookies() will fail during rendering.
|
|
2539
|
-
// Context will be cleared when the next request starts (via
|
|
2578
|
+
// Context will be cleared when the next request starts (via runWithRequestContext).
|
|
2540
2579
|
const responseHeaders = { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" };
|
|
2541
2580
|
// Include matched route params so the client can hydrate useParams()
|
|
2542
2581
|
if (params && Object.keys(params).length > 0) {
|