sandboxedjs 0.1.15 → 0.1.16

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/README.md CHANGED
@@ -579,29 +579,41 @@ resolve their implementation at call time (`node:zlib`/`node:crypto` on Node,
579
579
  `CompressionStream`/`crypto.subtle` plus a JS MD5 in a browser), so nothing pulls a `node:`
580
580
  builtin in when the module loads and a bundler will not fail on it.
581
581
 
582
- **You supply the pod.** The default boot path uses `@scelar/nodepod/headless`, which installs a
583
- `worker_threads` host. That entry is now loaded lazily, behind a runtime-built specifier, so a
584
- browser bundle never pulls `node:worker_threads` in through it. In a browser you boot Nodepod's
585
- browser build yourself — it needs a service worker, per Nodepod's own setup docs — and hand the
586
- instance over:
582
+ **One call, either side.** `createContainer()` picks its own host: the headless
583
+ `worker_threads` engine on Node, Nodepod's browser build in a browser. You do not import Nodepod,
584
+ and you do not pass a pod:
587
585
 
588
586
  ```ts
589
- import { Nodepod } from "@scelar/nodepod";
590
587
  import { createContainer } from "sandboxedjs";
591
588
 
592
- const pod = await Nodepod.boot({ /* your service-worker setup */ });
593
- const box = await createContainer({ pod });
589
+ const box = await createContainer({ files: { "/app/index.js": "console.log(1)" } });
594
590
 
595
591
  await box.exec("ls -la /"); // shell + coreutils
596
- await box.exec("node app.js"); // Node, through Nodepod's browser engine
592
+ await box.exec("node app/index.js");
597
593
  ```
598
594
 
599
- **Verified in a browser.** Booted under Vite with Nodepod's browser build, the following run:
595
+ **Serve the service worker.** In a browser, a container's preview iframe reaches an HTTP server
596
+ running inside the page through a service worker, and a browser will not register one from
597
+ `node_modules` — it has to come from your own origin at `/__sw__.js`. One line:
598
+
599
+ ```ts
600
+ // vite.config.ts
601
+ import sandboxedjs from "sandboxedjs/vite";
602
+ export default defineConfig({ plugins: [sandboxedjs()] });
603
+ ```
604
+
605
+ For anything else, `sandboxedjs/server` exports `serveSW()` (Fetch-style hosts) and
606
+ `serveSWNode()` (Express, Fastify, `node:http`). Skip it with
607
+ `createContainer({ browser: { serviceWorker: false } })`, which also disables preview iframes.
608
+
609
+ You can still boot the pod yourself and pass it as `pod` when you need control over Nodepod's
610
+ own options.
611
+
612
+ **Verified in a browser.** Booted under Vite, the following run:
600
613
 
601
614
  ```
602
615
  $ uname -a Linux sandbox 5.10.0 (sandboxedjs@nodepod) … x86_64 GNU/Linux
603
616
  $ ls -la /app the mounted files
604
- $ wc -l /app/data.txt 3 /app/data.txt
605
617
  $ grep beta … beta
606
618
  $ node /app/hello.js node runtime says hi
607
619
  ```
@@ -612,8 +624,8 @@ seconds, nearly all of it Nodepod starting.
612
624
  **What does not work in a browser:**
613
625
 
614
626
  - `copyIn()` / `copyOut()` — they read and write the host filesystem, which does not exist.
615
- - `expose()` — it opens a real `node:http` listener. In a browser you use Nodepod's service
616
- worker and preview iframe to reach an in-container server instead of a host port.
627
+ - `expose()` — it opens a real `node:http` listener. Use the service worker and a preview iframe
628
+ to reach an in-container server instead of a host port.
617
629
  - `python3` — see below.
618
630
  - The `sandboxedjs` CLI, obviously.
619
631
 
package/dist/index.cjs CHANGED
@@ -23893,8 +23893,8 @@ var Container = class _Container {
23893
23893
  // ── boot ──────────────────────────────────────────────────────────────────
23894
23894
  static async create(opts = {}) {
23895
23895
  if (opts.python) configurePython(opts.python);
23896
- if (!opts.pod) await installEsbuildRuntime();
23897
- const pod = opts.pod ?? await bootHeadlessPod(opts);
23896
+ if (!opts.pod && isNodeRuntime()) await installEsbuildRuntime();
23897
+ const pod = opts.pod ?? (isNodeRuntime() ? await bootHeadlessPod(opts) : await bootBrowserPod(opts));
23898
23898
  const kernel = new Kernel({
23899
23899
  pod,
23900
23900
  hostname: opts.hostname ?? "sandbox",
@@ -24316,6 +24316,18 @@ function normalizeHeaders(headers) {
24316
24316
  async function createContainer(opts = {}) {
24317
24317
  return Container.create(opts);
24318
24318
  }
24319
+ function isNodeRuntime() {
24320
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
24321
+ }
24322
+ async function bootBrowserPod(opts) {
24323
+ const { Nodepod } = await import('@scelar/nodepod');
24324
+ return Nodepod.boot({
24325
+ env: opts.env ?? {},
24326
+ workdir: opts.cwd ?? "/",
24327
+ ...opts.browser ?? {},
24328
+ ...opts.onServerReady ? { onServerReady: opts.onServerReady } : {}
24329
+ });
24330
+ }
24319
24331
  async function bootHeadlessPod(opts) {
24320
24332
  const { Nodepod } = await nodeOnlyModule(
24321
24333
  "@scelar/nodepod/headless"