sandlot 0.2.1 → 0.2.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 (43) hide show
  1. package/dist/browser/bundler.d.ts +8 -0
  2. package/dist/browser/bundler.d.ts.map +1 -1
  3. package/dist/browser/iframe-executor.d.ts +82 -0
  4. package/dist/browser/iframe-executor.d.ts.map +1 -0
  5. package/dist/browser/index.d.ts +4 -2
  6. package/dist/browser/index.d.ts.map +1 -1
  7. package/dist/browser/index.js +339 -76
  8. package/dist/browser/main-thread-executor.d.ts +46 -0
  9. package/dist/browser/main-thread-executor.d.ts.map +1 -0
  10. package/dist/browser/preset.d.ts +7 -2
  11. package/dist/browser/preset.d.ts.map +1 -1
  12. package/dist/core/bundler-utils.d.ts +43 -1
  13. package/dist/core/bundler-utils.d.ts.map +1 -1
  14. package/dist/core/executor.d.ts.map +1 -1
  15. package/dist/core/sandbox.d.ts.map +1 -1
  16. package/dist/core/sandlot.d.ts.map +1 -1
  17. package/dist/index.js +63 -0
  18. package/dist/node/bundler.d.ts +5 -0
  19. package/dist/node/bundler.d.ts.map +1 -1
  20. package/dist/node/index.d.ts +2 -0
  21. package/dist/node/index.d.ts.map +1 -1
  22. package/dist/node/index.js +243 -75
  23. package/dist/node/preset.d.ts +16 -1
  24. package/dist/node/preset.d.ts.map +1 -1
  25. package/dist/node/wasm-bundler.d.ts +86 -0
  26. package/dist/node/wasm-bundler.d.ts.map +1 -0
  27. package/dist/types.d.ts +25 -0
  28. package/dist/types.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/src/browser/bundler.ts +23 -106
  31. package/src/browser/iframe-executor.ts +320 -0
  32. package/src/browser/index.ts +9 -2
  33. package/src/browser/preset.ts +30 -6
  34. package/src/core/bundler-utils.ts +148 -0
  35. package/src/core/executor.ts +8 -7
  36. package/src/core/sandbox.ts +82 -0
  37. package/src/core/sandlot.ts +7 -0
  38. package/src/node/bundler.ts +17 -110
  39. package/src/node/index.ts +10 -0
  40. package/src/node/preset.ts +59 -5
  41. package/src/node/wasm-bundler.ts +195 -0
  42. package/src/types.ts +27 -0
  43. /package/src/browser/{executor.ts → main-thread-executor.ts} +0 -0
@@ -2,7 +2,8 @@ import { type EsmTypesResolverOptions } from "../core/esm-types-resolver";
2
2
  import type { Sandlot, SandlotOptions } from "../types";
3
3
  import { type EsbuildWasmBundlerOptions } from "./bundler";
4
4
  import { type TypecheckerOptions } from "../core/typechecker";
5
- import { type MainThreadExecutorOptions } from "./executor";
5
+ import { type MainThreadExecutorOptions } from "./main-thread-executor";
6
+ import { type IframeExecutorOptions } from "./iframe-executor";
6
7
  export interface CreateBrowserSandlotOptions extends Omit<SandlotOptions, "bundler" | "typechecker" | "typesResolver" | "executor"> {
7
8
  /**
8
9
  * Custom bundler options, or a pre-configured bundler instance.
@@ -21,9 +22,13 @@ export interface CreateBrowserSandlotOptions extends Omit<SandlotOptions, "bundl
21
22
  /**
22
23
  * Custom executor options, or a pre-configured executor instance.
23
24
  * Set to `false` to disable execution (sandbox.run() will throw).
25
+ * Set to `"iframe"` to use IframeExecutor with default options.
24
26
  * Defaults to MainThreadExecutor.
27
+ *
28
+ * Note: IframeExecutor does NOT support shared modules. Use MainThreadExecutor
29
+ * (the default) if you need shared modules like React.
25
30
  */
26
- executor?: MainThreadExecutorOptions | SandlotOptions["executor"] | false;
31
+ executor?: MainThreadExecutorOptions | IframeExecutorOptions | SandlotOptions["executor"] | "iframe" | false;
27
32
  }
