@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,269 +1,269 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Vista RSC Renderer
|
|
4
|
-
*
|
|
5
|
-
* Renders React Server Components to an RSC Payload format.
|
|
6
|
-
* This is the core of the "Zero Bundle Size Server Components" feature.
|
|
7
|
-
*
|
|
8
|
-
* RSC Payload Format:
|
|
9
|
-
* - Server components render to a special streaming format
|
|
10
|
-
* - Client component references are serialized as "holes" to be filled client-side
|
|
11
|
-
* - The client receives a stream of instructions + HTML
|
|
12
|
-
*/
|
|
13
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.RSCRenderer = void 0;
|
|
18
|
-
exports.resetMountIdCounter = resetMountIdCounter;
|
|
19
|
-
exports.createRSCRenderer = createRSCRenderer;
|
|
20
|
-
exports.generateHydrationScript = generateHydrationScript;
|
|
21
|
-
const react_1 = __importDefault(require("react"));
|
|
22
|
-
const server_1 = require("react-dom/server");
|
|
23
|
-
const path_1 = __importDefault(require("path"));
|
|
24
|
-
const fs_1 = __importDefault(require("fs"));
|
|
25
|
-
// Import RSC module system for client component interception
|
|
26
|
-
let rscModuleSystem = null;
|
|
27
|
-
try {
|
|
28
|
-
rscModuleSystem = require('../../server/rsc-module-system');
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
// Module system not available (during build)
|
|
32
|
-
}
|
|
33
|
-
// Counter for generating unique mount IDs
|
|
34
|
-
let mountIdCounter = 0;
|
|
35
|
-
/**
|
|
36
|
-
* Reset mount ID counter (call at start of each request)
|
|
37
|
-
*/
|
|
38
|
-
function resetMountIdCounter() {
|
|
39
|
-
mountIdCounter = 0;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Generate a unique mount ID for a client component
|
|
43
|
-
*/
|
|
44
|
-
function generateMountId() {
|
|
45
|
-
return `__vista_cc_${++mountIdCounter}`;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Check if a component module is a client component
|
|
49
|
-
*/
|
|
50
|
-
function isClientComponent(modulePath, manifest) {
|
|
51
|
-
return modulePath in manifest.pathToId;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Create a client component placeholder
|
|
55
|
-
* This renders a marker div that will be hydrated on the client
|
|
56
|
-
*/
|
|
57
|
-
function createClientComponentPlaceholder(entry, props, children) {
|
|
58
|
-
const mountId = generateMountId();
|
|
59
|
-
// Create the reference for hydration
|
|
60
|
-
const reference = {
|
|
61
|
-
id: entry.id,
|
|
62
|
-
mountId,
|
|
63
|
-
props: serializeProps(props),
|
|
64
|
-
chunkUrl: `/_vista/static/chunks/${entry.chunkName}.js`,
|
|
65
|
-
exportName: 'default',
|
|
66
|
-
};
|
|
67
|
-
// Create placeholder element
|
|
68
|
-
// Children are rendered server-side if they're server components
|
|
69
|
-
const element = react_1.default.createElement('div', {
|
|
70
|
-
'data-vista-cc': entry.id,
|
|
71
|
-
'data-vista-mount': mountId,
|
|
72
|
-
id: mountId,
|
|
73
|
-
suppressHydrationWarning: true,
|
|
74
|
-
}, children);
|
|
75
|
-
return { element, reference };
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Serialize props for client-side hydration
|
|
79
|
-
* Handles Date, undefined, functions, etc.
|
|
80
|
-
*/
|
|
81
|
-
function serializeProps(props) {
|
|
82
|
-
const serialized = {};
|
|
83
|
-
for (const [key, value] of Object.entries(props)) {
|
|
84
|
-
if (key === 'children') {
|
|
85
|
-
// Children are handled separately
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
if (typeof value === 'function') {
|
|
89
|
-
// Functions can't be serialized - skip or warn
|
|
90
|
-
console.warn(`[Vista RSC] Cannot serialize function prop "${key}" to client`);
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (value instanceof Date) {
|
|
94
|
-
serialized[key] = { __type: 'Date', value: value.toISOString() };
|
|
95
|
-
}
|
|
96
|
-
else if (value === undefined) {
|
|
97
|
-
serialized[key] = { __type: 'undefined' };
|
|
98
|
-
}
|
|
99
|
-
else if (react_1.default.isValidElement(value)) {
|
|
100
|
-
// React elements need special handling
|
|
101
|
-
serialized[key] = { __type: 'ReactElement', rendered: true };
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
serialized[key] = value;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return serialized;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* RSC Renderer class
|
|
111
|
-
* Handles rendering a route with proper server/client component separation
|
|
112
|
-
*/
|
|
113
|
-
class RSCRenderer {
|
|
114
|
-
clientManifest;
|
|
115
|
-
serverManifest;
|
|
116
|
-
clientReferences = [];
|
|
117
|
-
cwd;
|
|
118
|
-
constructor(options) {
|
|
119
|
-
this.clientManifest = options.clientManifest;
|
|
120
|
-
this.serverManifest = options.serverManifest;
|
|
121
|
-
this.cwd = options.cwd;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Render a route to RSC Payload
|
|
125
|
-
*/
|
|
126
|
-
async render(context) {
|
|
127
|
-
// Reset counters
|
|
128
|
-
resetMountIdCounter();
|
|
129
|
-
this.clientReferences = [];
|
|
130
|
-
// Reset RSC module system state (for client component interception)
|
|
131
|
-
if (rscModuleSystem) {
|
|
132
|
-
rscModuleSystem.resetRSCState();
|
|
133
|
-
}
|
|
134
|
-
const { route, params, searchParams } = context;
|
|
135
|
-
// Load and render layouts + page
|
|
136
|
-
const element = await this.renderRoute(route, params, searchParams);
|
|
137
|
-
// Render to HTML string
|
|
138
|
-
const html = (0, server_1.renderToString)(element);
|
|
139
|
-
// Collect client references from module system (intercepted requires)
|
|
140
|
-
let collectedReferences = this.clientReferences;
|
|
141
|
-
if (rscModuleSystem) {
|
|
142
|
-
const moduleReferences = rscModuleSystem.getClientReferences();
|
|
143
|
-
collectedReferences = [...collectedReferences, ...moduleReferences];
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
html,
|
|
147
|
-
clientReferences: collectedReferences,
|
|
148
|
-
data: {
|
|
149
|
-
params,
|
|
150
|
-
searchParams,
|
|
151
|
-
route: route.pattern,
|
|
152
|
-
},
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Render a route with nested layouts
|
|
157
|
-
*/
|
|
158
|
-
async renderRoute(route, params, searchParams) {
|
|
159
|
-
// Load the page component
|
|
160
|
-
const PageModule = this.requireComponent(route.pagePath);
|
|
161
|
-
const PageComponent = PageModule.default;
|
|
162
|
-
// Fetch page metadata if exists
|
|
163
|
-
let metadata = {};
|
|
164
|
-
if (PageModule.metadata) {
|
|
165
|
-
metadata = { ...metadata, ...PageModule.metadata };
|
|
166
|
-
}
|
|
167
|
-
if (typeof PageModule.generateMetadata === 'function') {
|
|
168
|
-
try {
|
|
169
|
-
const dynamicMeta = await PageModule.generateMetadata({ params, searchParams });
|
|
170
|
-
metadata = { ...metadata, ...dynamicMeta };
|
|
171
|
-
}
|
|
172
|
-
catch (e) {
|
|
173
|
-
console.error('[Vista RSC] generateMetadata error:', e);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// Create page element
|
|
177
|
-
let pageElement = react_1.default.createElement(PageComponent, {
|
|
178
|
-
params,
|
|
179
|
-
searchParams,
|
|
180
|
-
});
|
|
181
|
-
// Check if page is a client component
|
|
182
|
-
if (this.isClientComponent(route.pagePath)) {
|
|
183
|
-
const entry = this.clientManifest.clientModules[this.clientManifest.pathToId[route.pagePath]];
|
|
184
|
-
const { element, reference } = createClientComponentPlaceholder(entry, {
|
|
185
|
-
params,
|
|
186
|
-
searchParams,
|
|
187
|
-
});
|
|
188
|
-
this.clientReferences.push(reference);
|
|
189
|
-
pageElement = element;
|
|
190
|
-
}
|
|
191
|
-
// Wrap in layouts (innermost to outermost)
|
|
192
|
-
let wrappedElement = pageElement;
|
|
193
|
-
for (let i = route.layoutPaths.length - 1; i >= 0; i--) {
|
|
194
|
-
const layoutPath = route.layoutPaths[i];
|
|
195
|
-
const LayoutModule = this.requireComponent(layoutPath);
|
|
196
|
-
const LayoutComponent = LayoutModule.default;
|
|
197
|
-
if (this.isClientComponent(layoutPath)) {
|
|
198
|
-
// Client component layout
|
|
199
|
-
const entry = this.clientManifest.clientModules[this.clientManifest.pathToId[layoutPath]];
|
|
200
|
-
const { element, reference } = createClientComponentPlaceholder(entry, { params, searchParams }, wrappedElement);
|
|
201
|
-
this.clientReferences.push(reference);
|
|
202
|
-
wrappedElement = element;
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
// Server component layout
|
|
206
|
-
wrappedElement = react_1.default.createElement(LayoutComponent, { params, searchParams }, wrappedElement);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return wrappedElement;
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Require a component with cache clearing in dev
|
|
213
|
-
*/
|
|
214
|
-
requireComponent(componentPath) {
|
|
215
|
-
// Clear cache in development
|
|
216
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
217
|
-
delete require.cache[require.resolve(componentPath)];
|
|
218
|
-
}
|
|
219
|
-
return require(componentPath);
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Check if a component is a client component
|
|
223
|
-
*/
|
|
224
|
-
isClientComponent(componentPath) {
|
|
225
|
-
return componentPath in this.clientManifest.pathToId;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
exports.RSCRenderer = RSCRenderer;
|
|
229
|
-
/**
|
|
230
|
-
* Create an RSC renderer instance
|
|
231
|
-
*/
|
|
232
|
-
function createRSCRenderer(cwd) {
|
|
233
|
-
const clientManifestPath = path_1.default.join(cwd, '.vista', 'client-manifest.json');
|
|
234
|
-
const serverManifestPath = path_1.default.join(cwd, '.vista', 'server', 'server-manifest.json');
|
|
235
|
-
if (!fs_1.default.existsSync(clientManifestPath) || !fs_1.default.existsSync(serverManifestPath)) {
|
|
236
|
-
console.warn('[Vista RSC] Manifests not found. Run build first.');
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
239
|
-
try {
|
|
240
|
-
const clientManifest = JSON.parse(fs_1.default.readFileSync(clientManifestPath, 'utf-8'));
|
|
241
|
-
const serverManifest = JSON.parse(fs_1.default.readFileSync(serverManifestPath, 'utf-8'));
|
|
242
|
-
return new RSCRenderer({
|
|
243
|
-
clientManifest,
|
|
244
|
-
serverManifest,
|
|
245
|
-
cwd,
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
catch (e) {
|
|
249
|
-
console.error('[Vista RSC] Failed to load manifests:', e);
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Generate the client-side hydration script
|
|
255
|
-
*
|
|
256
|
-
* This just sets the data - the actual hydration is handled by rsc-client.tsx
|
|
257
|
-
* which is bundled and has all client components pre-imported.
|
|
258
|
-
*/
|
|
259
|
-
function generateHydrationScript(payload) {
|
|
260
|
-
const references = JSON.stringify(payload.clientReferences);
|
|
261
|
-
const data = JSON.stringify(payload.data);
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Vista RSC Renderer
|
|
4
|
+
*
|
|
5
|
+
* Renders React Server Components to an RSC Payload format.
|
|
6
|
+
* This is the core of the "Zero Bundle Size Server Components" feature.
|
|
7
|
+
*
|
|
8
|
+
* RSC Payload Format:
|
|
9
|
+
* - Server components render to a special streaming format
|
|
10
|
+
* - Client component references are serialized as "holes" to be filled client-side
|
|
11
|
+
* - The client receives a stream of instructions + HTML
|
|
12
|
+
*/
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.RSCRenderer = void 0;
|
|
18
|
+
exports.resetMountIdCounter = resetMountIdCounter;
|
|
19
|
+
exports.createRSCRenderer = createRSCRenderer;
|
|
20
|
+
exports.generateHydrationScript = generateHydrationScript;
|
|
21
|
+
const react_1 = __importDefault(require("react"));
|
|
22
|
+
const server_1 = require("react-dom/server");
|
|
23
|
+
const path_1 = __importDefault(require("path"));
|
|
24
|
+
const fs_1 = __importDefault(require("fs"));
|
|
25
|
+
// Import RSC module system for client component interception
|
|
26
|
+
let rscModuleSystem = null;
|
|
27
|
+
try {
|
|
28
|
+
rscModuleSystem = require('../../server/rsc-module-system');
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Module system not available (during build)
|
|
32
|
+
}
|
|
33
|
+
// Counter for generating unique mount IDs
|
|
34
|
+
let mountIdCounter = 0;
|
|
35
|
+
/**
|
|
36
|
+
* Reset mount ID counter (call at start of each request)
|
|
37
|
+
*/
|
|
38
|
+
function resetMountIdCounter() {
|
|
39
|
+
mountIdCounter = 0;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate a unique mount ID for a client component
|
|
43
|
+
*/
|
|
44
|
+
function generateMountId() {
|
|
45
|
+
return `__vista_cc_${++mountIdCounter}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check if a component module is a client component
|
|
49
|
+
*/
|
|
50
|
+
function isClientComponent(modulePath, manifest) {
|
|
51
|
+
return modulePath in manifest.pathToId;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a client component placeholder
|
|
55
|
+
* This renders a marker div that will be hydrated on the client
|
|
56
|
+
*/
|
|
57
|
+
function createClientComponentPlaceholder(entry, props, children) {
|
|
58
|
+
const mountId = generateMountId();
|
|
59
|
+
// Create the reference for hydration
|
|
60
|
+
const reference = {
|
|
61
|
+
id: entry.id,
|
|
62
|
+
mountId,
|
|
63
|
+
props: serializeProps(props),
|
|
64
|
+
chunkUrl: `/_vista/static/chunks/${entry.chunkName}.js`,
|
|
65
|
+
exportName: 'default',
|
|
66
|
+
};
|
|
67
|
+
// Create placeholder element
|
|
68
|
+
// Children are rendered server-side if they're server components
|
|
69
|
+
const element = react_1.default.createElement('div', {
|
|
70
|
+
'data-vista-cc': entry.id,
|
|
71
|
+
'data-vista-mount': mountId,
|
|
72
|
+
id: mountId,
|
|
73
|
+
suppressHydrationWarning: true,
|
|
74
|
+
}, children);
|
|
75
|
+
return { element, reference };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Serialize props for client-side hydration
|
|
79
|
+
* Handles Date, undefined, functions, etc.
|
|
80
|
+
*/
|
|
81
|
+
function serializeProps(props) {
|
|
82
|
+
const serialized = {};
|
|
83
|
+
for (const [key, value] of Object.entries(props)) {
|
|
84
|
+
if (key === 'children') {
|
|
85
|
+
// Children are handled separately
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (typeof value === 'function') {
|
|
89
|
+
// Functions can't be serialized - skip or warn
|
|
90
|
+
console.warn(`[Vista RSC] Cannot serialize function prop "${key}" to client`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (value instanceof Date) {
|
|
94
|
+
serialized[key] = { __type: 'Date', value: value.toISOString() };
|
|
95
|
+
}
|
|
96
|
+
else if (value === undefined) {
|
|
97
|
+
serialized[key] = { __type: 'undefined' };
|
|
98
|
+
}
|
|
99
|
+
else if (react_1.default.isValidElement(value)) {
|
|
100
|
+
// React elements need special handling
|
|
101
|
+
serialized[key] = { __type: 'ReactElement', rendered: true };
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
serialized[key] = value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return serialized;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* RSC Renderer class
|
|
111
|
+
* Handles rendering a route with proper server/client component separation
|
|
112
|
+
*/
|
|
113
|
+
class RSCRenderer {
|
|
114
|
+
clientManifest;
|
|
115
|
+
serverManifest;
|
|
116
|
+
clientReferences = [];
|
|
117
|
+
cwd;
|
|
118
|
+
constructor(options) {
|
|
119
|
+
this.clientManifest = options.clientManifest;
|
|
120
|
+
this.serverManifest = options.serverManifest;
|
|
121
|
+
this.cwd = options.cwd;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Render a route to RSC Payload
|
|
125
|
+
*/
|
|
126
|
+
async render(context) {
|
|
127
|
+
// Reset counters
|
|
128
|
+
resetMountIdCounter();
|
|
129
|
+
this.clientReferences = [];
|
|
130
|
+
// Reset RSC module system state (for client component interception)
|
|
131
|
+
if (rscModuleSystem) {
|
|
132
|
+
rscModuleSystem.resetRSCState();
|
|
133
|
+
}
|
|
134
|
+
const { route, params, searchParams } = context;
|
|
135
|
+
// Load and render layouts + page
|
|
136
|
+
const element = await this.renderRoute(route, params, searchParams);
|
|
137
|
+
// Render to HTML string
|
|
138
|
+
const html = (0, server_1.renderToString)(element);
|
|
139
|
+
// Collect client references from module system (intercepted requires)
|
|
140
|
+
let collectedReferences = this.clientReferences;
|
|
141
|
+
if (rscModuleSystem) {
|
|
142
|
+
const moduleReferences = rscModuleSystem.getClientReferences();
|
|
143
|
+
collectedReferences = [...collectedReferences, ...moduleReferences];
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
html,
|
|
147
|
+
clientReferences: collectedReferences,
|
|
148
|
+
data: {
|
|
149
|
+
params,
|
|
150
|
+
searchParams,
|
|
151
|
+
route: route.pattern,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Render a route with nested layouts
|
|
157
|
+
*/
|
|
158
|
+
async renderRoute(route, params, searchParams) {
|
|
159
|
+
// Load the page component
|
|
160
|
+
const PageModule = this.requireComponent(route.pagePath);
|
|
161
|
+
const PageComponent = PageModule.default;
|
|
162
|
+
// Fetch page metadata if exists
|
|
163
|
+
let metadata = {};
|
|
164
|
+
if (PageModule.metadata) {
|
|
165
|
+
metadata = { ...metadata, ...PageModule.metadata };
|
|
166
|
+
}
|
|
167
|
+
if (typeof PageModule.generateMetadata === 'function') {
|
|
168
|
+
try {
|
|
169
|
+
const dynamicMeta = await PageModule.generateMetadata({ params, searchParams });
|
|
170
|
+
metadata = { ...metadata, ...dynamicMeta };
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
console.error('[Vista RSC] generateMetadata error:', e);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Create page element
|
|
177
|
+
let pageElement = react_1.default.createElement(PageComponent, {
|
|
178
|
+
params,
|
|
179
|
+
searchParams,
|
|
180
|
+
});
|
|
181
|
+
// Check if page is a client component
|
|
182
|
+
if (this.isClientComponent(route.pagePath)) {
|
|
183
|
+
const entry = this.clientManifest.clientModules[this.clientManifest.pathToId[route.pagePath]];
|
|
184
|
+
const { element, reference } = createClientComponentPlaceholder(entry, {
|
|
185
|
+
params,
|
|
186
|
+
searchParams,
|
|
187
|
+
});
|
|
188
|
+
this.clientReferences.push(reference);
|
|
189
|
+
pageElement = element;
|
|
190
|
+
}
|
|
191
|
+
// Wrap in layouts (innermost to outermost)
|
|
192
|
+
let wrappedElement = pageElement;
|
|
193
|
+
for (let i = route.layoutPaths.length - 1; i >= 0; i--) {
|
|
194
|
+
const layoutPath = route.layoutPaths[i];
|
|
195
|
+
const LayoutModule = this.requireComponent(layoutPath);
|
|
196
|
+
const LayoutComponent = LayoutModule.default;
|
|
197
|
+
if (this.isClientComponent(layoutPath)) {
|
|
198
|
+
// Client component layout
|
|
199
|
+
const entry = this.clientManifest.clientModules[this.clientManifest.pathToId[layoutPath]];
|
|
200
|
+
const { element, reference } = createClientComponentPlaceholder(entry, { params, searchParams }, wrappedElement);
|
|
201
|
+
this.clientReferences.push(reference);
|
|
202
|
+
wrappedElement = element;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// Server component layout
|
|
206
|
+
wrappedElement = react_1.default.createElement(LayoutComponent, { params, searchParams }, wrappedElement);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return wrappedElement;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Require a component with cache clearing in dev
|
|
213
|
+
*/
|
|
214
|
+
requireComponent(componentPath) {
|
|
215
|
+
// Clear cache in development
|
|
216
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
217
|
+
delete require.cache[require.resolve(componentPath)];
|
|
218
|
+
}
|
|
219
|
+
return require(componentPath);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Check if a component is a client component
|
|
223
|
+
*/
|
|
224
|
+
isClientComponent(componentPath) {
|
|
225
|
+
return componentPath in this.clientManifest.pathToId;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
exports.RSCRenderer = RSCRenderer;
|
|
229
|
+
/**
|
|
230
|
+
* Create an RSC renderer instance
|
|
231
|
+
*/
|
|
232
|
+
function createRSCRenderer(cwd) {
|
|
233
|
+
const clientManifestPath = path_1.default.join(cwd, '.vista', 'client-manifest.json');
|
|
234
|
+
const serverManifestPath = path_1.default.join(cwd, '.vista', 'server', 'server-manifest.json');
|
|
235
|
+
if (!fs_1.default.existsSync(clientManifestPath) || !fs_1.default.existsSync(serverManifestPath)) {
|
|
236
|
+
console.warn('[Vista RSC] Manifests not found. Run build first.');
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const clientManifest = JSON.parse(fs_1.default.readFileSync(clientManifestPath, 'utf-8'));
|
|
241
|
+
const serverManifest = JSON.parse(fs_1.default.readFileSync(serverManifestPath, 'utf-8'));
|
|
242
|
+
return new RSCRenderer({
|
|
243
|
+
clientManifest,
|
|
244
|
+
serverManifest,
|
|
245
|
+
cwd,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
catch (e) {
|
|
249
|
+
console.error('[Vista RSC] Failed to load manifests:', e);
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Generate the client-side hydration script
|
|
255
|
+
*
|
|
256
|
+
* This just sets the data - the actual hydration is handled by rsc-client.tsx
|
|
257
|
+
* which is bundled and has all client components pre-imported.
|
|
258
|
+
*/
|
|
259
|
+
function generateHydrationScript(payload) {
|
|
260
|
+
const references = JSON.stringify(payload.clientReferences);
|
|
261
|
+
const data = JSON.stringify(payload.data);
|
|
262
262
|
return `
|
|
263
263
|
<script>
|
|
264
264
|
window.__VISTA_RSC_DATA__ = ${data};
|
|
265
265
|
window.__VISTA_CLIENT_REFERENCES__ = ${references};
|
|
266
266
|
console.log('[Vista RSC] Client references:', ${references.length > 2 ? references.length : 0});
|
|
267
267
|
</script>
|
|
268
|
-
`;
|
|
269
|
-
}
|
|
268
|
+
`;
|
|
269
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vista Server Component Loader
|
|
3
|
-
*
|
|
4
|
-
* Webpack loader that transforms server component imports in client bundles.
|
|
5
|
-
*
|
|
6
|
-
* When a server component is imported in a client bundle:
|
|
7
|
-
* 1. The loader detects if the file has 'use client' directive
|
|
8
|
-
* 2. If NOT a client component, replace the module with a proxy
|
|
9
|
-
* 3. The proxy provides helpful error messages when misused
|
|
10
|
-
*/
|
|
11
|
-
import type { LoaderContext } from 'webpack';
|
|
12
|
-
export interface ServerComponentLoaderOptions {
|
|
13
|
-
appDir: string;
|
|
14
|
-
clientManifestPath: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Server Component Loader
|
|
18
|
-
*/
|
|
19
|
-
export default function serverComponentLoader(this: LoaderContext<ServerComponentLoaderOptions>, source: string): string;
|
|
1
|
+
/**
|
|
2
|
+
* Vista Server Component Loader
|
|
3
|
+
*
|
|
4
|
+
* Webpack loader that transforms server component imports in client bundles.
|
|
5
|
+
*
|
|
6
|
+
* When a server component is imported in a client bundle:
|
|
7
|
+
* 1. The loader detects if the file has 'use client' directive
|
|
8
|
+
* 2. If NOT a client component, replace the module with a proxy
|
|
9
|
+
* 3. The proxy provides helpful error messages when misused
|
|
10
|
+
*/
|
|
11
|
+
import type { LoaderContext } from 'webpack';
|
|
12
|
+
export interface ServerComponentLoaderOptions {
|
|
13
|
+
appDir: string;
|
|
14
|
+
clientManifestPath: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Server Component Loader
|
|
18
|
+
*/
|
|
19
|
+
export default function serverComponentLoader(this: LoaderContext<ServerComponentLoaderOptions>, source: string): string;
|