@illuma-ai/code-sandbox 1.4.0 → 1.5.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.
- package/LICENSE +18 -12
- package/README.md +10 -11
- package/dist/index.cjs +91 -96
- package/dist/index.js +11895 -17954
- package/dist/styles.css +1 -1
- package/package.json +9 -12
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/src/components/BootOverlay.tsx +0 -145
- package/src/components/CodeEditor.tsx +0 -298
- package/src/components/FileTree.tsx +0 -678
- package/src/components/Preview.tsx +0 -262
- package/src/components/Terminal.tsx +0 -111
- package/src/components/ViewSlider.tsx +0 -87
- package/src/components/Workbench.tsx +0 -382
- package/src/hooks/useRuntime.ts +0 -637
- package/src/index.ts +0 -51
- package/src/services/runtime.ts +0 -775
- package/src/styles.css +0 -178
- package/src/templates/fullstack-starter.ts +0 -3507
- package/src/templates/index.ts +0 -607
- package/src/types.ts +0 -375
package/src/types.ts
DELETED
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @illuma-ai/code-sandbox — Type definitions
|
|
3
|
-
*
|
|
4
|
-
* Core types for the browser-native code sandbox.
|
|
5
|
-
* Covers file maps, runtime states, imperative handle, and component props.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
// File System
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
/** A flat map of file paths to their string contents */
|
|
13
|
-
export type FileMap = Record<string, string>;
|
|
14
|
-
|
|
15
|
-
/** Represents a single file or directory node in the tree */
|
|
16
|
-
export interface FileNode {
|
|
17
|
-
name: string;
|
|
18
|
-
path: string;
|
|
19
|
-
type: "file" | "directory";
|
|
20
|
-
children?: FileNode[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Change status for a file relative to the baseline (original) snapshot.
|
|
25
|
-
*
|
|
26
|
-
* - `new`: File exists in current but not in original
|
|
27
|
-
* - `modified`: File exists in both but content differs
|
|
28
|
-
* - `deleted`: File exists in original but not in current
|
|
29
|
-
* - `unchanged`: File content is identical
|
|
30
|
-
*/
|
|
31
|
-
export type FileChangeStatus = "new" | "modified" | "deleted" | "unchanged";
|
|
32
|
-
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
// Errors (structured error types for AI agent consumption)
|
|
35
|
-
// ---------------------------------------------------------------------------
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Categories of errors that can occur in the sandbox.
|
|
39
|
-
*
|
|
40
|
-
* - `process-stderr`: Output written to stderr by the Node.js process
|
|
41
|
-
* - `process-exit`: Process exited with a non-zero code
|
|
42
|
-
* - `runtime-exception`: Uncaught exception in the Node.js runtime (Nodepod)
|
|
43
|
-
* - `browser-error`: JavaScript error in the preview iframe (window.onerror)
|
|
44
|
-
* - `browser-unhandled-rejection`: Unhandled promise rejection in the iframe
|
|
45
|
-
* - `browser-console-error`: console.error() calls in the iframe
|
|
46
|
-
* - `compilation`: Syntax/import errors detected at module load time
|
|
47
|
-
* - `network`: Failed HTTP requests from the preview (fetch/XHR errors)
|
|
48
|
-
* - `boot`: Error during Nodepod boot, file writing, or dependency install
|
|
49
|
-
*/
|
|
50
|
-
export type SandboxErrorCategory =
|
|
51
|
-
| "process-stderr"
|
|
52
|
-
| "process-exit"
|
|
53
|
-
| "runtime-exception"
|
|
54
|
-
| "browser-error"
|
|
55
|
-
| "browser-unhandled-rejection"
|
|
56
|
-
| "browser-console-error"
|
|
57
|
-
| "compilation"
|
|
58
|
-
| "network"
|
|
59
|
-
| "boot";
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* A structured error emitted by the sandbox.
|
|
63
|
-
*
|
|
64
|
-
* Designed for AI agent consumption — includes enough context for the
|
|
65
|
-
* agent to construct a targeted fix prompt (file path, line number,
|
|
66
|
-
* surrounding code, stack trace).
|
|
67
|
-
*
|
|
68
|
-
* @see Ranger's auto-fix: client/src/components/Artifacts/Artifacts.tsx
|
|
69
|
-
*/
|
|
70
|
-
export interface SandboxError {
|
|
71
|
-
/** Unique ID for deduplication */
|
|
72
|
-
id: string;
|
|
73
|
-
/** Error category — determines how the agent should interpret it */
|
|
74
|
-
category: SandboxErrorCategory;
|
|
75
|
-
/** Human-readable error message (the "what") */
|
|
76
|
-
message: string;
|
|
77
|
-
/** Full stack trace if available */
|
|
78
|
-
stack?: string;
|
|
79
|
-
/** File path where the error occurred (relative to workdir) */
|
|
80
|
-
filePath?: string;
|
|
81
|
-
/** Line number in the file (1-indexed) */
|
|
82
|
-
line?: number;
|
|
83
|
-
/** Column number in the file (1-indexed) */
|
|
84
|
-
column?: number;
|
|
85
|
-
/** ISO 8601 timestamp */
|
|
86
|
-
timestamp: string;
|
|
87
|
-
/**
|
|
88
|
-
* Surrounding source code lines for context.
|
|
89
|
-
* Format: "lineNum: content" per line (e.g., "42: const x = foo();")
|
|
90
|
-
* Typically ~10 lines centered on the error line.
|
|
91
|
-
*/
|
|
92
|
-
sourceContext?: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
// Runtime (Nodepod lifecycle)
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
|
|
99
|
-
/** Boot stages shown during the loading animation */
|
|
100
|
-
export type BootStage =
|
|
101
|
-
| "initializing" // Nodepod.boot() in progress
|
|
102
|
-
| "writing-files" // Writing project files to virtual FS
|
|
103
|
-
| "installing" // npm install running
|
|
104
|
-
| "starting" // Entry command executing (e.g., node server.js)
|
|
105
|
-
| "ready" // Server is listening, preview iframe can load
|
|
106
|
-
| "error"; // Something failed
|
|
107
|
-
|
|
108
|
-
export interface BootProgress {
|
|
109
|
-
stage: BootStage;
|
|
110
|
-
message: string;
|
|
111
|
-
/** 0-100 percent, approximate */
|
|
112
|
-
percent: number;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Configuration for the Nodepod runtime */
|
|
116
|
-
export interface RuntimeConfig {
|
|
117
|
-
/** Project files to write into the virtual filesystem */
|
|
118
|
-
files: FileMap;
|
|
119
|
-
/** Command to start the dev server, e.g. "node server.js" */
|
|
120
|
-
entryCommand: string;
|
|
121
|
-
/** Working directory inside Nodepod (default: "/app") */
|
|
122
|
-
workdir?: string;
|
|
123
|
-
/** Environment variables passed to processes */
|
|
124
|
-
env?: Record<string, string>;
|
|
125
|
-
/** Port to watch for server readiness (default: 3000) */
|
|
126
|
-
port?: number;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/** State exposed by the runtime to UI components */
|
|
130
|
-
export interface RuntimeState {
|
|
131
|
-
status: BootStage;
|
|
132
|
-
progress: BootProgress;
|
|
133
|
-
/** URL for the preview iframe once server is ready, e.g. "/__virtual__/3000/" */
|
|
134
|
-
previewUrl: string | null;
|
|
135
|
-
/** All terminal output lines (stdout + stderr) */
|
|
136
|
-
terminalOutput: string[];
|
|
137
|
-
/** Current files in the virtual FS (may differ from original after edits) */
|
|
138
|
-
files: FileMap;
|
|
139
|
-
/**
|
|
140
|
-
* Baseline file snapshot — the files as they were before the latest
|
|
141
|
-
* update (via updateFiles). Used by the diff viewer to show what changed.
|
|
142
|
-
* Empty on first load (everything is "new"), populated after the first
|
|
143
|
-
* file update.
|
|
144
|
-
*/
|
|
145
|
-
originalFiles: FileMap;
|
|
146
|
-
/**
|
|
147
|
-
* Per-file change status relative to originalFiles.
|
|
148
|
-
*
|
|
149
|
-
* Only includes files that have a non-"unchanged" status.
|
|
150
|
-
* Missing keys should be treated as "unchanged".
|
|
151
|
-
*/
|
|
152
|
-
fileChanges: Record<string, FileChangeStatus>;
|
|
153
|
-
/**
|
|
154
|
-
* Monotonically increasing counter that triggers an iframe reload
|
|
155
|
-
* without restarting the server process. Incremented when only
|
|
156
|
-
* hot-reloadable files change (CSS, HTML, static assets).
|
|
157
|
-
*/
|
|
158
|
-
previewReloadKey: number;
|
|
159
|
-
/** Error message if status is 'error' */
|
|
160
|
-
error: string | null;
|
|
161
|
-
/**
|
|
162
|
-
* All structured errors collected during this session.
|
|
163
|
-
* New errors are appended — the array grows monotonically.
|
|
164
|
-
* Use `errors[errors.length - 1]` to get the latest.
|
|
165
|
-
*/
|
|
166
|
-
errors: SandboxError[];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// ---------------------------------------------------------------------------
|
|
170
|
-
// Imperative Handle
|
|
171
|
-
// ---------------------------------------------------------------------------
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Imperative handle exposed by CodeSandbox via React.forwardRef.
|
|
175
|
-
*
|
|
176
|
-
* This is the primary API for host applications (like Ranger) to
|
|
177
|
-
* control the sandbox programmatically. The sandbox is a "dumb renderer"
|
|
178
|
-
* — the host pushes files in and reads state out.
|
|
179
|
-
*
|
|
180
|
-
* @example
|
|
181
|
-
* ```tsx
|
|
182
|
-
* const ref = useRef<CodeSandboxHandle>(null);
|
|
183
|
-
*
|
|
184
|
-
* // Push files from any source
|
|
185
|
-
* ref.current?.updateFiles(fileMap);
|
|
186
|
-
*
|
|
187
|
-
* // Push a single file (e.g., agent modified one file)
|
|
188
|
-
* ref.current?.updateFile('server.js', newContent);
|
|
189
|
-
*
|
|
190
|
-
* // Read current state
|
|
191
|
-
* const files = ref.current?.getFiles();
|
|
192
|
-
* const changes = ref.current?.getChangedFiles();
|
|
193
|
-
* const errors = ref.current?.getErrors();
|
|
194
|
-
* ```
|
|
195
|
-
*/
|
|
196
|
-
export interface CodeSandboxHandle {
|
|
197
|
-
/**
|
|
198
|
-
* Replace the entire file set. Diffs against current files, writes only
|
|
199
|
-
* changed files to Nodepod FS, and restarts the server if anything changed.
|
|
200
|
-
*
|
|
201
|
-
* The previous file set becomes `originalFiles` for diff tracking.
|
|
202
|
-
*
|
|
203
|
-
* @param files - Complete new file set
|
|
204
|
-
* @param options - Optional: restartServer (default true)
|
|
205
|
-
*/
|
|
206
|
-
updateFiles: (
|
|
207
|
-
files: FileMap,
|
|
208
|
-
options?: { restartServer?: boolean },
|
|
209
|
-
) => Promise<void>;
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Update a single file. Writes to Nodepod FS and updates state.
|
|
213
|
-
* Does NOT restart the server — call `restart()` manually if needed,
|
|
214
|
-
* or use `updateFiles()` for bulk updates with auto-restart.
|
|
215
|
-
*
|
|
216
|
-
* @param path - File path (e.g., "server.js", "public/index.html")
|
|
217
|
-
* @param content - New file content
|
|
218
|
-
*/
|
|
219
|
-
updateFile: (path: string, content: string) => Promise<void>;
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Force restart the server process. Kills the current process
|
|
223
|
-
* and re-runs the entry command.
|
|
224
|
-
*/
|
|
225
|
-
restart: () => Promise<void>;
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Get the current file map (all files including edits).
|
|
229
|
-
*/
|
|
230
|
-
getFiles: () => FileMap;
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Get only files that have been modified relative to originalFiles.
|
|
234
|
-
* Returns a FileMap containing only the changed files.
|
|
235
|
-
*/
|
|
236
|
-
getChangedFiles: () => FileMap;
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Get the per-file change status map (new/modified/deleted).
|
|
240
|
-
* Missing keys should be treated as "unchanged".
|
|
241
|
-
*/
|
|
242
|
-
getFileChanges: () => Record<string, FileChangeStatus>;
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Get all structured errors collected during this session.
|
|
246
|
-
*/
|
|
247
|
-
getErrors: () => SandboxError[];
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Get the current runtime state snapshot.
|
|
251
|
-
*/
|
|
252
|
-
getState: () => RuntimeState;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// ---------------------------------------------------------------------------
|
|
256
|
-
// Component Props
|
|
257
|
-
// ---------------------------------------------------------------------------
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Props for the CodeSandbox component.
|
|
261
|
-
*
|
|
262
|
-
* The sandbox is a pure renderer — it receives files via props and
|
|
263
|
-
* exposes an imperative handle for programmatic updates. It does NOT
|
|
264
|
-
* interact with any storage backend directly.
|
|
265
|
-
*
|
|
266
|
-
* File sources (for initial load, pick ONE):
|
|
267
|
-
* - `files` — pass a FileMap directly
|
|
268
|
-
* - `template` — use a built-in template name (e.g., "fullstack-starter")
|
|
269
|
-
*
|
|
270
|
-
* For live updates after mount, use the imperative handle:
|
|
271
|
-
* ```tsx
|
|
272
|
-
* const ref = useRef<CodeSandboxHandle>(null);
|
|
273
|
-
* <CodeSandbox ref={ref} files={initialFiles} />
|
|
274
|
-
* // Later:
|
|
275
|
-
* ref.current.updateFiles(newFiles);
|
|
276
|
-
* ```
|
|
277
|
-
*/
|
|
278
|
-
export interface CodeSandboxProps {
|
|
279
|
-
/** Pass files directly (from any source) */
|
|
280
|
-
files?: FileMap;
|
|
281
|
-
/** OR use a built-in template name */
|
|
282
|
-
template?: string;
|
|
283
|
-
/** Command to start the dev server (default inferred from package.json or template) */
|
|
284
|
-
entryCommand?: string;
|
|
285
|
-
/** Port the server listens on (default: 3000) */
|
|
286
|
-
port?: number;
|
|
287
|
-
/** Environment variables */
|
|
288
|
-
env?: Record<string, string>;
|
|
289
|
-
|
|
290
|
-
// Callbacks
|
|
291
|
-
/** Fires when a file is modified in the editor by the user */
|
|
292
|
-
onFileChange?: (path: string, content: string) => void;
|
|
293
|
-
/** Fires when the dev server is ready (initial boot or after restart) */
|
|
294
|
-
onServerReady?: (port: number, url: string) => void;
|
|
295
|
-
/** Fires on boot progress changes */
|
|
296
|
-
onProgress?: (progress: BootProgress) => void;
|
|
297
|
-
/** Fires on errors (legacy — simple string message) */
|
|
298
|
-
onError?: (error: string) => void;
|
|
299
|
-
/**
|
|
300
|
-
* Fires when a structured error is detected.
|
|
301
|
-
*
|
|
302
|
-
* This is the primary error channel for AI agent integration.
|
|
303
|
-
* Errors include file path, line number, source context, and category
|
|
304
|
-
* so the agent can construct a targeted fix prompt.
|
|
305
|
-
*
|
|
306
|
-
* Max 2 auto-fix attempts per error is recommended (see Ranger pattern).
|
|
307
|
-
*/
|
|
308
|
-
onSandboxError?: (error: SandboxError) => void;
|
|
309
|
-
/**
|
|
310
|
-
* Fires after updateFiles() completes (files written + server restarted).
|
|
311
|
-
* Useful for the host to know when the sandbox has finished processing
|
|
312
|
-
* a file push.
|
|
313
|
-
*/
|
|
314
|
-
onFilesUpdated?: (fileChanges: Record<string, FileChangeStatus>) => void;
|
|
315
|
-
|
|
316
|
-
// Layout
|
|
317
|
-
/** CSS class name for the root element */
|
|
318
|
-
className?: string;
|
|
319
|
-
/** Height of the sandbox (default: '100vh') */
|
|
320
|
-
height?: string;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
export interface FileTreeProps {
|
|
324
|
-
files: FileNode[];
|
|
325
|
-
selectedFile: string | null;
|
|
326
|
-
onSelectFile: (path: string) => void;
|
|
327
|
-
/** Per-file change status for visual indicators (colored dots) */
|
|
328
|
-
fileChanges?: Record<string, FileChangeStatus>;
|
|
329
|
-
onCreateFile?: (path: string) => void;
|
|
330
|
-
onCreateFolder?: (path: string) => void;
|
|
331
|
-
onDeleteFile?: (path: string) => void;
|
|
332
|
-
onRenameFile?: (oldPath: string, newPath: string) => void;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
export interface CodeEditorProps {
|
|
336
|
-
files: FileMap;
|
|
337
|
-
/** Baseline files for diff comparison (empty = no diff available) */
|
|
338
|
-
originalFiles: FileMap;
|
|
339
|
-
/** Per-file change status for tab indicators */
|
|
340
|
-
fileChanges: Record<string, FileChangeStatus>;
|
|
341
|
-
activeFile: string | null;
|
|
342
|
-
openFiles: string[];
|
|
343
|
-
onSelectFile: (path: string) => void;
|
|
344
|
-
onCloseFile: (path: string) => void;
|
|
345
|
-
onFileChange: (path: string, content: string) => void;
|
|
346
|
-
readOnly?: boolean;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export interface TerminalProps {
|
|
350
|
-
output: string[];
|
|
351
|
-
className?: string;
|
|
352
|
-
/** Whether the terminal is collapsed to just its header bar */
|
|
353
|
-
minimized?: boolean;
|
|
354
|
-
/** Called when the user clicks the minimize/expand toggle */
|
|
355
|
-
onToggleMinimize?: () => void;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
export interface PreviewProps {
|
|
359
|
-
url: string | null;
|
|
360
|
-
className?: string;
|
|
361
|
-
onRefresh?: () => void;
|
|
362
|
-
/** Called when a JavaScript error occurs inside the preview iframe */
|
|
363
|
-
onBrowserError?: (error: SandboxError) => void;
|
|
364
|
-
/**
|
|
365
|
-
* Monotonically increasing counter. When this changes, the iframe
|
|
366
|
-
* is soft-reloaded (location.reload) without restarting the server.
|
|
367
|
-
* Used for hot-reloading static asset changes (CSS, HTML, images).
|
|
368
|
-
*/
|
|
369
|
-
reloadKey?: number;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
export interface BootOverlayProps {
|
|
373
|
-
progress: BootProgress;
|
|
374
|
-
className?: string;
|
|
375
|
-
}
|