sandlot 0.1.4 → 0.2.1

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 (115) hide show
  1. package/dist/browser/bundler.d.ts +68 -0
  2. package/dist/browser/bundler.d.ts.map +1 -0
  3. package/dist/browser/executor.d.ts +46 -0
  4. package/dist/browser/executor.d.ts.map +1 -0
  5. package/dist/browser/index.d.ts +9 -0
  6. package/dist/browser/index.d.ts.map +1 -0
  7. package/dist/browser/index.js +2690 -0
  8. package/dist/browser/preset.d.ts +63 -0
  9. package/dist/browser/preset.d.ts.map +1 -0
  10. package/dist/commands/index.d.ts +20 -11
  11. package/dist/commands/index.d.ts.map +1 -1
  12. package/dist/commands/types.d.ts +37 -130
  13. package/dist/commands/types.d.ts.map +1 -1
  14. package/dist/core/bundler-utils.d.ts +142 -0
  15. package/dist/core/bundler-utils.d.ts.map +1 -0
  16. package/dist/core/esm-types-resolver.d.ts +125 -0
  17. package/dist/core/esm-types-resolver.d.ts.map +1 -0
  18. package/dist/core/executor.d.ts +35 -0
  19. package/dist/core/executor.d.ts.map +1 -0
  20. package/dist/{fs.d.ts → core/fs.d.ts} +27 -29
  21. package/dist/core/fs.d.ts.map +1 -0
  22. package/dist/core/sandbox.d.ts +30 -0
  23. package/dist/core/sandbox.d.ts.map +1 -0
  24. package/dist/core/sandlot.d.ts +30 -0
  25. package/dist/core/sandlot.d.ts.map +1 -0
  26. package/dist/core/shared-module-registry.d.ts +46 -0
  27. package/dist/core/shared-module-registry.d.ts.map +1 -0
  28. package/dist/core/typechecker.d.ts +60 -0
  29. package/dist/core/typechecker.d.ts.map +1 -0
  30. package/dist/index.d.ts +11 -16
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1398 -2010
  33. package/dist/node/bundler.d.ts +48 -0
  34. package/dist/node/bundler.d.ts.map +1 -0
  35. package/dist/node/executor.d.ts +48 -0
  36. package/dist/node/executor.d.ts.map +1 -0
  37. package/dist/node/index.d.ts +9 -0
  38. package/dist/node/index.d.ts.map +1 -0
  39. package/dist/node/index.js +2644 -0
  40. package/dist/node/preset.d.ts +62 -0
  41. package/dist/node/preset.d.ts.map +1 -0
  42. package/dist/types.d.ts +528 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/package.json +16 -6
  45. package/src/browser/bundler.ts +294 -0
  46. package/src/browser/executor.ts +71 -0
  47. package/src/browser/index.ts +57 -0
  48. package/src/browser/preset.ts +179 -0
  49. package/src/commands/index.ts +498 -37
  50. package/src/commands/types.ts +117 -145
  51. package/src/core/bundler-utils.ts +630 -0
  52. package/src/core/esm-types-resolver.ts +432 -0
  53. package/src/core/executor.ts +161 -0
  54. package/src/{fs.ts → core/fs.ts} +59 -37
  55. package/src/core/sandbox.ts +624 -0
  56. package/src/core/sandlot.ts +77 -0
  57. package/src/core/shared-module-registry.ts +138 -0
  58. package/src/core/typechecker.ts +609 -0
  59. package/src/index.ts +106 -139
  60. package/src/node/bundler.ts +194 -0
  61. package/src/node/executor.ts +87 -0
  62. package/src/node/index.ts +39 -0
  63. package/src/node/preset.ts +178 -0
  64. package/src/types.ts +672 -0
  65. package/README.md +0 -243
  66. package/dist/build-emitter.d.ts +0 -47
  67. package/dist/build-emitter.d.ts.map +0 -1
  68. package/dist/builder.d.ts +0 -370
  69. package/dist/builder.d.ts.map +0 -1
  70. package/dist/bundler.d.ts +0 -152
  71. package/dist/bundler.d.ts.map +0 -1
  72. package/dist/commands/compile.d.ts +0 -13
  73. package/dist/commands/compile.d.ts.map +0 -1
  74. package/dist/commands/packages.d.ts +0 -17
  75. package/dist/commands/packages.d.ts.map +0 -1
  76. package/dist/commands/run.d.ts +0 -40
  77. package/dist/commands/run.d.ts.map +0 -1
  78. package/dist/commands.d.ts +0 -179
  79. package/dist/commands.d.ts.map +0 -1
  80. package/dist/fs.d.ts.map +0 -1
  81. package/dist/internal.d.ts +0 -79
  82. package/dist/internal.d.ts.map +0 -1
  83. package/dist/internal.js +0 -1942
  84. package/dist/loader.d.ts +0 -164
  85. package/dist/loader.d.ts.map +0 -1
  86. package/dist/packages.d.ts +0 -199
  87. package/dist/packages.d.ts.map +0 -1
  88. package/dist/runner.d.ts +0 -314
  89. package/dist/runner.d.ts.map +0 -1
  90. package/dist/sandbox-manager.d.ts +0 -261
  91. package/dist/sandbox-manager.d.ts.map +0 -1
  92. package/dist/sandbox.d.ts +0 -267
  93. package/dist/sandbox.d.ts.map +0 -1
  94. package/dist/shared-modules.d.ts +0 -148
  95. package/dist/shared-modules.d.ts.map +0 -1
  96. package/dist/shared-resources.d.ts +0 -102
  97. package/dist/shared-resources.d.ts.map +0 -1
  98. package/dist/ts-libs.d.ts +0 -85
  99. package/dist/ts-libs.d.ts.map +0 -1
  100. package/dist/typechecker.d.ts +0 -127
  101. package/dist/typechecker.d.ts.map +0 -1
  102. package/src/build-emitter.ts +0 -64
  103. package/src/builder.ts +0 -498
  104. package/src/bundler.ts +0 -575
  105. package/src/commands/compile.ts +0 -236
  106. package/src/commands/packages.ts +0 -154
  107. package/src/commands/run.ts +0 -245
  108. package/src/internal.ts +0 -119
  109. package/src/loader.ts +0 -229
  110. package/src/packages.ts +0 -936
  111. package/src/sandbox.ts +0 -398
  112. package/src/shared-modules.ts +0 -280
  113. package/src/shared-resources.ts +0 -166
  114. package/src/ts-libs.ts +0 -218
  115. package/src/typechecker.ts +0 -635
