vinext 1.0.0-beta.11 → 1.0.0-beta.12
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/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +24 -4
- package/dist/index.js +21 -5
- package/dist/plugins/use-cache-callable.js +32 -6
- package/dist/server/app-browser-entry.js +1 -0
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +14 -2
- package/dist/server/app-page-render.js +1 -0
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +16 -12
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -1
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +2 -2
- package/dist/server/app-rsc-handler.d.ts +8 -1
- package/dist/server/app-rsc-handler.js +26 -6
- package/dist/server/app-rsc-response-stage.js +5 -2
- package/dist/server/app-server-action-execution.js +31 -2
- package/dist/server/app-ssr-entry.js +7 -2
- package/dist/server/app-ssr-stream.js +25 -6
- package/dist/server/app-worker-stages.d.ts +4 -1
- package/dist/server/app-worker-stages.js +4 -4
- package/dist/server/html.d.ts +0 -20
- package/dist/server/html.js +16 -1
- package/dist/server/instrumentation.d.ts +4 -9
- package/dist/server/instrumentation.js +10 -15
- package/dist/server/isr-cache.js +2 -2
- package/dist/server/metadata-route-response.d.ts +1 -0
- package/dist/server/metadata-route-response.js +57 -0
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +37 -2
- package/dist/server/pages-client-assets.d.ts +7 -0
- package/dist/server/pages-document-initial-props.d.ts +1 -0
- package/dist/server/pages-document-initial-props.js +1 -1
- package/dist/server/pages-page-handler.js +4 -1
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +2 -1
- package/dist/server/prod-server.js +12 -6
- package/dist/server/rsc-stream-hints.d.ts +12 -0
- package/dist/server/rsc-stream-hints.js +70 -35
- package/dist/server/seed-cache.js +3 -4
- package/dist/shims/cache-runtime.js +7 -2
- package/dist/shims/constants.js +1 -1
- package/dist/shims/dynamic-preload-chunks.js +6 -2
- package/dist/shims/head.js +1 -1
- package/dist/shims/image-config.js +2 -0
- package/dist/shims/script-nonce-context.d.ts +4 -1
- package/dist/shims/script-nonce-context.js +15 -6
- package/dist/utils/client-runtime-metadata.d.ts +6 -0
- package/dist/utils/client-runtime-metadata.js +16 -0
- package/dist/utils/lazy-chunks.js +1 -1
- package/dist/utils/project.js +1 -1
- package/package.json +1 -1
|
@@ -43,6 +43,8 @@ type AppRouterConfig = {
|
|
|
43
43
|
* @see https://nextjs.org/docs/app/api-reference/config/next-config-js/assetPrefix
|
|
44
44
|
*/
|
|
45
45
|
assetPrefix?: string;
|
|
46
|
+
/** CORS mode for framework-managed assets from next.config. */
|
|
47
|
+
crossOrigin?: "anonymous" | "use-credentials";
|
|
46
48
|
/** Route-level expire fallback in seconds for ISR entries with numeric revalidate. */
|
|
47
49
|
expireTime?: number;
|
|
48
50
|
/**
|
|
@@ -190,6 +190,7 @@ const __trailingSlash = ${JSON.stringify(ts)};
|
|
|
190
190
|
const __draftModeSecret = ${JSON.stringify(config?.draftModeSecret ?? "")};
|
|
191
191
|
export const __prerenderSecret = ${JSON.stringify(config?.prerenderSecret ?? "")};
|
|
192
192
|
export const __assetPrefix = ${JSON.stringify(config?.assetPrefix ?? "")};
|
|
193
|
+
export const __crossOrigin = ${JSON.stringify(config?.crossOrigin ?? "")};
|
|
193
194
|
export { __basePath };
|
|
194
195
|
export const __imageAllowedWidths = ${JSON.stringify([...config?.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...config?.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES])};
|
|
195
196
|
export const __imageConfig = ${JSON.stringify({
|
|
@@ -371,6 +372,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
371
372
|
const htmlLimitedBots = config?.htmlLimitedBots;
|
|
372
373
|
const clientTraceMetadata = config?.clientTraceMetadata;
|
|
373
374
|
const assetPrefix = config?.assetPrefix ?? "";
|
|
375
|
+
const crossOrigin = config?.crossOrigin ?? "";
|
|
374
376
|
const expireTime = config?.expireTime ?? DEFAULT_EXPIRE_TIME;
|
|
375
377
|
const reactMaxHeadersLength = config?.reactMaxHeadersLength ?? DEFAULT_REACT_MAX_HEADERS_LENGTH;
|
|
376
378
|
const cacheMaxMemorySize = config?.cacheMaxMemorySize;
|
|
@@ -820,6 +822,7 @@ const __reactMaxHeadersLength = ${JSON.stringify(reactMaxHeadersLength)};
|
|
|
820
822
|
// mirrors the embedded \`__basePath\` pattern (and Pages Router's
|
|
821
823
|
// \`vinextConfig\` export). Empty string when unset.
|
|
822
824
|
export const __assetPrefix = ${JSON.stringify(assetPrefix)};
|
|
825
|
+
export const __crossOrigin = ${JSON.stringify(crossOrigin)};
|
|
823
826
|
export const __imageAllowedWidths = ${JSON.stringify(imageAllowedWidths)};
|
|
824
827
|
export const __imageConfig = ${JSON.stringify(imageConfig)};
|
|
825
828
|
export const __inlineCss = ${JSON.stringify(inlineCss)};
|
|
@@ -898,6 +901,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
898
901
|
draftModeSecret: __draftModeSecret,
|
|
899
902
|
dispatchMatchedPage({
|
|
900
903
|
bypassInterceptionContextCache,
|
|
904
|
+
cachePathname,
|
|
901
905
|
clientReuseManifest,
|
|
902
906
|
cleanPathname,
|
|
903
907
|
displayPathname,
|
|
@@ -1025,8 +1029,18 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1025
1029
|
isRscRequest,
|
|
1026
1030
|
isrDebug: __isrDebug,
|
|
1027
1031
|
isrGet: __isrGet,
|
|
1028
|
-
isrHtmlKey
|
|
1029
|
-
|
|
1032
|
+
isrHtmlKey(pathname) {
|
|
1033
|
+
return __isrHtmlKey(pathname === cleanPathname ? cachePathname : pathname);
|
|
1034
|
+
},
|
|
1035
|
+
isrRscKey(pathname, mountedSlots, requestedRenderMode, requestedInterceptionContext, requestedInterceptionId) {
|
|
1036
|
+
return __isrRscKey(
|
|
1037
|
+
pathname === cleanPathname ? cachePathname : pathname,
|
|
1038
|
+
mountedSlots,
|
|
1039
|
+
requestedRenderMode,
|
|
1040
|
+
requestedInterceptionContext,
|
|
1041
|
+
requestedInterceptionId,
|
|
1042
|
+
);
|
|
1043
|
+
},
|
|
1030
1044
|
isrSet: __isrSet,
|
|
1031
1045
|
loadSsrHandler() {
|
|
1032
1046
|
return import.meta.viteRsc.loadModule("ssr", "index");
|
|
@@ -1133,6 +1147,8 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1133
1147
|
});
|
|
1134
1148
|
},
|
|
1135
1149
|
async dispatchMatchedRouteHandler({
|
|
1150
|
+
bypassInterceptionContextCache,
|
|
1151
|
+
cachePathname,
|
|
1136
1152
|
cleanPathname,
|
|
1137
1153
|
middlewareContext,
|
|
1138
1154
|
params,
|
|
@@ -1144,6 +1160,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1144
1160
|
await __loadAppRouteHandlerDispatch();
|
|
1145
1161
|
return __dispatchAppRouteHandler({
|
|
1146
1162
|
basePath: __basePath,
|
|
1163
|
+
bypassSharedCache: bypassInterceptionContextCache,
|
|
1147
1164
|
cleanPathname,
|
|
1148
1165
|
clearRequestContext() {
|
|
1149
1166
|
__clearRequestContext();
|
|
@@ -1153,7 +1170,9 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1153
1170
|
trailingSlash: __trailingSlash,
|
|
1154
1171
|
isrDebug: __isrDebug,
|
|
1155
1172
|
isrGet: __isrGet,
|
|
1156
|
-
isrRouteKey
|
|
1173
|
+
isrRouteKey(pathname) {
|
|
1174
|
+
return __isrRouteKey(pathname === cleanPathname ? cachePathname : pathname);
|
|
1175
|
+
},
|
|
1157
1176
|
isrSet: __isrSet,
|
|
1158
1177
|
middlewareContext,
|
|
1159
1178
|
middlewareRequestHeaders: middlewareContext.requestHeaders,
|
|
@@ -1461,7 +1480,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1461
1480
|
await __loadMetadataRouteResponse();
|
|
1462
1481
|
return __isMetadataRouteRequestPath(metadataRoutes, cleanPathname);
|
|
1463
1482
|
},` : ""}
|
|
1464
|
-
${(metadataRoutes?.length ?? 0) > 0 ? `async handleMetadataRouteRequest(cleanPathname) {
|
|
1483
|
+
${(metadataRoutes?.length ?? 0) > 0 ? `async handleMetadataRouteRequest(cleanPathname, routePathname) {
|
|
1465
1484
|
const { handleMetadataRouteRequest: __handleMetadataRouteRequest } =
|
|
1466
1485
|
await __loadMetadataRouteResponse();
|
|
1467
1486
|
return __handleMetadataRouteRequest({
|
|
@@ -1471,6 +1490,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1471
1490
|
isrRouteKey: __isrRouteKey,
|
|
1472
1491
|
isrSet: __isrSet,
|
|
1473
1492
|
makeThenableParams,
|
|
1493
|
+
routePathname,
|
|
1474
1494
|
scheduleBackgroundRegeneration: __triggerBackgroundRegeneration,
|
|
1475
1495
|
});
|
|
1476
1496
|
},` : ""}
|
package/dist/index.js
CHANGED
|
@@ -115,7 +115,7 @@ import { VINEXT_PRERENDER_CONFIG_PLUGIN_PROPERTY, VINEXT_ROUTE_ROOT_CONFIG_PLUGI
|
|
|
115
115
|
import { staticExportApp, staticExportPages } from "./build/static-export.js";
|
|
116
116
|
import { createRequire } from "node:module";
|
|
117
117
|
import fs from "node:fs";
|
|
118
|
-
import { createIdResolver, createLogger, parseAst, transformWithOxc } from "vite";
|
|
118
|
+
import { createIdResolver, createLogger, isRunnableDevEnvironment, parseAst, transformWithOxc } from "vite";
|
|
119
119
|
import { pathToFileURL } from "node:url";
|
|
120
120
|
import { createHash, randomBytes } from "node:crypto";
|
|
121
121
|
import commonjs from "vite-plugin-commonjs";
|
|
@@ -316,7 +316,7 @@ function createDevPagesModuleDependencyReader(root, resolve) {
|
|
|
316
316
|
if (typeof specifier !== "string") continue;
|
|
317
317
|
const resolved = await resolve(specifier, cleanModulePath, { skipSelf: true });
|
|
318
318
|
if (!resolved?.id) continue;
|
|
319
|
-
if (isStylesheetSpecifier(specifier)) {
|
|
319
|
+
if (isStylesheetSpecifier(specifier) || isStylesheetSpecifier(resolved.id)) {
|
|
320
320
|
const asset = resolvedStylesheetToDevManifestAsset(root, resolved.id);
|
|
321
321
|
if (asset) dependencies.push({
|
|
322
322
|
type: "stylesheet",
|
|
@@ -1550,6 +1550,7 @@ function vinext(options = {}) {
|
|
|
1550
1550
|
}
|
|
1551
1551
|
};
|
|
1552
1552
|
pagesOptimizeEntries = !hasAppDir ? [...hasPagesDir ? [toRelativeFileEntry(root, pagesDir) + "/**/*.{tsx,ts,jsx,js}"] : [], ...[instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : [])] : [];
|
|
1553
|
+
if (env.command === "serve" && !hasAppDir && !hasCloudflarePlugin && !shouldInjectPlainPagesEnvironments) viteConfig.optimizeDeps.include = [.../* @__PURE__ */ new Set([...incomingInclude, "react-dom/client"])];
|
|
1553
1554
|
if (hasAppDir) {
|
|
1554
1555
|
const appEntries = [`${path.relative(root, appDir)}/**/*.{tsx,ts,jsx,js}`];
|
|
1555
1556
|
const explicitInstrumentationEntries = [instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : []);
|
|
@@ -1631,6 +1632,7 @@ function vinext(options = {}) {
|
|
|
1631
1632
|
} else if (hasCloudflarePlugin) viteConfig.environments = { client: {
|
|
1632
1633
|
consumer: "client",
|
|
1633
1634
|
optimizeDeps: {
|
|
1635
|
+
include: ["react-dom/client"],
|
|
1634
1636
|
...pagesOptimizeEntries.length > 0 ? { entries: pagesOptimizeEntries } : {},
|
|
1635
1637
|
...depOptimizeNodeEnvOptions
|
|
1636
1638
|
},
|
|
@@ -1649,6 +1651,7 @@ function vinext(options = {}) {
|
|
|
1649
1651
|
client: {
|
|
1650
1652
|
consumer: "client",
|
|
1651
1653
|
optimizeDeps: {
|
|
1654
|
+
include: ["react-dom/client"],
|
|
1652
1655
|
...pagesOptimizeEntries.length > 0 ? { entries: pagesOptimizeEntries } : {},
|
|
1653
1656
|
...depOptimizeNodeEnvOptions
|
|
1654
1657
|
},
|
|
@@ -1913,7 +1916,10 @@ function vinext(options = {}) {
|
|
|
1913
1916
|
}
|
|
1914
1917
|
if (id === RESOLVED_CLIENT_ENTRY) return await generateClientEntry$1();
|
|
1915
1918
|
if (id === RESOLVED_PAGES_CLIENT_ASSETS) {
|
|
1916
|
-
const metadata = {
|
|
1919
|
+
const metadata = {
|
|
1920
|
+
clientEntry: DEV_PAGES_CLIENT_ENTRY,
|
|
1921
|
+
crossOrigin: nextConfig?.crossOrigin ?? ""
|
|
1922
|
+
};
|
|
1917
1923
|
const ssrManifest = {};
|
|
1918
1924
|
const appFilePath = findFileWithExts(pagesDir, "_app", fileMatcher);
|
|
1919
1925
|
const pagesRoutes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
|
|
@@ -1952,6 +1958,7 @@ function vinext(options = {}) {
|
|
|
1952
1958
|
clientTraceMetadata: nextConfig?.clientTraceMetadata,
|
|
1953
1959
|
nodeOpenTelemetryLoader: registerNodeOpenTelemetryLoader,
|
|
1954
1960
|
assetPrefix: nextConfig?.assetPrefix,
|
|
1961
|
+
crossOrigin: nextConfig?.crossOrigin,
|
|
1955
1962
|
expireTime: nextConfig?.expireTime,
|
|
1956
1963
|
reactMaxHeadersLength: nextConfig?.reactMaxHeadersLength,
|
|
1957
1964
|
cacheMaxMemorySize: nextConfig?.cacheMaxMemorySize,
|
|
@@ -2668,7 +2675,14 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
2668
2675
|
restore();
|
|
2669
2676
|
return false;
|
|
2670
2677
|
};
|
|
2671
|
-
const pagesInstrumentationReady =
|
|
2678
|
+
const pagesInstrumentationReady = (async () => {
|
|
2679
|
+
if (!instrumentationPath || hasAppDir && hasCloudflarePlugin) return;
|
|
2680
|
+
if (hasAppDir) {
|
|
2681
|
+
const environment = server.environments["rsc"];
|
|
2682
|
+
if (!isRunnableDevEnvironment(environment)) return;
|
|
2683
|
+
return runInstrumentation(environment.runner, instrumentationPath);
|
|
2684
|
+
} else return runInstrumentation(getPagesRunner(), instrumentationPath);
|
|
2685
|
+
})();
|
|
2672
2686
|
pagesInstrumentationReady.catch(() => {});
|
|
2673
2687
|
if (hasAppDir) server.middlewares.use((req, res, next) => {
|
|
2674
2688
|
const url = req.url ?? "/";
|
|
@@ -3645,8 +3659,10 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
3645
3659
|
clientEntry: runtimeMetadata.clientEntryFile ?? void 0,
|
|
3646
3660
|
appBootstrapPreinitModules: runtimeMetadata.appBootstrapPreinitModules,
|
|
3647
3661
|
ssrManifest,
|
|
3662
|
+
cssGraph: runtimeMetadata.cssGraph,
|
|
3648
3663
|
lazyChunks: runtimeMetadata.lazyChunks ?? void 0,
|
|
3649
|
-
dynamicPreloads: runtimeMetadata.dynamicPreloads ?? void 0
|
|
3664
|
+
dynamicPreloads: runtimeMetadata.dynamicPreloads ?? void 0,
|
|
3665
|
+
crossOrigin: nextConfig.crossOrigin ?? ""
|
|
3650
3666
|
});
|
|
3651
3667
|
const buildSession = process.env.__VINEXT_PAGES_CLIENT_ASSETS_BUILD_SESSION;
|
|
3652
3668
|
if (hasAppDir && hasPagesDir && buildSession) setPagesClientAssetsBuildMetadata(buildSession, pagesClientAssetsModule);
|
|
@@ -4,6 +4,7 @@ import { magicStringTransformResult } from "./transform-result.js";
|
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { parseAstAsync } from "vite";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { createHmac, randomBytes } from "node:crypto";
|
|
7
8
|
//#region src/plugins/use-cache-callable.ts
|
|
8
9
|
const PLUGIN_NAME = "vinext:server-function-directives";
|
|
9
10
|
const SOURCE_MODULE_ID_RE = /\.(?:tsx?|jsx?|mjs)(?:\?.*)?$/;
|
|
@@ -65,6 +66,17 @@ function hasFunctionDirective(meta, directive) {
|
|
|
65
66
|
if (node?.type !== "FunctionDeclaration" && node?.type !== "FunctionExpression" && node?.type !== "ArrowFunctionExpression" || node.body.type !== "BlockStatement") return false;
|
|
66
67
|
return node.body.body.some((statement) => statement.type === "ExpressionStatement" && "directive" in statement && statement.directive === directive);
|
|
67
68
|
}
|
|
69
|
+
function getFunctionDirectiveExportNames(transforms, ast, directive) {
|
|
70
|
+
const names = /* @__PURE__ */ new Set();
|
|
71
|
+
for (const group of transforms.scanModuleExports(ast)) {
|
|
72
|
+
const entries = group.type === "declaration" ? [group.export] : group.type === "variable-declaration" ? group.declarators.flatMap((declarator) => declarator.exports) : group.type === "specifiers" ? group.exports : group.type === "default" ? [{
|
|
73
|
+
exportName: "default",
|
|
74
|
+
meta: group.meta
|
|
75
|
+
}] : [];
|
|
76
|
+
for (const entry of entries) if (hasFunctionDirective(entry.meta, directive)) names.add(entry.exportName);
|
|
77
|
+
}
|
|
78
|
+
return names;
|
|
79
|
+
}
|
|
68
80
|
function getCacheWrapperOptions(options, id, name, isModuleDirective, meta) {
|
|
69
81
|
const argumentCount = getArgumentCount(meta);
|
|
70
82
|
return {
|
|
@@ -78,6 +90,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
78
90
|
const transformsPath = resolvePluginRscModule(options.projectRoot, "@vitejs/plugin-rsc/transforms");
|
|
79
91
|
const rscModule = await import(pathToFileURL(rscModulePath).href);
|
|
80
92
|
const transforms = await import(pathToFileURL(transformsPath).href);
|
|
93
|
+
const referenceSecret = randomBytes(32);
|
|
81
94
|
let manager;
|
|
82
95
|
return {
|
|
83
96
|
name: PLUGIN_NAME,
|
|
@@ -109,6 +122,8 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
109
122
|
const useServerBoundary = transforms.hasDirective(ast.body, "use server");
|
|
110
123
|
if (moduleDirective && useServerBoundary) throw new Error(`A module cannot contain both ${JSON.stringify(moduleDirective)} and "use server" directives.`);
|
|
111
124
|
const reference = manager.serverReferences.resolve(id, "rsc");
|
|
125
|
+
const relativeImportId = manager.toRelativeId(reference.importId);
|
|
126
|
+
const secureExportName = (name) => `$$vinext_cache_${createHmac("sha256", referenceSecret).update(relativeImportId).update("\0").update(name).digest("hex")}`;
|
|
112
127
|
if (!(this.environment.name === "rsc")) {
|
|
113
128
|
if (useServerBoundary) {
|
|
114
129
|
manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
|
|
@@ -126,6 +141,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
126
141
|
manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
|
|
127
142
|
return;
|
|
128
143
|
}
|
|
144
|
+
const useServerExportNames = getFunctionDirectiveExportNames(transforms, ast, "use server");
|
|
129
145
|
const result = transforms.transformDirectiveProxyExport(ast, {
|
|
130
146
|
code,
|
|
131
147
|
directive: moduleDirective,
|
|
@@ -134,7 +150,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
134
150
|
validateModuleExport(transforms, meta);
|
|
135
151
|
return true;
|
|
136
152
|
},
|
|
137
|
-
runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(`${reference.referenceKey}#${name}`)},$$ReactClient.callServer,undefined,${this.environment.mode === "dev" ? "$$ReactClient.findSourceMapURL" : "undefined"},${JSON.stringify(name)})`
|
|
153
|
+
runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(`${reference.referenceKey}#${useServerExportNames.has(name) ? name : secureExportName(name)}`)},$$ReactClient.callServer,undefined,${this.environment.mode === "dev" ? "$$ReactClient.findSourceMapURL" : "undefined"},${JSON.stringify(name)})`
|
|
138
154
|
});
|
|
139
155
|
if (!result?.output.hasChanged()) {
|
|
140
156
|
manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
|
|
@@ -142,7 +158,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
142
158
|
}
|
|
143
159
|
manager.serverReferences.replaceClaim(PLUGIN_NAME, id, {
|
|
144
160
|
...reference,
|
|
145
|
-
exportNames: result.exportNames
|
|
161
|
+
exportNames: result.exportNames.map((name) => useServerExportNames.has(name) ? name : secureExportName(name))
|
|
146
162
|
});
|
|
147
163
|
const runtimeEnvironment = this.environment.name === "client" ? "browser" : "ssr";
|
|
148
164
|
result.output.prepend(`import * as $$ReactClient from "@vitejs/plugin-rsc/react/${runtimeEnvironment}";\n`);
|
|
@@ -151,19 +167,23 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
151
167
|
source: id
|
|
152
168
|
});
|
|
153
169
|
}
|
|
170
|
+
const secureExports = /* @__PURE__ */ new Set();
|
|
154
171
|
const wrap = (value, name, directiveMatch, meta, isModuleDirective) => {
|
|
155
172
|
const variant = directiveMatch[1] ?? "";
|
|
173
|
+
const secureName = secureExportName(name);
|
|
174
|
+
secureExports.add(secureName);
|
|
156
175
|
const wrapperOptions = {
|
|
157
176
|
...getCacheWrapperOptions(options, id, name, isModuleDirective, meta),
|
|
158
|
-
serverReferenceId: `${reference.referenceKey}#${
|
|
177
|
+
serverReferenceId: `${reference.referenceKey}#${secureName}`
|
|
159
178
|
};
|
|
160
179
|
return `$$cacheRuntime.registerCachedFunction(${value}, ${JSON.stringify(`${id}:${name}`)}, ${JSON.stringify(variant)}, ${JSON.stringify(wrapperOptions)})`;
|
|
161
180
|
};
|
|
162
181
|
let needsReactServer = false;
|
|
163
182
|
const runtime = (value, name, directiveMatch, meta, isModuleDirective) => {
|
|
164
183
|
const cached = wrap(value, name, directiveMatch, meta, isModuleDirective);
|
|
184
|
+
const secureName = secureExportName(name);
|
|
165
185
|
needsReactServer = true;
|
|
166
|
-
return
|
|
186
|
+
return `(${secureName} = $$VinextReactServer.registerServerReference(${cached}, ${JSON.stringify(reference.referenceKey)}, ${JSON.stringify(secureName)}))`;
|
|
167
187
|
};
|
|
168
188
|
const result = moduleDirective ? transforms.transformWrapExport(code, ast, {
|
|
169
189
|
filter: (name, meta) => {
|
|
@@ -176,6 +196,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
176
196
|
directive: USE_CACHE_DIRECTIVE_CANDIDATE,
|
|
177
197
|
rejectNonAsyncFunction: true,
|
|
178
198
|
hoistRuntime: true,
|
|
199
|
+
noExport: true,
|
|
179
200
|
runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(meta.directiveMatch[0]), meta, false),
|
|
180
201
|
encode: (value) => `$$cacheRuntime.encryptCacheCaptures(${value})`,
|
|
181
202
|
decode: (value) => value
|
|
@@ -186,10 +207,15 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
186
207
|
}
|
|
187
208
|
manager.serverReferences.replaceClaim(PLUGIN_NAME, id, {
|
|
188
209
|
...reference,
|
|
189
|
-
exportNames:
|
|
210
|
+
exportNames: [...secureExports]
|
|
190
211
|
});
|
|
191
212
|
const importPosition = ast.body.find((node) => !("directive" in node))?.start ?? code.length;
|
|
192
|
-
result.output.prependLeft(importPosition, [
|
|
213
|
+
result.output.prependLeft(importPosition, [
|
|
214
|
+
`import * as $$cacheRuntime from ${JSON.stringify(options.cacheRuntime)};`,
|
|
215
|
+
needsReactServer && `import * as $$VinextReactServer from "@vitejs/plugin-rsc/react/rsc/server";`,
|
|
216
|
+
secureExports.size > 0 && `let ${[...secureExports].join(",")};`
|
|
217
|
+
].filter(Boolean).join("\n") + "\n");
|
|
218
|
+
if (secureExports.size > 0) result.output.append(`\nexport { ${[...secureExports].join(",")} };\n`);
|
|
193
219
|
return magicStringTransformResult(result.output, {
|
|
194
220
|
hires: "boundary",
|
|
195
221
|
source: id
|
|
@@ -848,6 +848,7 @@ function registerServerActionCallback() {
|
|
|
848
848
|
navigationPlanner,
|
|
849
849
|
performHardNavigation: (url, historyMode) => browserNavigationController.performHardNavigation(url, historyMode),
|
|
850
850
|
renderRedirectPayload(elements, target, actionInitiation, revalidation) {
|
|
851
|
+
if (browserNavigationController.isCurrentNavigation(actionInitiation.navigationId)) getNavigationRuntime()?.functions.notifyLinkNavigationStart?.();
|
|
851
852
|
const hashIdx = target.href.indexOf("#");
|
|
852
853
|
const hash = hashIdx !== -1 ? target.href.slice(hashIdx) : "";
|
|
853
854
|
const actionScrollIntent = beginAppRouterScrollIntent(hash || null);
|
|
@@ -24,6 +24,7 @@ type FinalizeAppPageCacheabilityEvaluationOptions = {
|
|
|
24
24
|
revalidateSeconds: number | null;
|
|
25
25
|
};
|
|
26
26
|
type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
27
|
+
bypassInterceptionContextCache?: boolean;
|
|
27
28
|
capturedDynamicUsageBeforeContextCleanup?: () => boolean;
|
|
28
29
|
capturedRscDataPromise: Promise<ArrayBuffer> | null;
|
|
29
30
|
cleanPathname: string;
|
|
@@ -19,7 +19,7 @@ function applyPendingDynamicCdnHeaders(headers, tags, options = {}) {
|
|
|
19
19
|
});
|
|
20
20
|
finalizePendingCacheStateHeaders(headers, options);
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function applyUncacheableVariantNoStoreHeaders(headers, options = {}) {
|
|
23
23
|
applyCdnResponseHeaders(headers, { cacheControl: NO_STORE_CACHE_CONTROL });
|
|
24
24
|
finalizePendingCacheStateHeaders(headers, {
|
|
25
25
|
...options,
|
|
@@ -114,6 +114,18 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
|
|
|
114
114
|
}
|
|
115
115
|
return probeResponse;
|
|
116
116
|
}
|
|
117
|
+
if (options.bypassInterceptionContextCache === true) {
|
|
118
|
+
options.capturedRscDataPromise?.catch(() => {});
|
|
119
|
+
const headers = new Headers(response.headers);
|
|
120
|
+
applyUncacheableVariantNoStoreHeaders(headers, { omitCacheState: options.omitPendingDynamicCacheState === true });
|
|
121
|
+
const clientResponse = new Response(response.body, {
|
|
122
|
+
status: response.status,
|
|
123
|
+
statusText: response.statusText,
|
|
124
|
+
headers
|
|
125
|
+
});
|
|
126
|
+
markFrameworkLinkHeaders(clientResponse.headers, options.linkHeader);
|
|
127
|
+
return clientResponse;
|
|
128
|
+
}
|
|
117
129
|
if (!response.body) return response;
|
|
118
130
|
const [streamForClient, streamForCache] = response.body.tee();
|
|
119
131
|
const htmlKey = options.isrHtmlKey(options.cleanPathname);
|
|
@@ -184,7 +196,7 @@ function finalizeAppPageRscCacheResponse(response, options) {
|
|
|
184
196
|
const isUncacheableVariant = Boolean(options.mountedSlotsHeader) || options.bypassInterceptionContextCache === true;
|
|
185
197
|
if (options.preserveClientResponseHeaders === true && !isUncacheableVariant) return response;
|
|
186
198
|
const clientHeaders = new Headers(response.headers);
|
|
187
|
-
if (isUncacheableVariant)
|
|
199
|
+
if (isUncacheableVariant) applyUncacheableVariantNoStoreHeaders(clientHeaders, { omitCacheState: options.omitPendingDynamicCacheState === true });
|
|
188
200
|
else applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
|
|
189
201
|
return new Response(response.body, {
|
|
190
202
|
status: response.status,
|
|
@@ -705,6 +705,7 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
705
705
|
});
|
|
706
706
|
if (options.isPrerender === true) return isrResponse;
|
|
707
707
|
return finalizeAppPageHtmlCacheResponse(isrResponse, {
|
|
708
|
+
bypassInterceptionContextCache: options.bypassInterceptionContextCache,
|
|
708
709
|
capturedDynamicUsageBeforeContextCleanup() {
|
|
709
710
|
return dynamicUsedBeforeContextCleanup;
|
|
710
711
|
},
|
|
@@ -35,7 +35,9 @@ export type ValidateAppPageDynamicParamsOptions = {
|
|
|
35
35
|
enforceStaticParamsOnly: boolean;
|
|
36
36
|
generateStaticParams?: GenerateStaticParams | GenerateStaticParamsSource | readonly (GenerateStaticParams | GenerateStaticParamsSource | null | undefined)[] | null;
|
|
37
37
|
isDynamicRoute: boolean;
|
|
38
|
+
optionalCatchAllParamNames?: readonly string[];
|
|
38
39
|
params: AppPageParams;
|
|
40
|
+
requiredParamNames?: readonly string[];
|
|
39
41
|
};
|
|
40
42
|
type ResolveAppPageGenerateStaticParamsSourcesOptions = {
|
|
41
43
|
layouts?: readonly (GenerateStaticParamsModule | null | undefined)[];
|
|
@@ -110,18 +110,21 @@ function resolveAppPageGenerateStaticParamsSources(options) {
|
|
|
110
110
|
}
|
|
111
111
|
return sources;
|
|
112
112
|
}
|
|
113
|
-
function areStaticParamsAllowed(params, staticParams, allowMissingValues = false) {
|
|
114
|
-
const paramKeys = Object.keys(params);
|
|
113
|
+
function areStaticParamsAllowed(params, staticParams, allowMissingValues = false, paramKeys = Object.keys(params), optionalCatchAllParamNames = []) {
|
|
115
114
|
const stringParamMatches = (value, staticValue) => value === encodeURIComponent(staticValue);
|
|
116
|
-
return staticParams.some((staticParamSet) =>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
return staticParams.some((staticParamSet) => {
|
|
116
|
+
if (!staticParamSet || typeof staticParamSet !== "object" || Array.isArray(staticParamSet)) return false;
|
|
117
|
+
return paramKeys.every((key) => {
|
|
118
|
+
const value = params[key];
|
|
119
|
+
const staticValue = staticParamSet[key];
|
|
120
|
+
if (!Object.hasOwn(staticParamSet, key)) return allowMissingValues;
|
|
121
|
+
if (value === void 0) return optionalCatchAllParamNames.includes(key) && (staticValue === void 0 || staticValue === null || staticValue === false || Array.isArray(staticValue) && staticValue.length === 0);
|
|
122
|
+
if (Array.isArray(value)) return Array.isArray(staticValue) && value.length === staticValue.length && value.every((part, index) => typeof staticValue[index] === "string" ? stringParamMatches(part, staticValue[index]) : part === staticValue[index]);
|
|
123
|
+
if (typeof staticValue === "string") return stringParamMatches(value, staticValue);
|
|
124
|
+
if (typeof staticValue === "number" || typeof staticValue === "boolean") return String(value) === String(staticValue);
|
|
125
|
+
return JSON.stringify(value) === JSON.stringify(staticValue);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
125
128
|
}
|
|
126
129
|
function remapStaticParamsToRouteParams(staticParams, source) {
|
|
127
130
|
if (!source.paramAliases) return [...staticParams];
|
|
@@ -227,9 +230,10 @@ async function validateAppPageDynamicParams(options) {
|
|
|
227
230
|
const result = await generateIndependentStaticParams(sources, chainedStaticParams, options.params);
|
|
228
231
|
if (result.validated) {
|
|
229
232
|
validatedIndependentResults = true;
|
|
230
|
-
if (!areStaticParamsAllowed(options.params, result.staticParams,
|
|
233
|
+
if (!areStaticParamsAllowed(options.params, result.staticParams, options.requiredParamNames === void 0, options.requiredParamNames, options.optionalCatchAllParamNames)) return notFoundResponse();
|
|
231
234
|
}
|
|
232
235
|
}
|
|
236
|
+
if (options.requiredParamNames && !validatedIndependentResults) return notFoundResponse();
|
|
233
237
|
if (chainedStaticParams && !validatedIndependentResults) {
|
|
234
238
|
if (!areStaticParamsAllowed(options.params, chainedStaticParams)) return notFoundResponse();
|
|
235
239
|
}
|
|
@@ -40,7 +40,7 @@ async function dispatchAppRequestStage(request, ctx, dispatchResponseStage, opti
|
|
|
40
40
|
draftModeCookie: null,
|
|
41
41
|
middlewareCookieOverlay: null,
|
|
42
42
|
prerenderDiscovery: options.prerenderDiscovery,
|
|
43
|
-
protocolVersion:
|
|
43
|
+
protocolVersion: 10,
|
|
44
44
|
requestOrigin: new URL(request.url).origin,
|
|
45
45
|
scriptNonce: null,
|
|
46
46
|
staticFileSignalToken,
|
|
@@ -18,6 +18,7 @@ type RouteHandlerBackgroundRegenerationErrorContext = {
|
|
|
18
18
|
type RouteHandlerBackgroundRegenerator = (key: string, renderFn: () => Promise<void>, errorContext?: RouteHandlerBackgroundRegenerationErrorContext) => void;
|
|
19
19
|
type DispatchAppRouteHandlerOptions = {
|
|
20
20
|
basePath?: string;
|
|
21
|
+
bypassSharedCache?: boolean;
|
|
21
22
|
cleanPathname: string;
|
|
22
23
|
clearRequestContext: () => void;
|
|
23
24
|
draftModeSecret: string;
|
|
@@ -91,7 +91,7 @@ async function dispatchAppRouteHandlerImpl(options) {
|
|
|
91
91
|
headers: { Allow: allowHeaderForOptions }
|
|
92
92
|
}));
|
|
93
93
|
const resolvedHandlerFn = isAppRouteHandlerFunction(handlerFn) ? handlerFn : void 0;
|
|
94
|
-
const shouldReadRouteCache = revalidateSeconds !== null && !getRouteCacheabilityDynamicReason() && shouldReadAppRouteHandlerCache({
|
|
94
|
+
const shouldReadRouteCache = options.bypassSharedCache !== true && revalidateSeconds !== null && !getRouteCacheabilityDynamicReason() && shouldReadAppRouteHandlerCache({
|
|
95
95
|
dynamicConfig: handler.dynamic,
|
|
96
96
|
handlerFn: resolvedHandlerFn,
|
|
97
97
|
isAutoHead,
|
|
@@ -160,6 +160,7 @@ async function dispatchAppRouteHandlerImpl(options) {
|
|
|
160
160
|
if (resolvedHandlerFn) {
|
|
161
161
|
const response = await executeAppRouteHandler({
|
|
162
162
|
basePath: options.basePath,
|
|
163
|
+
bypassSharedCache: options.bypassSharedCache,
|
|
163
164
|
buildPageCacheTags(pathname, extraTags) {
|
|
164
165
|
return buildRouteHandlerPageCacheTags(pathname, extraTags, route.routeSegments);
|
|
165
166
|
},
|
|
@@ -65,6 +65,7 @@ type RunAppRouteHandlerResult = {
|
|
|
65
65
|
export declare function applyDraftModeCachePolicy(response: Response, isDraftMode: boolean): Response;
|
|
66
66
|
type ExecuteAppRouteHandlerOptions = {
|
|
67
67
|
buildPageCacheTags: (pathname: string, extraTags: string[]) => string[];
|
|
68
|
+
bypassSharedCache?: boolean;
|
|
68
69
|
clearRequestContext: () => void;
|
|
69
70
|
cleanPathname: string;
|
|
70
71
|
executionContext: ExecutionContextLike | null;
|
|
@@ -214,7 +214,7 @@ async function executeAppRouteHandlerImpl(options) {
|
|
|
214
214
|
dynamicUsedInHandler = handlerResult.didAccessDynamicRequest() || dynamicUsedDuringCompletion || dynamicUsedInHandler;
|
|
215
215
|
}
|
|
216
216
|
const requestCacheabilityVeto = getRouteCacheabilityDynamicReason();
|
|
217
|
-
const responseMustStayPrivate = Boolean(options.handler.dynamic === "force-dynamic" || dynamicUsedInHandler || requestCacheabilityVeto || cleanupDeferredToBody);
|
|
217
|
+
const responseMustStayPrivate = Boolean(options.bypassSharedCache === true || options.handler.dynamic === "force-dynamic" || dynamicUsedInHandler || requestCacheabilityVeto || cleanupDeferredToBody);
|
|
218
218
|
if (dynamicUsedInHandler) markKnownDynamicAppRoute(options.routePattern);
|
|
219
219
|
const pendingCookies = options.getAndClearPendingCookies();
|
|
220
220
|
const handlerDraftCookie = options.getDraftModeCookieHeader() ?? handlerDraftCookieBeforeCompletion;
|
|
@@ -269,7 +269,7 @@ async function executeAppRouteHandlerImpl(options) {
|
|
|
269
269
|
isHead: options.isAutoHead
|
|
270
270
|
}), options.middlewareContext, middlewareMergeOptions), shouldApplyDraftPolicy);
|
|
271
271
|
const preserveHandlerPolicy = isRouteCacheabilityEvaluation() ? hasExplicitCacheablePolicy : handlerSetCachePolicy;
|
|
272
|
-
if (responseMustStayPrivate && !preserveHandlerPolicy) {
|
|
272
|
+
if (options.bypassSharedCache === true || responseMustStayPrivate && !preserveHandlerPolicy) {
|
|
273
273
|
const headers = new Headers(finalized.headers);
|
|
274
274
|
applyCdnResponseHeaders(headers, { cacheControl: NEVER_CACHE_CONTROL });
|
|
275
275
|
finalized = new Response(finalized.body, {
|
|
@@ -50,6 +50,7 @@ type AppRscRouteMatch<TRoute> = {
|
|
|
50
50
|
};
|
|
51
51
|
type DispatchMatchedPageOptions<TRoute> = {
|
|
52
52
|
bypassInterceptionContextCache: boolean;
|
|
53
|
+
cachePathname: string;
|
|
53
54
|
clientReuseManifest: ClientReuseManifestParseResult;
|
|
54
55
|
cleanPathname: string;
|
|
55
56
|
displayPathname: string;
|
|
@@ -86,6 +87,12 @@ type DispatchMatchedPageOptions<TRoute> = {
|
|
|
86
87
|
renderMode: AppRscRenderMode;
|
|
87
88
|
};
|
|
88
89
|
type DispatchMatchedRouteHandlerOptions<TRoute> = {
|
|
90
|
+
/**
|
|
91
|
+
* Legacy transported cache-bypass bit. Also covers request/cache route-identity
|
|
92
|
+
* divergence so the response cannot be published under another route's key.
|
|
93
|
+
*/
|
|
94
|
+
bypassInterceptionContextCache: boolean;
|
|
95
|
+
cachePathname: string;
|
|
89
96
|
cleanPathname: string;
|
|
90
97
|
middlewareContext: AppRscMiddlewareContext;
|
|
91
98
|
/**
|
|
@@ -207,7 +214,7 @@ export type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
|
|
|
207
214
|
/** Request-only entries dynamically load the response graph for local bypasses. */
|
|
208
215
|
renderResponseStageLocally?: RenderAppWorkerResponseStageLocally;
|
|
209
216
|
handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions<TRoute>) => Promise<Response | ProgressiveActionFormStateResult | null>;
|
|
210
|
-
handleMetadataRouteRequest?: (cleanPathname: string) => Promise<Response | null>;
|
|
217
|
+
handleMetadataRouteRequest?: (cleanPathname: string, routePathname: string) => Promise<Response | null>;
|
|
211
218
|
isMetadataRoutePath?: (cleanPathname: string) => boolean | Promise<boolean>;
|
|
212
219
|
getPrerenderMetadataRoutePaths?: () => Promise<unknown>;
|
|
213
220
|
createPprFallbackShells?: (route: Pick<AppRscHandlerRoute, "params" | "pattern" | "rootParamNames">, params: AppPageParams) => AppPagePprFallbackCacheShell[];
|