28
33
  /**
29
34
  * Create a Sandlot instance pre-configured for browser environments.
@@ -1 +1 @@
1
- {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/browser/preset.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAsB,KAAK,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,2BACf,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,UAAU,CAAC;IACtF;;OAEG;IACH,OAAO,CAAC,EAAE,yBAAyB,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAEhE;;;OAGG;IACH,WAAW,CAAC,EACV,kBAAkB,GAClB,cAAc,CAAC,aAAa,CAAC,GAC7B,KAAK,CAAC;IAER;;;OAGG;IACH,aAAa,CAAC,EACZ,uBAAuB,GACvB,cAAc,CAAC,eAAe,CAAC,GAC/B,KAAK,CAAC;IAER;;;;OAIG;IACH,QAAQ,CAAC,EACP,yBAAyB,GACzB,cAAc,CAAC,UAAU,CAAC,GAC1B,KAAK,CAAC;CACT;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,OAAO,CAAC,CAgDlB"}
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/browser/preset.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAsB,KAAK,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,2BACf,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,UAAU,CAAC;IACtF;;OAEG;IACH,OAAO,CAAC,EAAE,yBAAyB,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAEhE;;;OAGG;IACH,WAAW,CAAC,EACV,kBAAkB,GAClB,cAAc,CAAC,aAAa,CAAC,GAC7B,KAAK,CAAC;IAER;;;OAGG;IACH,aAAa,CAAC,EACZ,uBAAuB,GACvB,cAAc,CAAC,eAAe,CAAC,GAC/B,KAAK,CAAC;IAER;;;;;;;;OAQG;IACH,QAAQ,CAAC,EACP,yBAAyB,GACzB,qBAAqB,GACrB,cAAc,CAAC,UAAU,CAAC,GAC1B,QAAQ,GACR,KAAK,CAAC;CACT;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,OAAO,CAAC,CAoDlB"}
@@ -4,7 +4,7 @@
4
4
  * This module contains the VFS plugin, path resolution, and shared module
5
5
  * code generation logic that is common to both esbuild and esbuild-wasm.
6
6
  */
7
- import type { ISharedModuleRegistry, BundleWarning, BundleError, Filesystem } from "../types";
7
+ import type { ISharedModuleRegistry, BundleOptions, BundleResult, BundleWarning, BundleError, Filesystem } from "../types";
8
8
  /**
9
9
  * Minimal esbuild types needed for the shared utilities.
10
10
  * These are compatible with both esbuild and esbuild-wasm.
@@ -139,4 +139,46 @@ export declare function getLoader(path: string): EsbuildLoader;
139
139
  * Generate JavaScript code that accesses a shared module at runtime.
140
140
  */
141
141
  export declare function generateSharedModuleCode(moduleId: string, registry: ISharedModuleRegistry | null): string;
