sandlot 0.1.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 (47) hide show
  1. package/README.md +616 -0
  2. package/dist/bundler.d.ts +148 -0
  3. package/dist/bundler.d.ts.map +1 -0
  4. package/dist/commands.d.ts +179 -0
  5. package/dist/commands.d.ts.map +1 -0
  6. package/dist/fs.d.ts +125 -0
  7. package/dist/fs.d.ts.map +1 -0
  8. package/dist/index.d.ts +16 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +2920 -0
  11. package/dist/internal.d.ts +74 -0
  12. package/dist/internal.d.ts.map +1 -0
  13. package/dist/internal.js +1897 -0
  14. package/dist/loader.d.ts +164 -0
  15. package/dist/loader.d.ts.map +1 -0
  16. package/dist/packages.d.ts +199 -0
  17. package/dist/packages.d.ts.map +1 -0
  18. package/dist/react.d.ts +159 -0
  19. package/dist/react.d.ts.map +1 -0
  20. package/dist/react.js +149 -0
  21. package/dist/sandbox-manager.d.ts +249 -0
  22. package/dist/sandbox-manager.d.ts.map +1 -0
  23. package/dist/sandbox.d.ts +193 -0
  24. package/dist/sandbox.d.ts.map +1 -0
  25. package/dist/shared-modules.d.ts +129 -0
  26. package/dist/shared-modules.d.ts.map +1 -0
  27. package/dist/shared-resources.d.ts +105 -0
  28. package/dist/shared-resources.d.ts.map +1 -0
  29. package/dist/ts-libs.d.ts +98 -0
  30. package/dist/ts-libs.d.ts.map +1 -0
  31. package/dist/typechecker.d.ts +127 -0
  32. package/dist/typechecker.d.ts.map +1 -0
  33. package/package.json +64 -0
  34. package/src/bundler.ts +513 -0
  35. package/src/commands.ts +733 -0
  36. package/src/fs.ts +935 -0
  37. package/src/index.ts +149 -0
  38. package/src/internal.ts +116 -0
  39. package/src/loader.ts +229 -0
  40. package/src/packages.ts +936 -0
  41. package/src/react.tsx +331 -0
  42. package/src/sandbox-manager.ts +490 -0
  43. package/src/sandbox.ts +402 -0
  44. package/src/shared-modules.ts +210 -0
  45. package/src/shared-resources.ts +169 -0
  46. package/src/ts-libs.ts +320 -0
  47. package/src/typechecker.ts +635 -0
