@vistagenic/vista 0.3.2 → 0.3.4
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 +79 -109
- package/dist/ai/embeddings.d.ts +11 -11
- package/dist/ai/embeddings.js +71 -71
- package/dist/ai/index.d.ts +10 -10
- package/dist/ai/index.js +26 -26
- package/dist/ai/providers/base.js +85 -85
- package/dist/ai/react/react-server.d.ts +1 -1
- package/dist/ai/react/react-server.js +17 -17
- package/dist/ai/react/use-agent.js +138 -138
- package/dist/auth/core.d.ts +140 -140
- package/dist/auth/core.js +165 -165
- package/dist/auth/index.d.ts +20 -20
- package/dist/auth/index.js +369 -369
- package/dist/auth/react-server.d.ts +1 -1
- package/dist/auth/react-server.js +10 -10
- package/dist/auth/react.d.ts +18 -18
- package/dist/auth/react.js +71 -71
- package/dist/bin/build-rsc-flashpack.js +6 -0
- package/dist/bin/build-rsc.js +555 -492
- package/dist/bin/build.js +365 -353
- package/dist/bin/generate.js +513 -510
- package/dist/bin/webpack.config.d.ts +3 -1
- package/dist/bin/webpack.config.js +7 -4
- package/dist/build/manifest.d.ts +169 -169
- package/dist/build/manifest.js +423 -423
- package/dist/build/rsc/client-manifest.d.ts +62 -62
- package/dist/build/rsc/client-manifest.js +295 -295
- package/dist/build/rsc/compiler.d.ts +3 -1
- package/dist/build/rsc/compiler.js +12 -7
- package/dist/build/rsc/native-scanner.d.ts +135 -135
- package/dist/build/rsc/native-scanner.js +203 -203
- package/dist/build/rsc/react-client-reference-manifest.d.ts +35 -28
- package/dist/build/rsc/react-client-reference-manifest.js +366 -240
- package/dist/build/standalone.js +260 -254
- package/dist/client/dynamic.react-server.d.ts +2 -2
- package/dist/client/dynamic.react-server.js +23 -23
- package/dist/client/link.js +1 -1
- package/dist/client/link.react-server.d.ts +2 -2
- package/dist/client/link.react-server.js +11 -11
- package/dist/client/navigation.js +2 -2
- package/dist/client/navigation.react-server.d.ts +1 -1
- package/dist/client/navigation.react-server.js +17 -17
- package/dist/client/router.react-server.d.ts +1 -1
- package/dist/client/router.react-server.js +17 -17
- package/dist/client/rsc-router.d.ts +1 -3
- package/dist/client/rsc-router.js +98 -45
- package/dist/client/rsc-router.react-server.d.ts +1 -1
- package/dist/client/rsc-router.react-server.js +17 -17
- package/dist/client/script.react-server.d.ts +2 -2
- package/dist/client/script.react-server.js +23 -23
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -7
- package/dist/deploy/adapters/cloudflare.js +42 -41
- package/dist/deploy/adapters/docker.d.ts +1 -0
- package/dist/deploy/adapters/docker.js +5 -4
- package/dist/deploy/adapters/netlify.js +60 -27
- package/dist/deploy/adapters/vercel.js +80 -50
- package/dist/deploy/preflight.js +4 -3
- package/dist/deploy/runtime-pack.d.ts +11 -0
- package/dist/deploy/runtime-pack.js +300 -0
- package/dist/deploy/utils.d.ts +7 -1
- package/dist/deploy/utils.js +95 -3
- package/dist/flashpack/command.js +1 -0
- package/dist/flashpack/runtime.js +2 -1
- package/dist/image/get-img-props.js +21 -11
- package/dist/image/image-config.d.ts +2 -0
- package/dist/image/image-config.js +17 -0
- package/dist/image/index.d.ts +18 -3
- package/dist/image/index.js +1 -1
- package/dist/image/react-server.d.ts +1 -2
- package/dist/image/react-server.js +1 -1
- package/dist/index.d.ts +23 -23
- package/dist/index.js +61 -61
- package/dist/server/app-dir.d.ts +22 -0
- package/dist/server/app-dir.js +77 -0
- package/dist/server/app-router-runtime.d.ts +1 -0
- package/dist/server/app-router-runtime.js +34 -9
- package/dist/server/cookie-parse.d.ts +4 -4
- package/dist/server/cookie-parse.js +14 -14
- package/dist/server/engine.js +5 -5
- package/dist/server/hydration-chunks.d.ts +7 -0
- package/dist/server/hydration-chunks.js +49 -0
- package/dist/server/image-optimizer.js +2 -1
- package/dist/server/index.d.ts +109 -109
- package/dist/server/index.js +315 -315
- package/dist/server/middleware-runner.d.ts +125 -125
- package/dist/server/middleware-runner.js +607 -615
- package/dist/server/middleware-security.d.ts +36 -36
- package/dist/server/middleware-security.js +183 -183
- package/dist/server/module-compile-hook.js +706 -695
- package/dist/server/root-resolver.js +6 -5
- package/dist/server/rsc-engine-flashpack.d.ts +3 -1
- package/dist/server/rsc-engine-flashpack.js +12 -1
- package/dist/server/rsc-engine.d.ts +6 -1
- package/dist/server/rsc-engine.js +217 -280
- package/dist/server/rsc-upstream.js +900 -892
- package/dist/server/ssr-webpack-shim.d.ts +6 -0
- package/dist/server/ssr-webpack-shim.js +29 -0
- package/dist/server/static-generator.d.ts +2 -0
- package/dist/server/static-generator.js +33 -32
- package/dist/server/structure-validator.js +2 -1
- package/dist/server/structure-watch.js +2 -0
- package/dist/server/typed-api-runtime.js +639 -635
- package/dist/server/vista-import-map.js +134 -134
- package/dist/stack/index.d.ts +34 -34
- package/dist/stack/index.js +49 -49
- package/dist/stack/server/caller.d.ts +13 -13
- package/dist/stack/server/caller.js +42 -42
- package/dist/stack/server/executor.d.ts +40 -40
- package/dist/stack/server/executor.js +222 -222
- package/dist/stack/server/index.d.ts +11 -11
- package/dist/stack/server/index.js +24 -24
- package/dist/stack/server/procedure.d.ts +20 -20
- package/dist/stack/server/procedure.js +66 -66
- package/dist/stack/server/types.d.ts +113 -113
- package/dist/theme/react-server.d.ts +10 -10
- package/dist/theme/react-server.js +16 -16
- package/package.json +1 -1
|
@@ -12,6 +12,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.createRSCApp = createRSCApp;
|
|
16
|
+
exports.getRSCRequestListener = getRSCRequestListener;
|
|
15
17
|
exports.startRSCServer = startRSCServer;
|
|
16
18
|
exports.default = startRSCServer;
|
|
17
19
|
const path_1 = __importDefault(require("path"));
|
|
@@ -22,7 +24,7 @@ const server_1 = require("react-dom/server");
|
|
|
22
24
|
const webpack_dev_middleware_1 = __importDefault(require("webpack-dev-middleware"));
|
|
23
25
|
const stream_1 = require("stream");
|
|
24
26
|
const child_process_1 = require("child_process");
|
|
25
|
-
const
|
|
27
|
+
const ssr_webpack_shim_1 = require("./ssr-webpack-shim");
|
|
26
28
|
const middleware_runner_1 = require("./middleware-runner");
|
|
27
29
|
const image_optimizer_1 = require("./image-optimizer");
|
|
28
30
|
const ppr_1 = require("./ppr");
|
|
@@ -31,39 +33,10 @@ const logger_1 = require("./logger");
|
|
|
31
33
|
const not_found_page_1 = require("./not-found-page");
|
|
32
34
|
const static_cache_1 = require("./static-cache");
|
|
33
35
|
const static_generator_1 = require("./static-generator");
|
|
36
|
+
const hydration_chunks_1 = require("./hydration-chunks");
|
|
34
37
|
const react_client_reference_manifest_1 = require("../build/rsc/react-client-reference-manifest");
|
|
35
38
|
const constants_1 = require("../constants");
|
|
36
39
|
const CjsModule = require('module');
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// SSR Webpack Shim
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// The Flight SSR decoder (react-server-dom-webpack/client.node) calls
|
|
41
|
-
// __webpack_require__(specifier) to load client components during SSR.
|
|
42
|
-
// In Vista the SSR process runs in plain Node.js (not through webpack),
|
|
43
|
-
// so we provide a shim that converts file:// URLs to absolute paths and
|
|
44
|
-
// delegates to Node's require().
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
function installSSRWebpackShim() {
|
|
47
|
-
if (typeof globalThis.__webpack_require__ === 'function')
|
|
48
|
-
return;
|
|
49
|
-
globalThis.__webpack_require__ = function ssrWebpackRequire(specifier) {
|
|
50
|
-
let modulePath = specifier;
|
|
51
|
-
// Convert file:// URLs to absolute paths
|
|
52
|
-
if (specifier.startsWith('file://')) {
|
|
53
|
-
try {
|
|
54
|
-
modulePath = (0, url_1.fileURLToPath)(specifier);
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
modulePath = specifier;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return require(modulePath);
|
|
61
|
-
};
|
|
62
|
-
// Chunk loading is a no-op on the server — all code is already local.
|
|
63
|
-
globalThis.__webpack_chunk_load__ = function ssrChunkLoad(_chunkId) {
|
|
64
|
-
return Promise.resolve();
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
40
|
const config_1 = require("../config");
|
|
68
41
|
const dev_error_1 = require("../dev-error");
|
|
69
42
|
const artifact_validator_1 = require("./artifact-validator");
|
|
@@ -81,6 +54,7 @@ const app_router_runtime_1 = require("./app-router-runtime");
|
|
|
81
54
|
const fetch_policy_1 = require("./fetch-policy");
|
|
82
55
|
const vista_import_map_1 = require("./vista-import-map");
|
|
83
56
|
const project_alias_resolver_1 = require("./project-alias-resolver");
|
|
57
|
+
const app_dir_1 = require("./app-dir");
|
|
84
58
|
// Support CSS imports on server runtime
|
|
85
59
|
// - Regular .css: ignored (handled by PostCSS)
|
|
86
60
|
// - .module.css: return empty class mapping (webpack build handles real mappings)
|
|
@@ -335,32 +309,7 @@ function cleanHotUpdateFiles(cwd) {
|
|
|
335
309
|
}
|
|
336
310
|
}
|
|
337
311
|
function findChunkFiles(cwd, isDev) {
|
|
338
|
-
|
|
339
|
-
if (!fs_1.default.existsSync(chunksDir))
|
|
340
|
-
return [];
|
|
341
|
-
const files = fs_1.default
|
|
342
|
-
.readdirSync(chunksDir)
|
|
343
|
-
.filter((name) => name.endsWith('.js') && !name.endsWith('.map') && !name.includes('.hot-update.'));
|
|
344
|
-
// In dev, avoid loading stale production artifacts left from a previous build.
|
|
345
|
-
// Production chunks end with a hash suffix like `main-1a2b3c4d.js`.
|
|
346
|
-
const normalizedFiles = isDev
|
|
347
|
-
? files.filter((name) => !/-[0-9a-f]{8,}\.js$/i.test(name))
|
|
348
|
-
: files;
|
|
349
|
-
// Load webpack runtime first, then framework, then the rest alphabetically.
|
|
350
|
-
// This ensures the chunk registry (__webpack_require__) is available before
|
|
351
|
-
// any deferred chunk tries to self-register.
|
|
352
|
-
const priority = ['webpack.js', 'framework.js', 'vendor.js'];
|
|
353
|
-
return normalizedFiles.sort((a, b) => {
|
|
354
|
-
const ai = priority.indexOf(a);
|
|
355
|
-
const bi = priority.indexOf(b);
|
|
356
|
-
if (ai !== -1 && bi !== -1)
|
|
357
|
-
return ai - bi;
|
|
358
|
-
if (ai !== -1)
|
|
359
|
-
return -1;
|
|
360
|
-
if (bi !== -1)
|
|
361
|
-
return 1;
|
|
362
|
-
return a.localeCompare(b);
|
|
363
|
-
});
|
|
312
|
+
return (0, hydration_chunks_1.listHydrationChunkFiles)(cwd, isDev);
|
|
364
313
|
}
|
|
365
314
|
function normalizeSSRManifest(manifest) {
|
|
366
315
|
if (!manifest || !manifest.moduleMap) {
|
|
@@ -432,6 +381,46 @@ function loadSSRManifestFromDisk(absolutePath) {
|
|
|
432
381
|
const manifest = (0, react_client_reference_manifest_1.normalizeReactServerConsumerManifest)(JSON.parse(fs_1.default.readFileSync(absolutePath, 'utf-8')));
|
|
433
382
|
return normalizeSSRManifest(manifest);
|
|
434
383
|
}
|
|
384
|
+
/** Stub `{}` manifests written before the first webpack emit are not usable for Flight SSR. */
|
|
385
|
+
function isSSRManifestReady(manifest) {
|
|
386
|
+
if (!manifest || !manifest.moduleMap)
|
|
387
|
+
return false;
|
|
388
|
+
return Object.keys(manifest.moduleMap).length > 0;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Tee an upstream Flight body: one copy for createFromNodeStream (SSR), one
|
|
392
|
+
* buffer for inline hydration bootstrap in the HTML response.
|
|
393
|
+
*/
|
|
394
|
+
function teeFlightReadable(source) {
|
|
395
|
+
const decodeStream = new stream_1.PassThrough();
|
|
396
|
+
const chunks = [];
|
|
397
|
+
let resolveBuffer;
|
|
398
|
+
let rejectBuffer;
|
|
399
|
+
const bufferPromise = new Promise((resolve, reject) => {
|
|
400
|
+
resolveBuffer = resolve;
|
|
401
|
+
rejectBuffer = reject;
|
|
402
|
+
});
|
|
403
|
+
source.on('data', (chunk) => {
|
|
404
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
405
|
+
chunks.push(buf);
|
|
406
|
+
if (!decodeStream.write(buf)) {
|
|
407
|
+
source.pause();
|
|
408
|
+
decodeStream.once('drain', () => source.resume());
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
source.on('end', () => {
|
|
412
|
+
decodeStream.end();
|
|
413
|
+
resolveBuffer(Buffer.concat(chunks));
|
|
414
|
+
});
|
|
415
|
+
source.on('error', (error) => {
|
|
416
|
+
decodeStream.destroy(error);
|
|
417
|
+
rejectBuffer(error);
|
|
418
|
+
});
|
|
419
|
+
return { decodeStream, bufferPromise };
|
|
420
|
+
}
|
|
421
|
+
function buildInlineFlightBootstrapScript(flightText) {
|
|
422
|
+
return `<script>window.${constants_1.RSC_DATA_FLAG}=${JSON.stringify(flightText)};</script>`;
|
|
423
|
+
}
|
|
435
424
|
function matchPattern(pathname, pattern) {
|
|
436
425
|
const patternParts = pattern.split('/').filter(Boolean);
|
|
437
426
|
const pathParts = pathname.split('/').filter(Boolean);
|
|
@@ -563,7 +552,7 @@ function applySegmentBoundaries(dir, element) {
|
|
|
563
552
|
return wrappedElement;
|
|
564
553
|
}
|
|
565
554
|
async function renderAppSubtreeElement(input) {
|
|
566
|
-
const appDir =
|
|
555
|
+
const appDir = (0, app_dir_1.resolveAppDir)(input.cwd);
|
|
567
556
|
let element = await createRenderableRouteModuleElement(input.entryFilePath, {
|
|
568
557
|
params: input.params,
|
|
569
558
|
searchParams: input.searchParams,
|
|
@@ -573,9 +562,15 @@ async function renderAppSubtreeElement(input) {
|
|
|
573
562
|
});
|
|
574
563
|
const directoryChain = (0, app_router_runtime_1.resolveDirectoryChain)(input.subtreeRootDir, input.entryFilePath);
|
|
575
564
|
for (let i = directoryChain.length - 1; i >= 0; i--) {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
565
|
+
element = applySegmentBoundaries(directoryChain[i], element);
|
|
566
|
+
}
|
|
567
|
+
const layoutPaths = input.layoutPaths && input.layoutPaths.length > 0
|
|
568
|
+
? input.layoutPaths
|
|
569
|
+
: directoryChain
|
|
570
|
+
.map((dir) => (0, app_router_runtime_1.resolveConventionModule)(dir, 'root') ?? (0, app_router_runtime_1.resolveConventionModule)(dir, 'layout'))
|
|
571
|
+
.filter((layoutPath) => Boolean(layoutPath));
|
|
572
|
+
for (let i = layoutPaths.length - 1; i >= 0; i--) {
|
|
573
|
+
const layoutPath = layoutPaths[i];
|
|
579
574
|
if (!layoutPath || path_1.default.resolve(layoutPath) === path_1.default.resolve(input.entryFilePath)) {
|
|
580
575
|
continue;
|
|
581
576
|
}
|
|
@@ -630,7 +625,7 @@ async function createRouteElement(route, context, isDev, rootLayout, runtimeRoot
|
|
|
630
625
|
metadata = { ...metadata, ...dynamicMeta };
|
|
631
626
|
}
|
|
632
627
|
const element = await renderAppSubtreeElement({
|
|
633
|
-
subtreeRootDir:
|
|
628
|
+
subtreeRootDir: (0, app_dir_1.resolveAppDir)(runtimeRoot),
|
|
634
629
|
entryFilePath: route.pagePath,
|
|
635
630
|
pathname: req.path,
|
|
636
631
|
params,
|
|
@@ -639,6 +634,7 @@ async function createRouteElement(route, context, isDev, rootLayout, runtimeRoot
|
|
|
639
634
|
cwd: runtimeRoot,
|
|
640
635
|
evaluateLeafMetadata: false,
|
|
641
636
|
disableParallelSlots: options.disableParallelSlots,
|
|
637
|
+
layoutPaths: route.layoutPaths,
|
|
642
638
|
});
|
|
643
639
|
return { element, metadata, rootMode: rootLayout.mode };
|
|
644
640
|
}
|
|
@@ -748,8 +744,8 @@ function spawnUpstream(cwd, runtimeRoot, upstreamPort) {
|
|
|
748
744
|
// ---------------------------------------------------------------------------
|
|
749
745
|
/**
|
|
750
746
|
* Fetch the Flight stream from the upstream RSC process, decode it with
|
|
751
|
-
* createFromNodeStream,
|
|
752
|
-
*
|
|
747
|
+
* createFromNodeStream, render HTML via renderToPipeableStream, and inline the
|
|
748
|
+
* raw Flight payload so the browser can hydrate without a second /rsc fetch.
|
|
753
749
|
*/
|
|
754
750
|
async function renderFlightToHTMLStream(upstreamOrigin, pathname, search, metadataHtml, chunkFiles, rootMode, flightSSRClient, ssrManifest, res, isDev) {
|
|
755
751
|
const flightUrl = `${upstreamOrigin}/rsc${pathname}${search ? `?${search}` : ''}`;
|
|
@@ -763,30 +759,20 @@ async function renderFlightToHTMLStream(upstreamOrigin, pathname, search, metada
|
|
|
763
759
|
if (!upstream.body) {
|
|
764
760
|
throw new Error('Upstream returned empty body');
|
|
765
761
|
}
|
|
766
|
-
// 2.
|
|
762
|
+
// 2. Tee: decode stream for SSR + buffer for inline hydration bootstrap
|
|
767
763
|
const nodeStream = stream_1.Readable.fromWeb(upstream.body);
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
element = react_1.default.createElement(react_1.default.Fragment, null, resolvedTree);
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
779
|
-
// 4. Wrap in a component that consumes the Flight response
|
|
780
|
-
function FlightRoot() {
|
|
781
|
-
return react_1.default.use(flightResponse);
|
|
782
|
-
}
|
|
783
|
-
element = react_1.default.createElement(FlightRoot);
|
|
784
|
-
}
|
|
785
|
-
// 5. Build script tags for client chunks
|
|
764
|
+
const { decodeStream, bufferPromise } = teeFlightReadable(nodeStream);
|
|
765
|
+
// 3. Decode Flight stream into a React tree (stream in both dev and prod)
|
|
766
|
+
const flightResponse = flightSSRClient.createFromNodeStream(decodeStream, ssrManifest);
|
|
767
|
+
function FlightRoot() {
|
|
768
|
+
return react_1.default.use(flightResponse);
|
|
769
|
+
}
|
|
770
|
+
const element = react_1.default.createElement(FlightRoot);
|
|
771
|
+
// 4. Build script tags for client chunks
|
|
786
772
|
const scripts = chunkFiles
|
|
787
773
|
.map((chunk) => `<script defer src="${constants_1.STATIC_CHUNKS_PATH}${chunk}"></script>`)
|
|
788
774
|
.join('\n ');
|
|
789
|
-
//
|
|
775
|
+
// 5. Render to a pipeable HTML stream; inject inline Flight before client scripts
|
|
790
776
|
return new Promise((resolve, reject) => {
|
|
791
777
|
let shellSent = false;
|
|
792
778
|
const { pipe } = (0, server_1.renderToPipeableStream)(element, {
|
|
@@ -795,11 +781,10 @@ async function renderFlightToHTMLStream(upstreamOrigin, pathname, search, metada
|
|
|
795
781
|
res.status(upstream.status === 404 ? 404 : 200);
|
|
796
782
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
797
783
|
res.setHeader('Transfer-Encoding', 'chunked');
|
|
798
|
-
|
|
784
|
+
let heldTail = '';
|
|
799
785
|
const transform = new stream_1.Transform({
|
|
800
786
|
transform(chunk, _encoding, callback) {
|
|
801
787
|
let html = chunk.toString();
|
|
802
|
-
// Inject into <head> if present
|
|
803
788
|
if (html.includes('</head>')) {
|
|
804
789
|
const fontHtml = (0, registry_1.getAllFontHTML)();
|
|
805
790
|
const headInjection = `
|
|
@@ -810,15 +795,29 @@ async function renderFlightToHTMLStream(upstreamOrigin, pathname, search, metada
|
|
|
810
795
|
${getCSSLinks()}`;
|
|
811
796
|
html = html.replace('</head>', `${headInjection}\n</head>`);
|
|
812
797
|
}
|
|
813
|
-
//
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
798
|
+
// Hold </body>… so flush can inject Flight + scripts before it.
|
|
799
|
+
const bodyCloseIdx = html.indexOf('</body>');
|
|
800
|
+
if (bodyCloseIdx !== -1) {
|
|
801
|
+
const beforeBodyClose = html.slice(0, bodyCloseIdx);
|
|
802
|
+
heldTail = html.slice(bodyCloseIdx);
|
|
803
|
+
const hydrateFlag = `<script>window.${constants_1.HYDRATE_DOCUMENT_FLAG} = ${rootMode === 'document'};</script>`;
|
|
804
|
+
callback(null, `${beforeBodyClose}\n ${hydrateFlag}\n`);
|
|
805
|
+
return;
|
|
819
806
|
}
|
|
820
807
|
callback(null, html);
|
|
821
808
|
},
|
|
809
|
+
flush(callback) {
|
|
810
|
+
bufferPromise
|
|
811
|
+
.then((buf) => {
|
|
812
|
+
const flightScript = buildInlineFlightBootstrapScript(buf.toString('utf8'));
|
|
813
|
+
// Flight first, then deferred client chunks, then </body></html>
|
|
814
|
+
this.push(`${flightScript}\n ${scripts}\n${heldTail || '</body></html>'}`);
|
|
815
|
+
callback();
|
|
816
|
+
})
|
|
817
|
+
.catch((error) => {
|
|
818
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
|
819
|
+
});
|
|
820
|
+
},
|
|
822
821
|
});
|
|
823
822
|
pipe(transform);
|
|
824
823
|
transform.pipe(res);
|
|
@@ -927,6 +926,23 @@ function renderCompilePendingHTML() {
|
|
|
927
926
|
</body>
|
|
928
927
|
</html>`;
|
|
929
928
|
}
|
|
929
|
+
function failRSCStartup(message, listen) {
|
|
930
|
+
console.error(message);
|
|
931
|
+
if (!listen) {
|
|
932
|
+
throw new Error(message);
|
|
933
|
+
}
|
|
934
|
+
process.exit(1);
|
|
935
|
+
}
|
|
936
|
+
let cachedRequestListener = null;
|
|
937
|
+
function createRSCApp(options = {}) {
|
|
938
|
+
return startRSCServer({ ...options, listen: false });
|
|
939
|
+
}
|
|
940
|
+
function getRSCRequestListener(options = {}) {
|
|
941
|
+
if (!cachedRequestListener) {
|
|
942
|
+
cachedRequestListener = createRSCApp(options);
|
|
943
|
+
}
|
|
944
|
+
return cachedRequestListener;
|
|
945
|
+
}
|
|
930
946
|
function startRSCServer(options = {}) {
|
|
931
947
|
const app = (0, express_1.default)();
|
|
932
948
|
const cwd = path_1.default.resolve(options.projectRoot || process.env.VISTA_ARTIFACT_ROOT || process.cwd());
|
|
@@ -943,7 +959,8 @@ function startRSCServer(options = {}) {
|
|
|
943
959
|
cleanHotUpdateFiles(cwd);
|
|
944
960
|
// Request logger — logs GET/POST with timing
|
|
945
961
|
app.use((0, logger_1.requestLogger)());
|
|
946
|
-
const
|
|
962
|
+
const shouldListen = options.listen !== false;
|
|
963
|
+
const port = resolvePort(String(options.port || vistaConfig.server?.port || process.env.PORT || 3003), 3003);
|
|
947
964
|
const upstreamPort = resolvePort(String(process.env.RSC_UPSTREAM_PORT || port + 1), port + 1);
|
|
948
965
|
const upstreamOrigin = `http://127.0.0.1:${upstreamPort}`;
|
|
949
966
|
installSingleReactResolution(runtimeRoot);
|
|
@@ -953,11 +970,10 @@ function startRSCServer(options = {}) {
|
|
|
953
970
|
cacheComponentsEnabled: cacheComponentsConfig.enabled,
|
|
954
971
|
});
|
|
955
972
|
(0, fetch_policy_1.installSegmentFetchPolicyShim)();
|
|
956
|
-
installSSRWebpackShim();
|
|
973
|
+
(0, ssr_webpack_shim_1.installSSRWebpackShim)();
|
|
957
974
|
const serverManifestPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'server', 'server-manifest.json');
|
|
958
975
|
if (!fs_1.default.existsSync(serverManifestPath)) {
|
|
959
|
-
|
|
960
|
-
process.exit(1);
|
|
976
|
+
failRSCStartup(`[vista:rsc] Missing server manifest at ${serverManifestPath}. Run "vista build --rsc" first.`, shouldListen);
|
|
961
977
|
}
|
|
962
978
|
try {
|
|
963
979
|
if (!isDev || !options.compiler) {
|
|
@@ -965,8 +981,7 @@ function startRSCServer(options = {}) {
|
|
|
965
981
|
}
|
|
966
982
|
}
|
|
967
983
|
catch (error) {
|
|
968
|
-
|
|
969
|
-
process.exit(1);
|
|
984
|
+
failRSCStartup(error.message, shouldListen);
|
|
970
985
|
}
|
|
971
986
|
// ========================================================================
|
|
972
987
|
// Flight SSR Client + SSR Manifest
|
|
@@ -978,7 +993,8 @@ function startRSCServer(options = {}) {
|
|
|
978
993
|
flightSSRClient = require(flightClientPath);
|
|
979
994
|
}
|
|
980
995
|
catch (err) {
|
|
981
|
-
// Flight SSR
|
|
996
|
+
// Flight SSR client missing — requests will fail closed (no renderToString).
|
|
997
|
+
(0, logger_1.logError)(`[vista:rsc] react-server-dom-webpack/client.node unavailable: ${err?.message || String(err)}`);
|
|
982
998
|
}
|
|
983
999
|
const ssrManifestPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'react-server-manifest.json');
|
|
984
1000
|
const ssrManifestLegacyPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'react-ssr-manifest.json');
|
|
@@ -988,13 +1004,21 @@ function startRSCServer(options = {}) {
|
|
|
988
1004
|
? ssrManifestLegacyPath
|
|
989
1005
|
: null;
|
|
990
1006
|
if (resolvedSSRManifestPath) {
|
|
991
|
-
|
|
1007
|
+
try {
|
|
1008
|
+
ssrManifest = loadSSRManifestFromDisk(resolvedSSRManifestPath);
|
|
1009
|
+
}
|
|
1010
|
+
catch {
|
|
1011
|
+
ssrManifest = null;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (ssrManifest && !isSSRManifestReady(ssrManifest)) {
|
|
1015
|
+
// Stub manifests written before the first webpack emit must not drive SSR.
|
|
1016
|
+
ssrManifest = null;
|
|
992
1017
|
}
|
|
993
|
-
|
|
994
|
-
// Can't use Flight SSR without the manifest
|
|
1018
|
+
if (!resolvedSSRManifestPath && flightSSRClient) {
|
|
995
1019
|
flightSSRClient = null;
|
|
996
1020
|
}
|
|
997
|
-
|
|
1021
|
+
let useFlightSSR = !!flightSSRClient && isSSRManifestReady(ssrManifest);
|
|
998
1022
|
// ========================================================================
|
|
999
1023
|
// Structure Validation (dev + strict-block)
|
|
1000
1024
|
// ========================================================================
|
|
@@ -1098,11 +1122,15 @@ function startRSCServer(options = {}) {
|
|
|
1098
1122
|
httpServer.close();
|
|
1099
1123
|
}
|
|
1100
1124
|
// 6. Force exit after brief grace period (Windows Ctrl+C fix)
|
|
1101
|
-
|
|
1125
|
+
if (shouldListen) {
|
|
1126
|
+
setTimeout(() => process.exit(0), 500);
|
|
1127
|
+
}
|
|
1102
1128
|
};
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1129
|
+
if (shouldListen) {
|
|
1130
|
+
process.on('SIGINT', shutdown);
|
|
1131
|
+
process.on('SIGTERM', shutdown);
|
|
1132
|
+
process.on('exit', shutdown);
|
|
1133
|
+
}
|
|
1106
1134
|
// ========================================================================
|
|
1107
1135
|
// Live-Reload SSE for RSC dev mode
|
|
1108
1136
|
// - Pushes reload events when server components change (fs.watch)
|
|
@@ -1134,6 +1162,7 @@ function startRSCServer(options = {}) {
|
|
|
1134
1162
|
'lib',
|
|
1135
1163
|
'ctx',
|
|
1136
1164
|
'data',
|
|
1165
|
+
'src',
|
|
1137
1166
|
'middleware.ts',
|
|
1138
1167
|
'vista.config.ts',
|
|
1139
1168
|
'content-collections.ts',
|
|
@@ -1228,9 +1257,18 @@ function startRSCServer(options = {}) {
|
|
|
1228
1257
|
if (fs_1.default.existsSync(serverManifestPath)) {
|
|
1229
1258
|
serverManifest = JSON.parse(fs_1.default.readFileSync(serverManifestPath, 'utf-8'));
|
|
1230
1259
|
}
|
|
1231
|
-
// Reload SSR manifest on rebuild
|
|
1260
|
+
// Reload SSR manifest on rebuild; ignore stub `{}` until webpack writes a real map.
|
|
1232
1261
|
if (resolvedSSRManifestPath && fs_1.default.existsSync(resolvedSSRManifestPath)) {
|
|
1233
|
-
|
|
1262
|
+
try {
|
|
1263
|
+
const nextManifest = loadSSRManifestFromDisk(resolvedSSRManifestPath);
|
|
1264
|
+
if (isSSRManifestReady(nextManifest)) {
|
|
1265
|
+
ssrManifest = nextManifest;
|
|
1266
|
+
useFlightSSR = !!flightSSRClient;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
catch {
|
|
1270
|
+
// Manifest may be mid-write during compilation.
|
|
1271
|
+
}
|
|
1234
1272
|
}
|
|
1235
1273
|
});
|
|
1236
1274
|
}
|
|
@@ -1503,28 +1541,50 @@ function startRSCServer(options = {}) {
|
|
|
1503
1541
|
return;
|
|
1504
1542
|
}
|
|
1505
1543
|
// ==================================================================
|
|
1506
|
-
// Flight-Based SSR Path
|
|
1544
|
+
// Flight-Based SSR Path (fail-closed — no renderToString page HTML)
|
|
1507
1545
|
// ==================================================================
|
|
1508
|
-
|
|
1509
|
-
// by fetching the Flight stream from upstream and using
|
|
1510
|
-
// renderToPipeableStream for streaming HTML with proper hydration.
|
|
1511
|
-
// Falls back to legacy renderToString if Flight SSR is unavailable.
|
|
1512
|
-
// ==================================================================
|
|
1513
|
-
if (useFlightSSR) {
|
|
1546
|
+
if (isDev && resolvedSSRManifestPath && fs_1.default.existsSync(resolvedSSRManifestPath)) {
|
|
1514
1547
|
try {
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
catch {
|
|
1520
|
-
// Manifest may be mid-write during compilation; keep the last good in-memory copy.
|
|
1521
|
-
}
|
|
1548
|
+
const nextManifest = loadSSRManifestFromDisk(resolvedSSRManifestPath);
|
|
1549
|
+
if (isSSRManifestReady(nextManifest)) {
|
|
1550
|
+
ssrManifest = nextManifest;
|
|
1551
|
+
useFlightSSR = !!flightSSRClient;
|
|
1522
1552
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1553
|
+
}
|
|
1554
|
+
catch {
|
|
1555
|
+
// Manifest may be mid-write during compilation; keep the last good in-memory copy.
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
if (!useFlightSSR || !flightSSRClient || !isSSRManifestReady(ssrManifest)) {
|
|
1559
|
+
if (isDev && options.compiler) {
|
|
1560
|
+
// Wait for a non-empty SSR manifest after the first webpack emit.
|
|
1561
|
+
res.status(503).type('text/html').send(renderCompilePendingHTML());
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
const message = 'Flight SSR is unavailable. A usable react-server-manifest.json is required; Vista no longer falls back to renderToString.';
|
|
1565
|
+
if (isDev) {
|
|
1566
|
+
res.status(500).send((0, dev_error_1.renderErrorHTML)([
|
|
1567
|
+
{
|
|
1568
|
+
type: 'build',
|
|
1569
|
+
source: 'server',
|
|
1570
|
+
message,
|
|
1571
|
+
},
|
|
1572
|
+
]));
|
|
1573
|
+
}
|
|
1574
|
+
else {
|
|
1575
|
+
res.status(500).type('text/plain').send(message);
|
|
1576
|
+
}
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
try {
|
|
1580
|
+
// Metadata extraction: still done locally so we have <head> content.
|
|
1581
|
+
// notFound() here must not skip Flight — upstream renders the nearest
|
|
1582
|
+
// segment not-found as a 404 Flight payload.
|
|
1583
|
+
const rootLayout = (0, root_resolver_1.resolveRootLayout)(runtimeRoot, isDev);
|
|
1584
|
+
const route = currentRoute;
|
|
1585
|
+
let metadataHtml = '';
|
|
1586
|
+
if (route) {
|
|
1587
|
+
try {
|
|
1528
1588
|
if (isDev) {
|
|
1529
1589
|
clearProjectRequireCache(runtimeRoot);
|
|
1530
1590
|
}
|
|
@@ -1542,173 +1602,49 @@ function startRSCServer(options = {}) {
|
|
|
1542
1602
|
const { generateMetadataHtml } = require('../metadata/generate');
|
|
1543
1603
|
metadataHtml = metadata ? generateMetadataHtml(metadata) : '';
|
|
1544
1604
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
}
|
|
1549
|
-
catch (flightError) {
|
|
1550
|
-
if (flightError?.name === 'NotFoundError' && !res.headersSent) {
|
|
1551
|
-
try {
|
|
1552
|
-
const rootLayout = (0, root_resolver_1.resolveRootLayout)(runtimeRoot, isDev);
|
|
1553
|
-
const route = currentRoute;
|
|
1554
|
-
if (route) {
|
|
1555
|
-
const segmentNotFoundPath = (0, app_router_runtime_1.resolveNearestSegmentNotFoundPath)(path_1.default.join(runtimeRoot, 'app'), route.routeDir);
|
|
1556
|
-
if (segmentNotFoundPath) {
|
|
1557
|
-
const params = extractParams(req.path, route);
|
|
1558
|
-
const searchParams = Object.fromEntries(new URLSearchParams(req.query).entries());
|
|
1559
|
-
const notFoundResult = await createRouteElement({
|
|
1560
|
-
...route,
|
|
1561
|
-
pagePath: segmentNotFoundPath,
|
|
1562
|
-
}, { params, searchParams, req }, isDev, rootLayout, runtimeRoot, { disableParallelSlots: true });
|
|
1563
|
-
const html = (0, server_1.renderToString)(notFoundResult.element);
|
|
1564
|
-
const { generateMetadataHtml } = require('../metadata/generate');
|
|
1565
|
-
const metadataHtml = notFoundResult.metadata
|
|
1566
|
-
? generateMetadataHtml(notFoundResult.metadata)
|
|
1567
|
-
: '';
|
|
1568
|
-
res
|
|
1569
|
-
.status(404)
|
|
1570
|
-
.type('text/html')
|
|
1571
|
-
.send(createHtmlDocument(html, metadataHtml, findChunkFiles(cwd, isDev), notFoundResult.rootMode));
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
catch (notFoundError) {
|
|
1577
|
-
console.error('[vista:rsc] Failed to render segment not-found fallback:', notFoundError);
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1580
|
-
console.error('[vista:rsc] Flight SSR failed:', flightError.message);
|
|
1581
|
-
// If headers haven't been sent yet, show the error overlay directly.
|
|
1582
|
-
// This is much better than falling through to legacy renderToString,
|
|
1583
|
-
// which will likely hit the same error (e.g. useState in a server component).
|
|
1584
|
-
if (isDev && !res.headersSent) {
|
|
1585
|
-
res.status(500).send((0, dev_error_1.renderErrorHTML)([(0, dev_error_1.fromCaughtError)(flightError, { source: 'server' })]));
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
// If headers were already sent (stream was partially flushed),
|
|
1589
|
-
// we can't change the status code, but we can inject an error
|
|
1590
|
-
// overlay script at the end of the stream.
|
|
1591
|
-
if (isDev && res.headersSent) {
|
|
1592
|
-
try {
|
|
1593
|
-
const errMsg = (flightError.message || 'Flight SSR Error')
|
|
1594
|
-
.replace(/'/g, "\\'")
|
|
1595
|
-
.replace(/\n/g, '\\n');
|
|
1596
|
-
res.write(`<script>document.body.innerHTML='';document.body.style.background='#1a1a2e';document.body.style.color='#ff6b6b';document.body.style.fontFamily='monospace';document.body.style.padding='40px';document.body.innerHTML='<h2 style="color:#ff6b6b">\\u26a0 Server Error</h2><pre style="white-space:pre-wrap;color:#ffa07a">${errMsg}</pre>';</script>`);
|
|
1597
|
-
res.end();
|
|
1605
|
+
catch (metadataError) {
|
|
1606
|
+
if (metadataError?.name !== 'NotFoundError') {
|
|
1607
|
+
throw metadataError;
|
|
1598
1608
|
}
|
|
1599
|
-
catch {
|
|
1600
|
-
res.end();
|
|
1601
|
-
}
|
|
1602
|
-
return;
|
|
1603
1609
|
}
|
|
1604
1610
|
}
|
|
1605
|
-
|
|
1606
|
-
// ==================================================================
|
|
1607
|
-
// Legacy Fallback: Direct renderToString
|
|
1608
|
-
// ==================================================================
|
|
1609
|
-
// Used when Flight SSR is unavailable or fails. This path does NOT
|
|
1610
|
-
// go through the Flight protocol — it requires page modules directly
|
|
1611
|
-
// and renders them with renderToString (synchronous, no streaming).
|
|
1612
|
-
// ==================================================================
|
|
1613
|
-
try {
|
|
1614
|
-
// Check upstream availability for the legacy path
|
|
1615
|
-
await withTimeout(`${upstreamOrigin}/rsc/`, { headers: { Accept: 'text/x-component' } }, 3000);
|
|
1616
|
-
}
|
|
1617
|
-
catch (error) {
|
|
1618
|
-
res.status(503).type('text/plain').send(getUpstreamUnavailableMessage());
|
|
1611
|
+
await renderFlightToHTMLStream(upstreamOrigin, req.path, req.query ? new URLSearchParams(req.query).toString() : '', metadataHtml, findChunkFiles(cwd, isDev), rootLayout.mode, flightSSRClient, ssrManifest, res, isDev);
|
|
1619
1612
|
return;
|
|
1620
1613
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
const route = currentRoute;
|
|
1624
|
-
(0, request_context_1.setCurrentSegmentConfig)(route?.segmentConfig);
|
|
1625
|
-
if (!route) {
|
|
1626
|
-
const resolvedNotFound = (0, root_resolver_1.resolveNotFoundComponent)(runtimeRoot, rootLayout, isDev);
|
|
1627
|
-
if (resolvedNotFound) {
|
|
1628
|
-
const notFoundElement = react_1.default.createElement(resolvedNotFound.component, {
|
|
1629
|
-
params: {},
|
|
1630
|
-
searchParams: {},
|
|
1631
|
-
});
|
|
1632
|
-
const wrapped = react_1.default.createElement(rootLayout.component, { params: {}, searchParams: {} }, notFoundElement);
|
|
1633
|
-
const html = (0, server_1.renderToString)(wrapped);
|
|
1634
|
-
res
|
|
1635
|
-
.status(404)
|
|
1636
|
-
.type('text/html')
|
|
1637
|
-
.send(createHtmlDocument(html, '', findChunkFiles(cwd, isDev), rootLayout.mode));
|
|
1638
|
-
return;
|
|
1639
|
-
}
|
|
1614
|
+
catch (flightError) {
|
|
1615
|
+
if (flightError?.name === 'NotFoundError' && !res.headersSent) {
|
|
1640
1616
|
res.status(404).type('text/html').send((0, not_found_page_1.getStyledNotFoundHTML)());
|
|
1641
1617
|
return;
|
|
1642
1618
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
const { generateMetadataHtml } = require('../metadata/generate');
|
|
1648
|
-
const metadataHtml = metadata ? generateMetadataHtml(metadata) : '';
|
|
1649
|
-
res
|
|
1650
|
-
.status(200)
|
|
1651
|
-
.type('text/html')
|
|
1652
|
-
.send(createHtmlDocument(appHtml, metadataHtml, findChunkFiles(cwd, isDev), rootMode));
|
|
1653
|
-
}
|
|
1654
|
-
catch (error) {
|
|
1655
|
-
if (error?.name === 'NotFoundError') {
|
|
1656
|
-
try {
|
|
1657
|
-
const rootLayout = (0, root_resolver_1.resolveRootLayout)(runtimeRoot, isDev);
|
|
1658
|
-
const route = currentRoute;
|
|
1659
|
-
(0, request_context_1.setCurrentSegmentConfig)(route?.segmentConfig);
|
|
1660
|
-
if (route) {
|
|
1661
|
-
const segmentNotFoundPath = (0, app_router_runtime_1.resolveNearestSegmentNotFoundPath)(path_1.default.join(runtimeRoot, 'app'), route.routeDir);
|
|
1662
|
-
if (segmentNotFoundPath) {
|
|
1663
|
-
const params = extractParams(req.path, route);
|
|
1664
|
-
const searchParams = Object.fromEntries(new URLSearchParams(req.query).entries());
|
|
1665
|
-
const notFoundResult = await createRouteElement({
|
|
1666
|
-
...route,
|
|
1667
|
-
pagePath: segmentNotFoundPath,
|
|
1668
|
-
}, { params, searchParams, req }, isDev, rootLayout, runtimeRoot, { disableParallelSlots: true });
|
|
1669
|
-
const html = (0, server_1.renderToString)(notFoundResult.element);
|
|
1670
|
-
const { generateMetadataHtml } = require('../metadata/generate');
|
|
1671
|
-
const metadataHtml = notFoundResult.metadata
|
|
1672
|
-
? generateMetadataHtml(notFoundResult.metadata)
|
|
1673
|
-
: '';
|
|
1674
|
-
res
|
|
1675
|
-
.status(404)
|
|
1676
|
-
.type('text/html')
|
|
1677
|
-
.send(createHtmlDocument(html, metadataHtml, findChunkFiles(cwd, isDev), notFoundResult.rootMode));
|
|
1678
|
-
return;
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
const resolvedNotFound = (0, root_resolver_1.resolveNotFoundComponent)(runtimeRoot, rootLayout, isDev);
|
|
1682
|
-
if (resolvedNotFound) {
|
|
1683
|
-
const notFoundElement = react_1.default.createElement(resolvedNotFound.component, {
|
|
1684
|
-
params: {},
|
|
1685
|
-
searchParams: {},
|
|
1686
|
-
});
|
|
1687
|
-
const wrapped = react_1.default.createElement(rootLayout.component, { params: {}, searchParams: {} }, notFoundElement);
|
|
1688
|
-
const html = (0, server_1.renderToString)(wrapped);
|
|
1689
|
-
res
|
|
1690
|
-
.status(404)
|
|
1691
|
-
.type('text/html')
|
|
1692
|
-
.send(createHtmlDocument(html, '', findChunkFiles(cwd, isDev), rootLayout.mode));
|
|
1693
|
-
return;
|
|
1694
|
-
}
|
|
1695
|
-
res.status(404).type('text/html').send((0, not_found_page_1.getStyledNotFoundHTML)());
|
|
1696
|
-
return;
|
|
1619
|
+
console.error('[vista:rsc] Flight SSR failed:', flightError.message);
|
|
1620
|
+
if (!res.headersSent) {
|
|
1621
|
+
if (isDev) {
|
|
1622
|
+
res.status(500).send((0, dev_error_1.renderErrorHTML)([(0, dev_error_1.fromCaughtError)(flightError, { source: 'server' })]));
|
|
1697
1623
|
}
|
|
1698
|
-
|
|
1699
|
-
|
|
1624
|
+
else {
|
|
1625
|
+
res.status(500).send('<h1>Internal Server Error</h1>');
|
|
1700
1626
|
}
|
|
1627
|
+
return;
|
|
1701
1628
|
}
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1629
|
+
if (isDev && res.headersSent) {
|
|
1630
|
+
try {
|
|
1631
|
+
const errMsg = (flightError.message || 'Flight SSR Error')
|
|
1632
|
+
.replace(/'/g, "\\'")
|
|
1633
|
+
.replace(/\n/g, '\\n');
|
|
1634
|
+
res.write(`<script>document.body.innerHTML='';document.body.style.background='#1a1a2e';document.body.style.color='#ff6b6b';document.body.style.fontFamily='monospace';document.body.style.padding='40px';document.body.innerHTML='<h2 style="color:#ff6b6b">\\u26a0 Server Error</h2><pre style="white-space:pre-wrap;color:#ffa07a">${errMsg}</pre>';</script>`);
|
|
1635
|
+
res.end();
|
|
1636
|
+
}
|
|
1637
|
+
catch {
|
|
1638
|
+
res.end();
|
|
1639
|
+
}
|
|
1708
1640
|
}
|
|
1641
|
+
return;
|
|
1709
1642
|
}
|
|
1710
1643
|
});
|
|
1711
1644
|
});
|
|
1645
|
+
if (!shouldListen) {
|
|
1646
|
+
return app;
|
|
1647
|
+
}
|
|
1712
1648
|
const server = app.listen(port, () => {
|
|
1713
1649
|
(0, logger_1.printServerReady)({ port, mode: 'rsc', rscFlight: useFlightSSR });
|
|
1714
1650
|
});
|
|
@@ -1722,4 +1658,5 @@ function startRSCServer(options = {}) {
|
|
|
1722
1658
|
(0, logger_1.logError)(`RSC startup failed: ${error?.message || String(error)}`);
|
|
1723
1659
|
process.exit(1);
|
|
1724
1660
|
});
|
|
1661
|
+
return app;
|
|
1725
1662
|
}
|