package/src/types.ts ADDED
@@ -0,0 +1,672 @@
1
+ import type { IFileSystem, FsEntry, FsStat } from "just-bash/browser";
2
+ import type { Filesystem } from "./core/fs";
3
+
4
+ // =============================================================================
5
+ // Re-export filesystem types for convenience
6
+ // =============================================================================
7
+
8
+ export type { IFileSystem, FsEntry, FsStat } from "just-bash/browser";
9
+ export type { Filesystem } from "./core/fs";
10
+
11
+ // =============================================================================
12
+ // Bundler Interface
13
+ // =============================================================================
14
+
15
+ /**
16
+ * Bundler interface - transforms source files into executable JavaScript.
17
+ *
18
+ * Implementations handle their own initialization and caching (e.g., WASM loading).
19
+ */
20
+ export interface IBundler {
21
+ /**
22
+ * Bundle source files from a filesystem into a single output
23
+ */
24
+ bundle(options: BundleOptions): Promise<BundleResult>;
25
+ }
26
+
27
+ export interface BundleOptions {
28
+ fs: Filesystem;
29
+ entryPoint: string;
30
+
31
+ /**
32
+ * Map of installed package names to versions.
33
+ * Used by the bundler to resolve imports to specific versions.
34
+ *
35
+ * @example { "lodash": "4.17.21", "react": "18.2.0" }
36
+ */
37
+ installedPackages?: Record<string, string>;
38
+
39
+ /**
40
+ * Module IDs that resolve to shared modules instead of bundling.
41
+ * These are provided by the host environment at runtime.
42
+ */
43
+ sharedModules?: string[];
44
+
45
+ /** Shared module registry for resolving shared imports */
46
+ sharedModuleRegistry?: ISharedModuleRegistry;
47
+
48
+ /** Modules to treat as external (don't bundle or rewrite) */
49
+ external?: string[];
50
+
51
+ format?: "esm" | "iife" | "cjs";
52
+ minify?: boolean;
53
+ sourcemap?: boolean;
54
+ target?: string[];
55
+ }
56
+
57
+ /**
58
+ * Bundle result - success or failure with structured errors.
59
+ */
60
+ export type BundleResult = BundleSuccess | BundleFailure;
61
+
62
+ export interface BundleSuccess {
63
+ success: true;
64
+ code: string;
65
+ warnings: BundleWarning[];
66
+ includedFiles: string[];
67
+ }
68
+
69
+ export interface BundleFailure {
70
+ success: false;
71
+ errors: BundleError[];
72
+ warnings: BundleWarning[];
73
+ }
74
+
75
+ export interface BundleWarning {
76
+ text: string;
77
+ location?: BundleLocation;
78
+ }
79
+
80
+ export interface BundleError {
81
+ text: string;
82
+ location?: BundleLocation;
83
+ }
84
+
85
+ export interface BundleLocation {
86
+ file: string;
87
+ line: number;
88
+ column?: number;
89
+ /** The source line text (if available from esbuild) */
90
+ lineText?: string;
91
+ }
92
+
93
+ // =============================================================================
94
+ // Typechecker Interface
95
+ // =============================================================================
96
+
97
+ /**
98
+ * Typechecker interface - validates TypeScript code.
99
+ *
100
+ * Implementations handle their own lib file loading and caching.
101
+ */
102
+ export interface ITypechecker {
103
+ /**
104
+ * Type check files against a virtual filesystem
105
+ */
106
+ typecheck(options: TypecheckOptions): Promise<TypecheckResult>;
107
+ }
108
+
109
+ export interface TypecheckOptions {
110
+ /** Sync filesystem to read source files from */
111
+ fs: Filesystem;
112
+ /** Entry point path (absolute path in the filesystem) */
113
+ entryPoint: string;
114
+ /** Path to tsconfig.json (default: "/tsconfig.json") */
115
+ tsconfigPath?: string;
116
+ }
117
+
118
+ export interface TypecheckResult {
119
+ success: boolean;
120
+ diagnostics: Diagnostic[];
121
+ }
122
+
123
+ export interface Diagnostic {
124
+ file?: string;
125
+ line?: number;
126
+ column?: number;
127
+ message: string;
128
+ severity: "error" | "warning" | "info";
129
+ }
130
+
131
+ // =============================================================================
132
+ // Types Resolver Interface
133
+ // =============================================================================
134
+
135
+ /**
136
+ * Types resolver interface - fetches type definitions for npm packages.
137
+ *
138
+ * Implementations handle their own caching (in-memory, KV, R2, etc.).
139
+ */
140
+ export interface ITypesResolver {
141
+ /**
142
+ * Fetch type definitions for a package.
143
+ * Returns a map of file paths to content for .d.ts files.
144
+ */
145
+ resolveTypes(
146
+ packageName: string,
147
+ version?: string
148
+ ): Promise<Record<string, string>>;
149
+ }
150
+
151
+ // =============================================================================
152
+ // Shared Module Registry Interface
153
+ // =============================================================================
154
+
155
+ /**
156
+ * Shared module registry interface - provides host modules to bundled code.
157
+ *
158
+ * This allows dynamic code to use the same React/library instances as the host,
159
+ * avoiding the "multiple React instances" problem.
160
+ *
161
+ * Each registry instance has a unique key for global exposure, allowing multiple
162
+ * Sandlot instances to coexist without sharing module state.
163
+ */
164
+ export interface ISharedModuleRegistry {
165
+ /**
166
+ * The unique global key where this registry is exposed.
167
+ * Bundled code accesses the registry via `globalThis[registryKey]`.
168
+ */
169
+ readonly registryKey: string;
170
+
171
+ /**
172
+ * Get a registered module by ID
173
+ */
174
+ get(moduleId: string): unknown;
175
+
176
+ /**
177
+ * Check if a module is registered
178
+ */
179
+ has(moduleId: string): boolean;
180
+
181
+ /**
182
+ * Get export names for a module (for generating re-exports)
183
+ */
184
+ getExportNames(moduleId: string): string[];
185
+
186
+ /**
187
+ * List all registered module IDs
188
+ */
189
+ list(): string[];
190
+ }
191
+
192
+ // =============================================================================
193
+ // Executor Interface
194
+ // =============================================================================
195
+
196
+ /**
197
+ * Executor interface - runs bundled code in an isolated context.
198
+ *
199
+ * Different implementations provide different isolation levels:
200
+ * - MainThreadExecutor: Runs in the main thread (no isolation, for trusted code)
201
+ * - WorkerExecutor: Runs in a Web Worker (memory isolation, can be terminated)
202
+ * - IframeExecutor: Runs in a sandboxed iframe (DOM isolation, CSP control)
203
+ *
204
+ * The executor receives a code string (bundled JavaScript) and options,
205
+ * and returns the execution result including captured logs and return value.
206
+ */
207
+ export interface IExecutor {
208
+ /**
209
+ * Execute bundled code and return the result.
210
+ *
211
+ * @param code - The bundled JavaScript code to execute
212
+ * @param options - Execution options (entry export, context, timeout)
213
+ * @returns Execution result with logs, return value, and any error
214
+ */
215
+ execute(code: string, options?: ExecuteOptions): Promise<ExecuteResult>;
216
+ }
217
+
218
+ /**
219
+ * Options for code execution.
220
+ */
221
+ export interface ExecuteOptions {
222
+ /**
223
+ * Which export to call:
224
+ * - 'main': Calls `main(context)` export with the provided context
225
+ * - 'default': Calls the default export (no arguments)
226
+ *
227
+ * If neither export exists, top-level code still runs on import.
228
+ * @default 'main'
229
+ */
230
+ entryExport?: "main" | "default";
231
+
232
+ /**
233
+ * Context object passed to `main(context)` when entryExport is 'main'.
234
+ * Typically includes things like args, env, logging functions.
235
+ */
236
+ context?: Record<string, unknown>;
237
+
238
+ /**
239
+ * Execution timeout in milliseconds.
240
+ * Set to 0 to disable timeout.
241
+ * @default 30000
242
+ */
243
+ timeout?: number;
244
+ }
245
+
246
+ /**
247
+ * Result of code execution.
248
+ */
249
+ export interface ExecuteResult {
250
+ /** Whether execution completed successfully */
251
+ success: boolean;
252
+
253
+ /** Captured console output (log, warn, error, info, debug) */
254
+ logs: string[];
255
+
256
+ /** Return value from the executed function (if any) */
257
+ returnValue?: unknown;
258
+
259
+ /** Error message if execution failed */
260
+ error?: string;
261
+
262
+ /** Execution time in milliseconds */
263
+ executionTimeMs?: number;
264
+ }
265
+
266
+ // =============================================================================
267
+ // Sandlot Configuration
268
+ // =============================================================================
269
+
270
+ export interface SandlotOptions {
271
+ /**
272
+ * Bundler implementation.
273
+ * Handles its own initialization and WASM loading.
274
+ */
275
+ bundler: IBundler;
276
+
277
+ /**
278
+ * Executor implementation (optional).
279
+ * Handles running bundled code in an appropriate context.
280
+ * If not provided, sandbox.run() will throw an error.
281
+ */
282
+ executor?: IExecutor;
283
+
284
+ /**
285
+ * Typechecker implementation (optional - skip type checking if not provided).
286
+ * Handles its own TypeScript lib file loading and caching.
287
+ */
288
+ typechecker?: ITypechecker;
289
+
290
+ /**
291
+ * Types resolver for npm packages (optional).
292
+ * Handles its own caching. If not provided, `install` command won't fetch types.
293
+ */
294
+ typesResolver?: ITypesResolver;
295
+
296
+ /**
297
+ * Shared modules - host modules to share with sandboxed code.
298
+ * Keys are import specifiers, values are the actual module objects.
299
+ *
300
+ * @example { 'react': React, 'react-dom/client': ReactDOM }
301
+ */
302
+ sharedModules?: Record<string, unknown>;
303
+
304
+ /**
305
+ * Default options for sandboxes created from this instance
306
+ */
307
+ sandboxDefaults?: {
308
+ maxFilesystemSize?: number;
309
+ };
310
+ }
311
+
312
+ // =============================================================================
313
+ // Sandbox Types
314
+ // =============================================================================
315
+
316
+ export interface SandboxOptions {
317
+ /**
318
+ * Initial files to populate the filesystem with.
319
+ *
320
+ * If `/package.json` is not provided, a default one will be created with:
321
+ * ```json
322
+ * { "main": "./index.ts", "dependencies": {} }
323
+ * ```
324
+ *
325
+ * If `/tsconfig.json` is not provided, sensible defaults will be created.
326
+ *
327
+ * The `main` field in package.json determines the entry point for build/typecheck.
328
+ */
329
+ initialFiles?: Record<string, string>;
330
+
331
+ /**
332
+ * Maximum filesystem size in bytes
333
+ */
334
+ maxFilesystemSize?: number;
335
+
336
+ /**
337
+ * Callback invoked when a build succeeds
338
+ */
339
+ onBuild?: (result: BuildSuccess) => void | Promise<void>;
340
+ }
341
+
342
+ /**
343
+ * Build phases that can fail.
344
+ */
345
+ export type BuildPhase = "entry" | "typecheck" | "bundle";
346
+
347
+ /**
348
+ * Build result - success or failure with structured errors.
349
+ *
350
+ * On success, contains the bundled code string.
351
+ * On failure, contains the phase that failed and structured error information.
352
+ *
353
+ * Note: Build does NOT load or execute the module. Use an executor to run the code.
354
+ * This keeps the build phase pure (no code execution) and allows different execution
355
+ * contexts (main thread, web worker, iframe, remote server).
356
+ */
357
+ export type BuildResult = BuildSuccess | BuildFailure;
358
+
359
+ export interface BuildSuccess {
360
+ success: true;
361
+ /** The bundled JavaScript code */
362
+ code: string;
363
+ /** Files that were included in the bundle */
364
+ includedFiles: string[];
365
+ /** Any warnings from the bundler */
366
+ warnings: BundleWarning[];
367
+ }
368
+
369
+ /**
370
+ * Details about why a build failed.
371
+ * Used by both BuildResult and RunResult.
372
+ */
373
+ export interface BuildFailureDetails {
374
+ /** Which phase of the build failed */
375
+ phase: BuildPhase;
376
+ /** Error message (for entry failures) */
377
+ message?: string;
378
+ /** Type check diagnostics (for typecheck failures) */
379
+ diagnostics?: Diagnostic[];
380
+ /** Bundle errors (for bundle failures) */
381
+ bundleErrors?: BundleError[];
382
+ /** Bundle warnings (may be present even on failure) */
383
+ bundleWarnings?: BundleWarning[];
384
+ }
385
+
386
+ export interface BuildFailure extends BuildFailureDetails {
387
+ success: false;
388
+ }
389
+
390
+
391
+ // -----------------------------------------------------------------------------
392
+ // Install/Uninstall Types
393
+ // -----------------------------------------------------------------------------
394
+
395
+ export interface InstallResult {
396
+ /** Package name */
397
+ name: string;
398
+ /** Resolved version */
399
+ version: string;
400
+ /** Whether type definitions were installed */
401
+ typesInstalled: boolean;
402
+ /** Number of .d.ts files written */
403
+ typeFilesCount: number;
404
+ /** Whether types came from cache */
405
+ fromCache?: boolean;
406
+ /** Error message if types failed to install */
407
+ typesError?: string;
408
+ }
409
+
410
+ export interface UninstallResult {
411
+ /** Package name */
412
+ name: string;
413
+ /** Whether the package was installed (and thus removed) */
414
+ removed: boolean;
415
+ }
416
+
417
+ // -----------------------------------------------------------------------------
418
+ // Build Options
419
+ // -----------------------------------------------------------------------------
420
+
421
+ export interface SandboxBuildOptions {
422
+ /**
423
+ * Entry point to build.
424
+ * If not specified, reads from `main` field in /package.json.
425
+ * Falls back to "./index.ts" if not found.
426
+ */
427
+ entryPoint?: string;
428
+
429
+ /**
430
+ * Skip type checking before bundling.
431
+ * @default false
432
+ */
433
+ skipTypecheck?: boolean;
434
+
435
+ /**
436
+ * Minify the output.
437
+ * @default false
438
+ */
439
+ minify?: boolean;
440
+
441
+ /**
442
+ * Output format.
443
+ * @default "esm"
444
+ */
445
+ format?: "esm" | "iife" | "cjs";
446
+ }
447
+
448
+ // -----------------------------------------------------------------------------
449
+ // Typecheck Options
450
+ // -----------------------------------------------------------------------------
451
+
452
+ export interface SandboxTypecheckOptions {
453
+ /**
454
+ * Entry point to typecheck.
455
+ * If not specified, reads from `main` field in /package.json.
456
+ * Falls back to "./index.ts" if not found.
457
+ */
458
+ entryPoint?: string;
459
+ }
460
+
461
+ // -----------------------------------------------------------------------------
462
+ // Run Options and Result
463
+ // -----------------------------------------------------------------------------
464
+
465
+ /**
466
+ * Options for running code in the sandbox.
467
+ */
468
+ export interface RunOptions {
469
+ /**
470
+ * Entry point to build and run.
471
+ * If not specified, reads from `main` field in /package.json.
472
+ * Falls back to "./index.ts" if not found.
473
+ */
474
+ entryPoint?: string;
475
+
476
+ /**
477
+ * Skip type checking before building.
478
+ * @default false
479
+ */
480
+ skipTypecheck?: boolean;
481
+
482
+ /**
483
+ * Which export to call:
484
+ * - 'main': Calls `main(context)` export with the provided context
485
+ * - 'default': Calls the default export (no arguments)
486
+ * @default 'main'
487
+ */
488
+ entryExport?: "main" | "default";
489
+
490
+ /**
491
+ * Context object passed to `main(context)` when entryExport is 'main'.
492
+ */
493
+ context?: Record<string, unknown>;
494
+
495
+ /**
496
+ * Execution timeout in milliseconds.
497
+ * Set to 0 to disable timeout.
498
+ * @default 30000
499
+ */
500
+ timeout?: number;
501
+ }
502
+
503
+ /**
504
+ * Result of running code in the sandbox.
505
+ *
506
+ * Extends ExecuteResult with build failure information.
507
+ * If `buildFailure` is present, the build failed before execution.
508
+ */
509
+ export interface RunResult extends ExecuteResult {
510
+ /** If build failed, contains failure details (same structure as BuildFailure) */
511
+ buildFailure?: BuildFailureDetails;
512
+ }
513
+
514
+ // -----------------------------------------------------------------------------
515
+ // Sandbox Interface
516
+ // -----------------------------------------------------------------------------
517
+
518
+ export interface Sandbox {
519
+ /**
520
+ * The virtual filesystem (sync)
521
+ */
522
+ readonly fs: Filesystem;
523
+
524
+ /**
525
+ * Execute a shell command
526
+ */
527
+ exec(command: string): Promise<ExecResult>;
528
+
529
+ /**
530
+ * The last successful build result (code string + metadata)
531
+ */
532
+ readonly lastBuild: BuildSuccess | null;
533
+
534
+ /**
535
+ * Get the current sandbox state for persistence
536
+ */
537
+ getState(): SandboxState;
538
+
539
+ // ---------------------------------------------------------------------------
540
+ // File Operations (convenience methods)
541
+ // ---------------------------------------------------------------------------
542
+
543
+ /**
544
+ * Read a file from the virtual filesystem.
545
+ *
546
+ * @param path - Absolute path to the file (e.g., "/src/app.ts")
547
+ * @returns File contents as a string
548
+ * @throws If the file does not exist
549
+ */
550
+ readFile(path: string): string;
551
+
552
+ /**
553
+ * Write a file to the virtual filesystem.
554
+ * Creates parent directories automatically if they don't exist.
555
+ *
556
+ * @param path - Absolute path to the file (e.g., "/src/app.ts")
557
+ * @param content - File contents to write
558
+ */
559
+ writeFile(path: string, content: string): void;
560
+
561
+ /**
562
+ * Subscribe to build events
563
+ */
564
+ onBuild(callback: (result: BuildSuccess) => void | Promise<void>): () => void;
565
+
566
+ // ---------------------------------------------------------------------------
567
+ // Direct Methods (also available via exec)
568
+ // ---------------------------------------------------------------------------
569
+
570
+ /**
571
+ * Install a package from npm.
572
+ * Updates /package.json and fetches type definitions if typesResolver is configured.
573
+ *
574
+ * @param packageSpec - Package specifier (e.g., "lodash", "lodash@4.17.21", "@types/node@20")
575
+ * @returns Installation result with version and types info
576
+ *
577
+ * @example
578
+ * await sandbox.install("lodash@4.17.21");
579
+ * await sandbox.install("@tanstack/react-query");
580
+ */
581
+ install(packageSpec: string): Promise<InstallResult>;
582
+
583
+ /**
584
+ * Uninstall a package.
585
+ * Removes from /package.json and deletes type definition files.
586
+ *
587
+ * @param packageName - Package name (e.g., "lodash", "@tanstack/react-query")
588
+ * @returns Whether the package was removed
589
+ */
590
+ uninstall(packageName: string): Promise<UninstallResult>;
591
+
592
+ /**
593
+ * Build the project.
594
+ * Reads dependencies from /package.json, optionally typechecks, and bundles.
595
+ * Returns the bundled code string (does NOT execute it).
596
+ *
597
+ * @param options - Build options
598
+ * @returns Build result - check `success` field to determine outcome
599
+ */
600
+ build(options?: SandboxBuildOptions): Promise<BuildResult>;
601
+
602
+ /**
603
+ * Type check the project.
604
+ * Reads tsconfig from filesystem and runs the typechecker.
605
+ *
606
+ * @param options - Typecheck options
607
+ * @returns Typecheck result with diagnostics
608
+ */
609
+ typecheck(options?: SandboxTypecheckOptions): Promise<TypecheckResult>;
610
+
611
+ /**
612
+ * Build and run code using the configured executor.
613
+ *
614
+ * This is a convenience method that:
615
+ * 1. Builds the code (typecheck + bundle)
616
+ * 2. Passes the bundled code to the executor
617
+ * 3. Returns the execution result
618
+ *
619
+ * Requires an executor to be configured when creating Sandlot.
620
+ *
621
+ * @param options - Run options (entry point, context, timeout, etc.)
622
+ * @returns Run result with logs, return value, and any error
623
+ * @throws If no executor was configured
624
+ *
625
+ * @example
626
+ * ```ts
627
+ * // Script style - top-level code runs on import
628
+ * sandbox.writeFile('/index.ts', 'console.log("Hello!")');
629
+ * const result = await sandbox.run();
630
+ * console.log(result.logs); // ['Hello!']
631
+ *
632
+ * // Main function style - gets context
633
+ * sandbox.writeFile('/index.ts', `
634
+ * export function main(ctx) {
635
+ * ctx.log("Args:", ctx.args);
636
+ * return { success: true };
637
+ * }
638
+ * `);
639
+ * const result = await sandbox.run({
640
+ * context: { args: ['--verbose'] }
641
+ * });
642
+ * console.log(result.returnValue); // { success: true }
643
+ * ```
644
+ */
645
+ run(options?: RunOptions): Promise<RunResult>;
646
+ }
647
+
648
+ export interface ExecResult {
649
+ exitCode: number;
650
+ stdout: string;
651
+ stderr: string;
652
+ }
653
+
654
+ export interface SandboxState {
655
+ files: Record<string, string>;
656
+ }
657
+
658
+ // =============================================================================
659
+ // Sandlot Interface
660
+ // =============================================================================
661
+
662
+ export interface Sandlot {
663
+ /**
664
+ * Create a new sandbox environment
665
+ */
666
+ createSandbox(options?: SandboxOptions): Promise<Sandbox>;
667
+
668
+ /**
669
+ * The shared module registry (if shared modules were provided)
670
+ */
671
+ readonly sharedModules: ISharedModuleRegistry | null;
672
+ }