sandlot 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/internal.js CHANGED
@@ -1081,12 +1081,35 @@ function formatDiagnosticsForAgent(diagnostics) {
1081
1081
  }
1082
1082
 
1083
1083
  // src/bundler.ts
1084
- import * as esbuild from "esbuild-wasm";
1084
+ var esbuild = null;
1085
+ async function getEsbuild() {
1086
+ if (esbuild)
1087
+ return esbuild;
1088
+ const cdnUrl = `https://esm.sh/esbuild-wasm@${ESBUILD_VERSION}`;
1089
+ const mod = await import(cdnUrl);
1090
+ esbuild = mod.default ?? mod;
1091
+ if (typeof esbuild?.initialize !== "function") {
1092
+ console.error("esbuild-wasm module structure:", mod);
1093
+ throw new Error("Failed to load esbuild-wasm: initialize function not found");
1094
+ }
1095
+ return esbuild;
1096
+ }
1097
+ var ESBUILD_VERSION = "0.27.2";
1085
1098
  var initialized = false;
1086
1099
  var initPromise = null;
1087
1100
  function getWasmUrl() {
1088
- const version = "0.27.2";
1089
- return `https://unpkg.com/esbuild-wasm@${version}/esbuild.wasm`;
1101
+ return `https://unpkg.com/esbuild-wasm@${ESBUILD_VERSION}/esbuild.wasm`;
1102
+ }
1103
+ function checkCrossOriginIsolation() {
1104
+ if (typeof window === "undefined")
1105
+ return;
1106
+ if (!window.crossOriginIsolated) {
1107
+ console.warn(`[sandlot] Cross-origin isolation is not enabled. esbuild-wasm may have reduced performance or fail on some browsers.
1108
+ To enable, add these headers to your dev server:
1109
+ Cross-Origin-Embedder-Policy: require-corp
1110
+ Cross-Origin-Opener-Policy: same-origin
1111
+ In Vite, add a plugin to configureServer. See sandlot README for details.`);
1112
+ }
1090
1113
  }
1091
1114
  async function initBundler() {
1092
1115
  if (initialized)
@@ -1095,9 +1118,13 @@ async function initBundler() {
1095
1118
  await initPromise;
1096
1119
  return;
1097
1120
  }
1098
- initPromise = esbuild.initialize({
1099
- wasmURL: getWasmUrl()
1100
- });
1121
+ checkCrossOriginIsolation();
1122
+ initPromise = (async () => {
1123
+ const es = await getEsbuild();
1124
+ await es.initialize({
1125
+ wasmURL: getWasmUrl()
1126
+ });
1127
+ })();
1101
1128
  await initPromise;
1102
1129
  initialized = true;
1103
1130
  }
@@ -1148,8 +1175,8 @@ function createVfsPlugin(options) {
1148
1175
  } = options;