@@ -0,0 +1,249 @@
1
+ /**
2
+ * SandboxManager - Manages shared resources for multiple concurrent sandboxes.
3
+ *
4
+ * When running many sandboxes concurrently (e.g., for multiple AI agents),
5
+ * this manager ensures heavy resources are loaded once and shared:
6
+ *
7
+ * - TypeScript lib files (~5MB) - loaded once, shared across all sandboxes
8
+ * - esbuild WASM (~10MB) - already singleton, but pre-initialized here
9
+ *
10
+ * Usage:
11
+ * ```ts
12
+ * const manager = await createSandboxManager();
13
+ *
14
+ * // Create multiple sandboxes - all share the same libs and bundler
15
+ * const sandbox1 = await manager.createSandbox({ ... });
16
+ * const sandbox2 = await manager.createSandbox({ ... });
17
+ *
18
+ * // ... use sandboxes ...
19
+ *
20
+ * // Clean up
21
+ * manager.destroyAll();
22
+ * ```
23
+ */
24
+ import { defineCommand } from "just-bash/browser";
25
+ import { type IndexedDbFsOptions } from "./fs";
26
+ import { type BundleResult } from "./bundler";
27
+ import { type SharedResources, type SharedResourcesOptions } from "./shared-resources";
28
+ import type { Sandbox } from "./sandbox";
29
+ export type { BundleResult } from "./bundler";
30
+ export type { TypecheckResult } from "./typechecker";
31
+ export type { SharedResources, TypesCache } from "./shared-resources";
32
+ export type { PackageManifest, InstallResult } from "./packages";
33
+ export { installPackage, uninstallPackage, listPackages, getPackageManifest } from "./packages";
34
+ export { InMemoryTypesCache } from "./shared-resources";
35
+ export { loadModule, loadExport, loadDefault, getExportNames, hasExport, createModuleUrl, revokeModuleUrl, ModuleLoadError, ExportNotFoundError, } from "./loader";
36
+ /**
37
+ * Options for creating a sandbox via the manager
38
+ */
39
+ export interface ManagedSandboxOptions {
40
+ /**
41
+ * Unique identifier for this sandbox.
42
+ *
43
+ * Also used as the IndexedDB database name if `fsOptions.dbName` is not provided
44
+ * and `inMemory` is false. If both are provided, `fsOptions.dbName` takes precedence.
45
+ *
46
+ * @default Auto-generated as "sandbox-1", "sandbox-2", etc.
47
+ */
48
+ id?: string;
49
+ /**
50
+ * Options for the IndexedDB filesystem.
51
+ *
52
+ * Note: `fsOptions.dbName` takes precedence over `id` for the database name.
53
+ * If neither is provided, the auto-generated `id` is used.
54
+ */
55
+ fsOptions?: IndexedDbFsOptions;
56
+ /**
57
+ * Initial files to populate the filesystem with
58
+ */
59
+ initialFiles?: Record<string, string>;
60
+ /**
61
+ * Path to tsconfig.json in the virtual filesystem.
62
+ * Default: "/tsconfig.json"
63
+ */
64
+ tsconfigPath?: string;
65
+ /**
66
+ * Callback invoked when a build succeeds.
67
+ * Receives the bundle result with the compiled code.
68
+ */
69
+ onBuild?: (result: BundleResult) => void | Promise<void>;
70
+ /**
71
+ * Additional custom commands to add to the bash environment
72
+ */
73
+ customCommands?: ReturnType<typeof defineCommand>[];
74
+ /**
75
+ * If true, use in-memory filesystem only (no IndexedDB persistence).
76
+ * Default: true
77
+ */
78
+ inMemory?: boolean;
79
+ /**
80
+ * Module IDs that should be resolved from the host's SharedModuleRegistry
81
+ * instead of esm.sh CDN. Overrides manager-level sharedModules for this sandbox.
82
+ *
83
+ * @see SandboxOptions.sharedModules for full documentation
84
+ */
85
+ sharedModules?: string[];
86
+ }
87
+ /**
88
+ * A sandbox instance managed by the SandboxManager.
89
+ *
90
+ * Extends the base Sandbox interface with an `id` property for
91
+ * identification within the manager. This ensures ManagedSandbox
92
+ * has full feature parity with Sandbox.
93
+ */
94
+ export interface ManagedSandbox extends Sandbox {
95
+ /**
96
+ * Unique identifier for this sandbox within the manager.
97
+ */
98
+ id: string;
99
+ }
100
+ /**
101
+ * Statistics about the sandbox manager
102
+ */
103
+ export interface SandboxManagerStats {
104
+ /**
105
+ * Whether shared resources have been initialized
106
+ */
107
+ initialized: boolean;
108
+ /**
109
+ * Number of currently active sandboxes
110
+ */
111
+ activeSandboxes: number;
112
+ /**
113
+ * Number of TypeScript lib files loaded
114
+ */
115
+ libFilesCount: number;
116
+ /**
117
+ * IDs of active sandboxes
118
+ */
119
+ sandboxIds: string[];
120
+ }
121
+ /**
122
+ * Options for creating a SandboxManager
123
+ */
124
+ export interface SandboxManagerOptions extends SharedResourcesOptions {
125
+ /**
126
+ * TypeScript libs to load. Defaults to browser libs (ES2020 + DOM).
127
+ */
128
+ libs?: string[];
129
+ /**
130
+ * Default shared modules for all sandboxes created by this manager.
131
+ * Individual sandboxes can override with their own sharedModules option.
132
+ *
133
+ * Module IDs that should be resolved from the host's SharedModuleRegistry
134
+ * instead of esm.sh CDN. The host must have registered these modules
135
+ * using `registerSharedModules()` before loading dynamic code.
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * const manager = await createSandboxManager({
140
+ * sharedModules: ['react', 'react-dom/client'],
141
+ * });
142
+ * ```
143
+ */
144
+ sharedModules?: string[];
145
+ }
146
+ /**
147
+ * Manager for creating and managing multiple sandboxes with shared resources.
148
+ */
149
+ export declare class SandboxManager {
150
+ private resources;
151
+ private sandboxes;
152
+ private initialized;
153
+ private initPromise;
154
+ private nextId;
155
+ private options;
156
+ constructor(options?: SandboxManagerOptions);
157
+ /**
158
+ * Initialize shared resources (libs and bundler).
159
+ * Called automatically on first sandbox creation, but can be called
160
+ * explicitly to pre-warm.
161
+ */
162
+ initialize(): Promise<void>;
163
+ private doInitialize;
164
+ /**
165
+ * Create a new managed sandbox.
166
+ * Shares TypeScript libs and bundler with all other sandboxes.
167
+ */
168
+ createSandbox(options?: ManagedSandboxOptions): Promise<ManagedSandbox>;
169
+ /**
170
+ * Get a sandbox by ID
171
+ */
172
+ getSandbox(id: string): ManagedSandbox | undefined;
173
+ /**
174
+ * Get all active sandboxes
175
+ */
176
+ getAllSandboxes(): ManagedSandbox[];
177
+ /**
178
+ * Close a specific sandbox
179
+ */
180
+ closeSandbox(id: string): boolean;
181
+ /**
182
+ * Close all sandboxes and release resources
183
+ */
184
+ destroyAll(): void;
185
+ /**
186
+ * Save all sandboxes that have unsaved changes.
187
+ *
188
+ * @returns Map of sandbox ID to save result (true if saved, false if nothing to save)
189
+ *
190
+ * @example
191
+ * ```ts
192
+ * const results = await manager.saveAll();
193
+ * for (const [id, saved] of results) {
194
+ * console.log(`${id}: ${saved ? 'saved' : 'no changes'}`);
195
+ * }
196
+ * ```
197
+ */
198
+ saveAll(): Promise<Map<string, boolean>>;
199
+ /**
200
+ * Get IDs of sandboxes with unsaved changes.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * const dirtyIds = manager.getDirtySandboxes();
205
+ * if (dirtyIds.length > 0) {
206
+ * console.log('Unsaved sandboxes:', dirtyIds.join(', '));
207
+ * }
208
+ * ```
209
+ */
210
+ getDirtySandboxes(): string[];
211
+ /**
212
+ * Get statistics about the manager
213
+ */
214
+ getStats(): SandboxManagerStats;
215
+ /**
216
+ * Get the shared resources (for advanced use cases)
217
+ */
218
+ getResources(): SharedResources | null;
219
+ /**
220
+ * Get the shared lib files (for advanced use cases)
221
+ * @deprecated Use getResources().libFiles instead
222
+ */
223
+ getLibFiles(): Map<string, string>;
224
+ }
225
+ /**
226
+ * Create a new SandboxManager instance.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * const manager = await createSandboxManager();
231
+ *
232
+ * // Create multiple sandboxes concurrently
233
+ * const [sandbox1, sandbox2] = await Promise.all([
234
+ * manager.createSandbox({ id: "agent-1", initialFiles: { ... } }),
235
+ * manager.createSandbox({ id: "agent-2", initialFiles: { ... } }),
236
+ * ]);
237
+ *
238
+ * // Run operations in parallel
239
+ * const [result1, result2] = await Promise.all([
240
+ * sandbox1.bash.exec("build"),
241
+ * sandbox2.bash.exec("build"),
242
+ * ]);
243
+ *
244
+ * // Clean up
245
+ * manager.destroyAll();
246
+ * ```
247
+ */
248
+ export declare function createSandboxManager(options?: SandboxManagerOptions): Promise<SandboxManager>;
249
+ //# sourceMappingURL=sandbox-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-manager.d.ts","sourceRoot":"","sources":["../src/sandbox-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,193 @@
1
+ import { Bash, defineCommand } from "just-bash/browser";
2
+ import { IndexedDbFs, type IndexedDbFsOptions } from "./fs";
3
+ import { type BundleResult } from "./bundler";
4
+ import { type SharedResources } from "./shared-resources";
5
+ export type { BundleResult } from "./bundler";
6
+ export type { TypecheckResult } from "./typechecker";
7
+ export type { SharedResources, TypesCache } from "./shared-resources";
8
+ export type { PackageManifest, InstallResult } from "./packages";
9
+ export type { RunContext, RunOptions, RunResult } from "./commands";
10
+ export { installPackage, uninstallPackage, listPackages, getPackageManifest } from "./packages";
11
+ export { InMemoryTypesCache } from "./shared-resources";
12
+ export { loadModule, loadExport, loadDefault, getExportNames, hasExport, createModuleUrl, revokeModuleUrl, ModuleLoadError, ExportNotFoundError, } from "./loader";
13
+ /**
14
+ * Options for creating a sandbox environment
15
+ */
16
+ export interface SandboxOptions {
17
+ /**
18
+ * Options for the IndexedDB filesystem
19
+ */
20
+ fsOptions?: IndexedDbFsOptions;
21
+ /**
22
+ * Path to tsconfig.json in the virtual filesystem.
23
+ * Default: "/tsconfig.json"
24
+ */
25
+ tsconfigPath?: string;
26
+ /**
27
+ * Shared resources (lib files, bundler).
28
+ * If not provided, uses the default singleton resources.
29
+ *
30
+ * Provide this to share resources across multiple sandboxes,
31
+ * or to use custom TypeScript libs.
32
+ */
33
+ resources?: SharedResources;
34
+ /**
35
+ * Callback invoked when a build succeeds.
36
+ * Receives the bundle result with the compiled code.
37
+ * Use this to dynamically import the bundle or halt the agent.
38
+ */
39
+ onBuild?: (result: BundleResult) => void | Promise<void>;
40
+ /**
41
+ * Additional custom commands to add to the bash environment
42
+ */
43
+ customCommands?: ReturnType<typeof defineCommand>[];
44
+ /**
45
+ * Module IDs that should be resolved from the host's SharedModuleRegistry
46
+ * instead of esm.sh CDN. The host must have registered these modules
47
+ * using `registerSharedModules()` before loading dynamic code.
48
+ *
49
+ * This solves the "multiple React instances" problem by allowing dynamic
50
+ * components to share the same React instance as the host application.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * // Host setup
55
+ * import * as React from 'react';
56
+ * import * as ReactDOM from 'react-dom/client';
57
+ * import { registerSharedModules } from 'sandlot';
58
+ *
59
+ * registerSharedModules({
60
+ * 'react': React,
61
+ * 'react-dom/client': ReactDOM,
62
+ * });
63
+ *
64
+ * // Create sandbox with shared modules
65
+ * const sandbox = await createInMemorySandbox({
66
+ * sharedModules: ['react', 'react-dom/client'],
67
+ * });
68
+ * ```
69
+ */
70
+ sharedModules?: string[];
71
+ }
72
+ /**
73
+ * The sandbox environment containing the filesystem and bash shell
74
+ */
75
+ export interface Sandbox {
76
+ /**
77
+ * The virtual filesystem (IndexedDB-backed)
78
+ */
79
+ fs: IndexedDbFs;
80
+ /**
81
+ * The just-bash shell environment
82
+ */
83
+ bash: Bash;
84
+ /**
85
+ * Check if there are unsaved changes in the filesystem.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * await sandbox.bash.exec('echo "hello" > /test.txt');
90
+ * console.log(sandbox.isDirty()); // true
91
+ * await sandbox.save();
92
+ * console.log(sandbox.isDirty()); // false
93
+ * ```
94
+ */
95
+ isDirty(): boolean;
96
+ /**
97
+ * Save the filesystem to IndexedDB.
98
+ *
99
+ * @returns true if saved, false if nothing to save or in-memory only
100
+ */
101
+ save(): Promise<boolean>;
102
+ /**
103
+ * Close all resources (filesystem, etc.)
104
+ */
105
+ close(): void;
106
+ /**
107
+ * Subscribe to build events. Called whenever a build succeeds.
108
+ * Returns an unsubscribe function.
109
+ *
110
+ * Use this to capture the bundle result when build succeeds.
111
+ * The callback receives the BundleResult with the compiled code.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * let bundle: BundleResult | null = null;
116
+ *
117
+ * const sandbox = await createInMemorySandbox({
118
+ * onBuild: (result) => {
119
+ * bundle = result;
120
+ * console.log('Built:', result.code.length, 'bytes');
121
+ * },
122
+ * });
123
+ *
124
+ * // ... agent writes files and calls build ...
125
+ *
126
+ * // After successful build, bundle is available
127
+ * console.log(bundle?.code);
128
+ * ```
129
+ */
130
+ onBuild(callback: (result: BundleResult) => void | Promise<void>): () => void;
131
+ }
132
+ /**
133
+ * Create an in-browser agent sandbox with a virtual filesystem, TypeScript
134
+ * type checking, and bundling capabilities.
135
+ *
136
+ * The sandbox provides a just-bash shell with custom commands:
137
+ * - `tsc [entry]` - Type check the project
138
+ * - `build [entry] [options]` - Build the project (runs typecheck first)
139
+ *
140
+ * Build options:
141
+ * - `--output, -o <path>` - Output path (default: /dist/bundle.js)
142
+ * - `--format, -f <esm|iife|cjs>` - Output format (default: esm)
143
+ * - `--minify, -m` - Enable minification
144
+ * - `--skip-typecheck, -s` - Skip type checking
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * let bundleResult: BundleResult | null = null;
149
+ *
150
+ * const sandbox = await createSandbox({
151
+ * fsOptions: {
152
+ * dbName: "my-project",
153
+ * initialFiles: {
154
+ * "/src/index.ts": "export const hello = 'world';",
155
+ * "/tsconfig.json": JSON.stringify({
156
+ * compilerOptions: { target: "ES2020", strict: true }
157
+ * }),
158
+ * },
159
+ * },
160
+ * onBuild: (result) => {
161
+ * bundleResult = result;
162
+ * // Could also: dynamically import, halt agent, etc.
163
+ * },
164
+ * });
165
+ *
166
+ * // Use bash commands
167
+ * await sandbox.bash.exec('echo "console.log(1);" > /src/index.ts');
168
+ *
169
+ * // Type check
170
+ * const tscResult = await sandbox.bash.exec("tsc");
171
+ * console.log(tscResult.stdout);
172
+ *
173
+ * // Build (includes typecheck, triggers onBuild callback)
174
+ * const buildResult = await sandbox.bash.exec("build");
175
+ * console.log(buildResult.stdout);
176
+ * console.log(bundleResult?.code); // The compiled bundle
177
+ *
178
+ * // Save to IndexedDB
179
+ * await sandbox.save();
180
+ *
181
+ * // Clean up
182
+ * sandbox.close();
183
+ * ```
184
+ */
185
+ export declare function createSandbox(options?: SandboxOptions): Promise<Sandbox>;
186
+ /**
187
+ * Create an in-memory sandbox (no IndexedDB persistence).
188
+ * Useful for testing or temporary workspaces.
189
+ */
190
+ export declare function createInMemorySandbox(options?: Omit<SandboxOptions, "fsOptions"> & {
191
+ initialFiles?: Record<string, string>;
192
+ }): Promise<Sandbox>;
193
+ //# sourceMappingURL=sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG/E,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACT,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAuDlB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD;;OAEG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,EAAE,CAAC;IAEpD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,EAAE,EAAE,WAAW,CAAC;IAEhB;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC;IAEX;;;;;;;;;;OAUG;IACH,OAAO,IAAI,OAAO,CAAC;IAEnB;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEzB;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;CAC/E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgElF;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,GAAG;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,GACL,OAAO,CAAC,OAAO,CAAC,CA8DlB"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Shared Module Registry for Sandlot
3
+ *
4
+ * Allows host applications to register their module instances (like React)
5
+ * so that dynamically bundled code can use the same instances instead of
6
+ * loading separate copies from esm.sh CDN.
7
+ *
8
+ * This solves the "multiple React instances" problem where hooks fail
9
+ * because the host and dynamic code use different React copies.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Host application setup
14
+ * import * as React from 'react';
15
+ * import * as ReactDOM from 'react-dom/client';
16
+ * import { registerSharedModules } from 'sandlot';
17
+ *
18
+ * registerSharedModules({
19
+ * 'react': React,
20
+ * 'react-dom/client': ReactDOM,
21
+ * });
22
+ *
23
+ * // Now create sandbox with sharedModules option
24
+ * const sandbox = await createInMemorySandbox({
25
+ * sharedModules: ['react', 'react-dom/client'],
26
+ * });
27
+ * ```
28
+ */
29
+ /**
30
+ * Registry for sharing host modules with dynamic bundles.
31
+ * Modules registered here will be used instead of esm.sh CDN
32
+ * when the sandbox is configured with matching sharedModules.
33
+ */
34
+ export declare class SharedModuleRegistry {
35
+ private modules;
36
+ constructor();
37
+ /**
38
+ * Register a module to be shared with dynamic bundles
39
+ *
40
+ * @param moduleId - The import specifier (e.g., 'react', 'react-dom/client')
41
+ * @param module - The module's exports object
42
+ * @returns this for chaining
43
+ */
44
+ register(moduleId: string, module: unknown): this;
45
+ /**
46
+ * Register multiple modules at once
47
+ *
48
+ * @param modules - Object mapping module IDs to their exports
49
+ * @returns this for chaining
50
+ */
51
+ registerAll(modules: Record<string, unknown>): this;
52
+ /**
53
+ * Unregister a previously registered module
54
+ *
55
+ * @param moduleId - The import specifier to remove
56
+ * @returns true if the module was registered and removed
57
+ */
58
+ unregister(moduleId: string): boolean;
59
+ /**
60
+ * Get a registered module (used by dynamic bundles at runtime)
61
+ *
62
+ * @param moduleId - The import specifier
63
+ * @returns The registered module exports
64
+ * @throws Error if the module is not registered
65
+ */
66
+ get(moduleId: string): unknown;
67
+ /**
68
+ * Check if a module is registered
69
+ *
70
+ * @param moduleId - The import specifier to check
71
+ */
72
+ has(moduleId: string): boolean;
73
+ /**
74
+ * Get list of all registered module IDs
75
+ */
76
+ list(): string[];
77
+ /**
78
+ * Clear all registrations
79
+ */
80
+ clear(): void;
81
+ /**
82
+ * Get the number of registered modules
83
+ */
84
+ get size(): number;
85
+ }
86
+ /**
87
+ * Get the default shared module registry.
88
+ * Creates it if it doesn't exist.
89
+ */
90
+ export declare function getSharedModuleRegistry(): SharedModuleRegistry;
91
+ /**
92
+ * Check if a shared module registry exists on globalThis
93
+ */
94
+ export declare function hasSharedModuleRegistry(): boolean;
95
+ /**
96
+ * Convenience function to register modules with the default registry.
97
+ *
98
+ * @param modules - Object mapping module IDs to their exports
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * import * as React from 'react';
103
+ * import * as ReactDOM from 'react-dom/client';
104
+ * import { registerSharedModules } from 'sandlot';
105
+ *
106
+ * registerSharedModules({
107
+ * 'react': React,
108
+ * 'react-dom/client': ReactDOM,
109
+ * });
110
+ * ```
111
+ */
112
+ export declare function registerSharedModules(modules: Record<string, unknown>): void;
113
+ /**
114
+ * Convenience function to unregister a module from the default registry.
115
+ *
116
+ * @param moduleId - The import specifier to remove
117
+ * @returns true if the module was registered and removed
118
+ */
119
+ export declare function unregisterSharedModule(moduleId: string): boolean;
120
+ /**
121
+ * Clear all shared modules from the default registry.
122
+ */
123
+ export declare function clearSharedModules(): void;
124
+ /**
125
+ * Generate the runtime code that dynamic bundles use to access shared modules.
126
+ * This is injected into bundles when they import from shared modules.
127
+ */
128
+ export declare function getSharedModuleRuntimeCode(moduleId: string): string;
129
+ //# sourceMappingURL=shared-modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-modules.d.ts","sourceRoot":"","sources":["../src/shared-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAOH;;;;GAIG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,OAAO,CAA8B;;IAO7C;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAKjD;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAOnD;;;;;OAKG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIrC;;;;;;OAMG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAa9B;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI9B;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE;IAIhB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAKD;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,CAK9D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE5E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAanE"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Shared resources for sandbox environments.
3
+ *
4
+ * Provides centralized management of expensive shared resources:
5
+ * - TypeScript lib files (~5MB) - loaded once, shared across all sandboxes
6
+ * - esbuild WASM (~10MB) - singleton bundler initialization
7
+ * - Types cache - avoids redundant network fetches when multiple sandboxes
8
+ * install the same packages
9
+ *
10
+ * This module consolidates what was previously scattered across
11
+ * sandbox.ts and sandbox-manager.ts into a single source of truth.
12
+ */
13
+ import { type TypesCache } from "./packages";
14
+ export type { TypesCache } from "./packages";
15
+ export { InMemoryTypesCache } from "./packages";
16
+ /**
17
+ * Shared resources that can be reused across multiple sandboxes
18
+ */
19
+ export interface SharedResources {
20
+ /**
21
+ * Pre-loaded TypeScript lib files for type checking
22
+ */
23
+ libFiles: Map<string, string>;
24
+ /**
25
+ * Promise that resolves when the bundler is ready
26
+ */
27
+ bundlerReady: Promise<void>;
28
+ /**
29
+ * Cache for package type definitions.
30
+ * Avoids redundant network fetches when multiple sandboxes
31
+ * install the same packages.
32
+ */
33
+ typesCache: TypesCache;
34
+ }
35
+ /**
36
+ * Options for creating shared resources
37
+ */
38
+ export interface SharedResourcesOptions {
39
+ /**
40
+ * TypeScript libs to load. Defaults to browser libs (ES2020 + DOM).
41
+ */
42
+ libs?: string[];
43
+ /**
44
+ * If true, skip fetching TypeScript libs.
45
+ * libFiles will be an empty Map.
46
+ * Default: false
47
+ */
48
+ skipLibs?: boolean;
49
+ /**
50
+ * If true, skip pre-initializing the bundler.
51
+ * bundlerReady will resolve immediately.
52
+ * Default: false
53
+ */
54
+ skipBundler?: boolean;
55
+ }
56
+ /**
57
+ * Create a new SharedResources instance.
58
+ *
59
+ * Use this when you want to manage resource lifecycle explicitly,
60
+ * or when you need custom libs configuration.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * // Create resources with custom libs
65
+ * const resources = await createSharedResources({
66
+ * libs: ['es2022', 'dom', 'webworker'],
67
+ * });
68
+ *
69
+ * // Pass to sandbox creation
70
+ * const sandbox = await createSandbox({
71
+ * resources,
72
+ * fsOptions: { ... },
73
+ * });
74
+ * ```
75
+ */
76
+ export declare function createSharedResources(options?: SharedResourcesOptions): Promise<SharedResources>;
77
+ /**
78
+ * Get the default shared resources singleton.
79
+ *
80
+ * Loads resources once and returns the same instance for all callers.
81
+ * This is the recommended way to get shared resources for most use cases.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * // Get default resources (creates on first call)
86
+ * const resources = await getDefaultResources();
87
+ *
88
+ * // Create multiple sandboxes sharing the same resources
89
+ * const sandbox1 = await createSandbox({ resources, ... });
90
+ * const sandbox2 = await createSandbox({ resources, ... });
91
+ * ```
92
+ */
93
+ export declare function getDefaultResources(): Promise<SharedResources>;
94
+ /**
95
+ * Clear the default resources singleton (for testing).
96
+ *
97
+ * Note: This doesn't unload the bundler WASM - that stays in memory
98
+ * until page reload. This only clears the cached lib files reference.
99
+ */
100
+ export declare function clearDefaultResources(): void;
101
+ /**
102
+ * Check if the default resources have been initialized.
103
+ */
104
+ export declare function hasDefaultResources(): boolean;
105
+ //# sourceMappingURL=shared-resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-resources.d.ts","sourceRoot":"","sources":["../src/shared-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAGjE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE9B;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;;;OAIG;IACH,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,CAAC,CAqB1B;AAWD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,eAAe,CAAC,CAapE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C"}