@vistagenic/vista 0.2.16 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vista.js +184 -177
- package/dist/ai/agent.d.ts +37 -0
- package/dist/ai/agent.js +385 -0
- package/dist/ai/embeddings.d.ts +11 -0
- package/dist/ai/embeddings.js +71 -0
- package/dist/ai/index.d.ts +10 -0
- package/dist/ai/index.js +26 -0
- package/dist/ai/memory.d.ts +16 -0
- package/dist/ai/memory.js +39 -0
- package/dist/ai/observability.d.ts +21 -0
- package/dist/ai/observability.js +69 -0
- package/dist/ai/providers/anthropic.d.ts +2 -0
- package/dist/ai/providers/anthropic.js +190 -0
- package/dist/ai/providers/base.d.ts +7 -0
- package/dist/ai/providers/base.js +85 -0
- package/dist/ai/providers/gemini.d.ts +2 -0
- package/dist/ai/providers/gemini.js +194 -0
- package/dist/ai/providers/index.d.ts +5 -0
- package/dist/ai/providers/index.js +21 -0
- package/dist/ai/providers/mock.d.ts +8 -0
- package/dist/ai/providers/mock.js +77 -0
- package/dist/ai/providers/openai.d.ts +2 -0
- package/dist/ai/providers/openai.js +211 -0
- package/dist/ai/rag.d.ts +35 -0
- package/dist/ai/rag.js +110 -0
- package/dist/ai/react/index.d.ts +1 -0
- package/dist/ai/react/index.js +17 -0
- package/dist/ai/react/react-server.d.ts +1 -0
- package/dist/ai/react/react-server.js +17 -0
- package/dist/ai/react/use-agent.d.ts +23 -0
- package/dist/ai/react/use-agent.js +138 -0
- package/dist/ai/stream.d.ts +24 -0
- package/dist/ai/stream.js +109 -0
- package/dist/ai/tool.d.ts +11 -0
- package/dist/ai/tool.js +47 -0
- package/dist/ai/types.d.ts +117 -0
- package/dist/ai/types.js +5 -0
- package/dist/auth/core.d.ts +140 -0
- package/dist/auth/core.js +165 -0
- package/dist/auth/index.d.ts +20 -8
- package/dist/auth/index.js +369 -16
- package/dist/auth/react-server.d.ts +1 -0
- package/dist/auth/react-server.js +10 -0
- package/dist/auth/react.d.ts +18 -0
- package/dist/auth/react.js +71 -0
- package/dist/bin/build-rsc.js +602 -604
- package/dist/bin/build.js +389 -388
- package/dist/bin/deploy-output.d.ts +2 -7
- package/dist/bin/deploy-output.js +3 -76
- package/dist/bin/deploy.d.ts +7 -0
- package/dist/bin/deploy.js +102 -0
- package/dist/bin/dev-error-overlay-snippet.js +778 -552
- package/dist/bin/devtools-indicator-snippet.js +387 -387
- package/dist/bin/generate.js +510 -248
- package/dist/build/manifest.d.ts +169 -139
- package/dist/build/manifest.js +423 -367
- package/dist/build/rsc/client-manifest.d.ts +62 -52
- package/dist/build/rsc/client-manifest.js +295 -193
- package/dist/build/rsc/client-reference-plugin.d.ts +37 -37
- package/dist/build/rsc/client-reference-plugin.js +160 -160
- package/dist/build/rsc/native-scanner.d.ts +135 -123
- package/dist/build/rsc/native-scanner.js +203 -170
- package/dist/build/rsc/react-client-reference-manifest.d.ts +28 -22
- package/dist/build/rsc/react-client-reference-manifest.js +240 -219
- package/dist/build/rsc/rsc-renderer.d.ts +99 -99
- package/dist/build/rsc/rsc-renderer.js +263 -263
- package/dist/build/rsc/server-component-loader.d.ts +19 -19
- package/dist/build/rsc/server-component-loader.js +91 -91
- package/dist/build/rsc/server-manifest.d.ts +17 -0
- package/dist/build/rsc/server-manifest.js +20 -0
- package/dist/build/standalone.js +337 -334
- package/dist/build/webpack/plugins/vista-flight-plugin.js +5 -5
- package/dist/client/dynamic.react-server.d.ts +2 -0
- package/dist/client/dynamic.react-server.js +23 -0
- package/dist/client/link.react-server.d.ts +2 -0
- package/dist/client/link.react-server.js +11 -0
- package/dist/client/navigation.react-server.d.ts +1 -0
- package/dist/client/navigation.react-server.js +17 -0
- package/dist/client/router.react-server.d.ts +1 -0
- package/dist/client/router.react-server.js +17 -0
- package/dist/client/rsc-router.react-server.d.ts +1 -0
- package/dist/client/rsc-router.react-server.js +17 -0
- package/dist/client/script.react-server.d.ts +2 -0
- package/dist/client/script.react-server.js +23 -0
- package/dist/components/client-island.d.ts +34 -34
- package/dist/components/client-island.js +75 -75
- package/dist/config.d.ts +17 -0
- package/dist/config.js +60 -1
- package/dist/deploy/adapters/cloudflare.d.ts +2 -0
- package/dist/deploy/adapters/cloudflare.js +124 -0
- package/dist/deploy/adapters/docker.d.ts +2 -0
- package/dist/deploy/adapters/docker.js +112 -0
- package/dist/deploy/adapters/index.d.ts +15 -0
- package/dist/deploy/adapters/index.js +24 -0
- package/dist/deploy/adapters/netlify.d.ts +2 -0
- package/dist/deploy/adapters/netlify.js +115 -0
- package/dist/deploy/adapters/render.d.ts +2 -0
- package/dist/deploy/adapters/render.js +95 -0
- package/dist/deploy/adapters/vercel.d.ts +7 -0
- package/dist/deploy/adapters/vercel.js +164 -0
- package/dist/deploy/cli-runner.d.ts +8 -0
- package/dist/deploy/cli-runner.js +58 -0
- package/dist/deploy/detect.d.ts +6 -0
- package/dist/deploy/detect.js +77 -0
- package/dist/deploy/index.d.ts +24 -0
- package/dist/deploy/index.js +112 -0
- package/dist/deploy/preflight.d.ts +8 -0
- package/dist/deploy/preflight.js +80 -0
- package/dist/deploy/types.d.ts +48 -0
- package/dist/deploy/types.js +2 -0
- package/dist/deploy/utils.d.ts +18 -0
- package/dist/deploy/utils.js +70 -0
- package/dist/dev-error.d.ts +14 -0
- package/dist/dev-error.js +1763 -705
- package/dist/index.d.ts +23 -21
- package/dist/index.js +61 -57
- package/dist/server/cookie-parse.d.ts +4 -0
- package/dist/server/cookie-parse.js +14 -0
- package/dist/server/engine.js +7 -26
- package/dist/server/index.d.ts +109 -102
- package/dist/server/index.js +315 -286
- package/dist/server/middleware-runner.d.ts +125 -57
- package/dist/server/middleware-runner.js +615 -218
- package/dist/server/middleware-security.d.ts +36 -0
- package/dist/server/middleware-security.js +183 -0
- package/dist/server/module-compile-hook.js +695 -662
- package/dist/server/route-handler-registry.d.ts +65 -0
- package/dist/server/route-handler-registry.js +195 -0
- package/dist/server/route-patterns.d.ts +67 -0
- package/dist/server/route-patterns.js +186 -0
- package/dist/server/rsc-engine.js +75 -92
- package/dist/server/rsc-module-system.d.ts +33 -33
- package/dist/server/rsc-module-system.js +87 -87
- package/dist/server/rsc-upstream.js +892 -888
- package/dist/server/static-generator.js +10 -10
- package/dist/server/typed-api-runtime.d.ts +18 -0
- package/dist/server/typed-api-runtime.js +635 -507
- package/dist/server/vista-import-map.js +134 -123
- package/dist/stack/index.d.ts +34 -32
- package/dist/stack/index.js +49 -45
- package/dist/stack/server/caller.d.ts +13 -0
- package/dist/stack/server/caller.js +42 -0
- package/dist/stack/server/executor.d.ts +40 -36
- package/dist/stack/server/executor.js +222 -174
- package/dist/stack/server/index.d.ts +11 -10
- package/dist/stack/server/index.js +24 -23
- package/dist/stack/server/procedure.d.ts +20 -18
- package/dist/stack/server/procedure.js +66 -58
- package/dist/stack/server/types.d.ts +113 -100
- package/dist/theme/react-server.d.ts +10 -0
- package/dist/theme/react-server.js +16 -0
- package/package.json +28 -3
- package/LICENSE +0 -21
|
@@ -1,888 +1,892 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const express_1 = __importDefault(require("express"));
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const react_1 = __importDefault(require("react"));
|
|
10
|
-
const stream_1 = require("stream");
|
|
11
|
-
const url_1 = require("url");
|
|
12
|
-
const react_client_reference_manifest_1 = require("../build/rsc/react-client-reference-manifest");
|
|
13
|
-
const root_resolver_1 = require("./root-resolver");
|
|
14
|
-
const constants_1 = require("../constants");
|
|
15
|
-
const module_compile_hook_1 = require("./module-compile-hook");
|
|
16
|
-
const request_context_1 = require("./request-context");
|
|
17
|
-
const runtime_actions_1 = require("./runtime-actions");
|
|
18
|
-
const app_router_runtime_1 = require("./app-router-runtime");
|
|
19
|
-
const fetch_policy_1 = require("./fetch-policy");
|
|
20
|
-
const runtime_artifacts_1 = require("./runtime-artifacts");
|
|
21
|
-
const config_1 = require("../config");
|
|
22
|
-
const vista_import_map_1 = require("./vista-import-map");
|
|
23
|
-
const project_alias_resolver_1 = require("./project-alias-resolver");
|
|
24
|
-
// NOTE: RouteErrorBoundary and RouteSuspense are 'use client' components.
|
|
25
|
-
// Under --conditions react-server, React.Component is not available, so we
|
|
26
|
-
// must NOT import them at the top level. Instead we lazy-require them after
|
|
27
|
-
// the client-load hook has been installed (which turns them into Flight
|
|
28
|
-
// client references automatically).
|
|
29
|
-
let _RouteErrorBoundary = null;
|
|
30
|
-
let _RouteSuspense = null;
|
|
31
|
-
function getRouteErrorBoundary() {
|
|
32
|
-
if (!_RouteErrorBoundary) {
|
|
33
|
-
_RouteErrorBoundary = require('../components/error-boundary').RouteErrorBoundary;
|
|
34
|
-
}
|
|
35
|
-
return _RouteErrorBoundary;
|
|
36
|
-
}
|
|
37
|
-
function getRouteSuspense() {
|
|
38
|
-
if (!_RouteSuspense) {
|
|
39
|
-
_RouteSuspense = require('../components/route-suspense').RouteSuspense;
|
|
40
|
-
}
|
|
41
|
-
return _RouteSuspense;
|
|
42
|
-
}
|
|
43
|
-
const CjsModule = require('module');
|
|
44
|
-
// Support CSS imports on server runtime
|
|
45
|
-
require.extensions['.css'] = (m, filename) => {
|
|
46
|
-
if (filename.endsWith('.module.css')) {
|
|
47
|
-
m.exports = {};
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
let installedClientLoadHook = false;
|
|
51
|
-
let originalCompile = null;
|
|
52
|
-
let reactResolutionInstalled = false;
|
|
53
|
-
let originalResolveFilename = null;
|
|
54
|
-
const clientDirectiveCache = new Map();
|
|
55
|
-
function resolveVistaInternalRequest(request) {
|
|
56
|
-
return (0, vista_import_map_1.resolveVistaSourceRequest)(request, path_1.default.resolve(__dirname, '..'));
|
|
57
|
-
}
|
|
58
|
-
function parseCliArg(flag) {
|
|
59
|
-
const index = process.argv.indexOf(flag);
|
|
60
|
-
if (index === -1)
|
|
61
|
-
return undefined;
|
|
62
|
-
return process.argv[index + 1];
|
|
63
|
-
}
|
|
64
|
-
function resolvePort(defaultPort) {
|
|
65
|
-
const raw = parseCliArg('--port') ?? process.env.RSC_UPSTREAM_PORT ?? String(defaultPort);
|
|
66
|
-
const port = Number(raw);
|
|
67
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
68
|
-
throw new Error(`Invalid upstream port: ${raw}`);
|
|
69
|
-
}
|
|
70
|
-
return port;
|
|
71
|
-
}
|
|
72
|
-
function resolveFromWorkspace(specifier, cwd) {
|
|
73
|
-
const searchRoots = [
|
|
74
|
-
cwd,
|
|
75
|
-
path_1.default.resolve(cwd, '..'),
|
|
76
|
-
path_1.default.resolve(cwd, '..', '..'),
|
|
77
|
-
path_1.default.resolve(cwd, '..', '..', 'rsc'),
|
|
78
|
-
path_1.default.resolve(cwd, '..', '..', '..'),
|
|
79
|
-
path_1.default.resolve(cwd, '..', '..', '..', 'rsc'),
|
|
80
|
-
];
|
|
81
|
-
for (const root of searchRoots) {
|
|
82
|
-
try {
|
|
83
|
-
return require.resolve(specifier, { paths: [root] });
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// continue
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return require.resolve(specifier);
|
|
90
|
-
}
|
|
91
|
-
function normalizeModulePath(filePath) {
|
|
92
|
-
return filePath.replace(/\\/g, '/').toLowerCase();
|
|
93
|
-
}
|
|
94
|
-
function shouldInvalidateDevModule(modulePath, cwd) {
|
|
95
|
-
const normalized = normalizeModulePath(modulePath);
|
|
96
|
-
const rootPrefix = normalizeModulePath(`${cwd}${path_1.default.sep}`);
|
|
97
|
-
if (!normalized.startsWith(rootPrefix))
|
|
98
|
-
return false;
|
|
99
|
-
if (normalized.includes('/node_modules/'))
|
|
100
|
-
return false;
|
|
101
|
-
if (normalized.includes(`/${constants_1.BUILD_DIR.toLowerCase()}/`))
|
|
102
|
-
return false;
|
|
103
|
-
return /\.(?:[cm]?[jt]sx?|json)$/i.test(normalized);
|
|
104
|
-
}
|
|
105
|
-
function clearProjectRequireCache(cwd) {
|
|
106
|
-
for (const key of Object.keys(require.cache)) {
|
|
107
|
-
if (!shouldInvalidateDevModule(key, cwd))
|
|
108
|
-
continue;
|
|
109
|
-
delete require.cache[key];
|
|
110
|
-
clientDirectiveCache.delete(key);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
function setupTypeScriptRuntime(cwd) {
|
|
114
|
-
try {
|
|
115
|
-
const swcRegisterPath = resolveFromWorkspace('@swc-node/register/register', cwd);
|
|
116
|
-
const typescriptPath = resolveFromWorkspace('typescript', cwd);
|
|
117
|
-
const { register } = require(swcRegisterPath);
|
|
118
|
-
const ts = require(typescriptPath);
|
|
119
|
-
register({
|
|
120
|
-
module: ts.ModuleKind.CommonJS,
|
|
121
|
-
jsx: ts.JsxEmit.ReactJSX,
|
|
122
|
-
moduleResolution: ts.ModuleResolutionKind.Node16,
|
|
123
|
-
esModuleInterop: true,
|
|
124
|
-
allowJs: true,
|
|
125
|
-
});
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
// fallback
|
|
130
|
-
}
|
|
131
|
-
try {
|
|
132
|
-
const tsNodePath = resolveFromWorkspace('ts-node', cwd);
|
|
133
|
-
require(tsNodePath).register({
|
|
134
|
-
transpileOnly: true,
|
|
135
|
-
compilerOptions: {
|
|
136
|
-
module: 'commonjs',
|
|
137
|
-
jsx: 'react-jsx',
|
|
138
|
-
moduleResolution: 'node16',
|
|
139
|
-
esModuleInterop: true,
|
|
140
|
-
allowJs: true,
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
// fallback
|
|
147
|
-
}
|
|
148
|
-
try {
|
|
149
|
-
const tsxPath = resolveFromWorkspace('tsx/cjs', cwd);
|
|
150
|
-
// tsx/cjs registers the TypeScript loader for require()
|
|
151
|
-
require(tsxPath);
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
throw new Error('No TypeScript compiler available for RSC upstream runtime. Install one of: @swc-node/register, ts-node, or tsx');
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
function hasClientBoundaryDirective(source) {
|
|
159
|
-
let trimmed = source;
|
|
160
|
-
while (true) {
|
|
161
|
-
trimmed = trimmed.trimStart();
|
|
162
|
-
if (trimmed.startsWith('//')) {
|
|
163
|
-
const newlineIndex = trimmed.indexOf('\n');
|
|
164
|
-
trimmed = newlineIndex === -1 ? '' : trimmed.slice(newlineIndex + 1);
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (trimmed.startsWith('/*')) {
|
|
168
|
-
const commentEndIndex = trimmed.indexOf('*/');
|
|
169
|
-
if (commentEndIndex === -1) {
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
trimmed = trimmed.slice(commentEndIndex + 2);
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
return trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"');
|
|
178
|
-
}
|
|
179
|
-
function isClientBoundaryFile(filename, transpiledSource) {
|
|
180
|
-
const cached = clientDirectiveCache.get(filename);
|
|
181
|
-
if (cached !== undefined)
|
|
182
|
-
return cached;
|
|
183
|
-
let isClient = false;
|
|
184
|
-
try {
|
|
185
|
-
const originalSource = fs_1.default.readFileSync(filename, 'utf-8');
|
|
186
|
-
isClient = hasClientBoundaryDirective(originalSource);
|
|
187
|
-
}
|
|
188
|
-
catch {
|
|
189
|
-
isClient = hasClientBoundaryDirective(transpiledSource);
|
|
190
|
-
}
|
|
191
|
-
clientDirectiveCache.set(filename, isClient);
|
|
192
|
-
return isClient;
|
|
193
|
-
}
|
|
194
|
-
function installSingleReactResolution(cwd) {
|
|
195
|
-
if (reactResolutionInstalled)
|
|
196
|
-
return;
|
|
197
|
-
let reactPath;
|
|
198
|
-
let reactDomPath;
|
|
199
|
-
try {
|
|
200
|
-
reactPath = require.resolve('react');
|
|
201
|
-
reactDomPath = require.resolve('react-dom');
|
|
202
|
-
}
|
|
203
|
-
catch {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
originalResolveFilename = CjsModule._resolveFilename;
|
|
207
|
-
const projectAliasResolver = (0, project_alias_resolver_1.createProjectAliasResolver)(cwd, resolveFromWorkspace);
|
|
208
|
-
CjsModule._resolveFilename = function (request, parent, isMain, options) {
|
|
209
|
-
const vistaResolvedPath = resolveVistaInternalRequest(request);
|
|
210
|
-
if (vistaResolvedPath)
|
|
211
|
-
return vistaResolvedPath;
|
|
212
|
-
const aliasResolvedPath = projectAliasResolver?.resolve(request);
|
|
213
|
-
if (aliasResolvedPath) {
|
|
214
|
-
return originalResolveFilename.call(this, aliasResolvedPath, parent, isMain, options);
|
|
215
|
-
}
|
|
216
|
-
if (request === 'react')
|
|
217
|
-
return reactPath;
|
|
218
|
-
if (request === 'react-dom')
|
|
219
|
-
return reactDomPath;
|
|
220
|
-
if (request.startsWith('react/')) {
|
|
221
|
-
const subPath = request.slice('react/'.length);
|
|
222
|
-
try {
|
|
223
|
-
return require.resolve(`react/${subPath}`, { paths: [path_1.default.dirname(reactPath)] });
|
|
224
|
-
}
|
|
225
|
-
catch {
|
|
226
|
-
// fall through
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (request.startsWith('react-dom/')) {
|
|
230
|
-
const subPath = request.slice('react-dom/'.length);
|
|
231
|
-
try {
|
|
232
|
-
return require.resolve(`react-dom/${subPath}`, { paths: [path_1.default.dirname(reactDomPath)] });
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
// fall through
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
239
|
-
};
|
|
240
|
-
reactResolutionInstalled = true;
|
|
241
|
-
}
|
|
242
|
-
function installClientLoadHook(cwd, createClientModuleProxy) {
|
|
243
|
-
if (installedClientLoadHook)
|
|
244
|
-
return;
|
|
245
|
-
const cacheComponentsConfig = (0, config_1.resolveCacheComponentsConfig)((0, config_1.loadConfig)(cwd));
|
|
246
|
-
(0, module_compile_hook_1.installModuleCompileHook)({
|
|
247
|
-
cwd,
|
|
248
|
-
createClientModuleProxy,
|
|
249
|
-
cacheComponentsEnabled: cacheComponentsConfig.enabled,
|
|
250
|
-
});
|
|
251
|
-
installedClientLoadHook = true;
|
|
252
|
-
}
|
|
253
|
-
function matchPattern(pathname, pattern) {
|
|
254
|
-
const patternParts = pattern.split('/').filter(Boolean);
|
|
255
|
-
const pathParts = pathname.split('/').filter(Boolean);
|
|
256
|
-
if (patternParts.length === 0 && pathParts.length === 0)
|
|
257
|
-
return true;
|
|
258
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
259
|
-
const patternPart = patternParts[i];
|
|
260
|
-
const pathPart = pathParts[i];
|
|
261
|
-
// Optional catch-all: matches zero or more segments
|
|
262
|
-
if (patternPart.endsWith('*?')) {
|
|
263
|
-
return true;
|
|
264
|
-
}
|
|
265
|
-
// Required catch-all: matches one or more remaining segments
|
|
266
|
-
if (patternPart.endsWith('*')) {
|
|
267
|
-
return pathParts.length >= i + 1;
|
|
268
|
-
}
|
|
269
|
-
if (patternPart.startsWith(':')) {
|
|
270
|
-
if (!pathPart)
|
|
271
|
-
return false;
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
if (patternPart !== pathPart)
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
return patternParts.length === pathParts.length;
|
|
278
|
-
}
|
|
279
|
-
function matchRoute(pathname, routes) {
|
|
280
|
-
const sorted = [...routes].sort((a, b) => {
|
|
281
|
-
const aOptional = a.pattern.includes('*?');
|
|
282
|
-
const bOptional = b.pattern.includes('*?');
|
|
283
|
-
if (aOptional && !bOptional)
|
|
284
|
-
return 1;
|
|
285
|
-
if (!aOptional && bOptional)
|
|
286
|
-
return -1;
|
|
287
|
-
return b.pattern.split('/').length - a.pattern.split('/').length;
|
|
288
|
-
});
|
|
289
|
-
for (const route of sorted) {
|
|
290
|
-
if (matchPattern(pathname, route.pattern))
|
|
291
|
-
return route;
|
|
292
|
-
}
|
|
293
|
-
return null;
|
|
294
|
-
}
|
|
295
|
-
function extractParams(pathname, route) {
|
|
296
|
-
const params = {};
|
|
297
|
-
const patternParts = route.pattern.split('/').filter(Boolean);
|
|
298
|
-
const pathParts = pathname.split('/').filter(Boolean);
|
|
299
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
300
|
-
const patternPart = patternParts[i];
|
|
301
|
-
if (!patternPart.startsWith(':'))
|
|
302
|
-
continue;
|
|
303
|
-
const name = patternPart.slice(1).replace(/\*\??/, '');
|
|
304
|
-
if (patternPart.endsWith('*?') || patternPart.endsWith('*')) {
|
|
305
|
-
params[name] = pathParts.slice(i).join('/');
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
params[name] = pathParts[i] || '';
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return params;
|
|
312
|
-
}
|
|
313
|
-
async function createRenderableRouteModuleElement(modulePath, context, options = {}) {
|
|
314
|
-
const { params, searchParams, req } = context;
|
|
315
|
-
const RouteModule = require(modulePath);
|
|
316
|
-
const RouteComponent = RouteModule.default;
|
|
317
|
-
if (!RouteComponent) {
|
|
318
|
-
throw new Error(`Route module does not export default component: ${modulePath}`);
|
|
319
|
-
}
|
|
320
|
-
if (options.evaluateMetadata && typeof RouteModule.generateMetadata === 'function') {
|
|
321
|
-
await RouteModule.generateMetadata({ params, searchParams }, RouteModule.metadata ?? {});
|
|
322
|
-
}
|
|
323
|
-
const routeProps = typeof RouteModule.getServerProps === 'function'
|
|
324
|
-
? await RouteModule.getServerProps({ query: req.query, params, req })
|
|
325
|
-
: {};
|
|
326
|
-
const moduleStem = path_1.default.basename(modulePath).replace(/\.[jt]sx?$/, '');
|
|
327
|
-
if (moduleStem === 'default' || moduleStem === 'not-found') {
|
|
328
|
-
const eagerResult = await RouteComponent({
|
|
329
|
-
...routeProps,
|
|
330
|
-
params,
|
|
331
|
-
searchParams,
|
|
332
|
-
});
|
|
333
|
-
return react_1.default.isValidElement(eagerResult)
|
|
334
|
-
? eagerResult
|
|
335
|
-
: react_1.default.createElement(react_1.default.Fragment, null, eagerResult);
|
|
336
|
-
}
|
|
337
|
-
return react_1.default.createElement(RouteComponent, {
|
|
338
|
-
...routeProps,
|
|
339
|
-
params,
|
|
340
|
-
searchParams,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
function applySegmentBoundaries(dir, element) {
|
|
344
|
-
const loadingPath = (0, app_router_runtime_1.resolveConventionModule)(dir, 'loading');
|
|
345
|
-
const errorPath = (0, app_router_runtime_1.resolveConventionModule)(dir, 'error');
|
|
346
|
-
const loadingComponent = loadingPath
|
|
347
|
-
? (() => {
|
|
348
|
-
try {
|
|
349
|
-
return require(loadingPath).default;
|
|
350
|
-
}
|
|
351
|
-
catch {
|
|
352
|
-
return undefined;
|
|
353
|
-
}
|
|
354
|
-
})()
|
|
355
|
-
: undefined;
|
|
356
|
-
const errorComponent = errorPath
|
|
357
|
-
? (() => {
|
|
358
|
-
try {
|
|
359
|
-
return require(errorPath).default;
|
|
360
|
-
}
|
|
361
|
-
catch {
|
|
362
|
-
return undefined;
|
|
363
|
-
}
|
|
364
|
-
})()
|
|
365
|
-
: undefined;
|
|
366
|
-
let wrappedElement = element;
|
|
367
|
-
if (loadingComponent) {
|
|
368
|
-
wrappedElement = react_1.default.createElement(getRouteSuspense(), {
|
|
369
|
-
loadingComponent,
|
|
370
|
-
children: wrappedElement,
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
if (errorComponent) {
|
|
374
|
-
wrappedElement = react_1.default.createElement(getRouteErrorBoundary(), {
|
|
375
|
-
fallbackComponent: errorComponent,
|
|
376
|
-
children: wrappedElement,
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
return wrappedElement;
|
|
380
|
-
}
|
|
381
|
-
async function renderAppSubtreeElement(input) {
|
|
382
|
-
const appDir = path_1.default.join(input.cwd, 'app');
|
|
383
|
-
let element = await createRenderableRouteModuleElement(input.entryFilePath, {
|
|
384
|
-
params: input.params,
|
|
385
|
-
searchParams: input.searchParams,
|
|
386
|
-
req: input.req,
|
|
387
|
-
}, {
|
|
388
|
-
evaluateMetadata: input.evaluateLeafMetadata,
|
|
389
|
-
});
|
|
390
|
-
const directoryChain = (0, app_router_runtime_1.resolveDirectoryChain)(input.subtreeRootDir, input.entryFilePath);
|
|
391
|
-
for (let i = directoryChain.length - 1; i >= 0; i--) {
|
|
392
|
-
const dir = directoryChain[i];
|
|
393
|
-
element = applySegmentBoundaries(dir, element);
|
|
394
|
-
const layoutPath = (0, app_router_runtime_1.resolveConventionModule)(dir, 'root') ?? (0, app_router_runtime_1.resolveConventionModule)(dir, 'layout');
|
|
395
|
-
if (!layoutPath || path_1.default.resolve(layoutPath) === path_1.default.resolve(input.entryFilePath)) {
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
const LayoutModule = require(layoutPath);
|
|
399
|
-
const LayoutComponent = LayoutModule.default;
|
|
400
|
-
if (!LayoutComponent) {
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
const slotProps = {};
|
|
404
|
-
if (!input.disableParallelSlots) {
|
|
405
|
-
const slotMatches = (0, app_router_runtime_1.resolveParallelSlotMatches)({
|
|
406
|
-
appDir,
|
|
407
|
-
layoutPath,
|
|
408
|
-
pathname: input.pathname,
|
|
409
|
-
});
|
|
410
|
-
for (const slotMatch of slotMatches) {
|
|
411
|
-
slotProps[slotMatch.slotName] = await renderAppSubtreeElement({
|
|
412
|
-
subtreeRootDir: slotMatch.slotRootDir,
|
|
413
|
-
entryFilePath: slotMatch.filePath,
|
|
414
|
-
pathname: input.pathname,
|
|
415
|
-
params: {
|
|
416
|
-
...input.params,
|
|
417
|
-
...slotMatch.params,
|
|
418
|
-
},
|
|
419
|
-
searchParams: input.searchParams,
|
|
420
|
-
req: input.req,
|
|
421
|
-
cwd: input.cwd,
|
|
422
|
-
evaluateLeafMetadata: true,
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
element = react_1.default.createElement(LayoutComponent, {
|
|
427
|
-
params: input.params,
|
|
428
|
-
searchParams: input.searchParams,
|
|
429
|
-
...slotProps,
|
|
430
|
-
}, element);
|
|
431
|
-
}
|
|
432
|
-
return element;
|
|
433
|
-
}
|
|
434
|
-
async function createRouteElement(route, context, isDev, runtimeRoot, options = {}) {
|
|
435
|
-
const { pathname, params, searchParams, req } = context;
|
|
436
|
-
if (isDev) {
|
|
437
|
-
clearProjectRequireCache(runtimeRoot);
|
|
438
|
-
}
|
|
439
|
-
return renderAppSubtreeElement({
|
|
440
|
-
subtreeRootDir: path_1.default.join(runtimeRoot, 'app'),
|
|
441
|
-
entryFilePath: route.pagePath,
|
|
442
|
-
pathname,
|
|
443
|
-
params,
|
|
444
|
-
searchParams,
|
|
445
|
-
req,
|
|
446
|
-
cwd: runtimeRoot,
|
|
447
|
-
evaluateLeafMetadata: true,
|
|
448
|
-
disableParallelSlots: options.disableParallelSlots,
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
async function readRawRequestBody(req) {
|
|
452
|
-
if (typeof req.body === 'string') {
|
|
453
|
-
return Buffer.from(req.body);
|
|
454
|
-
}
|
|
455
|
-
if (Buffer.isBuffer(req.body)) {
|
|
456
|
-
return req.body;
|
|
457
|
-
}
|
|
458
|
-
const chunks = [];
|
|
459
|
-
for await (const chunk of req) {
|
|
460
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
461
|
-
}
|
|
462
|
-
return Buffer.concat(chunks);
|
|
463
|
-
}
|
|
464
|
-
async function parseMultipartFormData(req, rawBody) {
|
|
465
|
-
const request = new Request(`http://127.0.0.1${req.originalUrl || req.url || '/'}`, {
|
|
466
|
-
method: req.method || 'POST',
|
|
467
|
-
headers: req.headers,
|
|
468
|
-
body: rawBody,
|
|
469
|
-
});
|
|
470
|
-
return request.formData();
|
|
471
|
-
}
|
|
472
|
-
function getSearchParamsFromRequest(req) {
|
|
473
|
-
return Object.fromEntries(new URLSearchParams(req.query).entries());
|
|
474
|
-
}
|
|
475
|
-
function
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
(
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
gateStream.once('
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
await
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
app.
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
const
|
|
846
|
-
result = await
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
}
|
|
852
|
-
const
|
|
853
|
-
if (
|
|
854
|
-
res.setHeader('x-vista-revalidated-
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
res
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
}
|
|
888
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const express_1 = __importDefault(require("express"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const react_1 = __importDefault(require("react"));
|
|
10
|
+
const stream_1 = require("stream");
|
|
11
|
+
const url_1 = require("url");
|
|
12
|
+
const react_client_reference_manifest_1 = require("../build/rsc/react-client-reference-manifest");
|
|
13
|
+
const root_resolver_1 = require("./root-resolver");
|
|
14
|
+
const constants_1 = require("../constants");
|
|
15
|
+
const module_compile_hook_1 = require("./module-compile-hook");
|
|
16
|
+
const request_context_1 = require("./request-context");
|
|
17
|
+
const runtime_actions_1 = require("./runtime-actions");
|
|
18
|
+
const app_router_runtime_1 = require("./app-router-runtime");
|
|
19
|
+
const fetch_policy_1 = require("./fetch-policy");
|
|
20
|
+
const runtime_artifacts_1 = require("./runtime-artifacts");
|
|
21
|
+
const config_1 = require("../config");
|
|
22
|
+
const vista_import_map_1 = require("./vista-import-map");
|
|
23
|
+
const project_alias_resolver_1 = require("./project-alias-resolver");
|
|
24
|
+
// NOTE: RouteErrorBoundary and RouteSuspense are 'use client' components.
|
|
25
|
+
// Under --conditions react-server, React.Component is not available, so we
|
|
26
|
+
// must NOT import them at the top level. Instead we lazy-require them after
|
|
27
|
+
// the client-load hook has been installed (which turns them into Flight
|
|
28
|
+
// client references automatically).
|
|
29
|
+
let _RouteErrorBoundary = null;
|
|
30
|
+
let _RouteSuspense = null;
|
|
31
|
+
function getRouteErrorBoundary() {
|
|
32
|
+
if (!_RouteErrorBoundary) {
|
|
33
|
+
_RouteErrorBoundary = require('../components/error-boundary').RouteErrorBoundary;
|
|
34
|
+
}
|
|
35
|
+
return _RouteErrorBoundary;
|
|
36
|
+
}
|
|
37
|
+
function getRouteSuspense() {
|
|
38
|
+
if (!_RouteSuspense) {
|
|
39
|
+
_RouteSuspense = require('../components/route-suspense').RouteSuspense;
|
|
40
|
+
}
|
|
41
|
+
return _RouteSuspense;
|
|
42
|
+
}
|
|
43
|
+
const CjsModule = require('module');
|
|
44
|
+
// Support CSS imports on server runtime
|
|
45
|
+
require.extensions['.css'] = (m, filename) => {
|
|
46
|
+
if (filename.endsWith('.module.css')) {
|
|
47
|
+
m.exports = {};
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
let installedClientLoadHook = false;
|
|
51
|
+
let originalCompile = null;
|
|
52
|
+
let reactResolutionInstalled = false;
|
|
53
|
+
let originalResolveFilename = null;
|
|
54
|
+
const clientDirectiveCache = new Map();
|
|
55
|
+
function resolveVistaInternalRequest(request) {
|
|
56
|
+
return (0, vista_import_map_1.resolveVistaSourceRequest)(request, path_1.default.resolve(__dirname, '..'));
|
|
57
|
+
}
|
|
58
|
+
function parseCliArg(flag) {
|
|
59
|
+
const index = process.argv.indexOf(flag);
|
|
60
|
+
if (index === -1)
|
|
61
|
+
return undefined;
|
|
62
|
+
return process.argv[index + 1];
|
|
63
|
+
}
|
|
64
|
+
function resolvePort(defaultPort) {
|
|
65
|
+
const raw = parseCliArg('--port') ?? process.env.RSC_UPSTREAM_PORT ?? String(defaultPort);
|
|
66
|
+
const port = Number(raw);
|
|
67
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
68
|
+
throw new Error(`Invalid upstream port: ${raw}`);
|
|
69
|
+
}
|
|
70
|
+
return port;
|
|
71
|
+
}
|
|
72
|
+
function resolveFromWorkspace(specifier, cwd) {
|
|
73
|
+
const searchRoots = [
|
|
74
|
+
cwd,
|
|
75
|
+
path_1.default.resolve(cwd, '..'),
|
|
76
|
+
path_1.default.resolve(cwd, '..', '..'),
|
|
77
|
+
path_1.default.resolve(cwd, '..', '..', 'rsc'),
|
|
78
|
+
path_1.default.resolve(cwd, '..', '..', '..'),
|
|
79
|
+
path_1.default.resolve(cwd, '..', '..', '..', 'rsc'),
|
|
80
|
+
];
|
|
81
|
+
for (const root of searchRoots) {
|
|
82
|
+
try {
|
|
83
|
+
return require.resolve(specifier, { paths: [root] });
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// continue
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return require.resolve(specifier);
|
|
90
|
+
}
|
|
91
|
+
function normalizeModulePath(filePath) {
|
|
92
|
+
return filePath.replace(/\\/g, '/').toLowerCase();
|
|
93
|
+
}
|
|
94
|
+
function shouldInvalidateDevModule(modulePath, cwd) {
|
|
95
|
+
const normalized = normalizeModulePath(modulePath);
|
|
96
|
+
const rootPrefix = normalizeModulePath(`${cwd}${path_1.default.sep}`);
|
|
97
|
+
if (!normalized.startsWith(rootPrefix))
|
|
98
|
+
return false;
|
|
99
|
+
if (normalized.includes('/node_modules/'))
|
|
100
|
+
return false;
|
|
101
|
+
if (normalized.includes(`/${constants_1.BUILD_DIR.toLowerCase()}/`))
|
|
102
|
+
return false;
|
|
103
|
+
return /\.(?:[cm]?[jt]sx?|json)$/i.test(normalized);
|
|
104
|
+
}
|
|
105
|
+
function clearProjectRequireCache(cwd) {
|
|
106
|
+
for (const key of Object.keys(require.cache)) {
|
|
107
|
+
if (!shouldInvalidateDevModule(key, cwd))
|
|
108
|
+
continue;
|
|
109
|
+
delete require.cache[key];
|
|
110
|
+
clientDirectiveCache.delete(key);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function setupTypeScriptRuntime(cwd) {
|
|
114
|
+
try {
|
|
115
|
+
const swcRegisterPath = resolveFromWorkspace('@swc-node/register/register', cwd);
|
|
116
|
+
const typescriptPath = resolveFromWorkspace('typescript', cwd);
|
|
117
|
+
const { register } = require(swcRegisterPath);
|
|
118
|
+
const ts = require(typescriptPath);
|
|
119
|
+
register({
|
|
120
|
+
module: ts.ModuleKind.CommonJS,
|
|
121
|
+
jsx: ts.JsxEmit.ReactJSX,
|
|
122
|
+
moduleResolution: ts.ModuleResolutionKind.Node16,
|
|
123
|
+
esModuleInterop: true,
|
|
124
|
+
allowJs: true,
|
|
125
|
+
});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// fallback
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const tsNodePath = resolveFromWorkspace('ts-node', cwd);
|
|
133
|
+
require(tsNodePath).register({
|
|
134
|
+
transpileOnly: true,
|
|
135
|
+
compilerOptions: {
|
|
136
|
+
module: 'commonjs',
|
|
137
|
+
jsx: 'react-jsx',
|
|
138
|
+
moduleResolution: 'node16',
|
|
139
|
+
esModuleInterop: true,
|
|
140
|
+
allowJs: true,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// fallback
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const tsxPath = resolveFromWorkspace('tsx/cjs', cwd);
|
|
150
|
+
// tsx/cjs registers the TypeScript loader for require()
|
|
151
|
+
require(tsxPath);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
throw new Error('No TypeScript compiler available for RSC upstream runtime. Install one of: @swc-node/register, ts-node, or tsx');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function hasClientBoundaryDirective(source) {
|
|
159
|
+
let trimmed = source;
|
|
160
|
+
while (true) {
|
|
161
|
+
trimmed = trimmed.trimStart();
|
|
162
|
+
if (trimmed.startsWith('//')) {
|
|
163
|
+
const newlineIndex = trimmed.indexOf('\n');
|
|
164
|
+
trimmed = newlineIndex === -1 ? '' : trimmed.slice(newlineIndex + 1);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (trimmed.startsWith('/*')) {
|
|
168
|
+
const commentEndIndex = trimmed.indexOf('*/');
|
|
169
|
+
if (commentEndIndex === -1) {
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
trimmed = trimmed.slice(commentEndIndex + 2);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
return trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"');
|
|
178
|
+
}
|
|
179
|
+
function isClientBoundaryFile(filename, transpiledSource) {
|
|
180
|
+
const cached = clientDirectiveCache.get(filename);
|
|
181
|
+
if (cached !== undefined)
|
|
182
|
+
return cached;
|
|
183
|
+
let isClient = false;
|
|
184
|
+
try {
|
|
185
|
+
const originalSource = fs_1.default.readFileSync(filename, 'utf-8');
|
|
186
|
+
isClient = hasClientBoundaryDirective(originalSource);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
isClient = hasClientBoundaryDirective(transpiledSource);
|
|
190
|
+
}
|
|
191
|
+
clientDirectiveCache.set(filename, isClient);
|
|
192
|
+
return isClient;
|
|
193
|
+
}
|
|
194
|
+
function installSingleReactResolution(cwd) {
|
|
195
|
+
if (reactResolutionInstalled)
|
|
196
|
+
return;
|
|
197
|
+
let reactPath;
|
|
198
|
+
let reactDomPath;
|
|
199
|
+
try {
|
|
200
|
+
reactPath = require.resolve('react');
|
|
201
|
+
reactDomPath = require.resolve('react-dom');
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
originalResolveFilename = CjsModule._resolveFilename;
|
|
207
|
+
const projectAliasResolver = (0, project_alias_resolver_1.createProjectAliasResolver)(cwd, resolveFromWorkspace);
|
|
208
|
+
CjsModule._resolveFilename = function (request, parent, isMain, options) {
|
|
209
|
+
const vistaResolvedPath = resolveVistaInternalRequest(request);
|
|
210
|
+
if (vistaResolvedPath)
|
|
211
|
+
return vistaResolvedPath;
|
|
212
|
+
const aliasResolvedPath = projectAliasResolver?.resolve(request);
|
|
213
|
+
if (aliasResolvedPath) {
|
|
214
|
+
return originalResolveFilename.call(this, aliasResolvedPath, parent, isMain, options);
|
|
215
|
+
}
|
|
216
|
+
if (request === 'react')
|
|
217
|
+
return reactPath;
|
|
218
|
+
if (request === 'react-dom')
|
|
219
|
+
return reactDomPath;
|
|
220
|
+
if (request.startsWith('react/')) {
|
|
221
|
+
const subPath = request.slice('react/'.length);
|
|
222
|
+
try {
|
|
223
|
+
return require.resolve(`react/${subPath}`, { paths: [path_1.default.dirname(reactPath)] });
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// fall through
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (request.startsWith('react-dom/')) {
|
|
230
|
+
const subPath = request.slice('react-dom/'.length);
|
|
231
|
+
try {
|
|
232
|
+
return require.resolve(`react-dom/${subPath}`, { paths: [path_1.default.dirname(reactDomPath)] });
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// fall through
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
239
|
+
};
|
|
240
|
+
reactResolutionInstalled = true;
|
|
241
|
+
}
|
|
242
|
+
function installClientLoadHook(cwd, createClientModuleProxy) {
|
|
243
|
+
if (installedClientLoadHook)
|
|
244
|
+
return;
|
|
245
|
+
const cacheComponentsConfig = (0, config_1.resolveCacheComponentsConfig)((0, config_1.loadConfig)(cwd));
|
|
246
|
+
(0, module_compile_hook_1.installModuleCompileHook)({
|
|
247
|
+
cwd,
|
|
248
|
+
createClientModuleProxy,
|
|
249
|
+
cacheComponentsEnabled: cacheComponentsConfig.enabled,
|
|
250
|
+
});
|
|
251
|
+
installedClientLoadHook = true;
|
|
252
|
+
}
|
|
253
|
+
function matchPattern(pathname, pattern) {
|
|
254
|
+
const patternParts = pattern.split('/').filter(Boolean);
|
|
255
|
+
const pathParts = pathname.split('/').filter(Boolean);
|
|
256
|
+
if (patternParts.length === 0 && pathParts.length === 0)
|
|
257
|
+
return true;
|
|
258
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
259
|
+
const patternPart = patternParts[i];
|
|
260
|
+
const pathPart = pathParts[i];
|
|
261
|
+
// Optional catch-all: matches zero or more segments
|
|
262
|
+
if (patternPart.endsWith('*?')) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
// Required catch-all: matches one or more remaining segments
|
|
266
|
+
if (patternPart.endsWith('*')) {
|
|
267
|
+
return pathParts.length >= i + 1;
|
|
268
|
+
}
|
|
269
|
+
if (patternPart.startsWith(':')) {
|
|
270
|
+
if (!pathPart)
|
|
271
|
+
return false;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (patternPart !== pathPart)
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return patternParts.length === pathParts.length;
|
|
278
|
+
}
|
|
279
|
+
function matchRoute(pathname, routes) {
|
|
280
|
+
const sorted = [...routes].sort((a, b) => {
|
|
281
|
+
const aOptional = a.pattern.includes('*?');
|
|
282
|
+
const bOptional = b.pattern.includes('*?');
|
|
283
|
+
if (aOptional && !bOptional)
|
|
284
|
+
return 1;
|
|
285
|
+
if (!aOptional && bOptional)
|
|
286
|
+
return -1;
|
|
287
|
+
return b.pattern.split('/').length - a.pattern.split('/').length;
|
|
288
|
+
});
|
|
289
|
+
for (const route of sorted) {
|
|
290
|
+
if (matchPattern(pathname, route.pattern))
|
|
291
|
+
return route;
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function extractParams(pathname, route) {
|
|
296
|
+
const params = {};
|
|
297
|
+
const patternParts = route.pattern.split('/').filter(Boolean);
|
|
298
|
+
const pathParts = pathname.split('/').filter(Boolean);
|
|
299
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
300
|
+
const patternPart = patternParts[i];
|
|
301
|
+
if (!patternPart.startsWith(':'))
|
|
302
|
+
continue;
|
|
303
|
+
const name = patternPart.slice(1).replace(/\*\??/, '');
|
|
304
|
+
if (patternPart.endsWith('*?') || patternPart.endsWith('*')) {
|
|
305
|
+
params[name] = pathParts.slice(i).join('/');
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
params[name] = pathParts[i] || '';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return params;
|
|
312
|
+
}
|
|
313
|
+
async function createRenderableRouteModuleElement(modulePath, context, options = {}) {
|
|
314
|
+
const { params, searchParams, req } = context;
|
|
315
|
+
const RouteModule = require(modulePath);
|
|
316
|
+
const RouteComponent = RouteModule.default;
|
|
317
|
+
if (!RouteComponent) {
|
|
318
|
+
throw new Error(`Route module does not export default component: ${modulePath}`);
|
|
319
|
+
}
|
|
320
|
+
if (options.evaluateMetadata && typeof RouteModule.generateMetadata === 'function') {
|
|
321
|
+
await RouteModule.generateMetadata({ params, searchParams }, RouteModule.metadata ?? {});
|
|
322
|
+
}
|
|
323
|
+
const routeProps = typeof RouteModule.getServerProps === 'function'
|
|
324
|
+
? await RouteModule.getServerProps({ query: req.query, params, req })
|
|
325
|
+
: {};
|
|
326
|
+
const moduleStem = path_1.default.basename(modulePath).replace(/\.[jt]sx?$/, '');
|
|
327
|
+
if (moduleStem === 'default' || moduleStem === 'not-found') {
|
|
328
|
+
const eagerResult = await RouteComponent({
|
|
329
|
+
...routeProps,
|
|
330
|
+
params,
|
|
331
|
+
searchParams,
|
|
332
|
+
});
|
|
333
|
+
return react_1.default.isValidElement(eagerResult)
|
|
334
|
+
? eagerResult
|
|
335
|
+
: react_1.default.createElement(react_1.default.Fragment, null, eagerResult);
|
|
336
|
+
}
|
|
337
|
+
return react_1.default.createElement(RouteComponent, {
|
|
338
|
+
...routeProps,
|
|
339
|
+
params,
|
|
340
|
+
searchParams,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function applySegmentBoundaries(dir, element) {
|
|
344
|
+
const loadingPath = (0, app_router_runtime_1.resolveConventionModule)(dir, 'loading');
|
|
345
|
+
const errorPath = (0, app_router_runtime_1.resolveConventionModule)(dir, 'error');
|
|
346
|
+
const loadingComponent = loadingPath
|
|
347
|
+
? (() => {
|
|
348
|
+
try {
|
|
349
|
+
return require(loadingPath).default;
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
})()
|
|
355
|
+
: undefined;
|
|
356
|
+
const errorComponent = errorPath
|
|
357
|
+
? (() => {
|
|
358
|
+
try {
|
|
359
|
+
return require(errorPath).default;
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
return undefined;
|
|
363
|
+
}
|
|
364
|
+
})()
|
|
365
|
+
: undefined;
|
|
366
|
+
let wrappedElement = element;
|
|
367
|
+
if (loadingComponent) {
|
|
368
|
+
wrappedElement = react_1.default.createElement(getRouteSuspense(), {
|
|
369
|
+
loadingComponent,
|
|
370
|
+
children: wrappedElement,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
if (errorComponent) {
|
|
374
|
+
wrappedElement = react_1.default.createElement(getRouteErrorBoundary(), {
|
|
375
|
+
fallbackComponent: errorComponent,
|
|
376
|
+
children: wrappedElement,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return wrappedElement;
|
|
380
|
+
}
|
|
381
|
+
async function renderAppSubtreeElement(input) {
|
|
382
|
+
const appDir = path_1.default.join(input.cwd, 'app');
|
|
383
|
+
let element = await createRenderableRouteModuleElement(input.entryFilePath, {
|
|
384
|
+
params: input.params,
|
|
385
|
+
searchParams: input.searchParams,
|
|
386
|
+
req: input.req,
|
|
387
|
+
}, {
|
|
388
|
+
evaluateMetadata: input.evaluateLeafMetadata,
|
|
389
|
+
});
|
|
390
|
+
const directoryChain = (0, app_router_runtime_1.resolveDirectoryChain)(input.subtreeRootDir, input.entryFilePath);
|
|
391
|
+
for (let i = directoryChain.length - 1; i >= 0; i--) {
|
|
392
|
+
const dir = directoryChain[i];
|
|
393
|
+
element = applySegmentBoundaries(dir, element);
|
|
394
|
+
const layoutPath = (0, app_router_runtime_1.resolveConventionModule)(dir, 'root') ?? (0, app_router_runtime_1.resolveConventionModule)(dir, 'layout');
|
|
395
|
+
if (!layoutPath || path_1.default.resolve(layoutPath) === path_1.default.resolve(input.entryFilePath)) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
const LayoutModule = require(layoutPath);
|
|
399
|
+
const LayoutComponent = LayoutModule.default;
|
|
400
|
+
if (!LayoutComponent) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const slotProps = {};
|
|
404
|
+
if (!input.disableParallelSlots) {
|
|
405
|
+
const slotMatches = (0, app_router_runtime_1.resolveParallelSlotMatches)({
|
|
406
|
+
appDir,
|
|
407
|
+
layoutPath,
|
|
408
|
+
pathname: input.pathname,
|
|
409
|
+
});
|
|
410
|
+
for (const slotMatch of slotMatches) {
|
|
411
|
+
slotProps[slotMatch.slotName] = await renderAppSubtreeElement({
|
|
412
|
+
subtreeRootDir: slotMatch.slotRootDir,
|
|
413
|
+
entryFilePath: slotMatch.filePath,
|
|
414
|
+
pathname: input.pathname,
|
|
415
|
+
params: {
|
|
416
|
+
...input.params,
|
|
417
|
+
...slotMatch.params,
|
|
418
|
+
},
|
|
419
|
+
searchParams: input.searchParams,
|
|
420
|
+
req: input.req,
|
|
421
|
+
cwd: input.cwd,
|
|
422
|
+
evaluateLeafMetadata: true,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
element = react_1.default.createElement(LayoutComponent, {
|
|
427
|
+
params: input.params,
|
|
428
|
+
searchParams: input.searchParams,
|
|
429
|
+
...slotProps,
|
|
430
|
+
}, element);
|
|
431
|
+
}
|
|
432
|
+
return element;
|
|
433
|
+
}
|
|
434
|
+
async function createRouteElement(route, context, isDev, runtimeRoot, options = {}) {
|
|
435
|
+
const { pathname, params, searchParams, req } = context;
|
|
436
|
+
if (isDev) {
|
|
437
|
+
clearProjectRequireCache(runtimeRoot);
|
|
438
|
+
}
|
|
439
|
+
return renderAppSubtreeElement({
|
|
440
|
+
subtreeRootDir: path_1.default.join(runtimeRoot, 'app'),
|
|
441
|
+
entryFilePath: route.pagePath,
|
|
442
|
+
pathname,
|
|
443
|
+
params,
|
|
444
|
+
searchParams,
|
|
445
|
+
req,
|
|
446
|
+
cwd: runtimeRoot,
|
|
447
|
+
evaluateLeafMetadata: true,
|
|
448
|
+
disableParallelSlots: options.disableParallelSlots,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
async function readRawRequestBody(req) {
|
|
452
|
+
if (typeof req.body === 'string') {
|
|
453
|
+
return Buffer.from(req.body);
|
|
454
|
+
}
|
|
455
|
+
if (Buffer.isBuffer(req.body)) {
|
|
456
|
+
return req.body;
|
|
457
|
+
}
|
|
458
|
+
const chunks = [];
|
|
459
|
+
for await (const chunk of req) {
|
|
460
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
461
|
+
}
|
|
462
|
+
return Buffer.concat(chunks);
|
|
463
|
+
}
|
|
464
|
+
async function parseMultipartFormData(req, rawBody) {
|
|
465
|
+
const request = new Request(`http://127.0.0.1${req.originalUrl || req.url || '/'}`, {
|
|
466
|
+
method: req.method || 'POST',
|
|
467
|
+
headers: req.headers,
|
|
468
|
+
body: rawBody,
|
|
469
|
+
});
|
|
470
|
+
return request.formData();
|
|
471
|
+
}
|
|
472
|
+
function getSearchParamsFromRequest(req) {
|
|
473
|
+
return Object.fromEntries(new URLSearchParams(req.query).entries());
|
|
474
|
+
}
|
|
475
|
+
function loadFlightManifest(flightManifestPath) {
|
|
476
|
+
const raw = JSON.parse(fs_1.default.readFileSync(flightManifestPath, 'utf-8'));
|
|
477
|
+
return (0, react_client_reference_manifest_1.createGuardedReactClientManifest)((0, react_client_reference_manifest_1.normalizeReactClientReferenceManifest)(raw));
|
|
478
|
+
}
|
|
479
|
+
function startUpstream() {
|
|
480
|
+
const cwd = path_1.default.resolve(process.env.VISTA_ARTIFACT_ROOT || process.cwd());
|
|
481
|
+
const runtimeRoot = (0, runtime_artifacts_1.resolveRuntimeProjectRoot)(cwd, process.env.VISTA_RUNTIME_ROOT);
|
|
482
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
483
|
+
const port = resolvePort(3101);
|
|
484
|
+
const vistaDirRoot = path_1.default.join(cwd, constants_1.BUILD_DIR);
|
|
485
|
+
installSingleReactResolution(runtimeRoot);
|
|
486
|
+
setupTypeScriptRuntime(runtimeRoot);
|
|
487
|
+
const flightServerPath = resolveFromWorkspace('react-server-dom-webpack/server.node', cwd);
|
|
488
|
+
const flightServer = require(flightServerPath);
|
|
489
|
+
installClientLoadHook(runtimeRoot, flightServer.createClientModuleProxy);
|
|
490
|
+
(0, fetch_policy_1.installSegmentFetchPolicyShim)();
|
|
491
|
+
const serverManifestPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'server', 'server-manifest.json');
|
|
492
|
+
const flightManifestPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'react-client-manifest.json');
|
|
493
|
+
if (!fs_1.default.existsSync(serverManifestPath)) {
|
|
494
|
+
throw new Error('Missing RSC server manifest. Run "vista build" first.');
|
|
495
|
+
}
|
|
496
|
+
// In dev mode the flight manifest may not exist yet (webpack-dev-middleware
|
|
497
|
+
// hasn't completed the first compilation). Write a stub so we can start,
|
|
498
|
+
// and reload on each request.
|
|
499
|
+
if (!fs_1.default.existsSync(flightManifestPath)) {
|
|
500
|
+
if (isDev) {
|
|
501
|
+
fs_1.default.writeFileSync(flightManifestPath, '{}');
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
throw new Error('Missing RSC flight manifest. Run "vista build" first.');
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
let serverManifest = JSON.parse(fs_1.default.readFileSync(serverManifestPath, 'utf-8'));
|
|
508
|
+
let flightManifest = loadFlightManifest(flightManifestPath);
|
|
509
|
+
const app = (0, express_1.default)();
|
|
510
|
+
const pipeFlightModel = async (res, model, status) => {
|
|
511
|
+
let capturedError = null;
|
|
512
|
+
let gateResolved = false;
|
|
513
|
+
let streamEnded = false;
|
|
514
|
+
const gateStream = new stream_1.PassThrough();
|
|
515
|
+
const bufferedChunks = [];
|
|
516
|
+
const finishGate = (() => {
|
|
517
|
+
let resolver = null;
|
|
518
|
+
const promise = new Promise((resolve) => {
|
|
519
|
+
resolver = () => {
|
|
520
|
+
if (gateResolved) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
gateResolved = true;
|
|
524
|
+
resolve();
|
|
525
|
+
};
|
|
526
|
+
});
|
|
527
|
+
return { promise, resolve: () => resolver?.() };
|
|
528
|
+
})();
|
|
529
|
+
const onData = (chunk) => {
|
|
530
|
+
bufferedChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
531
|
+
finishGate.resolve();
|
|
532
|
+
};
|
|
533
|
+
gateStream.on('data', onData);
|
|
534
|
+
gateStream.once('end', () => {
|
|
535
|
+
streamEnded = true;
|
|
536
|
+
finishGate.resolve();
|
|
537
|
+
});
|
|
538
|
+
gateStream.once('error', () => {
|
|
539
|
+
finishGate.resolve();
|
|
540
|
+
});
|
|
541
|
+
const stream = flightServer.renderToPipeableStream(model, flightManifest, {
|
|
542
|
+
onError(error) {
|
|
543
|
+
capturedError = error;
|
|
544
|
+
if (error?.name !== 'NotFoundError') {
|
|
545
|
+
console.error('[vista:rsc] Upstream flight render error:', error);
|
|
546
|
+
}
|
|
547
|
+
finishGate.resolve();
|
|
548
|
+
},
|
|
549
|
+
});
|
|
550
|
+
stream.pipe(gateStream);
|
|
551
|
+
const gateTimer = setTimeout(() => finishGate.resolve(), 75);
|
|
552
|
+
await finishGate.promise;
|
|
553
|
+
clearTimeout(gateTimer);
|
|
554
|
+
if (capturedError?.name === 'NotFoundError') {
|
|
555
|
+
gateStream.destroy();
|
|
556
|
+
throw capturedError;
|
|
557
|
+
}
|
|
558
|
+
gateStream.off('data', onData);
|
|
559
|
+
res.status(status);
|
|
560
|
+
res.setHeader('Content-Type', 'text/x-component');
|
|
561
|
+
res.setHeader('Vary', 'Accept');
|
|
562
|
+
for (const chunk of bufferedChunks) {
|
|
563
|
+
res.write(chunk);
|
|
564
|
+
}
|
|
565
|
+
if (streamEnded) {
|
|
566
|
+
res.end();
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
gateStream.pipe(res);
|
|
570
|
+
};
|
|
571
|
+
const drainFlightModel = async (model) => {
|
|
572
|
+
let capturedError = null;
|
|
573
|
+
const sink = new stream_1.PassThrough();
|
|
574
|
+
const completion = new Promise((resolve, reject) => {
|
|
575
|
+
sink.on('data', () => { });
|
|
576
|
+
sink.once('end', resolve);
|
|
577
|
+
sink.once('error', reject);
|
|
578
|
+
});
|
|
579
|
+
const stream = flightServer.renderToPipeableStream(model, flightManifest, {
|
|
580
|
+
onError(error) {
|
|
581
|
+
if (!capturedError) {
|
|
582
|
+
capturedError = error;
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
});
|
|
586
|
+
stream.pipe(sink);
|
|
587
|
+
await completion;
|
|
588
|
+
if (capturedError) {
|
|
589
|
+
throw capturedError;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
const resolveActionModulePath = (actionId) => {
|
|
593
|
+
const hashIdx = actionId.lastIndexOf('#');
|
|
594
|
+
const modulePath = hashIdx >= 0 ? actionId.slice(0, hashIdx) : actionId;
|
|
595
|
+
if (!modulePath.startsWith('file://')) {
|
|
596
|
+
return modulePath;
|
|
597
|
+
}
|
|
598
|
+
try {
|
|
599
|
+
return (0, url_1.fileURLToPath)(modulePath);
|
|
600
|
+
}
|
|
601
|
+
catch {
|
|
602
|
+
let fallbackPath = modulePath.replace(/^file:\/\/\//, '').replace(/^file:\/\//, '');
|
|
603
|
+
if (process.platform === 'win32' && /^[a-zA-Z]:/.test(fallbackPath) === false) {
|
|
604
|
+
fallbackPath = '/' + fallbackPath;
|
|
605
|
+
}
|
|
606
|
+
return fallbackPath;
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
const primeInlineActionRegistration = async (req, actionId) => {
|
|
610
|
+
const actionEntry = serverManifest.serverActions?.[actionId];
|
|
611
|
+
if (!actionEntry || actionEntry.kind !== 'inline') {
|
|
612
|
+
return undefined;
|
|
613
|
+
}
|
|
614
|
+
const pathname = req.path.replace(/^\/(?:_rsc|rsc)/, '') || '/';
|
|
615
|
+
const searchParams = getSearchParamsFromRequest(req);
|
|
616
|
+
const actionRoute = matchRoute(pathname, serverManifest.routes) ||
|
|
617
|
+
serverManifest.routes.find((candidate) => {
|
|
618
|
+
const targetPath = path_1.default.resolve(actionEntry.filePath);
|
|
619
|
+
return (path_1.default.resolve(candidate.pagePath) === targetPath ||
|
|
620
|
+
candidate.layoutPaths.some((layoutPath) => path_1.default.resolve(layoutPath) === targetPath));
|
|
621
|
+
}) ||
|
|
622
|
+
null;
|
|
623
|
+
const resolvedActionPath = path_1.default.resolve(actionEntry.filePath || resolveActionModulePath(actionId));
|
|
624
|
+
const routeParams = actionRoute ? extractParams(pathname, actionRoute) : {};
|
|
625
|
+
if (isDev) {
|
|
626
|
+
try {
|
|
627
|
+
delete require.cache[require.resolve(resolvedActionPath)];
|
|
628
|
+
}
|
|
629
|
+
catch {
|
|
630
|
+
// ignore missing cache entries
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const actionModule = require(resolvedActionPath);
|
|
634
|
+
if (typeof actionModule?.default === 'function') {
|
|
635
|
+
const probeProps = {
|
|
636
|
+
params: routeParams,
|
|
637
|
+
searchParams,
|
|
638
|
+
};
|
|
639
|
+
if (actionRoute && path_1.default.resolve(actionRoute.pagePath) !== resolvedActionPath) {
|
|
640
|
+
probeProps.children = null;
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
await actionModule.default(probeProps);
|
|
644
|
+
}
|
|
645
|
+
catch {
|
|
646
|
+
// Some components require a fuller tree to evaluate. Fall through to route priming.
|
|
647
|
+
}
|
|
648
|
+
const directResolution = (0, runtime_actions_1.resolveRegisteredServerReference)(actionId);
|
|
649
|
+
if (directResolution) {
|
|
650
|
+
return directResolution;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (actionRoute) {
|
|
654
|
+
const params = routeParams;
|
|
655
|
+
const model = await createRouteElement(actionRoute, { pathname, params, searchParams, req }, isDev, runtimeRoot);
|
|
656
|
+
await drainFlightModel(model);
|
|
657
|
+
return (0, runtime_actions_1.resolveRegisteredServerReference)(actionId);
|
|
658
|
+
}
|
|
659
|
+
return undefined;
|
|
660
|
+
};
|
|
661
|
+
const handleRSCRequest = async (req, res) => {
|
|
662
|
+
const pathname = req.path.replace(/^\/(?:_rsc|rsc)/, '') || '/';
|
|
663
|
+
await (0, request_context_1.runWithRequestContext)({
|
|
664
|
+
req,
|
|
665
|
+
res,
|
|
666
|
+
cwd: runtimeRoot,
|
|
667
|
+
vistaDirRoot,
|
|
668
|
+
urlPath: pathname,
|
|
669
|
+
}, async () => {
|
|
670
|
+
try {
|
|
671
|
+
// In dev mode, reload manifests from disk on each request so we
|
|
672
|
+
// always pick up the latest output from ReactFlightWebpackPlugin.
|
|
673
|
+
if (isDev) {
|
|
674
|
+
try {
|
|
675
|
+
serverManifest = JSON.parse(fs_1.default.readFileSync(serverManifestPath, 'utf-8'));
|
|
676
|
+
flightManifest = loadFlightManifest(flightManifestPath);
|
|
677
|
+
}
|
|
678
|
+
catch {
|
|
679
|
+
// Manifests may be mid-write; use whatever we have cached.
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
const route = matchRoute(pathname, serverManifest.routes);
|
|
683
|
+
(0, request_context_1.setCurrentSegmentConfig)(route?.segmentConfig);
|
|
684
|
+
if (!route) {
|
|
685
|
+
const rootLayout = (0, root_resolver_1.resolveRootLayout)(runtimeRoot, isDev);
|
|
686
|
+
const resolvedNotFound = (0, root_resolver_1.resolveNotFoundComponent)(runtimeRoot, rootLayout, isDev);
|
|
687
|
+
let model;
|
|
688
|
+
if (resolvedNotFound) {
|
|
689
|
+
const notFoundElement = react_1.default.createElement(resolvedNotFound.component, {
|
|
690
|
+
params: {},
|
|
691
|
+
searchParams: {},
|
|
692
|
+
});
|
|
693
|
+
model = react_1.default.createElement(rootLayout.component, { params: {}, searchParams: {} }, notFoundElement);
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
model = react_1.default.createElement('div', {
|
|
697
|
+
style: {
|
|
698
|
+
display: 'flex',
|
|
699
|
+
flexDirection: 'column',
|
|
700
|
+
alignItems: 'center',
|
|
701
|
+
justifyContent: 'center',
|
|
702
|
+
height: '100vh',
|
|
703
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
704
|
+
background: '#0a0a0a',
|
|
705
|
+
color: '#ededed',
|
|
706
|
+
margin: 0,
|
|
707
|
+
overflow: 'hidden',
|
|
708
|
+
textAlign: 'center',
|
|
709
|
+
userSelect: 'none',
|
|
710
|
+
},
|
|
711
|
+
}, react_1.default.createElement('span', {
|
|
712
|
+
style: {
|
|
713
|
+
fontSize: '6rem',
|
|
714
|
+
fontWeight: 800,
|
|
715
|
+
letterSpacing: '-0.04em',
|
|
716
|
+
lineHeight: 1,
|
|
717
|
+
background: 'linear-gradient(135deg, #7c3aed, #2563eb, #06b6d4)',
|
|
718
|
+
WebkitBackgroundClip: 'text',
|
|
719
|
+
WebkitTextFillColor: 'transparent',
|
|
720
|
+
backgroundClip: 'text',
|
|
721
|
+
},
|
|
722
|
+
}, '404'), react_1.default.createElement('p', {
|
|
723
|
+
style: {
|
|
724
|
+
marginTop: '0.75rem',
|
|
725
|
+
fontSize: '0.95rem',
|
|
726
|
+
fontWeight: 400,
|
|
727
|
+
color: '#555',
|
|
728
|
+
letterSpacing: '0.02em',
|
|
729
|
+
},
|
|
730
|
+
}, "There's nothing here."));
|
|
731
|
+
}
|
|
732
|
+
await pipeFlightModel(res, model, 404);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const params = extractParams(pathname, route);
|
|
736
|
+
const searchParams = getSearchParamsFromRequest(req);
|
|
737
|
+
const element = await createRouteElement(route, { pathname, params, searchParams, req }, isDev, runtimeRoot);
|
|
738
|
+
await pipeFlightModel(res, element, 200);
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
if (error?.name === 'NotFoundError') {
|
|
742
|
+
try {
|
|
743
|
+
const rootLayout = (0, root_resolver_1.resolveRootLayout)(runtimeRoot, isDev);
|
|
744
|
+
const route = matchRoute(pathname, serverManifest.routes);
|
|
745
|
+
(0, request_context_1.setCurrentSegmentConfig)(route?.segmentConfig);
|
|
746
|
+
if (route) {
|
|
747
|
+
const segmentNotFoundPath = (0, app_router_runtime_1.resolveNearestSegmentNotFoundPath)(path_1.default.join(runtimeRoot, 'app'), route.routeDir);
|
|
748
|
+
if (segmentNotFoundPath) {
|
|
749
|
+
const params = extractParams(pathname, route);
|
|
750
|
+
const searchParams = getSearchParamsFromRequest(req);
|
|
751
|
+
const model = await createRouteElement({
|
|
752
|
+
...route,
|
|
753
|
+
pagePath: segmentNotFoundPath,
|
|
754
|
+
}, { pathname, params, searchParams, req }, isDev, runtimeRoot, { disableParallelSlots: true });
|
|
755
|
+
await pipeFlightModel(res, model, 404);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
const resolvedNotFound = (0, root_resolver_1.resolveNotFoundComponent)(runtimeRoot, rootLayout, isDev);
|
|
760
|
+
let model;
|
|
761
|
+
if (resolvedNotFound) {
|
|
762
|
+
const notFoundElement = react_1.default.createElement(resolvedNotFound.component, {
|
|
763
|
+
params: {},
|
|
764
|
+
searchParams: {},
|
|
765
|
+
});
|
|
766
|
+
model = react_1.default.createElement(rootLayout.component, { params: {}, searchParams: {} }, notFoundElement);
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
model = react_1.default.createElement('h1', null, '404 - Page Not Found');
|
|
770
|
+
}
|
|
771
|
+
await pipeFlightModel(res, model, 404);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
catch (notFoundError) {
|
|
775
|
+
console.error('[vista:rsc] Failed to render NotFoundError fallback:', notFoundError);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
console.error('[vista:rsc] Upstream request failed:', error);
|
|
779
|
+
res
|
|
780
|
+
.status(500)
|
|
781
|
+
.type('text/plain')
|
|
782
|
+
.send(error.message);
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
};
|
|
786
|
+
app.get('/rsc*', handleRSCRequest);
|
|
787
|
+
app.get('/_rsc*', handleRSCRequest);
|
|
788
|
+
// -----------------------------------------------------------------------
|
|
789
|
+
// Server Actions — POST handler
|
|
790
|
+
// -----------------------------------------------------------------------
|
|
791
|
+
app.use(express_1.default.text({ type: 'text/plain', limit: '10mb' }));
|
|
792
|
+
const handleServerAction = async (req, res) => {
|
|
793
|
+
const pathname = req.path.replace(/^\/(?:_rsc|rsc)/, '') || '/';
|
|
794
|
+
await (0, request_context_1.runWithRequestContext)({
|
|
795
|
+
req,
|
|
796
|
+
res,
|
|
797
|
+
cwd: runtimeRoot,
|
|
798
|
+
vistaDirRoot,
|
|
799
|
+
urlPath: pathname,
|
|
800
|
+
}, async () => {
|
|
801
|
+
try {
|
|
802
|
+
const actionId = req.headers['rsc-action'];
|
|
803
|
+
if (!actionId) {
|
|
804
|
+
res.status(400).type('text/plain').send('Missing rsc-action header');
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
if (isDev) {
|
|
808
|
+
try {
|
|
809
|
+
serverManifest = JSON.parse(fs_1.default.readFileSync(serverManifestPath, 'utf-8'));
|
|
810
|
+
flightManifest = loadFlightManifest(flightManifestPath);
|
|
811
|
+
}
|
|
812
|
+
catch {
|
|
813
|
+
// Keep cached manifests if they're being rewritten.
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
(0, request_context_1.setCurrentSegmentConfig)(matchRoute(pathname, serverManifest.routes)?.segmentConfig);
|
|
817
|
+
let actionFn = (0, runtime_actions_1.resolveRegisteredServerReference)(actionId);
|
|
818
|
+
if (!actionFn) {
|
|
819
|
+
actionFn = await primeInlineActionRegistration(req, actionId);
|
|
820
|
+
}
|
|
821
|
+
if (!actionFn) {
|
|
822
|
+
const hashIdx = actionId.lastIndexOf('#');
|
|
823
|
+
const exportName = hashIdx >= 0 ? actionId.slice(hashIdx + 1) : 'default';
|
|
824
|
+
const resolvedPath = resolveActionModulePath(actionId);
|
|
825
|
+
if (isDev) {
|
|
826
|
+
try {
|
|
827
|
+
delete require.cache[require.resolve(resolvedPath)];
|
|
828
|
+
}
|
|
829
|
+
catch {
|
|
830
|
+
// ignore missing cache entries
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
const actionModule = require(resolvedPath);
|
|
834
|
+
actionFn = actionModule[exportName];
|
|
835
|
+
}
|
|
836
|
+
if (typeof actionFn !== 'function') {
|
|
837
|
+
res.status(404).type('text/plain').send(`Server action not found: ${actionId}`);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const rawBody = await readRawRequestBody(req);
|
|
841
|
+
const contentType = String(req.headers['content-type'] || '');
|
|
842
|
+
let result;
|
|
843
|
+
if (contentType.includes('multipart/form-data')) {
|
|
844
|
+
const formData = await parseMultipartFormData(req, rawBody);
|
|
845
|
+
const boundAction = await flightServer.decodeAction(formData, flightManifest);
|
|
846
|
+
result = await boundAction();
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
const args = (await flightServer.decodeReply(rawBody.toString('utf-8'), flightManifest));
|
|
850
|
+
result = await actionFn(...(Array.isArray(args) ? args : [args]));
|
|
851
|
+
}
|
|
852
|
+
const revalidatedPaths = (0, request_context_1.consumeRevalidatedPaths)();
|
|
853
|
+
if (revalidatedPaths.length > 0) {
|
|
854
|
+
res.setHeader('x-vista-revalidated-paths', JSON.stringify(revalidatedPaths));
|
|
855
|
+
}
|
|
856
|
+
const revalidatedTags = (0, request_context_1.consumeRevalidatedTags)();
|
|
857
|
+
if (revalidatedTags.length > 0) {
|
|
858
|
+
res.setHeader('x-vista-revalidated-tags', JSON.stringify(revalidatedTags));
|
|
859
|
+
}
|
|
860
|
+
res.setHeader('Content-Type', 'text/x-component');
|
|
861
|
+
const stream = flightServer.renderToPipeableStream(result, flightManifest, {
|
|
862
|
+
onError(error) {
|
|
863
|
+
console.error('[vista:rsc] Server action render error:', error);
|
|
864
|
+
},
|
|
865
|
+
});
|
|
866
|
+
stream.pipe(res);
|
|
867
|
+
}
|
|
868
|
+
catch (error) {
|
|
869
|
+
console.error('[vista:rsc] Server action failed:', error);
|
|
870
|
+
res
|
|
871
|
+
.status(500)
|
|
872
|
+
.type('text/plain')
|
|
873
|
+
.send(error.message);
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
};
|
|
877
|
+
app.post('/rsc*', handleServerAction);
|
|
878
|
+
app.post('/_rsc*', handleServerAction);
|
|
879
|
+
const server = app.listen(port, () => {
|
|
880
|
+
console.log(`[vista:rsc:upstream] Listening on http://127.0.0.1:${port}/rsc`);
|
|
881
|
+
});
|
|
882
|
+
server.on('error', (error) => {
|
|
883
|
+
if (error?.code === 'EADDRINUSE') {
|
|
884
|
+
console.error(`[vista:server] Port ${port} is already in use.`);
|
|
885
|
+
process.exit(1);
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
console.error('[vista:server] RSC upstream startup failed:', error);
|
|
889
|
+
process.exit(1);
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
startUpstream();
|