sandlot 0.1.1 → 0.1.3

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 (59) hide show
  1. package/README.md +145 -518
  2. package/dist/build-emitter.d.ts +47 -0
  3. package/dist/build-emitter.d.ts.map +1 -0
  4. package/dist/builder.d.ts +370 -0
  5. package/dist/builder.d.ts.map +1 -0
  6. package/dist/bundler.d.ts +3 -3
  7. package/dist/bundler.d.ts.map +1 -1
  8. package/dist/commands/compile.d.ts +13 -0
  9. package/dist/commands/compile.d.ts.map +1 -0
  10. package/dist/commands/index.d.ts +17 -0
  11. package/dist/commands/index.d.ts.map +1 -0
  12. package/dist/commands/packages.d.ts +17 -0
  13. package/dist/commands/packages.d.ts.map +1 -0
  14. package/dist/commands/run.d.ts +40 -0
  15. package/dist/commands/run.d.ts.map +1 -0
  16. package/dist/commands/types.d.ts +141 -0
  17. package/dist/commands/types.d.ts.map +1 -0
  18. package/dist/fs.d.ts +60 -42
  19. package/dist/fs.d.ts.map +1 -1
  20. package/dist/index.d.ts +5 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +304 -491
  23. package/dist/internal.d.ts +5 -0
  24. package/dist/internal.d.ts.map +1 -1
  25. package/dist/internal.js +174 -95
  26. package/dist/runner.d.ts +314 -0
  27. package/dist/runner.d.ts.map +1 -0
  28. package/dist/sandbox-manager.d.ts +45 -33
  29. package/dist/sandbox-manager.d.ts.map +1 -1
  30. package/dist/sandbox.d.ts +144 -70
  31. package/dist/sandbox.d.ts.map +1 -1
  32. package/dist/shared-modules.d.ts +22 -3
  33. package/dist/shared-modules.d.ts.map +1 -1
  34. package/dist/shared-resources.d.ts +0 -3
  35. package/dist/shared-resources.d.ts.map +1 -1
  36. package/dist/typechecker.d.ts +1 -1
  37. package/package.json +3 -17
  38. package/src/build-emitter.ts +64 -0
  39. package/src/builder.ts +498 -0
  40. package/src/bundler.ts +86 -57
  41. package/src/commands/compile.ts +236 -0
  42. package/src/commands/index.ts +51 -0
  43. package/src/commands/packages.ts +154 -0
  44. package/src/commands/run.ts +245 -0
  45. package/src/commands/types.ts +172 -0
  46. package/src/fs.ts +90 -216
  47. package/src/index.ts +34 -12
  48. package/src/internal.ts +5 -2
  49. package/src/sandbox.ts +214 -220
  50. package/src/shared-modules.ts +74 -4
  51. package/src/shared-resources.ts +0 -3
  52. package/src/ts-libs.ts +1 -1
  53. package/src/typechecker.ts +1 -1
  54. package/dist/react.d.ts +0 -159
  55. package/dist/react.d.ts.map +0 -1
  56. package/dist/react.js +0 -149
  57. package/src/commands.ts +0 -733
  58. package/src/react.tsx +0 -331
  59. package/src/sandbox-manager.ts +0 -490
package/dist/index.js CHANGED
@@ -7,47 +7,14 @@ var DEFAULT_DIR_MODE = 493;
7
7
  var DEFAULT_SYMLINK_MODE = 511;
8
8
  var DEFAULT_MAX_SIZE_BYTES = 50 * 1024 * 1024;
9
9
 
