@rayburst/cli 0.1.17 → 0.2.0

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.
Files changed (39) hide show
  1. package/README.md +165 -257
  2. package/dist/analysis/analyze-project.d.ts +9 -0
  3. package/dist/analysis/analyze-project.js +440 -0
  4. package/dist/git-utils.d.ts +33 -0
  5. package/dist/git-utils.js +96 -0
  6. package/dist/incremental-analyzer.d.ts +128 -0
  7. package/dist/incremental-analyzer.js +259 -0
  8. package/dist/index.d.ts +6 -0
  9. package/dist/index.js +6 -0
  10. package/dist/local-storage.d.ts +39 -0
  11. package/dist/local-storage.js +117 -0
  12. package/dist/registry.d.ts +89 -0
  13. package/dist/registry.js +287 -0
  14. package/dist/vite-plugin.d.ts +7 -0
  15. package/dist/vite-plugin.js +109 -0
  16. package/package.json +33 -30
  17. package/bin/rayburst.js +0 -232
  18. package/dist/assets/_commonjsHelpers-B85MJLTf.js +0 -5
  19. package/dist/assets/hostInit-BWYxHpMp.js +0 -9
  20. package/dist/assets/index-9R1akZrm.js +0 -578
  21. package/dist/assets/index-BW-RulSg.js +0 -258
  22. package/dist/assets/index-VnAMn3JB.js +0 -16587
  23. package/dist/assets/preload-helper-Dea3Szod.js +0 -54
  24. package/dist/assets/rayburstCli__loadRemote__rayburstApp_mf_1_App__loadRemote__-CHUYMhiU.js +0 -35
  25. package/dist/assets/rayburstCli__loadShare__react__loadShare__-CE7VtFm0.js +0 -19
  26. package/dist/assets/rayburstCli__mf_v__runtimeInit__mf_v__-C_SVfzik.js +0 -4173
  27. package/dist/assets/remoteEntry-B8biLITo.js +0 -122
  28. package/dist/assets/virtualExposes-DwA08f_D.js +0 -5
  29. package/dist/index.html +0 -56
  30. package/index.html +0 -54
  31. package/scripts/analyze-project.js +0 -475
  32. package/server.js +0 -188
  33. package/src/file-watcher.js +0 -174
  34. package/src/git-utils.js +0 -105
  35. package/src/incremental-analyzer.js +0 -295
  36. package/src/main.tsx +0 -126
  37. package/src/registry.js +0 -262
  38. package/vite-plugin-api.js +0 -123
  39. package/vite.config.ts +0 -73