1149
1176
  return {
1150
1177
  name: "virtual-fs",
1151
- setup(build2) {
1152
- build2.onResolve({ filter: /.*/ }, async (args) => {
1178
+ setup(build) {
1179
+ build.onResolve({ filter: /.*/ }, async (args) => {
1153
1180
  if (args.kind === "entry-point") {
1154
1181
  return { path: entryPoint, namespace: "vfs" };
1155
1182
  }
@@ -1205,28 +1232,18 @@ function createVfsPlugin(options) {
1205
1232
  }
1206
1233
  return { errors: [{ text: `Cannot resolve: ${args.path} from ${args.resolveDir}` }] };
1207
1234
  });
1208
- build2.onLoad({ filter: /.*/, namespace: "sandlot-shared" }, (args) => {
1209
- const contents = `export default ${getSharedModuleRuntimeCode(args.path)};
1210
- export * from ${JSON.stringify(args.path)};
1211
- // Re-export all named exports by importing from registry
1212
- const __mod__ = ${getSharedModuleRuntimeCode(args.path)};
1213
- for (const __k__ in __mod__) {
1214
- if (__k__ !== 'default') Object.defineProperty(exports, __k__, {
1215
- enumerable: true,
1216
- get: function() { return __mod__[__k__]; }
1217
- });
1218
- }`;
1219
- const esmContents = `
1235
+ build.onLoad({ filter: /.*/, namespace: "sandlot-shared" }, (args) => {
1236
+ const contents = `
1220
1237
  const __sandlot_mod__ = ${getSharedModuleRuntimeCode(args.path)};
1221
1238
  export default __sandlot_mod__.default ?? __sandlot_mod__;
1222
1239
  ${generateNamedExports(args.path)}
1223
1240
  `;
1224
1241
  return {
1225
- contents: esmContents.trim(),
1242
+ contents: contents.trim(),
1226
1243
  loader: "js"
1227
1244
  };
1228
1245
  });
1229
- build2.onLoad({ filter: /.*/, namespace: "vfs" }, async (args) => {
1246
+ build.onLoad({ filter: /.*/, namespace: "vfs" }, async (args) => {
1230
1247
  try {
1231
1248
  const contents = await fs.readFile(args.path);
1232
1249
  includedFiles.add(args.path);
@@ -1325,7 +1342,8 @@ async function bundle(options) {
1325
1342
  includedFiles,
1326
1343
  sharedModuleIds
1327
1344
  });
1328
- const result = await esbuild.build({
1345
+ const es = await getEsbuild();
1346
+ const result = await es.build({
1329
1347
  entryPoints: [normalizedEntry],
1330
1348
  bundle: true,
1331
1349
  write: false,
@@ -1876,6 +1894,42 @@ function createDefaultCommands(deps) {
1876
1894
  createListCommand(deps)
1877
1895
  ];
1878
1896
  }
1897
+ // src/build-emitter.ts
1898
+ class BuildEmitter {
1899
+ listeners = new Set;
1900
+ lastResult = null;
1901
+ emit = async (result) => {
1902
+ this.lastResult = result;
1903
+ const promises = [];
1904
+ for (const listener of this.listeners) {
1905
+ const ret = listener(result);
1906
+ if (ret instanceof Promise) {
1907
+ promises.push(ret);
1908
+ }
1909
+ }
1910
+ await Promise.all(promises);
1911
+ };
1912
+ on(callback) {
1913
+ this.listeners.add(callback);
1914
+ return () => {
1915
+ this.listeners.delete(callback);
1916
+ };
1917
+ }
1918
+ waitFor() {
1919
+ if (this.lastResult) {
1920
+ const result = this.lastResult;
1921
+ this.lastResult = null;
1922
+ return Promise.resolve(result);
1923
+ }
1924
+ return new Promise((resolve) => {
1925
+ const unsub = this.on((result) => {
1926
+ unsub();
1927
+ this.lastResult = null;
1928
+ resolve(result);
1929
+ });
1930
+ });
1931
+ }
1932
+ }
1879
1933
  export {
1880
1934
  revokeModuleUrl,
1881
1935
  resolveToEsmUrl,
@@ -1893,5 +1947,6 @@ export {
1893
1947
  createModuleUrl,
1894
1948
  SharedModuleRegistry,
1895
1949
  LibCache,
1896
- InMemoryTypesCache
1950
+ InMemoryTypesCache,
1951
+ BuildEmitter
1897
1952
  };
@@ -26,13 +26,6 @@ import { type IndexedDbFsOptions } from "./fs";
26
26
  import { type BundleResult } from "./bundler";
27
27
  import { type SharedResources, type SharedResourcesOptions } from "./shared-resources";
28
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
29
  /**
37
30
  * Options for creating a sandbox via the manager
38
31
  */
@@ -216,11 +209,6 @@ export declare class SandboxManager {
216
209
  * Get the shared resources (for advanced use cases)
217
210
  */
218
211
  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
212
  }
225
213
  /**
226
214
  * Create a new SandboxManager instance.
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox-manager.d.ts","sourceRoot":"","sources":["../src/sandbox-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandbox-manager.d.ts","sourceRoot":"","sources":["../src/sandbox-manager.ts"],"names":[],"mappings":"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"}
package/dist/sandbox.d.ts CHANGED
@@ -2,14 +2,6 @@ import { Bash, defineCommand } from "just-bash/browser";
2
2
  import { IndexedDbFs, type IndexedDbFsOptions } from "./fs";
3
3
  import { type BundleResult } from "./bundler";
4
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
5
  /**
14
6
  * Options for creating a sandbox environment
15
7
  */
@@ -1 +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"}
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;;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandlot",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Browser-based TypeScript sandbox with esbuild bundling and type checking",
5
5
  "author": "blindmansion",
6
6
  "license": "MIT",
@@ -22,11 +22,6 @@
22
22
  "import": "./dist/index.js",
23
23
  "default": "./dist/index.js"
24
24
  },
25
- "./react": {
26
- "types": "./dist/react.d.ts",
27
- "import": "./dist/react.js",
28
- "default": "./dist/react.js"
29
- },
30
25
  "./internal": {
31
26
  "types": "./dist/internal.d.ts",
32
27
  "import": "./dist/internal.js",
@@ -39,7 +34,7 @@
39
34
  ],
40
35
  "scripts": {
41
36
  "build": "bun run build:js && bun run build:types",
42
- "build:js": "bun build ./src/index.ts ./src/react.tsx ./src/internal.ts --outdir ./dist --format esm --packages external",
37
+ "build:js": "bun build ./src/index.ts ./src/internal.ts --outdir ./dist --format esm --packages external",
43
38
  "build:types": "tsc --emitDeclarationOnly",
44
39
  "prepublishOnly": "bun run build"
45
40
  },
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Build event emitter for sandbox environments.
3
+ *
4
+ * Simple typed event emitter for build results.
5
+ * Caches the last result so waitFor() can be called after build completes.
6
+ */
7
+
8
+ import type { BundleResult } from "./bundler";
9
+
10
+ /**
11
+ * Simple typed event emitter for build results.
12
+ * Caches the last result so waitFor() can be called after build completes.
13
+ */
14
+ export class BuildEmitter {
15
+ private listeners = new Set<(result: BundleResult) => void | Promise<void>>();
16
+ private lastResult: BundleResult | null = null;
17
+
18
+ /**
19
+ * Emit a build result to all listeners and cache it
20
+ */
21
+ emit = async (result: BundleResult): Promise<void> => {
22
+ this.lastResult = result;
23
+ const promises: Promise<void>[] = [];
24
+ for (const listener of this.listeners) {
25
+ const ret = listener(result);
26
+ if (ret instanceof Promise) {
27
+ promises.push(ret);
28
+ }
29
+ }
30
+ await Promise.all(promises);
31
+ };
32
+
33
+ /**
34
+ * Subscribe to build events. Returns an unsubscribe function.
35
+ */
36
+ on(callback: (result: BundleResult) => void | Promise<void>): () => void {
37
+ this.listeners.add(callback);
38
+ return () => {
39
+ this.listeners.delete(callback);
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Get the last build result, or wait for the next one if none exists.
45
+ * Clears the cached result after returning, so subsequent calls wait for new builds.
46
+ */
47
+ waitFor(): Promise<BundleResult> {
48
+ if (this.lastResult) {
49
+ const result = this.lastResult;
50
+ this.lastResult = null;
51
+ return Promise.resolve(result);
52
+ }
53
+ return new Promise((resolve) => {
54
+ const unsub = this.on((result) => {
55
+ unsub();
56
+ this.lastResult = null;
57
+ resolve(result);
58
+ });
59
+ });
60
+ }
61
+ }
package/src/bundler.ts CHANGED
@@ -1,8 +1,33 @@
1
1
  import type { IFileSystem } from "just-bash/browser";
2
- import * as esbuild from "esbuild-wasm";
2
+ import type * as EsbuildTypes from "esbuild-wasm";
3
3
  import { getPackageManifest, resolveToEsmUrl } from "./packages";
4
4
  import { getSharedModuleRuntimeCode } from "./shared-modules";
5
5
 
6
+ // Lazily loaded esbuild module - loaded from CDN to avoid bundler issues
7
+ let esbuild: typeof EsbuildTypes | null = null;
8
+
9
+ async function getEsbuild(): Promise<typeof EsbuildTypes> {
10
+ if (esbuild) return esbuild;
11
+
12
+ // Load esbuild-wasm from esm.sh CDN to avoid bundler transformation issues
13
+ // esm.sh provides proper ESM wrappers for npm packages
14
+ const cdnUrl = `https://esm.sh/esbuild-wasm@${ESBUILD_VERSION}`;
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ const mod: any = await import(/* @vite-ignore */ cdnUrl);
18
+
19
+ // esm.sh typically provides both default and named exports
20
+ esbuild = mod.default ?? mod;
21
+
22
+ // Verify we have the initialize function
23
+ if (typeof esbuild?.initialize !== 'function') {
24
+ console.error('esbuild-wasm module structure:', mod);
25
+ throw new Error('Failed to load esbuild-wasm: initialize function not found');
26
+ }
27
+
28
+ return esbuild;
29
+ }
30
+
6
31
  /**
7
32
  * How to handle npm package imports (bare imports like "react").
8
33
  *
@@ -96,7 +121,7 @@ export interface BundleResult {
96
121
  /**
97
122
  * Any warnings from esbuild
98
123
  */
99
- warnings: esbuild.Message[];
124
+ warnings: EsbuildTypes.Message[];
100
125
 
101
126
  /**
102
127
  * List of files that were included in the bundle
@@ -104,6 +129,11 @@ export interface BundleResult {
104
129
  includedFiles: string[];
105
130
  }
106
131
 
132
+ /**
133
+ * esbuild-wasm version - MUST match the version in package.json dependencies
134
+ */
135
+ const ESBUILD_VERSION = "0.27.2";
136
+
107
137
  // Track initialization state
108
138
  let initialized = false;
109
139
  let initPromise: Promise<void> | null = null;
@@ -112,9 +142,27 @@ let initPromise: Promise<void> | null = null;
112
142
  * Get the esbuild-wasm binary URL based on the installed version
113
143
  */
114
144
  function getWasmUrl(): string {
115
- // Use unpkg CDN to fetch the WASM binary matching our installed version
116
- const version = "0.27.2"; // Match installed version
117
- return `https://unpkg.com/esbuild-wasm@${version}/esbuild.wasm`;
145
+ return `https://unpkg.com/esbuild-wasm@${ESBUILD_VERSION}/esbuild.wasm`;
146
+ }
147
+
148
+ /**
149
+ * Check if the browser environment supports cross-origin isolation.
150
+ * This is needed for SharedArrayBuffer which esbuild-wasm may use.
151
+ */
152
+ function checkCrossOriginIsolation(): void {
153
+ if (typeof window === "undefined") return; // Not in browser
154
+
155
+ // crossOriginIsolated is true when COOP/COEP headers are set correctly
156
+ if (!window.crossOriginIsolated) {
157
+ console.warn(
158
+ "[sandlot] Cross-origin isolation is not enabled. " +
159
+ "esbuild-wasm may have reduced performance or fail on some browsers.\n" +
160
+ "To enable, add these headers to your dev server:\n" +
161
+ " Cross-Origin-Embedder-Policy: require-corp\n" +
162
+ " Cross-Origin-Opener-Policy: same-origin\n" +
163
+ "In Vite, add a plugin to configureServer. See sandlot README for details."
164
+ );
165
+ }
118
166
  }
119
167
 
120
168
  /**
@@ -129,9 +177,14 @@ export async function initBundler(): Promise<void> {
129
177
  return;
130
178
  }
131
179
 
132
- initPromise = esbuild.initialize({
133
- wasmURL: getWasmUrl(),
134
- });
180
+ checkCrossOriginIsolation();
181
+
182
+ initPromise = (async () => {
183
+ const es = await getEsbuild();
184
+ await es.initialize({
185
+ wasmURL: getWasmUrl(),
186
+ });
187
+ })();
135
188
 
136
189
  await initPromise;
137
190
  initialized = true;
@@ -147,7 +200,7 @@ function isBareImport(path: string): boolean {
147
200
  /**
148
201
  * Get the appropriate loader based on file extension
149
202
  */
150
- function getLoader(path: string): esbuild.Loader {
203
+ function getLoader(path: string): EsbuildTypes.Loader {
151
204
  const ext = path.split(".").pop()?.toLowerCase();
152
205
  switch (ext) {
153
206
  case "ts":
@@ -207,7 +260,7 @@ function matchesSharedModule(importPath: string, sharedModuleIds: Set<string>):
207
260
  /**
208
261
  * Create an esbuild plugin that reads from a virtual filesystem
209
262
  */
210
- function createVfsPlugin(options: VfsPluginOptions): esbuild.Plugin {
263
+ function createVfsPlugin(options: VfsPluginOptions): EsbuildTypes.Plugin {
211
264
  const {
212
265
  fs,
213
266
  entryPoint,
@@ -303,27 +356,14 @@ function createVfsPlugin(options: VfsPluginOptions): esbuild.Plugin {
303
356
 
304
357
  // Load shared modules from the registry
305
358
  build.onLoad({ filter: /.*/, namespace: "sandlot-shared" }, (args) => {
306
- // Generate code that looks up the module from the global registry
307
- const contents = `export default ${getSharedModuleRuntimeCode(args.path)};
308
- export * from ${JSON.stringify(args.path)};
309
- // Re-export all named exports by importing from registry
310
- const __mod__ = ${getSharedModuleRuntimeCode(args.path)};
311
- for (const __k__ in __mod__) {
312
- if (__k__ !== 'default') Object.defineProperty(exports, __k__, {
313
- enumerable: true,
314
- get: function() { return __mod__[__k__]; }
315
- });
316
- }`;
317
-
318
- // For ESM format, we need a different approach
319
- // Generate a simple module that re-exports from registry
320
- const esmContents = `
359
+ // Generate ESM code that re-exports from the shared module registry
360
+ const contents = `
321
361
  const __sandlot_mod__ = ${getSharedModuleRuntimeCode(args.path)};
322
362
  export default __sandlot_mod__.default ?? __sandlot_mod__;
323
363
  ${generateNamedExports(args.path)}
324
364
  `;
325
365
  return {
326
- contents: esmContents.trim(),
366
+ contents: contents.trim(),
327
367
  loader: 'js'
328
368
  };
329
369
  });
@@ -445,7 +485,8 @@ export async function bundle(options: BundleOptions): Promise<BundleResult> {
445
485
  sharedModuleIds,
446
486
  });
447
487
 
448
- const result = await esbuild.build({
488
+ const es = await getEsbuild();
489
+ const result = await es.build({
449
490
  entryPoints: [normalizedEntry],
450
491
  bundle: true,
451
492
  write: false,
package/src/fs.ts CHANGED
@@ -23,9 +23,12 @@ interface ReadFileOptions {
23
23
  }
24
24
 
25
25
  /**
26
- * Options for writing files
26
+ * Options for writing files.
27
+ * Note: In this browser-based filesystem, content is stored as-is.
28
+ * The encoding option is accepted for API compatibility but not used.
27
29
  */
28
30
  interface WriteFileOptions {
31
+ /** Accepted for API compatibility but not used - content is stored as-is */
29
32
  encoding?: BufferEncoding;
30
33
  }
31
34
 
@@ -276,7 +279,7 @@ export class IndexedDbFs implements IFileSystem {
276
279
  async writeFile(
277
280
  path: string,
278
281
  content: FileContent,
279
- options?: WriteFileOptions | BufferEncoding
282
+ _options?: WriteFileOptions | BufferEncoding
280
283
  ): Promise<void> {
281
284
  const normalizedPath = this.normalizePath(path);
282
285
  this.checkSizeLimit(content);
@@ -926,10 +929,20 @@ export class IndexedDbFs implements IFileSystem {
926
929
  }
927
930
 
928
931
  /**
929
- * Factory function matching the FileSystemFactory type
932
+ * Synchronous factory function for creating an in-memory filesystem.
933
+ *
934
+ * Note: For IndexedDB-backed persistence, use `IndexedDbFs.create()` instead.
935
+ * This function exists for compatibility with sync factory patterns.
936
+ *
937
+ * @param initialFiles - Optional initial files to populate the filesystem
938
+ * @returns An in-memory filesystem (no persistence)
930
939
  */
931
- export function createIndexedDbFs(initialFiles?: InitialFiles): IFileSystem {
932
- // For sync factory usage, return in-memory version
933
- // Use IndexedDbFs.create() for async with persistence
940
+ export function createInMemoryFs(initialFiles?: InitialFiles): IFileSystem {
934
941
  return IndexedDbFs.createInMemory({ initialFiles });
935
942
  }
943
+
944
+ /**
945
+ * @deprecated Use `createInMemoryFs` for in-memory filesystems or
946
+ * `IndexedDbFs.create()` for IndexedDB-backed persistence.
947
+ */
948
+ export const createIndexedDbFs = createInMemoryFs;
package/src/index.ts CHANGED
@@ -1,3 +1,20 @@
1
+ // =============================================================================
2
+ // Browser polyfills - inject before anything else loads
3
+ // =============================================================================
4
+
5
+ // Some dependencies (like just-bash) reference Node.js globals.
6
+ // Provide shims so they work in the browser without user configuration.
7
+ if (typeof window !== "undefined" && typeof globalThis.process === "undefined") {
8
+ (globalThis as Record<string, unknown>).process = {
9
+ env: {},
10
+ platform: "browser",
11
+ version: "v20.0.0",
12
+ browser: true,
13
+ cwd: () => "/",
14
+ nextTick: (fn: () => void) => setTimeout(fn, 0),
15
+ };
16
+ }
17
+
1
18
  // =============================================================================
2
19
  // CORE API - Most users only need these
3
20
  // =============================================================================
@@ -115,7 +132,7 @@ export {
115
132
 
116
133
  export {
117
134
  IndexedDbFs,
118
- createIndexedDbFs,
135
+ createInMemoryFs,
119
136
  type IndexedDbFsOptions,
120
137
  } from "./fs";
121
138
 
package/src/internal.ts CHANGED
@@ -112,5 +112,8 @@ export { formatEsbuildMessages } from "./commands";
112
112
  // BuildEmitter (for custom build event handling)
113
113
  // =============================================================================
114
114
 
115
- // Note: BuildEmitter is currently defined inline in sandbox.ts and sandbox-manager.ts
116
- // If needed externally, it should be extracted to a separate module.
115
+ /**
116
+ * Build event emitter for sandbox environments.
117
+ * Use this for custom build event handling in advanced use cases.
118
+ */
119
+ export { BuildEmitter } from "./build-emitter";
@@ -32,82 +32,9 @@ import {
32
32
  type SharedResourcesOptions,
33
33
  } from "./shared-resources";
34
34
  import { createDefaultCommands, type CommandDeps } from "./commands";
35
+ import { BuildEmitter } from "./build-emitter";
35
36
  import type { Sandbox } from "./sandbox";
36
37
 
37
- /**
38
- * Simple typed event emitter for build results.
39
- * Caches the last result so waitFor() can be called after build completes.
40
- */
41
- class BuildEmitter {
42
- private listeners = new Set<(result: BundleResult) => void | Promise<void>>();
43
- private lastResult: BundleResult | null = null;
44
-
45
- /**
46
- * Emit a build result to all listeners and cache it
47
- */
48
- emit = async (result: BundleResult): Promise<void> => {
49
- this.lastResult = result;
50
- const promises: Promise<void>[] = [];
51
- for (const listener of this.listeners) {
52
- const ret = listener(result);
53
- if (ret instanceof Promise) {
54
- promises.push(ret);
55
- }
56
- }
57
- await Promise.all(promises);
58
- };
59
-
60
- /**
61
- * Subscribe to build events. Returns an unsubscribe function.
62
- */
63
- on(callback: (result: BundleResult) => void | Promise<void>): () => void {
64
- this.listeners.add(callback);
65
- return () => {
66
- this.listeners.delete(callback);
67
- };
68
- }
69
-
70
- /**
71
- * Get the last build result, or wait for the next one if none exists.
72
- * Clears the cached result after returning, so subsequent calls wait for new builds.
73
- */
74
- waitFor(): Promise<BundleResult> {
75
- if (this.lastResult) {
76
- const result = this.lastResult;
77
- this.lastResult = null;
78
- return Promise.resolve(result);
79
- }
80
- return new Promise((resolve) => {
81
- const unsub = this.on((result) => {
82
- unsub();
83
- this.lastResult = null;
84
- resolve(result);
85
- });
86
- });
87
- }
88
- }
89
-
90
- // Re-export for convenience
91
- export type { BundleResult } from "./bundler";
92
- export type { TypecheckResult } from "./typechecker";
93
- export type { SharedResources, TypesCache } from "./shared-resources";
94
- export type { PackageManifest, InstallResult } from "./packages";
95
- export { installPackage, uninstallPackage, listPackages, getPackageManifest } from "./packages";
96
- export { InMemoryTypesCache } from "./shared-resources";
97
-
98
- // Loader utilities
99
- export {
100
- loadModule,
101
- loadExport,
102
- loadDefault,
103
- getExportNames,
104
- hasExport,
105
- createModuleUrl,
106
- revokeModuleUrl,
107
- ModuleLoadError,
108
- ExportNotFoundError,
109
- } from "./loader";
110
-
111
38
  /**
112
39
  * Options for creating a sandbox via the manager
113
40
  */
@@ -447,14 +374,6 @@ export class SandboxManager {
447
374
  getResources(): SharedResources | null {
448
375
  return this.resources;
449
376
  }
450
-
451
- /**
452
- * Get the shared lib files (for advanced use cases)
453
- * @deprecated Use getResources().libFiles instead
454
- */
455
- getLibFiles(): Map<string, string> {
456
- return this.resources?.libFiles ?? new Map();
457
- }
458
377
  }
459
378
 
460
379
  /**