10
- class IndexedDbFs {
10
+ class Filesystem {
11
11
  entries;
12
- db = null;
13
- dbName;
14
12
  maxSizeBytes;
15
- dirty = false;
16
- constructor(entries, db, dbName, maxSizeBytes) {
13
+ constructor(entries, maxSizeBytes) {
17
14
  this.entries = entries;
18
- this.db = db;
19
- this.dbName = dbName;
20
15
  this.maxSizeBytes = maxSizeBytes;
21
16
  }
22
- static async create(options = {}) {
23
- const dbName = options.dbName ?? "sandlot-fs";
24
- const maxSizeBytes = options.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES;
25
- const db = await IndexedDbFs.openDatabase(dbName);
26
- const entries = await IndexedDbFs.loadEntries(db);
27
- if (entries.size === 0) {
28
- entries.set("/", {
29
- type: "directory",
30
- mode: DEFAULT_DIR_MODE,
31
- mtime: new Date
32
- });
33
- if (options.initialFiles) {
34
- for (const [path, value] of Object.entries(options.initialFiles)) {
35
- const normalizedPath = IndexedDbFs.normalizePath(path);
36
- const init = IndexedDbFs.parseFileInit(value);
37
- IndexedDbFs.ensureParentDirs(entries, normalizedPath);
38
- entries.set(normalizedPath, {
39
- type: "file",
40
- content: init.content,
41
- mode: init.mode ?? DEFAULT_FILE_MODE,
42
- mtime: init.mtime ?? new Date
43
- });
44
- }
45
- }
46
- }
47
- const fs = new IndexedDbFs(entries, db, dbName, maxSizeBytes);
48
- return fs;
49
- }
50
- static createInMemory(options = {}) {
17
+ static create(options = {}) {
51
18
  const maxSizeBytes = options.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES;
52
19
  const entries = new Map;
53
20
  entries.set("/", {
@@ -57,9 +24,9 @@ class IndexedDbFs {
57
24
  });
58
25
  if (options.initialFiles) {
59
26
  for (const [path, value] of Object.entries(options.initialFiles)) {
60
- const normalizedPath = IndexedDbFs.normalizePath(path);
61
- const init = IndexedDbFs.parseFileInit(value);
62
- IndexedDbFs.ensureParentDirs(entries, normalizedPath);
27
+ const normalizedPath = Filesystem.normalizePath(path);
28
+ const init = Filesystem.parseFileInit(value);
29
+ Filesystem.ensureParentDirs(entries, normalizedPath);
63
30
  entries.set(normalizedPath, {
64
31
  type: "file",
65
32
  content: init.content,
@@ -68,31 +35,21 @@ class IndexedDbFs {
68
35
  });
69
36
  }
70
37
  }
71
- return new IndexedDbFs(entries, null, "", maxSizeBytes);
38
+ return new Filesystem(entries, maxSizeBytes);
72
39
  }
73
- async save() {
74
- if (!this.db || !this.dirty) {
75
- return false;
76
- }
77
- const tx = this.db.transaction("entries", "readwrite");
78
- const store = tx.objectStore("entries");
79
- await this.promisifyRequest(store.clear());
40
+ getFiles() {
41
+ const files = {};
80
42
  for (const [path, entry] of this.entries) {
81
- store.put({ path, entry: this.serializeEntry(entry) });
82
- }
83
- await this.promisifyTransaction(tx);
84
- this.dirty = false;
85
- return true;
86
- }
87
- async reload() {
88
- if (!this.db) {
89
- return;
43
+ if (entry.type === "file") {
44
+ if (typeof entry.content === "string") {
45
+ files[path] = entry.content;
46
+ } else {
47
+ const base64 = this.encodeBase64(entry.content);
48
+ files[path] = `data:application/octet-stream;base64,${base64}`;
49
+ }
50
+ }
90
51
  }
91
- this.entries = await IndexedDbFs.loadEntries(this.db);
92
- this.dirty = false;
93
- }
94
- isDirty() {
95
- return this.dirty;
52
+ return files;
96
53
  }
97
54
  getSize() {
98
55
  let size = 0;
@@ -108,12 +65,6 @@ class IndexedDbFs {
108
65
  }
109
66
  return size;
110
67
  }
111
- close() {
112
- if (this.db) {
113
- this.db.close();
114
- this.db = null;
115
- }
116
- }
117
68
  async readFile(path, options) {
118
69
  const normalizedPath = this.normalizePath(path);
119
70
  const entry = this.resolveSymlinks(normalizedPath);
@@ -145,7 +96,7 @@ class IndexedDbFs {
145
96
  }
146
97
  return new TextEncoder().encode(content);
147
98
  }
148
- async writeFile(path, content, options) {
99
+ async writeFile(path, content, _options) {
149
100
  const normalizedPath = this.normalizePath(path);
150
101
  this.checkSizeLimit(content);
151
102
  this.ensureParentDirs(normalizedPath);
@@ -159,7 +110,6 @@ class IndexedDbFs {
159
110
  mode: existing?.mode ?? DEFAULT_FILE_MODE,
160
111
  mtime: new Date
161
112
  });
162
- this.dirty = true;
163
113
  }
164
114
  async appendFile(path, content, options) {
165
115
  const normalizedPath = this.normalizePath(path);
@@ -211,7 +161,6 @@ class IndexedDbFs {
211
161
  mode: DEFAULT_DIR_MODE,
212
162
  mtime: new Date
213
163
  });
214
- this.dirty = true;
215
164
  }
216
165
  async readdir(path) {
217
166
  const normalizedPath = this.normalizePath(path);
@@ -287,7 +236,6 @@ class IndexedDbFs {
287
236
  }
288
237
  }
289
238
  this.entries.delete(normalizedPath);
290
- this.dirty = true;
291
239
  }
292
240
  async cp(src, dest, options) {
293
241
  const srcPath = this.normalizePath(src);
@@ -314,7 +262,6 @@ class IndexedDbFs {
314
262
  this.ensureParentDirs(destPath);
315
263
  this.entries.set(destPath, this.cloneEntry(entry));
316
264
  }
317
- this.dirty = true;
318
265
  }
319
266
  async mv(src, dest) {
320
267
  const srcPath = this.normalizePath(src);
@@ -341,7 +288,6 @@ class IndexedDbFs {
341
288
  this.entries.delete(srcPath);
342
289
  this.entries.set(destPath, entry);
343
290
  }
344
- this.dirty = true;
345
291
  }
346
292
  resolvePath(base, path) {
347
293
  if (path.startsWith("/")) {
@@ -371,7 +317,6 @@ class IndexedDbFs {
371
317
  }
372
318
  entry.mode = mode;
373
319
  entry.mtime = new Date;
374
- this.dirty = true;
375
320
  }
376
321
  async symlink(target, linkPath) {
377
322
  const normalizedLinkPath = this.normalizePath(linkPath);
@@ -385,7 +330,6 @@ class IndexedDbFs {
385
330
  mode: DEFAULT_SYMLINK_MODE,
386
331
  mtime: new Date
387
332
  });
388
- this.dirty = true;
389
333
  }
390
334
  async link(existingPath, newPath) {
391
335
  const srcPath = this.normalizePath(existingPath);
@@ -407,7 +351,6 @@ class IndexedDbFs {
407
351
  mode: entry.mode,
408
352
  mtime: new Date
409
353
  });
410
- this.dirty = true;
411
354
  }
412
355
  async readlink(path) {
413
356
  const normalizedPath = this.normalizePath(path);
@@ -453,10 +396,9 @@ class IndexedDbFs {
453
396
  throw new Error(`ENOENT: no such file or directory, utimes '${path}'`);
454
397
  }
455
398
  entry.mtime = mtime;
456
- this.dirty = true;
457
399
  }
458
400
  normalizePath(path) {
459
- return IndexedDbFs.normalizePath(path);
401
+ return Filesystem.normalizePath(path);
460
402
  }
461
403
  static normalizePath(path) {
462
404
  if (!path || path === ".")
@@ -484,8 +426,7 @@ class IndexedDbFs {
484
426
  return lastSlash === 0 ? "/" : path.slice(0, lastSlash);
485
427
  }
486
428
  ensureParentDirs(path) {
487
- IndexedDbFs.ensureParentDirs(this.entries, path);
488
- this.dirty = true;
429
+ Filesystem.ensureParentDirs(this.entries, path);
489
430
  }
490
431
  static ensureParentDirs(entries, path) {
491
432
  const parts = path.split("/").filter(Boolean);
@@ -562,17 +503,20 @@ class IndexedDbFs {
562
503
  return new TextDecoder("utf-8").decode(buffer);
563
504
  }
564
505
  if (encoding === "base64") {
565
- let binary = "";
566
- for (let i = 0;i < buffer.byteLength; i++) {
567
- binary += String.fromCharCode(buffer[i]);
568
- }
569
- return btoa(binary);
506
+ return this.encodeBase64(buffer);
570
507
  }
571
508
  if (encoding === "hex") {
572
509
  return Array.from(buffer).map((b) => b.toString(16).padStart(2, "0")).join("");
573
510
  }
574
511
  return new TextDecoder("utf-8").decode(buffer);
575
512
  }
513
+ encodeBase64(buffer) {
514
+ let binary = "";
515
+ for (let i = 0;i < buffer.byteLength; i++) {
516
+ binary += String.fromCharCode(buffer[i]);
517
+ }
518
+ return btoa(binary);
519
+ }
576
520
  concatBuffers(a, b) {
577
521
  const result = new Uint8Array(a.byteLength + b.byteLength);
578
522
  result.set(a, 0);
@@ -585,82 +529,11 @@ class IndexedDbFs {
585
529
  }
586
530
  return value;
587
531
  }
588
- static openDatabase(dbName) {
589
- return new Promise((resolve, reject) => {
590
- const request = indexedDB.open(dbName, 1);
591
- request.onerror = () => reject(request.error);
592
- request.onsuccess = () => resolve(request.result);
593
- request.onupgradeneeded = (event) => {
594
- const db = event.target.result;
595
- if (!db.objectStoreNames.contains("entries")) {
596
- db.createObjectStore("entries", { keyPath: "path" });
597
- }
598
- };
599
- });
600
- }
601
- static async loadEntries(db) {
602
- const tx = db.transaction("entries", "readonly");
603
- const store = tx.objectStore("entries");
604
- return new Promise((resolve, reject) => {
605
- const request = store.getAll();
606
- request.onerror = () => reject(request.error);
607
- request.onsuccess = () => {
608
- const entries = new Map;
609
- for (const record of request.result) {
610
- entries.set(record.path, IndexedDbFs.deserializeEntry(record.entry));
611
- }
612
- resolve(entries);
613
- };
614
- });
615
- }
616
- serializeEntry(entry) {
617
- if (entry.type === "file" && entry.content instanceof Uint8Array) {
618
- return {
619
- ...entry,
620
- content: Array.from(entry.content),
621
- contentType: "uint8array",
622
- mtime: entry.mtime.toISOString()
623
- };
624
- }
625
- return {
626
- ...entry,
627
- mtime: entry.mtime.toISOString()
628
- };
629
- }
630
- static deserializeEntry(data) {
631
- const mtime = new Date(data.mtime);
632
- if (data.type === "file") {
633
- let content = data.content;
634
- if (data.contentType === "uint8array" && Array.isArray(content)) {
635
- content = new Uint8Array(content);
636
- }
637
- return { type: "file", content, mode: data.mode, mtime };
638
- }
639
- if (data.type === "symlink") {
640
- return { type: "symlink", target: data.target, mode: data.mode, mtime };
641
- }
642
- return { type: "directory", mode: data.mode, mtime };
643
- }
644
- promisifyRequest(request) {
645
- return new Promise((resolve, reject) => {
646
- request.onerror = () => reject(request.error);
647
- request.onsuccess = () => resolve(request.result);
648
- });
649
- }
650
- promisifyTransaction(tx) {
651
- return new Promise((resolve, reject) => {
652
- tx.onerror = () => reject(tx.error);
653
- tx.oncomplete = () => resolve();
654
- });
655
- }
656
532
  }
657
- function createIndexedDbFs(initialFiles) {
658
- return IndexedDbFs.createInMemory({ initialFiles });
533
+ function createFilesystem(options) {
534
+ return Filesystem.create(options);
659
535
  }
660
536
 
661
- // src/bundler.ts
662
- import * as esbuild from "esbuild-wasm";
663
-
664
537
  // src/packages.ts
665
538
  var ESM_CDN_BASE = "https://esm.sh";
666
539
  var KNOWN_SUBPATHS = {
@@ -1125,16 +998,18 @@ var GLOBAL_KEY = "__sandlot_shared_modules__";
1125
998
 
1126
999
  class SharedModuleRegistry {
1127
1000
  modules = new Map;
1001
+ exportNames = new Map;
1128
1002
  constructor() {
1129
1003
  globalThis[GLOBAL_KEY] = this;
1130
1004
  }
1131
1005
  register(moduleId, module) {
1132
1006
  this.modules.set(moduleId, module);
1007
+ this.exportNames.set(moduleId, introspectExports(module));
1133
1008
  return this;
1134
1009
  }
1135
1010
  registerAll(modules) {
1136
1011
  for (const [id, mod] of Object.entries(modules)) {
1137
- this.modules.set(id, mod);
1012
+ this.register(id, mod);
1138
1013
  }
1139
1014
  return this;
1140
1015
  }
@@ -1155,13 +1030,44 @@ class SharedModuleRegistry {
1155
1030
  list() {
1156
1031
  return [...this.modules.keys()];
1157
1032
  }
1033
+ getExportNames(moduleId) {
1034
+ return this.exportNames.get(moduleId) ?? [];
1035
+ }
1158
1036
  clear() {
1159
1037
  this.modules.clear();
1038
+ this.exportNames.clear();
1160
1039
  }
1161
1040
  get size() {
1162
1041
  return this.modules.size;
1163
1042
  }
1164
1043
  }
1044
+ function introspectExports(module) {
1045
+ if (module === null || module === undefined) {
1046
+ return [];
1047
+ }
1048
+ if (typeof module !== "object" && typeof module !== "function") {
1049
+ return [];
1050
+ }
1051
+ const exports = [];
1052
+ for (const key of Object.keys(module)) {
1053
+ if (isValidIdentifier(key)) {
1054
+ exports.push(key);
1055
+ }
1056
+ }
1057
+ return exports;
1058
+ }
1059
+ function isValidIdentifier(name) {
1060
+ if (name.length === 0)
1061
+ return false;
1062
+ if (!/^[a-zA-Z_$]/.test(name))
1063
+ return false;
1064
+ if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))
1065
+ return false;
1066
+ const reserved = ["default", "class", "function", "var", "let", "const", "import", "export"];
1067
+ if (reserved.includes(name))
1068
+ return false;
1069
+ return true;
1070
+ }
1165
1071
  var defaultRegistry = null;
1166
1072
  function getSharedModuleRegistry() {
1167
1073
  if (!defaultRegistry) {
@@ -1181,6 +1087,9 @@ function unregisterSharedModule(moduleId) {
1181
1087
  function clearSharedModules() {
1182
1088
  getSharedModuleRegistry().clear();
1183
1089
  }
1090
+ function getSharedModuleExports(moduleId) {
1091
+ return getSharedModuleRegistry().getExportNames(moduleId);
1092
+ }
1184
1093
  function getSharedModuleRuntimeCode(moduleId) {
1185
1094
  return `
1186
1095
  (function() {
@@ -1197,11 +1106,35 @@ function getSharedModuleRuntimeCode(moduleId) {
1197
1106
  }
1198
1107
 
1199
1108
  // src/bundler.ts
1109
+ var esbuild = null;
1110
+ async function getEsbuild() {
1111
+ if (esbuild)
1112
+ return esbuild;
1113
+ const cdnUrl = `https://esm.sh/esbuild-wasm@${ESBUILD_VERSION}`;
1114
+ const mod = await import(cdnUrl);
1115
+ esbuild = mod.default ?? mod;
1116
+ if (typeof esbuild?.initialize !== "function") {
1117
+ console.error("esbuild-wasm module structure:", mod);
1118
+ throw new Error("Failed to load esbuild-wasm: initialize function not found");
1119
+ }
1120
+ return esbuild;
1121
+ }
1122
+ var ESBUILD_VERSION = "0.27.2";
1200
1123
  var initialized = false;
1201
1124
  var initPromise = null;
1202
1125
  function getWasmUrl() {
1203
- const version = "0.27.2";
1204
- return `https://unpkg.com/esbuild-wasm@${version}/esbuild.wasm`;
1126
+ return `https://unpkg.com/esbuild-wasm@${ESBUILD_VERSION}/esbuild.wasm`;
1127
+ }
1128
+ function checkCrossOriginIsolation() {
1129
+ if (typeof window === "undefined")
1130
+ return;
1131
+ if (!window.crossOriginIsolated) {
1132
+ console.warn(`[sandlot] Cross-origin isolation is not enabled. esbuild-wasm may have reduced performance or fail on some browsers.
1133
+ To enable, add these headers to your dev server:
1134
+ Cross-Origin-Embedder-Policy: require-corp
1135
+ Cross-Origin-Opener-Policy: same-origin
1136
+ In Vite, add a plugin to configureServer. See sandlot README for details.`);
1137
+ }
1205
1138
  }
1206
1139
  async function initBundler() {
1207
1140
  if (initialized)
@@ -1210,9 +1143,13 @@ async function initBundler() {
1210
1143
  await initPromise;
1211
1144
  return;
1212
1145
  }
1213
- initPromise = esbuild.initialize({
1214
- wasmURL: getWasmUrl()
1215
- });
1146
+ checkCrossOriginIsolation();
1147
+ initPromise = (async () => {
1148
+ const es = await getEsbuild();
1149
+ await es.initialize({
1150
+ wasmURL: getWasmUrl()
1151
+ });
1152
+ })();
1216
1153
  await initPromise;
1217
1154
  initialized = true;
1218
1155
  }
@@ -1263,8 +1200,8 @@ function createVfsPlugin(options) {
1263
1200
  } = options;
1264
1201
  return {
1265
1202
  name: "virtual-fs",
1266
- setup(build2) {
1267
- build2.onResolve({ filter: /.*/ }, async (args) => {
1203
+ setup(build) {
1204
+ build.onResolve({ filter: /.*/ }, async (args) => {
1268
1205
  if (args.kind === "entry-point") {
1269
1206
  return { path: entryPoint, namespace: "vfs" };
1270
1207
  }
@@ -1320,28 +1257,18 @@ function createVfsPlugin(options) {
1320
1257
  }
1321
1258
  return { errors: [{ text: `Cannot resolve: ${args.path} from ${args.resolveDir}` }] };
1322
1259
  });
1323
- build2.onLoad({ filter: /.*/, namespace: "sandlot-shared" }, (args) => {
1324
- const contents = `export default ${getSharedModuleRuntimeCode(args.path)};
1325
- export * from ${JSON.stringify(args.path)};
1326
- // Re-export all named exports by importing from registry
1327
- const __mod__ = ${getSharedModuleRuntimeCode(args.path)};
1328
- for (const __k__ in __mod__) {
1329
- if (__k__ !== 'default') Object.defineProperty(exports, __k__, {
1330
- enumerable: true,
1331
- get: function() { return __mod__[__k__]; }
1332
- });
1333
- }`;
1334
- const esmContents = `
1260
+ build.onLoad({ filter: /.*/, namespace: "sandlot-shared" }, (args) => {
1261
+ const contents = `
1335
1262
  const __sandlot_mod__ = ${getSharedModuleRuntimeCode(args.path)};
1336
1263
  export default __sandlot_mod__.default ?? __sandlot_mod__;
1337
1264
  ${generateNamedExports(args.path)}
1338
1265
  `;
1339
1266
  return {
1340
- contents: esmContents.trim(),
1267
+ contents: contents.trim(),
1341
1268
  loader: "js"
1342
1269
  };
1343
1270
  });
1344
- build2.onLoad({ filter: /.*/, namespace: "vfs" }, async (args) => {
1271
+ build.onLoad({ filter: /.*/, namespace: "vfs" }, async (args) => {
1345
1272
  try {
1346
1273
  const contents = await fs.readFile(args.path);
1347
1274
  includedFiles.add(args.path);
@@ -1360,55 +1287,12 @@ ${generateNamedExports(args.path)}
1360
1287
  };
1361
1288
  }
1362
1289
  function generateNamedExports(moduleId) {
1363
- const knownExports = {
1364
- react: [
1365
- "useState",
1366
- "useEffect",
1367
- "useContext",
1368
- "useReducer",
1369
- "useCallback",
1370
- "useMemo",
1371
- "useRef",
1372
- "useImperativeHandle",
1373
- "useLayoutEffect",
1374
- "useDebugValue",
1375
- "useDeferredValue",
1376
- "useTransition",
1377
- "useId",
1378
- "useSyncExternalStore",
1379
- "useInsertionEffect",
1380
- "useOptimistic",
1381
- "useActionState",
1382
- "createElement",
1383
- "cloneElement",
1384
- "createContext",
1385
- "forwardRef",
1386
- "lazy",
1387
- "memo",
1388
- "startTransition",
1389
- "Children",
1390
- "Component",
1391
- "PureComponent",
1392
- "Fragment",
1393
- "Profiler",
1394
- "StrictMode",
1395
- "Suspense",
1396
- "version",
1397
- "isValidElement"
1398
- ],
1399
- "react-dom": ["createPortal", "flushSync", "version"],
1400
- "react-dom/client": ["createRoot", "hydrateRoot"],
1401
- "react-dom/server": ["renderToString", "renderToStaticMarkup", "renderToPipeableStream"]
1402
- };
1403
- const exports = knownExports[moduleId];
1404
- if (!exports) {
1405
- return `
1406
- // Dynamic re-export for unknown module
1407
- export const __moduleProxy__ = __sandlot_mod__;
1408
- `;
1409
- }
1410
- return exports.map((name) => `export const ${name} = __sandlot_mod__.${name};`).join(`
1290
+ const exports = getSharedModuleExports(moduleId);
1291
+ if (exports.length > 0) {
1292
+ return exports.map((name) => `export const ${name} = __sandlot_mod__.${name};`).join(`
1411
1293
  `);
1294
+ }
1295
+ return `// No exports discovered for "${moduleId}" - use default import or call registerSharedModules() first`;
1412
1296
  }
1413
1297
  async function bundle(options) {
1414
1298
  await initBundler();
@@ -1440,7 +1324,8 @@ async function bundle(options) {
1440
1324
  includedFiles,
1441
1325
  sharedModuleIds
1442
1326
  });
1443
- const result = await esbuild.build({
1327
+ const es = await getEsbuild();
1328
+ const result = await es.build({
1444
1329
  entryPoints: [normalizedEntry],
1445
1330
  bundle: true,
1446
1331
  write: false,
@@ -1450,7 +1335,8 @@ async function bundle(options) {
1450
1335
  globalName,
1451
1336
  target,
1452
1337
  external,
1453
- plugins: [plugin]
1338
+ plugins: [plugin],
1339
+ jsx: "automatic"
1454
1340
  });
1455
1341
  const code = result.outputFiles?.[0]?.text ?? "";
1456
1342
  return {
@@ -1473,7 +1359,21 @@ async function bundleAndImport(options) {
1473
1359
  }
1474
1360
  }
1475
1361
 
1476
- // src/commands.ts
1362
+ // src/commands/types.ts
1363
+ function formatEsbuildMessages(messages) {
1364
+ if (messages.length === 0)
1365
+ return "";
1366
+ return messages.map((msg) => {
1367
+ if (msg.location) {
1368
+ const { file, line, column } = msg.location;
1369
+ const loc = file ? `${file}${line ? `:${line}` : ""}${column ? `:${column}` : ""}` : "";
1370
+ return loc ? `${loc}: ${msg.text}` : msg.text;
1371
+ }
1372
+ return msg.text;
1373
+ }).join(`
1374
+ `);
1375
+ }
1376
+ // src/commands/compile.ts
1477
1377
  import { defineCommand } from "just-bash/browser";
1478
1378
 
1479
1379
  // src/typechecker.ts
@@ -1864,20 +1764,7 @@ async function hasExport(result, exportName) {
1864
1764
  return exportName in module;
1865
1765
  }
1866
1766
 
1867
- // src/commands.ts
1868
- function formatEsbuildMessages(messages) {
1869
- if (messages.length === 0)
1870
- return "";
1871
- return messages.map((msg) => {
1872
- if (msg.location) {
1873
- const { file, line, column } = msg.location;
1874
- const loc = file ? `${file}${line ? `:${line}` : ""}${column ? `:${column}` : ""}` : "";
1875
- return loc ? `${loc}: ${msg.text}` : msg.text;
1876
- }
1877
- return msg.text;
1878
- }).join(`
1879
- `);
1880
- }
1767
+ // src/commands/compile.ts
1881
1768
  function createTscCommand(deps) {
1882
1769
  const { fs, libFiles, tsconfigPath } = deps;
1883
1770
  return defineCommand("tsc", async (args, _ctx) => {
@@ -1942,7 +1829,7 @@ ${formatDiagnosticsForAgent(result.diagnostics.filter((d) => d.category === "war
1942
1829
  });
1943
1830
  }
1944
1831
  function createBuildCommand(deps) {
1945
- const { fs, libFiles, tsconfigPath, onBuild, sharedModules } = deps;
1832
+ const { fs, libFiles, tsconfigPath, onBuild, getValidation, sharedModules } = deps;
1946
1833
  return defineCommand("build", async (args, _ctx) => {
1947
1834
  let entryPoint = null;
1948
1835
  let skipTypecheck = false;
@@ -2014,8 +1901,39 @@ ${formatted}
2014
1901
  minify,
2015
1902
  sharedModules
2016
1903
  });
1904
+ let loadedModule;
1905
+ try {
1906
+ loadedModule = await loadModule(bundleResult);
1907
+ } catch (err) {
1908
+ const errorMessage = err instanceof Error ? err.message : String(err);
1909
+ return {
1910
+ stdout: "",
1911
+ stderr: `Build failed: Module failed to load.
1912
+
1913
+ ${errorMessage}
1914
+ `,
1915
+ exitCode: 1
1916
+ };
1917
+ }
1918
+ const validateFn = getValidation?.();
1919
+ let validatedModule = loadedModule;
1920
+ if (validateFn) {
1921
+ try {
1922
+ validatedModule = validateFn(loadedModule);
1923
+ } catch (err) {
1924
+ const errorMessage = err instanceof Error ? err.message : String(err);
1925
+ return {
1926
+ stdout: "",
1927
+ stderr: `Build failed: Validation error.
1928
+
1929
+ ${errorMessage}
1930
+ `,
1931
+ exitCode: 1
1932
+ };
1933
+ }
1934
+ }
2017
1935
  if (onBuild) {
2018
- await onBuild(bundleResult);
1936
+ await onBuild({ bundle: bundleResult, module: validatedModule });
2019
1937
  }
2020
1938
  let output = `Build successful!
2021
1939
  `;
@@ -2031,6 +1949,15 @@ ${formatted}
2031
1949
  }
2032
1950
  output += `Bundled: ${bundleResult.includedFiles.length} file(s)
2033
1951
  `;
1952
+ const exportNames = Object.keys(loadedModule).filter((k) => !k.startsWith("__"));
1953
+ if (exportNames.length > 0) {
1954
+ output += `Exports: ${exportNames.join(", ")}
1955
+ `;
1956
+ }
1957
+ if (validateFn) {
1958
+ output += `Validation: passed
1959
+ `;
1960
+ }
2034
1961
  if (bundleResult.warnings.length > 0) {
2035
1962
  output += `
2036
1963
  Build warnings:
@@ -2062,9 +1989,11 @@ ${formatDiagnosticsForAgent(warnings)}
2062
1989
  }
2063
1990
  });
2064
1991
  }
1992
+ // src/commands/packages.ts
1993
+ import { defineCommand as defineCommand2 } from "just-bash/browser";
2065
1994
  function createInstallCommand(deps) {
2066
1995
  const { fs, typesCache } = deps;
2067
- return defineCommand("install", async (args, _ctx) => {
1996
+ return defineCommand2("install", async (args, _ctx) => {
2068
1997
  if (args.length === 0) {
2069
1998
  return {
2070
1999
  stdout: "",
@@ -2118,7 +2047,7 @@ Examples:
2118
2047
  }
2119
2048
  function createUninstallCommand(deps) {
2120
2049
  const { fs } = deps;
2121
- return defineCommand("uninstall", async (args, _ctx) => {
2050
+ return defineCommand2("uninstall", async (args, _ctx) => {
2122
2051
  if (args.length === 0) {
2123
2052
  return {
2124
2053
  stdout: "",
@@ -2163,7 +2092,7 @@ function createUninstallCommand(deps) {
2163
2092
  }
2164
2093
  function createListCommand(deps) {
2165
2094
  const { fs } = deps;
2166
- return defineCommand("list", async (_args, _ctx) => {
2095
+ return defineCommand2("list", async (_args, _ctx) => {
2167
2096
  try {
2168
2097
  const packages = await listPackages(fs);
2169
2098
  if (packages.length === 0) {
@@ -2193,9 +2122,11 @@ function createListCommand(deps) {
2193
2122
  }
2194
2123
  });
2195
2124
  }
2125
+ // src/commands/run.ts
2126
+ import { defineCommand as defineCommand3 } from "just-bash/browser";
2196
2127
  function createRunCommand(deps) {
2197
2128
  const { fs, libFiles, tsconfigPath, runOptions = {}, sharedModules } = deps;
2198
- return defineCommand("run", async (args, _ctx) => {
2129
+ return defineCommand3("run", async (args, _ctx) => {
2199
2130
  let entryPoint = null;
2200
2131
  let skipTypecheck = runOptions.skipTypecheck ?? false;
2201
2132
  let timeout = runOptions.timeout ?? 30000;
@@ -2372,6 +2303,7 @@ ${err.stack}` : "";
2372
2303
  }
2373
2304
  });
2374
2305
  }
2306
+ // src/commands/index.ts
2375
2307
  function createDefaultCommands(deps) {
2376
2308
  return [
2377
2309
  createTscCommand(deps),
@@ -2578,12 +2510,10 @@ function hasDefaultResources() {
2578
2510
  return defaultResourcesInstance !== null;
2579
2511
  }
2580
2512
 
2581
- // src/sandbox.ts
2513
+ // src/build-emitter.ts
2582
2514
  class BuildEmitter {
2583
2515
  listeners = new Set;
2584
- lastResult = null;
2585
2516
  emit = async (result) => {
2586
- this.lastResult = result;
2587
2517
  const promises = [];
2588
2518
  for (const listener of this.listeners) {
2589
2519
  const ret = listener(result);
@@ -2599,282 +2529,167 @@ class BuildEmitter {
2599
2529
  this.listeners.delete(callback);
2600
2530
  };
2601
2531
  }
2602
- waitFor() {
2603
- if (this.lastResult) {
2604
- const result = this.lastResult;
2605
- this.lastResult = null;
2606
- return Promise.resolve(result);
2607
- }
2608
- return new Promise((resolve) => {
2609
- const unsub = this.on((result) => {
2610
- unsub();
2611
- this.lastResult = null;
2612
- resolve(result);
2613
- });
2614
- });
2615
- }
2616
2532
  }
2533
+
2534
+ // src/sandbox.ts
2617
2535
  async function createSandbox(options = {}) {
2618
- const {
2619
- fsOptions = {},
2620
- tsconfigPath = "/tsconfig.json",
2621
- resources: providedResources,
2622
- onBuild: onBuildCallback,
2623
- customCommands = [],
2624
- sharedModules
2625
- } = options;
2626
- const fsPromise = IndexedDbFs.create(fsOptions);
2627
- const resourcesPromise = providedResources ? Promise.resolve(providedResources) : getDefaultResources();
2628
- const bundlerPromise = initBundler();
2629
- const [fs, resources] = await Promise.all([fsPromise, resourcesPromise, bundlerPromise]);
2630
- const libFiles = resources.libFiles;
2631
- const typesCache = resources.typesCache;
2632
- const buildEmitter = new BuildEmitter;
2633
- if (onBuildCallback) {
2634
- buildEmitter.on(onBuildCallback);
2635
- }
2636
- const commandDeps = {
2637
- fs,
2638
- libFiles,
2639
- tsconfigPath,
2640
- onBuild: buildEmitter.emit,
2641
- typesCache,
2642
- sharedModules
2643
- };
2644
- const defaultCommands = createDefaultCommands(commandDeps);
2645
- const bash = new Bash({
2646
- fs,
2647
- cwd: "/",
2648
- customCommands: [...defaultCommands, ...customCommands]
2649
- });
2650
- return {
2651
- fs,
2652
- bash,
2653
- isDirty: () => fs.isDirty(),
2654
- save: () => fs.save(),
2655
- close: () => fs.close(),
2656
- onBuild: (callback) => buildEmitter.on(callback)
2657
- };
2658
- }
2659
- async function createInMemorySandbox(options = {}) {
2660
2536
  const {
2661
2537
  initialFiles,
2538
+ maxFilesystemSize,
2662
2539
  tsconfigPath = "/tsconfig.json",
2663
2540
  resources: providedResources,
2664
2541
  onBuild: onBuildCallback,
2665
2542
  customCommands = [],
2666
- sharedModules
2543
+ sharedModules,
2544
+ bashOptions = {}
2667
2545
  } = options;
2546
+ const fs = Filesystem.create({
2547
+ initialFiles,
2548
+ maxSizeBytes: maxFilesystemSize
2549
+ });
2668
2550
  const resourcesPromise = providedResources ? Promise.resolve(providedResources) : getDefaultResources();
2669
2551
  const bundlerPromise = initBundler();
2670
- const fs = IndexedDbFs.createInMemory({ initialFiles });
2671
2552
  const [resources] = await Promise.all([resourcesPromise, bundlerPromise]);
2672
2553
  const libFiles = resources.libFiles;
2673
2554
  const typesCache = resources.typesCache;
2555
+ if (sharedModules && sharedModules.length > 0) {
2556
+ const basePackages = new Set;
2557
+ for (const moduleId of sharedModules) {
2558
+ const { packageName } = parseImportPath(moduleId);
2559
+ basePackages.add(packageName);
2560
+ }
2561
+ await Promise.all(Array.from(basePackages).map(async (packageName) => {
2562
+ try {
2563
+ await installPackage(fs, packageName, { cache: typesCache });
2564
+ } catch (err) {
2565
+ console.warn(`[sandlot] Failed to install types for shared module "${packageName}":`, err);
2566
+ }
2567
+ }));
2568
+ }
2674
2569
  const buildEmitter = new BuildEmitter;
2570
+ let lastBuild = null;
2571
+ buildEmitter.on((result) => {
2572
+ lastBuild = result;
2573
+ });
2675
2574
  if (onBuildCallback) {
2676
2575
  buildEmitter.on(onBuildCallback);
2677
2576
  }
2577
+ let validationFn = null;
2678
2578
  const commandDeps = {
2679
2579
  fs,
2680
2580
  libFiles,
2681
2581
  tsconfigPath,
2682
2582
  onBuild: buildEmitter.emit,
2583
+ getValidation: () => validationFn,
2683
2584
  typesCache,
2684
2585
  sharedModules
2685
2586
  };
2686
2587
  const defaultCommands = createDefaultCommands(commandDeps);
2687
2588
  const bash = new Bash({
2589
+ ...bashOptions,
2688
2590
  fs,
2689
- cwd: "/",
2690
2591
  customCommands: [...defaultCommands, ...customCommands]
2691
2592
  });
2692
2593
  return {
2693
2594
  fs,
2694
2595
  bash,
2695
- isDirty: () => fs.isDirty(),
2696
- save: () => Promise.resolve(false),
2697
- close: () => {},
2698
- onBuild: (callback) => buildEmitter.on(callback)
2699
- };
2700
- }
2701
- // src/sandbox-manager.ts
2702
- import { Bash as Bash2 } from "just-bash/browser";
2703
- class BuildEmitter2 {
2704
- listeners = new Set;
2705
- lastResult = null;
2706
- emit = async (result) => {
2707
- this.lastResult = result;
2708
- const promises = [];
2709
- for (const listener of this.listeners) {
2710
- const ret = listener(result);
2711
- if (ret instanceof Promise) {
2712
- promises.push(ret);
2713
- }
2596
+ get lastBuild() {
2597
+ return lastBuild;
2598
+ },
2599
+ getState: () => ({ files: fs.getFiles() }),
2600
+ onBuild: (callback) => buildEmitter.on(callback),
2601
+ setValidation: (fn) => {
2602
+ validationFn = fn;
2603
+ },
2604
+ clearValidation: () => {
2605
+ validationFn = null;
2714
2606
  }
2715
- await Promise.all(promises);
2716
2607
  };
2717
- on(callback) {
2718
- this.listeners.add(callback);
2719
- return () => {
2720
- this.listeners.delete(callback);
2721
- };
2722
- }
2723
- waitFor() {
2724
- if (this.lastResult) {
2725
- const result = this.lastResult;
2726
- this.lastResult = null;
2727
- return Promise.resolve(result);
2728
- }
2729
- return new Promise((resolve) => {
2730
- const unsub = this.on((result) => {
2731
- unsub();
2732
- this.lastResult = null;
2733
- resolve(result);
2734
- });
2735
- });
2736
- }
2737
2608
  }
2738
-
2739
- class SandboxManager {
2740
- resources = null;
2741
- sandboxes = new Map;
2742
- initialized = false;
2743
- initPromise = null;
2744
- nextId = 1;
2745
- options;
2746
- constructor(options = {}) {
2747
- this.options = {
2748
- libs: options.libs ?? getDefaultBrowserLibs(),
2749
- ...options
2750
- };
2751
- }
2752
- async initialize() {
2753
- if (this.initialized)
2754
- return;
2755
- if (this.initPromise) {
2756
- await this.initPromise;
2757
- return;
2758
- }
2759
- this.initPromise = this.doInitialize();
2760
- await this.initPromise;
2761
- this.initialized = true;
2762
- }
2763
- async doInitialize() {
2764
- this.resources = await createSharedResources({
2765
- libs: this.options.libs,
2766
- skipLibs: this.options.skipLibs,
2767
- skipBundler: this.options.skipBundler
2768
- });
2769
- }
2770
- async createSandbox(options = {}) {
2771
- await this.initialize();
2772
- const {
2773
- id = `sandbox-${this.nextId++}`,
2774
- fsOptions = {},
2775
- initialFiles,
2776
- tsconfigPath = "/tsconfig.json",
2777
- onBuild,
2778
- customCommands = [],
2779
- inMemory = true,
2780
- sharedModules = this.options.sharedModules
2781
- } = options;
2782
- let fs;
2783
- if (inMemory) {
2784
- fs = IndexedDbFs.createInMemory({
2785
- initialFiles,
2786
- maxSizeBytes: fsOptions.maxSizeBytes
2787
- });
2788
- } else {
2789
- fs = await IndexedDbFs.create({
2790
- dbName: fsOptions.dbName ?? id,
2791
- initialFiles,
2792
- maxSizeBytes: fsOptions.maxSizeBytes
2793
- });
2609
+ // src/builder.ts
2610
+ function createBuilder(options) {
2611
+ return async (prompt, callOptions) => {
2612
+ const sandbox = options.sandbox ?? await createSandbox(options.sandboxOptions);
2613
+ if (callOptions?.validate) {
2614
+ sandbox.setValidation(callOptions.validate);
2794
2615
  }
2795
- const buildEmitter = new BuildEmitter2;
2796
- if (onBuild) {
2797
- buildEmitter.on(onBuild);
2798
- }
2799
- const commandDeps = {
2800
- fs,
2801
- libFiles: this.resources.libFiles,
2802
- tsconfigPath,
2803
- onBuild: buildEmitter.emit,
2804
- typesCache: this.resources.typesCache,
2805
- sharedModules
2806
- };
2807
- const defaultCommands = createDefaultCommands(commandDeps);
2808
- const bash = new Bash2({
2809
- fs,
2810
- cwd: "/",
2811
- customCommands: [...defaultCommands, ...customCommands]
2616
+ const captured = { output: null };
2617
+ const unsubscribe = sandbox.onBuild((output) => {
2618
+ captured.output = output;
2812
2619
  });
2813
- const sandbox = {
2814
- id,
2815
- fs,
2816
- bash,
2817
- isDirty: () => fs.isDirty(),
2818
- save: () => fs.save(),
2819
- close: () => {
2820
- fs.close();
2821
- this.sandboxes.delete(id);
2822
- },
2823
- onBuild: (callback) => buildEmitter.on(callback)
2824
- };
2825
- this.sandboxes.set(id, sandbox);
2826
- return sandbox;
2827
- }
2828
- getSandbox(id) {
2829
- return this.sandboxes.get(id);
2830
- }
2831
- getAllSandboxes() {
2832
- return Array.from(this.sandboxes.values());
2833
- }
2834
- closeSandbox(id) {
2835
- const sandbox = this.sandboxes.get(id);
2836
- if (sandbox) {
2837
- sandbox.close();
2838
- return true;
2839
- }
2840
- return false;
2841
- }
2842
- destroyAll() {
2843
- for (const sandbox of this.sandboxes.values()) {
2844
- sandbox.fs.close();
2620
+ const { timeout, signal } = callOptions ?? {};
2621
+ let timeoutId;
2622
+ let abortController;
2623
+ if (timeout !== undefined || signal !== undefined) {
2624
+ abortController = new AbortController;
2625
+ if (timeout !== undefined) {
2626
+ timeoutId = setTimeout(() => {
2627
+ abortController.abort(new Error(`Build timed out after ${timeout}ms`));
2628
+ }, timeout);
2629
+ }
2630
+ if (signal !== undefined) {
2631
+ if (signal.aborted) {
2632
+ abortController.abort(signal.reason);
2633
+ } else {
2634
+ signal.addEventListener("abort", () => {
2635
+ abortController.abort(signal.reason);
2636
+ }, { once: true });
2637
+ }
2638
+ }
2845
2639
  }
2846
- this.sandboxes.clear();
2847
- }
2848
- async saveAll() {
2849
- const results = new Map;
2850
- for (const [id, sandbox] of this.sandboxes) {
2851
- const saved = await sandbox.save();
2852
- results.set(id, saved);
2640
+ let result;
2641
+ let error = null;
2642
+ try {
2643
+ const buildPromise = options.build(sandbox, prompt);
2644
+ if (abortController) {
2645
+ const abortPromise = new Promise((_, reject) => {
2646
+ abortController.signal.addEventListener("abort", () => {
2647
+ const err = abortController.signal.reason instanceof Error ? abortController.signal.reason : new Error("Build aborted");
2648
+ err.name = "AbortError";
2649
+ reject(err);
2650
+ }, { once: true });
2651
+ if (abortController.signal.aborted) {
2652
+ const err = abortController.signal.reason instanceof Error ? abortController.signal.reason : new Error("Build aborted");
2653
+ err.name = "AbortError";
2654
+ reject(err);
2655
+ }
2656
+ });
2657
+ result = await Promise.race([buildPromise, abortPromise]);
2658
+ } else {
2659
+ result = await buildPromise;
2660
+ }
2661
+ } catch (err) {
2662
+ error = err instanceof Error ? err : new Error(String(err));
2663
+ } finally {
2664
+ if (timeoutId !== undefined) {
2665
+ clearTimeout(timeoutId);
2666
+ }
2667
+ unsubscribe();
2668
+ if (callOptions?.validate) {
2669
+ sandbox.clearValidation();
2670
+ }
2853
2671
  }
2854
- return results;
2855
- }
2856
- getDirtySandboxes() {
2857
- return Array.from(this.sandboxes.entries()).filter(([_, sandbox]) => sandbox.isDirty()).map(([id]) => id);
2858
- }
2859
- getStats() {
2672
+ const buildOutput = captured.output;
2860
2673
  return {
2861
- initialized: this.initialized,
2862
- activeSandboxes: this.sandboxes.size,
2863
- libFilesCount: this.resources?.libFiles.size ?? 0,
2864
- sandboxIds: Array.from(this.sandboxes.keys())
2674
+ result,
2675
+ error,
2676
+ bundle: buildOutput?.bundle ?? null,
2677
+ module: buildOutput?.module ?? null,
2678
+ sandbox
2865
2679
  };
2866
- }
2867
- getResources() {
2868
- return this.resources;
2869
- }
2870
- getLibFiles() {
2871
- return this.resources?.libFiles ?? new Map;
2872
- }
2680
+ };
2873
2681
  }
2874
- async function createSandboxManager(options = {}) {
2875
- const manager = new SandboxManager(options);
2876
- await manager.initialize();
2877
- return manager;
2682
+
2683
+ // src/index.ts
2684
+ if (typeof window !== "undefined" && typeof globalThis.process === "undefined") {
2685
+ globalThis.process = {
2686
+ env: {},
2687
+ platform: "browser",
2688
+ version: "v20.0.0",
2689
+ browser: true,
2690
+ cwd: () => "/",
2691
+ nextTick: (fn) => setTimeout(fn, 0)
2692
+ };
2878
2693
  }
2879
2694
  export {
2880
2695
  unregisterSharedModule,
@@ -2899,22 +2714,20 @@ export {
2899
2714
  createUninstallCommand,
2900
2715
  createTscCommand,
2901
2716
  createSharedResources,
2902
- createSandboxManager,
2903
2717
  createSandbox,
2904
2718
  createRunCommand,
2905
2719
  createListCommand,
2906
2720
  createInstallCommand,
2907
- createIndexedDbFs,
2908
- createInMemorySandbox,
2721
+ createFilesystem,
2909
2722
  createDefaultCommands,
2723
+ createBuilder,
2910
2724
  createBuildCommand,
2911
2725
  clearSharedModules,
2912
2726
  clearDefaultResources,
2913
2727
  bundleToUrl,
2914
2728
  bundleAndImport,
2915
2729
  bundle,
2916
- SandboxManager,
2917
2730
  ModuleLoadError,
2918
- IndexedDbFs,
2731
+ Filesystem,
2919
2732
  ExportNotFoundError
2920
2733
  };