@@ -1,174 +0,0 @@
1
- import chokidar from 'chokidar';
2
- import path from 'path';
3
- import chalk from 'chalk';
4
-
5
- /**
6
- * File Watcher for Rayburst Projects
7
- *
8
- * Watches registered project directories for file changes and triggers
9
- * incremental analysis on relevant file modifications.
10
- */
11
-
12
- const watchers = new Map(); // Map<projectId, { watcher, callback }>
13
-
14
- /**
15
- * Start watching a project directory for file changes
16
- *
17
- * @param {string} projectId - Unique project identifier
18
- * @param {string} projectPath - Absolute path to project directory
19
- * @param {Function} onChange - Callback function (changedFiles: string[]) => void
20
- * @param {Object} options - Watch options
21
- * @returns {Object} - Watcher instance
22
- */
23
- export function watchProject(projectId, projectPath, onChange, options = {}) {
24
- // Stop existing watcher if any
25
- unwatchProject(projectId);
26
-
27
- const {
28
- debounceMs = 1500,
29
- ignorePatterns = [
30
- '**/node_modules/**',
31
- '**/.git/**',
32
- '**/dist/**',
33
- '**/build/**',
34
- '**/*.test.ts',
35
- '**/*.test.tsx',
36
- '**/*.spec.ts',
37
- '**/*.spec.tsx',
38
- ],
39
- } = options;
40
-
41
- console.log(chalk.blue(`👁️ Watching project: ${projectId}`));
42
- console.log(chalk.gray(` Path: ${projectPath}`));
43
-
44
- // Track pending changes for debouncing
45
- let pendingChanges = new Set();
46
- let debounceTimer = null;
47
-
48
- const handleChange = (filePath) => {
49
- const relativePath = path.relative(projectPath, filePath);
50
-
51
- // Only track relevant files
52
- if (!isRelevantFile(filePath)) {
53
- return;
54
- }
55
-
56
- pendingChanges.add(filePath);
57
-
58
- // Debounce: wait for a pause in file changes
59
- if (debounceTimer) {
60
- clearTimeout(debounceTimer);
61
- }
62
-
63
- debounceTimer = setTimeout(() => {
64
- const changedFiles = Array.from(pendingChanges);
65
- pendingChanges.clear();
66
-
67
- console.log(chalk.yellow(`📝 File changes detected in ${projectId}:`));
68
- changedFiles.forEach(file => {
69
- const rel = path.relative(projectPath, file);
70
- console.log(chalk.gray(` - ${rel}`));
71
- });
72
-
73
- // Trigger onChange callback
74
- onChange(changedFiles);
75
- }, debounceMs);
76
- };
77
-
78
- // Create watcher
79
- const watcher = chokidar.watch(projectPath, {
80
- ignored: ignorePatterns,
81
- persistent: true,
82
- ignoreInitial: true,
83
- awaitWriteFinish: {
84
- stabilityThreshold: 300,
85
- pollInterval: 100,
86
- },
87
- });
88
-
89
- // Listen for file change events
90
- watcher.on('change', handleChange);
91
- watcher.on('add', handleChange);
92
- watcher.on('unlink', handleChange);
93
-
94
- watcher.on('error', (error) => {
95
- console.error(chalk.red(`❌ Watcher error for ${projectId}:`), error);
96
- });
97
-
98
- // Store watcher reference
99
- watchers.set(projectId, {
100
- watcher,
101
- callback: onChange,
102
- projectPath,
103
- });
104
-
105
- return watcher;
106
- }
107
-
108
- /**
109
- * Stop watching a project
110
- *
111
- * @param {string} projectId - Project identifier
112
- */
113
- export function unwatchProject(projectId) {
114
- const watcherData = watchers.get(projectId);
115
-
116
- if (watcherData) {
117
- console.log(chalk.gray(`⏹️ Stopped watching project: ${projectId}`));
118
- watcherData.watcher.close();
119
- watchers.delete(projectId);
120
- }
121
- }
122
-
123
- /**
124
- * Get all currently watched projects
125
- *
126
- * @returns {Array<string>} - Array of project IDs
127
- */
128
- export function getWatchedProjects() {
129
- return Array.from(watchers.keys());
130
- }
131
-
132
- /**
133
- * Check if a project is being watched
134
- *
135
- * @param {string} projectId - Project identifier
136
- * @returns {boolean}
137
- */
138
- export function isWatching(projectId) {
139
- return watchers.has(projectId);
140
- }
141
-
142
- /**
143
- * Stop all watchers
144
- */
145
- export function unwatchAll() {
146
- console.log(chalk.gray('⏹️ Stopping all file watchers...'));
147
- for (const projectId of watchers.keys()) {
148
- unwatchProject(projectId);
149
- }
150
- }
151
-
152
- /**
153
- * Check if a file is relevant for analysis
154
- *
155
- * @param {string} filePath - Absolute file path
156
- * @returns {boolean}
157
- */
158
- function isRelevantFile(filePath) {
159
- const ext = path.extname(filePath).toLowerCase();
160
- const relevantExtensions = ['.ts', '.tsx', '.js', '.jsx'];
161
-
162
- // Check extension
163
- if (!relevantExtensions.includes(ext)) {
164
- return false;
165
- }
166
-
167
- // Skip test files
168
- const basename = path.basename(filePath);
169
- if (basename.includes('.test.') || basename.includes('.spec.')) {
170
- return false;
171
- }
172
-
173
- return true;
174
- }
package/src/git-utils.js DELETED
@@ -1,105 +0,0 @@
1
- import { execSync } from 'child_process';
2
- import path from 'path';
3
-
4
- /**
5
- * Git Utilities
6
- *
7
- * Helper functions to interact with git repositories
8
- */
9
-
10
- /**
11
- * Get list of uncommitted changed files in a git repository
12
- *
13
- * @param {string} projectPath - Absolute path to project directory
14
- * @returns {string[]} - Array of absolute file paths that have uncommitted changes
15
- */
16
- export function getUncommittedChanges(projectPath) {
17
- try {
18
- // Check if directory is a git repository
19
- if (!isGitRepository(projectPath)) {
20
- return [];
21
- }
22
-
23
- // Get modified, added, and deleted files (staged and unstaged)
24
- const command = 'git diff --name-only HEAD && git diff --name-only --cached';
25
-
26
- const output = execSync(command, {
27
- cwd: projectPath,
28
- encoding: 'utf8',
29
- stdio: ['pipe', 'pipe', 'ignore'], // Ignore stderr
30
- });
31
-
32
- // Parse output and convert to absolute paths
33
- const files = output
34
- .split('\n')
35
- .filter(Boolean)
36
- .map(file => path.resolve(projectPath, file.trim()));
37
-
38
- // Remove duplicates
39
- return [...new Set(files)];
40
- } catch (error) {
41
- // If git command fails, return empty array
42
- console.error('Failed to get git diff:', error.message);
43
- return [];
44
- }
45
- }
46
-
47
- /**
48
- * Check if a directory is a git repository
49
- *
50
- * @param {string} projectPath - Absolute path to project directory
51
- * @returns {boolean}
52
- */
53
- export function isGitRepository(projectPath) {
54
- try {
55
- execSync('git rev-parse --is-inside-work-tree', {
56
- cwd: projectPath,
57
- encoding: 'utf8',
58
- stdio: ['pipe', 'pipe', 'ignore'],
59
- });
60
- return true;
61
- } catch {
62
- return false;
63
- }
64
- }
65
-
66
- /**
67
- * Get list of untracked files in a git repository
68
- *
69
- * @param {string} projectPath - Absolute path to project directory
70
- * @returns {string[]} - Array of absolute file paths that are untracked
71
- */
72
- export function getUntrackedFiles(projectPath) {
73
- try {
74
- if (!isGitRepository(projectPath)) {
75
- return [];
76
- }
77
-
78
- const output = execSync('git ls-files --others --exclude-standard', {
79
- cwd: projectPath,
80
- encoding: 'utf8',
81
- stdio: ['pipe', 'pipe', 'ignore'],
82
- });
83
-
84
- return output
85
- .split('\n')
86
- .filter(Boolean)
87
- .map(file => path.resolve(projectPath, file.trim()));
88
- } catch (error) {
89
- console.error('Failed to get untracked files:', error.message);
90
- return [];
91
- }
92
- }
93
-
94
- /**
95
- * Get all files with changes (committed or not)
96
- *
97
- * @param {string} projectPath - Absolute path to project directory
98
- * @returns {string[]} - Array of absolute file paths
99
- */
100
- export function getAllChangedFiles(projectPath) {
101
- const uncommitted = getUncommittedChanges(projectPath);
102
- const untracked = getUntrackedFiles(projectPath);
103
-
104
- return [...new Set([...uncommitted, ...untracked])];
105
- }
@@ -1,295 +0,0 @@
1
- import { analyzeProject } from '../scripts/analyze-project.js';
2
- import { readAnalysisData, writeAnalysisData } from './registry.js';
3
- import chalk from 'chalk';
4
-
5
- /**
6
- * Incremental Analyzer
7
- *
8
- * Performs incremental analysis by comparing new analysis results with
9
- * previously stored results and generating a diff of changes.
10
- */
11
-
12
- /**
13
- * Perform incremental analysis on a project
14
- *
15
- * @param {string} projectId - Project identifier
16
- * @param {string} projectPath - Absolute path to project
17
- * @param {string[]} changedFiles - Optional array of changed file paths
18
- * @returns {Object} - Incremental update with added, removed, and modified nodes/edges
19
- */
20
- export function performIncrementalAnalysis(projectId, projectPath, changedFiles = []) {
21
- console.log(chalk.blue(`🔄 Running incremental analysis for ${projectId}...`));
22
-
23
- // Load previous analysis
24
- const previousAnalysis = readAnalysisData(projectId);
25
-
26
- if (!previousAnalysis) {
27
- console.log(chalk.yellow(' No previous analysis found, running full analysis...'));
28
- // Run full analysis if no previous data exists
29
- const newAnalysis = analyzeProject(projectPath);
30
- writeAnalysisData(projectId, newAnalysis);
31
-
32
- return {
33
- type: 'full',
34
- analysis: newAnalysis,
35
- update: null,
36
- };
37
- }
38
-
39
- // Run full analysis (in the future, this could be optimized to analyze only changed files)
40
- const newAnalysis = analyzeProject(projectPath);
41
-
42
- // Generate diff
43
- const update = generateDiff(previousAnalysis, newAnalysis);
44
-
45
- // Save new analysis
46
- writeAnalysisData(projectId, newAnalysis);
47
-
48
- // Log statistics
49
- const stats = getUpdateStats(update);
50
- console.log(chalk.green(`✓ Incremental analysis complete:`));
51
- console.log(chalk.gray(` Added: ${stats.addedNodes} nodes, ${stats.addedEdges} edges`));
52
- console.log(chalk.gray(` Removed: ${stats.removedNodes} nodes, ${stats.removedEdges} edges`));
53
- console.log(chalk.gray(` Modified: ${stats.modifiedNodes} nodes, ${stats.modifiedEdges} edges`));
54
-
55
- return {
56
- type: 'incremental',
57
- analysis: newAnalysis,
58
- update,
59
- };
60
- }
61
-
62
- /**
63
- * Generate diff between old and new analysis
64
- *
65
- * @param {Object} oldAnalysis - Previous analysis data
66
- * @param {Object} newAnalysis - New analysis data
67
- * @returns {Object} - Incremental update object
68
- */
69
- export function generateDiff(oldAnalysis, newAnalysis) {
70
- const update = {
71
- added: {
72
- nodes: [],
73
- edges: [],
74
- },
75
- removed: {
76
- nodeIds: [],
77
- edgeIds: [],
78
- },
79
- modified: {
80
- nodes: [],
81
- edges: [],
82
- },
83
- };
84
-
85
- // Process each branch
86
- const branches = new Set([
87
- ...Object.keys(oldAnalysis.planData || {}),
88
- ...Object.keys(newAnalysis.planData || {}),
89
- ]);
90
-
91
- for (const branchId of branches) {
92
- const oldPlanData = oldAnalysis.planData?.[branchId];
93
- const newPlanData = newAnalysis.planData?.[branchId];
94
-
95
- if (!oldPlanData && newPlanData) {
96
- // New branch - all nodes/edges are added
97
- update.added.nodes.push(...(newPlanData.nodes || []));
98
- update.added.edges.push(...(newPlanData.edges || []));
99
- continue;
100
- }
101
-
102
- if (oldPlanData && !newPlanData) {
103
- // Branch removed - all nodes/edges are removed
104
- update.removed.nodeIds.push(...(oldPlanData.nodes || []).map(n => n.id));
105
- update.removed.edgeIds.push(...(oldPlanData.edges || []).map(e => e.id));
106
- continue;
107
- }
108
-
109
- // Branch exists in both - compare nodes and edges
110
- const branchDiff = comparePlanData(oldPlanData, newPlanData);
111
- update.added.nodes.push(...branchDiff.added.nodes);
112
- update.added.edges.push(...branchDiff.added.edges);
113
- update.removed.nodeIds.push(...branchDiff.removed.nodeIds);
114
- update.removed.edgeIds.push(...branchDiff.removed.edgeIds);
115
- update.modified.nodes.push(...branchDiff.modified.nodes);
116
- update.modified.edges.push(...branchDiff.modified.edges);
117
- }
118
-
119
- return update;
120
- }
121
-
122
- /**
123
- * Compare plan data for a single branch
124
- *
125
- * @param {Object} oldPlanData - Previous plan data
126
- * @param {Object} newPlanData - New plan data
127
- * @returns {Object} - Diff object
128
- */
129
- function comparePlanData(oldPlanData, newPlanData) {
130
- const oldNodes = oldPlanData?.nodes || [];
131
- const newNodes = newPlanData?.nodes || [];
132
- const oldEdges = oldPlanData?.edges || [];
133
- const newEdges = newPlanData?.edges || [];
134
-
135
- // Create maps for quick lookup
136
- const oldNodeMap = new Map(oldNodes.map(n => [n.id, n]));
137
- const newNodeMap = new Map(newNodes.map(n => [n.id, n]));
138
- const oldEdgeMap = new Map(oldEdges.map(e => [e.id, e]));
139
- const newEdgeMap = new Map(newEdges.map(e => [e.id, e]));
140
-
141
- const diff = {
142
- added: { nodes: [], edges: [] },
143
- removed: { nodeIds: [], edgeIds: [] },
144
- modified: { nodes: [], edges: [] },
145
- };
146
-
147
- // Find added and modified nodes
148
- for (const [nodeId, newNode] of newNodeMap) {
149
- const oldNode = oldNodeMap.get(nodeId);
150
-
151
- if (!oldNode) {
152
- // Node was added
153
- diff.added.nodes.push(newNode);
154
- } else if (hasNodeChanged(oldNode, newNode)) {
155
- // Node was modified
156
- diff.modified.nodes.push({
157
- id: nodeId,
158
- ...getNodeChanges(oldNode, newNode),
159
- });
160
- }
161
- }
162
-
163
- // Find removed nodes
164
- for (const nodeId of oldNodeMap.keys()) {
165
- if (!newNodeMap.has(nodeId)) {
166
- diff.removed.nodeIds.push(nodeId);
167
- }
168
- }
169
-
170
- // Find added and modified edges
171
- for (const [edgeId, newEdge] of newEdgeMap) {
172
- const oldEdge = oldEdgeMap.get(edgeId);
173
-
174
- if (!oldEdge) {
175
- // Edge was added
176
- diff.added.edges.push(newEdge);
177
- } else if (hasEdgeChanged(oldEdge, newEdge)) {
178
- // Edge was modified
179
- diff.modified.edges.push({
180
- id: edgeId,
181
- ...getEdgeChanges(oldEdge, newEdge),
182
- });
183
- }
184
- }
185
-
186
- // Find removed edges
187
- for (const edgeId of oldEdgeMap.keys()) {
188
- if (!newEdgeMap.has(edgeId)) {
189
- diff.removed.edgeIds.push(edgeId);
190
- }
191
- }
192
-
193
- return diff;
194
- }
195
-
196
- /**
197
- * Check if a node has changed
198
- *
199
- * @param {Object} oldNode - Previous node
200
- * @param {Object} newNode - New node
201
- * @returns {boolean}
202
- */
203
- function hasNodeChanged(oldNode, newNode) {
204
- // Compare relevant properties (exclude position)
205
- const oldData = JSON.stringify({ ...oldNode.data, type: oldNode.type });
206
- const newData = JSON.stringify({ ...newNode.data, type: newNode.type });
207
-
208
- return oldData !== newData;
209
- }
210
-
211
- /**
212
- * Get node changes
213
- *
214
- * @param {Object} oldNode - Previous node
215
- * @param {Object} newNode - New node
216
- * @returns {Object} - Changed properties
217
- */
218
- function getNodeChanges(oldNode, newNode) {
219
- const changes = {};
220
-
221
- if (oldNode.type !== newNode.type) {
222
- changes.type = newNode.type;
223
- }
224
-
225
- if (JSON.stringify(oldNode.data) !== JSON.stringify(newNode.data)) {
226
- changes.data = newNode.data;
227
- }
228
-
229
- return changes;
230
- }
231
-
232
- /**
233
- * Check if an edge has changed
234
- *
235
- * @param {Object} oldEdge - Previous edge
236
- * @param {Object} newEdge - New edge
237
- * @returns {boolean}
238
- */
239
- function hasEdgeChanged(oldEdge, newEdge) {
240
- // Compare relevant properties
241
- return (
242
- oldEdge.source !== newEdge.source ||
243
- oldEdge.target !== newEdge.target ||
244
- oldEdge.type !== newEdge.type ||
245
- JSON.stringify(oldEdge.data) !== JSON.stringify(newEdge.data)
246
- );
247
- }
248
-
249
- /**
250
- * Get edge changes
251
- *
252
- * @param {Object} oldEdge - Previous edge
253
- * @param {Object} newEdge - New edge
254
- * @returns {Object} - Changed properties
255
- */
256
- function getEdgeChanges(oldEdge, newEdge) {
257
- const changes = {};
258
-
259
- if (oldEdge.source !== newEdge.source) changes.source = newEdge.source;
260
- if (oldEdge.target !== newEdge.target) changes.target = newEdge.target;
261
- if (oldEdge.type !== newEdge.type) changes.type = newEdge.type;
262
- if (JSON.stringify(oldEdge.data) !== JSON.stringify(newEdge.data)) {
263
- changes.data = newEdge.data;
264
- }
265
-
266
- return changes;
267
- }
268
-
269
- /**
270
- * Get statistics from an update
271
- *
272
- * @param {Object} update - Incremental update object
273
- * @returns {Object} - Statistics
274
- */
275
- function getUpdateStats(update) {
276
- return {
277
- addedNodes: update.added.nodes.length,
278
- addedEdges: update.added.edges.length,
279
- removedNodes: update.removed.nodeIds.length,
280
- removedEdges: update.removed.edgeIds.length,
281
- modifiedNodes: update.modified.nodes.length,
282
- modifiedEdges: update.modified.edges.length,
283
- };
284
- }
285
-
286
- /**
287
- * Check if an update has any changes
288
- *
289
- * @param {Object} update - Incremental update object
290
- * @returns {boolean}
291
- */
292
- export function hasChanges(update) {
293
- const stats = getUpdateStats(update);
294
- return Object.values(stats).some(count => count > 0);
295
- }
package/src/main.tsx DELETED
@@ -1,126 +0,0 @@
1
- import React, { Suspense, lazy, useEffect, useState } from 'react';
2
- import { createRoot } from 'react-dom/client';
3
- import * as ReactDOM from 'react-dom/client';
4
-
5
- // Expose React and ReactDOM globally for module federation
6
- (window as any).React = React;
7
- (window as any).ReactDOM = ReactDOM;
8
-
9
- // Loading component
10
- const LoadingFallback = () => (
11
- <div style={{
12
- display: 'flex',
13
- flexDirection: 'column',
14
- alignItems: 'center',
15
- justifyContent: 'center',
16
- height: '100vh',
17
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
18
- color: 'white',
19
- }}>
20
- <div style={{
21
- width: '50px',
22
- height: '50px',
23
- border: '4px solid rgba(255, 255, 255, 0.3)',
24
- borderTopColor: 'white',
25
- borderRadius: '50%',
26
- animation: 'spin 1s linear infinite',
27
- marginBottom: '20px',
28
- }} />
29
- <div style={{ fontSize: '18px', fontWeight: 500 }}>Loading Rayburst...</div>
30
- </div>
31
- );
32
-
33
- // Error boundary component
34
- class ErrorBoundary extends React.Component<
35
- { children: React.ReactNode },
36
- { hasError: boolean; error: Error | null }
37
- > {
38
- constructor(props: { children: React.ReactNode }) {
39
- super(props);
40
- this.state = { hasError: false, error: null };
41
- }
42
-
43
- static getDerivedStateFromError(error: Error) {
44
- return { hasError: true, error };
45
- }
46
-
47
- componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
48
- console.error('Remote app loading error:', error, errorInfo);
49
- }
50
-
51
- render() {
52
- if (this.state.hasError) {
53
- return (
54
- <div style={{
55
- display: 'flex',
56
- flexDirection: 'column',
57
- alignItems: 'center',
58
- justifyContent: 'center',
59
- height: '100vh',
60
- background: '#f5f5f5',
61
- padding: '20px',
62
- }}>
63
- <h1 style={{ color: '#d32f2f', marginBottom: '10px' }}>Failed to Load Rayburst</h1>
64
- <p style={{ color: '#666', marginBottom: '20px' }}>
65
- {this.state.error?.message || 'An unexpected error occurred'}
66
- </p>
67
- <button
68
- onClick={() => window.location.reload()}
69
- style={{
70
- padding: '10px 20px',
71
- background: '#667eea',
72
- color: 'white',
73
- border: 'none',
74
- borderRadius: '5px',
75
- cursor: 'pointer',
76
- fontSize: '16px',
77
- }}
78
- >
79
- Retry
80
- </button>
81
- </div>
82
- );
83
- }
84
-
85
- return this.props.children;
86
- }
87
- }
88
-
89
- // Dynamically import the remote app
90
- const RemoteApp = lazy(() => {
91
- // @ts-ignore - Module federation import
92
- return import('rayburstApp/App')
93
- .catch((err) => {
94
- console.error('[CLI] Failed to load remote app:', err);
95
- throw new Error('Could not load Rayburst application from remote.');
96
- });
97
- });
98
-
99
- function App() {
100
- const [isReady, setIsReady] = useState(false);
101
-
102
- useEffect(() => {
103
- // Small delay to ensure remote is ready
104
- const timer = setTimeout(() => setIsReady(true), 100);
105
- return () => clearTimeout(timer);
106
- }, []);
107
-
108
- if (!isReady) {
109
- return <LoadingFallback />;
110
- }
111
-
112
- return (
113
- <ErrorBoundary>
114
- <Suspense fallback={<LoadingFallback />}>
115
- <RemoteApp />
116
- </Suspense>
117
- </ErrorBoundary>
118
- );
119
- }
120
-
121
- // Mount the app
122
- const container = document.getElementById('app');
123
- if (container) {
124
- const root = createRoot(container);
125
- root.render(<App />);
126
- }