142
+ /**
143
+ * Minimal esbuild interface needed for bundling.
144
+ * Compatible with both esbuild and esbuild-wasm.
145
+ *
146
+ * Uses a loose `Record<string, unknown>` for build options to avoid
147
+ * type conflicts between the various esbuild module signatures.
148
+ */
149
+ export interface EsbuildInstance {
150
+ build(options: Record<string, unknown>): Promise<{
151
+ outputFiles?: Array<{
152
+ text: string;
153
+ }>;
154
+ warnings: EsbuildMessage[];
155
+ }>;
156
+ }
157
+ /**
158
+ * Options for the shared bundle execution helper.
159
+ */
160
+ export interface ExecuteBundleOptions {
161
+ /** The esbuild instance to use */
162
+ esbuild: EsbuildInstance;
163
+ /** Bundle options from the IBundler interface */
164
+ bundleOptions: BundleOptions;
165
+ /** Base URL for CDN imports */
166
+ cdnBaseUrl: string;
167
+ /**
168
+ * Whether to bundle CDN imports inline.
169
+ * - Browser: false (external) - browser can fetch at runtime
170
+ * - Node/Bun: true (bundle) - esbuild fetches during build
171
+ */
172
+ bundleCdnImports: boolean;
173
+ }
174
+ /**
175
+ * Execute a bundle using esbuild with the VFS plugin.
176
+ *
177
+ * This is the shared implementation used by both browser and node WASM bundlers.
178
+ * It handles entry point normalization, VFS plugin creation, and error handling.
179
+ *
180
+ * @param options - Bundle execution options
181
+ * @returns Bundle result with code or errors
182
+ */
183
+ export declare function executeBundleWithEsbuild(options: ExecuteBundleOptions): Promise<BundleResult>;
142
184
  //# sourceMappingURL=bundler-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundler-utils.d.ts","sourceRoot":"","sources":["../../src/core/bundler-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bundler-utils.d.ts","sourceRoot":"","sources":["../../src/core/bundler-utils.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiC,MAAM,UAAU,CAAC;AAEzE;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,YAAY,EACxB,OAAO,GAAE,oBAAyB,GACjC,SAAS,CAwHX"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiC,MAAM,UAAU,CAAC;AAEzE;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,YAAY,EACxB,OAAO,GAAE,oBAAyB,GACjC,SAAS,CAyHX"}
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,OAAO,EACP,cAAc,EAYf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAA6B,MAAM,MAAM,CAAC;AA2J7D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CA2ZlB"}
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,OAAO,EACP,cAAc,EAYf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAA6B,MAAM,MAAM,CAAC;AA2J7D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CA6elB"}
@@ -1 +1 @@
1
- {"version":3,"file":"sandlot.d.ts","sourceRoot":"","sources":["../../src/core/sandlot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EAIf,MAAM,UAAU,CAAC;AAKlB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAsC9D"}
1
+ {"version":3,"file":"sandlot.d.ts","sourceRoot":"","sources":["../../src/core/sandlot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EAIf,MAAM,UAAU,CAAC;AAKlB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CA6C9D"}
package/dist/index.js CHANGED
@@ -1283,6 +1283,64 @@ async function createSandboxImpl(fs, options, context) {
1283
1283
  if (!fs.exists(TSCONFIG_PATH)) {
1284
1284
  fs.writeFile(TSCONFIG_PATH, JSON.stringify(DEFAULT_TSCONFIG, null, 2));
1285
1285
  }
1286
+ if (sharedModuleRegistry && typesResolver) {
1287
+ const sharedModuleIds = sharedModuleRegistry.list();
1288
+ const typesFetches = sharedModuleIds.map(async (moduleId) => {
1289
+ try {
1290
+ const typeFiles = await typesResolver.resolveTypes(moduleId);
1291
+ return { moduleId, typeFiles, error: null };
1292
+ } catch (err) {
1293
+ console.warn(`[sandlot] Failed to fetch types for shared module "${moduleId}":`, err);
1294
+ return { moduleId, typeFiles: {}, error: err };
1295
+ }
1296
+ });
1297
+ const results = await Promise.all(typesFetches);
1298
+ for (const { moduleId, typeFiles } of results) {
1299
+ if (Object.keys(typeFiles).length === 0)
1300
+ continue;
1301
+ let packageName = moduleId;
1302
+ let subpath;
1303
+ if (moduleId.startsWith("@")) {
1304
+ const parts = moduleId.split("/");
1305
+ if (parts.length >= 2) {
1306
+ packageName = `${parts[0]}/${parts[1]}`;
1307
+ subpath = parts.length > 2 ? parts.slice(2).join("/") : undefined;
1308
+ }
1309
+ } else {
1310
+ const slashIndex = moduleId.indexOf("/");
1311
+ if (slashIndex !== -1) {
1312
+ packageName = moduleId.slice(0, slashIndex);
1313
+ subpath = moduleId.slice(slashIndex + 1);
1314
+ }
1315
+ }
1316
+ const packageDir = `/node_modules/${packageName}`;
1317
+ let typesEntry = null;
1318
+ let fallbackEntry = null;
1319
+ for (const [filePath, content] of Object.entries(typeFiles)) {
1320
+ const fullPath = filePath.startsWith("/") ? filePath : `${packageDir}/${filePath}`;
1321
+ const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
1322
+ ensureDir(fs, dir);
1323
+ fs.writeFile(fullPath, content);
1324
+ const relativePath = fullPath.replace(`${packageDir}/`, "");
1325
+ if (relativePath === "index.d.ts") {
1326
+ typesEntry = "index.d.ts";
1327
+ } else if (!fallbackEntry && relativePath.endsWith(".d.ts") && !relativePath.includes("/")) {
1328
+ fallbackEntry = relativePath;
1329
+ }
1330
+ }
1331
+ const finalTypesEntry = typesEntry ?? fallbackEntry ?? "index.d.ts";
1332
+ const pkgJsonPath = `${packageDir}/package.json`;
1333
+ if (!fs.exists(pkgJsonPath)) {
1334
+ const pkgJson = {
1335
+ name: packageName,
1336
+ version: "shared",
1337
+ types: finalTypesEntry,
1338
+ main: finalTypesEntry.replace(/\.d\.ts$/, ".js")
1339
+ };
1340
+ fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
1341
+ }
1342
+ }
1343
+ }
1286
1344
  async function install(packageSpec) {
1287
1345
  const { name, version } = parsePackageSpec(packageSpec);
1288
1346
  let resolvedVersion = version ?? "latest";
@@ -1550,6 +1608,11 @@ function createSandlot(options) {
1550
1608
  },
1551
1609
  get sharedModules() {
1552
1610
  return sharedModuleRegistry;
1611
+ },
1612
+ async dispose() {
1613
+ if (bundler.dispose) {
1614
+ await bundler.dispose();
1615
+ }
1553
1616
  }
1554
1617
  };
1555
1618
  }
@@ -39,6 +39,11 @@ export declare class EsbuildNativeBundler implements IBundler {
39
39
  */
40
40
  initialize(): Promise<void>;
41
41
  private getEsbuild;
42
+ /**
43
+ * Dispose of the esbuild service.
44
+ * This stops the esbuild child process and allows the Node.js process to exit.
45
+ */
46
+ dispose(): Promise<void>;
42
47
  bundle(options: BundleOptions): Promise<BundleResult>;
43
48
  }
44
49
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/node/bundler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EACb,YAAY,EAGb,MAAM,UAAU,CAAC;AAOlB,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,oBAAqB,YAAW,QAAQ;IACnD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAoC;gBAEvC,OAAO,GAAE,2BAAgC;IAOrD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,OAAO,CAAC,UAAU;IAOZ,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CA0G5D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,2BAA2B,GACpC,oBAAoB,CAEtB"}
1
+ {"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/node/bundler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGtE,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,oBAAqB,YAAW,QAAQ;IACnD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAoC;gBAEvC,OAAO,GAAE,2BAAgC;IAOrD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,OAAO,CAAC,UAAU;IAOlB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAY5D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,2BAA2B,GACpC,oBAAoB,CAEtB"}
@@ -1,5 +1,7 @@
1
1
  export { EsbuildNativeBundler, createEsbuildNativeBundler } from "./bundler";
2
2
  export type { EsbuildNativeBundlerOptions } from "./bundler";
3
+ export { EsbuildWasmNodeBundler, createEsbuildWasmNodeBundler, } from "./wasm-bundler";
4
+ export type { EsbuildWasmNodeBundlerOptions } from "./wasm-bundler";
3
5
  export { Typechecker, createTypechecker } from "../core/typechecker";
4
6
  export type { TypecheckerOptions } from "../core/typechecker";
5
7
  export { NodeExecutor, createNodeExecutor } from "./executor";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAC7E,YAAY,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAC;AAM7D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACrE,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAM9D,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC9D,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAC7E,YAAY,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAC;AAM7D,OAAO,EACL,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAMpE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACrE,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAM9D,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC9D,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC"}
@@ -319,6 +319,78 @@ function generateSharedModuleCode(moduleId, registry) {
319
319
  }
320
320
  return code;
321
321
  }
322
+ async function executeBundleWithEsbuild(options) {
323
+ const { esbuild, bundleOptions, cdnBaseUrl, bundleCdnImports } = options;
324
+ const {
325
+ fs,
326
+ entryPoint,
327
+ installedPackages = {},
328
+ sharedModules = [],
329
+ sharedModuleRegistry,
330
+ external = [],
331
+ format = "esm",
332
+ minify = false,
333
+ sourcemap = false,
334
+ target = ["es2020"]
335
+ } = bundleOptions;
336
+ const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
337
+ if (!fs.exists(normalizedEntry)) {
338
+ return {
339
+ success: false,
340
+ errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
341
+ warnings: []
342
+ };
343
+ }
344
+ const includedFiles = new Set;
345
+ const plugin = createVfsPlugin({
346
+ fs,
347
+ entryPoint: normalizedEntry,
348
+ installedPackages,
349
+ sharedModules: new Set(sharedModules),
350
+ sharedModuleRegistry: sharedModuleRegistry ?? null,
351
+ cdnBaseUrl,
352
+ includedFiles,
353
+ bundleCdnImports
354
+ });
355
+ try {
356
+ const result = await esbuild.build({
357
+ entryPoints: [normalizedEntry],
358
+ bundle: true,
359
+ write: false,
360
+ format,
361
+ minify,
362
+ sourcemap: sourcemap ? "inline" : false,
363
+ target,
364
+ external,
365
+ plugins: [plugin],
366
+ jsx: "automatic"
367
+ });
368
+ const code = result.outputFiles?.[0]?.text ?? "";
369
+ const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
370
+ return {
371
+ success: true,
372
+ code,
373
+ warnings,
374
+ includedFiles: Array.from(includedFiles)
375
+ };
376
+ } catch (err) {
377
+ if (isEsbuildBuildFailure(err)) {
378
+ const errors = err.errors.map((e) => convertEsbuildMessage(e));
379
+ const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
380
+ return {
381
+ success: false,
382
+ errors,
383
+ warnings
384
+ };
385
+ }
386
+ const message = err instanceof Error ? err.message : String(err);
387
+ return {
388
+ success: false,
389
+ errors: [{ text: message }],
390
+ warnings: []
391
+ };
392
+ }
393
+ }
322
394
 
323
395
  // src/node/bundler.ts
324
396
  class EsbuildNativeBundler {
@@ -342,83 +414,97 @@ class EsbuildNativeBundler {
342
414
  }
343
415
  return this.esbuild;
344
416
  }
417
+ async dispose() {
418
+ if (this.esbuild) {
419
+ await this.esbuild.stop();
420
+ this.esbuild = null;
421
+ }
422
+ }
345
423
  async bundle(options) {
346
424
  await this.initialize();
347
- const esbuild = this.getEsbuild();
348
- const {
349
- fs,
350
- entryPoint,
351
- installedPackages = {},
352
- sharedModules = [],
353
- sharedModuleRegistry,
354
- external = [],
355
- format = "esm",
356
- minify = false,
357
- sourcemap = false,
358
- target = ["es2020"]
359
- } = options;
360
- const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
361
- if (!fs.exists(normalizedEntry)) {
362
- return {
363
- success: false,
364
- errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
365
- warnings: []
366
- };
367
- }
368
- const includedFiles = new Set;
369
- const plugin = createVfsPlugin({
370
- fs,
371
- entryPoint: normalizedEntry,
372
- installedPackages,
373
- sharedModules: new Set(sharedModules),
374
- sharedModuleRegistry: sharedModuleRegistry ?? null,
425
+ return executeBundleWithEsbuild({
426
+ esbuild: this.getEsbuild(),
427
+ bundleOptions: options,
375
428
  cdnBaseUrl: this.options.cdnBaseUrl,
376
- includedFiles,
377
429
  bundleCdnImports: true
378
430
  });
379
- try {
380
- const result = await esbuild.build({
381
- entryPoints: [normalizedEntry],
382
- bundle: true,
383
- write: false,
384
- format,
385
- minify,
386
- sourcemap: sourcemap ? "inline" : false,
387
- target,
388
- external,
389
- plugins: [plugin],
390
- jsx: "automatic"
391
- });
392
- const code = result.outputFiles?.[0]?.text ?? "";
393
- const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
394
- return {
395
- success: true,
396
- code,
397
- warnings,
398
- includedFiles: Array.from(includedFiles)
399
- };
400
- } catch (err) {
401
- if (isEsbuildBuildFailure(err)) {
402
- const errors = err.errors.map((e) => convertEsbuildMessage(e));
403
- const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
404
- return {
405
- success: false,
406
- errors,
407
- warnings
408
- };
409
- }
410
- const message = err instanceof Error ? err.message : String(err);
411
- return {
412
- success: false,
413
- errors: [{ text: message }],
414
- warnings: []
415
- };
416
- }
417
431
  }
418
432
  }
419
433
  function createEsbuildNativeBundler(options) {
420
434
  return new EsbuildNativeBundler(options);
421
435
  }
436
+ // src/node/wasm-bundler.ts
437
+ var GLOBAL_KEY = "__sandlot_esbuild_wasm_node__";
438
+ function getGlobalState() {
439
+ const g = globalThis;
440
+ if (!g[GLOBAL_KEY]) {
441
+ g[GLOBAL_KEY] = {
442
+ esbuild: null,
443
+ initialized: false,
444
+ initPromise: null
445
+ };
446
+ }
447
+ return g[GLOBAL_KEY];
448
+ }
449
+
450
+ class EsbuildWasmNodeBundler {
451
+ options;
452
+ constructor(options = {}) {
453
+ this.options = {
454
+ cdnBaseUrl: "https://esm.sh",
455
+ ...options
456
+ };
457
+ }
458
+ async initialize() {
459
+ const state = getGlobalState();
460
+ if (state.initialized && state.esbuild) {
461
+ return;
462
+ }
463
+ if (state.initPromise) {
464
+ await state.initPromise;
465
+ return;
466
+ }
467
+ state.initPromise = this.doInitialize(state);
468
+ await state.initPromise;
469
+ }
470
+ async doInitialize(state) {
471
+ const esbuild = await import("esbuild-wasm");
472
+ if (typeof esbuild?.initialize !== "function") {
473
+ throw new Error("Failed to load esbuild-wasm: initialize function not found");
474
+ }
475
+ await esbuild.initialize({});
476
+ state.esbuild = esbuild;
477
+ state.initialized = true;
478
+ }
479
+ getEsbuild() {
480
+ const state = getGlobalState();
481
+ if (!state.esbuild) {
482
+ throw new Error("esbuild not initialized - call initialize() first");
483
+ }
484
+ return state.esbuild;
485
+ }
486
+ async dispose() {
487
+ const state = getGlobalState();
488
+ if (state.esbuild) {
489
+ await state.esbuild.stop();
490
+ state.esbuild = null;
491
+ state.initialized = false;
492
+ state.initPromise = null;
493
+ }
494
+ }
495
+ async bundle(options) {
496
+ await this.initialize();
497
+ return executeBundleWithEsbuild({
498
+ esbuild: this.getEsbuild(),
499
+ bundleOptions: options,
500
+ cdnBaseUrl: this.options.cdnBaseUrl,
501
+ bundleCdnImports: true
502
+ });
503
+ }
504
+ }
505
+ function createEsbuildWasmNodeBundler(options) {
506
+ return new EsbuildWasmNodeBundler(options);
507
+ }
422
508
  // src/core/typechecker.ts
423
509
  import ts from "typescript";
424
510
  var TS_VERSION = "5.9.3";
@@ -771,23 +857,18 @@ function createBasicExecutor(loadModule, options = {}) {
771
857
  const formatArgs = (...args) => args.map((v) => typeof v === "object" ? JSON.stringify(v) : String(v)).join(" ");
772
858
  const captureLog = (...args) => {
773
859
  logs.push(formatArgs(...args));
774
- originalConsole.log.apply(console, args);
775
860
  };
776
861
  const captureWarn = (...args) => {
777
862
  logs.push(`[warn] ${formatArgs(...args)}`);
778
- originalConsole.warn.apply(console, args);
779
863
  };
780
864
  const captureError = (...args) => {
781
865
  logs.push(`[error] ${formatArgs(...args)}`);
782
- originalConsole.error.apply(console, args);
783
866
  };
784
867
  const captureInfo = (...args) => {
785
868
  logs.push(`[info] ${formatArgs(...args)}`);
786
- originalConsole.info.apply(console, args);
787
869
  };
788
870
  const captureDebug = (...args) => {
789
871
  logs.push(`[debug] ${formatArgs(...args)}`);
790
- originalConsole.debug.apply(console, args);
791
872
  };
792
873
  const restoreConsole = () => {
793
874
  console.log = originalConsole.log;
@@ -814,10 +895,16 @@ function createBasicExecutor(loadModule, options = {}) {
814
895
  }
815
896
  };
816
897
  if (timeout > 0) {
898
+ let timeoutId;
817
899
  const timeoutPromise = new Promise((_, reject) => {
818
- setTimeout(() => reject(new Error(`Execution timed out after ${timeout}ms`)), timeout);
900
+ timeoutId = setTimeout(() => reject(new Error(`Execution timed out after ${timeout}ms`)), timeout);
819
901
  });
820
- await Promise.race([executeExport(), timeoutPromise]);
902
+ try {
903
+ await Promise.race([executeExport(), timeoutPromise]);
904
+ } finally {
905
+ if (timeoutId)
906
+ clearTimeout(timeoutId);
907
+ }
821
908
  } else {
822
909
  await executeExport();
823
910
  }
@@ -2148,6 +2235,64 @@ async function createSandboxImpl(fs, options, context) {
2148
2235
  if (!fs.exists(TSCONFIG_PATH)) {
2149
2236
  fs.writeFile(TSCONFIG_PATH, JSON.stringify(DEFAULT_TSCONFIG, null, 2));
2150
2237
  }
2238
+ if (sharedModuleRegistry && typesResolver) {
2239
+ const sharedModuleIds = sharedModuleRegistry.list();
2240
+ const typesFetches = sharedModuleIds.map(async (moduleId) => {
2241
+ try {
2242
+ const typeFiles = await typesResolver.resolveTypes(moduleId);
2243
+ return { moduleId, typeFiles, error: null };
2244
+ } catch (err) {
2245
+ console.warn(`[sandlot] Failed to fetch types for shared module "${moduleId}":`, err);
2246
+ return { moduleId, typeFiles: {}, error: err };
2247
+ }
2248
+ });
2249
+ const results = await Promise.all(typesFetches);
2250
+ for (const { moduleId, typeFiles } of results) {
2251
+ if (Object.keys(typeFiles).length === 0)
2252
+ continue;
2253
+ let packageName = moduleId;
2254
+ let subpath;
2255
+ if (moduleId.startsWith("@")) {
2256
+ const parts = moduleId.split("/");
2257
+ if (parts.length >= 2) {
2258
+ packageName = `${parts[0]}/${parts[1]}`;
2259
+ subpath = parts.length > 2 ? parts.slice(2).join("/") : undefined;
2260
+ }
2261
+ } else {
2262
+ const slashIndex = moduleId.indexOf("/");
2263
+ if (slashIndex !== -1) {
2264
+ packageName = moduleId.slice(0, slashIndex);
2265
+ subpath = moduleId.slice(slashIndex + 1);
2266
+ }
2267
+ }
2268
+ const packageDir = `/node_modules/${packageName}`;
2269
+ let typesEntry = null;
2270
+ let fallbackEntry = null;
2271
+ for (const [filePath, content] of Object.entries(typeFiles)) {
2272
+ const fullPath = filePath.startsWith("/") ? filePath : `${packageDir}/${filePath}`;
2273
+ const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
2274
+ ensureDir(fs, dir);
2275
+ fs.writeFile(fullPath, content);
2276
+ const relativePath = fullPath.replace(`${packageDir}/`, "");
2277
+ if (relativePath === "index.d.ts") {
2278
+ typesEntry = "index.d.ts";
2279
+ } else if (!fallbackEntry && relativePath.endsWith(".d.ts") && !relativePath.includes("/")) {
2280
+ fallbackEntry = relativePath;
2281
+ }
2282
+ }
2283
+ const finalTypesEntry = typesEntry ?? fallbackEntry ?? "index.d.ts";
2284
+ const pkgJsonPath = `${packageDir}/package.json`;
2285
+ if (!fs.exists(pkgJsonPath)) {
2286
+ const pkgJson = {
2287
+ name: packageName,
2288
+ version: "shared",
2289
+ types: finalTypesEntry,
2290
+ main: finalTypesEntry.replace(/\.d\.ts$/, ".js")
2291
+ };
2292
+ fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
2293
+ }
2294
+ }
2295
+ }
2151
2296
  async function install(packageSpec) {
2152
2297
  const { name, version } = parsePackageSpec(packageSpec);
2153
2298
  let resolvedVersion = version ?? "latest";
@@ -2415,6 +2560,11 @@ function createSandlot(options) {
2415
2560
  },
2416
2561
  get sharedModules() {
2417
2562
  return sharedModuleRegistry;
2563
+ },
2564
+ async dispose() {
2565
+ if (bundler.dispose) {
2566
+ await bundler.dispose();
2567
+ }
2418
2568
  }
2419
2569
  };
2420
2570
  }
@@ -2608,7 +2758,7 @@ function escapeRegex(str) {
2608
2758
  // src/node/preset.ts
2609
2759
  async function createNodeSandlot(options = {}) {
2610
2760
  const { bundler, typechecker, typesResolver, executor, ...rest } = options;
2611
- const bundlerInstance = isBundler(bundler) ? bundler : new EsbuildNativeBundler(bundler);
2761
+ const bundlerInstance = createBundlerInstance(bundler);
2612
2762
  await bundlerInstance.initialize();
2613
2763
  const typecheckerInstance = typechecker === false ? undefined : isTypechecker(typechecker) ? typechecker : new Typechecker(typechecker);
2614
2764
  const typesResolverInstance = typesResolver === false ? undefined : isTypesResolver(typesResolver) ? typesResolver : new EsmTypesResolver(typesResolver);
@@ -2621,6 +2771,22 @@ async function createNodeSandlot(options = {}) {
2621
2771
  executor: executorInstance
2622
2772
  });
2623
2773
  }
2774
+ function createBundlerInstance(bundler) {
2775
+ if (isBundler(bundler)) {
2776
+ return bundler;
2777
+ }
2778
+ if (bundler === "wasm") {
2779
+ return new EsbuildWasmNodeBundler;
2780
+ }
2781
+ if (isWasmBundlerOptions(bundler)) {
2782
+ const { wasm: _, ...wasmOptions } = bundler;
2783
+ return new EsbuildWasmNodeBundler(wasmOptions);
2784
+ }
2785
+ return new EsbuildNativeBundler(bundler);
2786
+ }
2787
+ function isWasmBundlerOptions(value) {
2788
+ return typeof value === "object" && value !== null && "wasm" in value && value.wasm === true;
2789
+ }
2624
2790
  function isBundler(value) {
2625
2791
  return typeof value === "object" && value !== null && "bundle" in value && typeof value.bundle === "function";
2626
2792
  }
@@ -2637,8 +2803,10 @@ export {
2637
2803
  createTypechecker,
2638
2804
  createNodeSandlot,
2639
2805
  createNodeExecutor,
2806
+ createEsbuildWasmNodeBundler,
2640
2807
  createEsbuildNativeBundler,
2641
2808
  Typechecker,
2642
2809
  NodeExecutor,
2810
+ EsbuildWasmNodeBundler,
2643
2811
  EsbuildNativeBundler
2644
2812
  };
@@ -1,13 +1,21 @@
1
1
  import { type EsmTypesResolverOptions } from "../core/esm-types-resolver";
2
2
  import type { Sandlot, SandlotOptions } from "../types";
3
3
  import { type EsbuildNativeBundlerOptions } from "./bundler";
4
+ import { type EsbuildWasmNodeBundlerOptions } from "./wasm-bundler";
4
5
  import { type TypecheckerOptions } from "../core/typechecker";
5
6
  import { type NodeExecutorOptions } from "./executor";
6
7
  export interface CreateNodeSandlotOptions extends Omit<SandlotOptions, "bundler" | "typechecker" | "typesResolver" | "executor"> {
7
8
  /**
8
9
  * Custom bundler options, or a pre-configured bundler instance.
10
+ *
11
+ * Set to `"wasm"` to use the WASM bundler (for testing consistency with browser).
12
+ * You can also pass `{ wasm: true, ...options }` for WASM bundler with custom options.
13
+ *
14
+ * @default EsbuildNativeBundler (fastest, uses native esbuild binary)
9
15
  */
10
- bundler?: EsbuildNativeBundlerOptions | SandlotOptions["bundler"];
16
+ bundler?: EsbuildNativeBundlerOptions | (EsbuildWasmNodeBundlerOptions & {
17
+ wasm: true;
18
+ }) | SandlotOptions["bundler"] | "wasm";
11
19
  /**
12
20
  * Custom typechecker options, or a pre-configured typechecker instance.
13
21
  * Set to `false` to disable type checking.
@@ -57,6 +65,13 @@ export interface CreateNodeSandlotOptions extends Omit<SandlotOptions, "bundler"
57
65
  * typechecker: false,
58
66
  * });
59
67
  * ```
68
+ *
69
+ * @example Use WASM bundler for testing consistency with browser
70
+ * ```ts
71
+ * const sandlot = await createNodeSandlot({
72
+ * bundler: "wasm",
73
+ * });
74
+ * ```
60
75
  */
61
76
  export declare function createNodeSandlot(options?: CreateNodeSandlotOptions): Promise<Sandlot>;
62
77
  //# sourceMappingURL=preset.d.ts.map