sandboxedjs 0.1.27 → 0.1.29

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
@@ -617,11 +617,21 @@ export default {
617
617
  "Cross-Origin-Opener-Policy": "same-origin",
618
618
  "Cross-Origin-Embedder-Policy": "require-corp",
619
619
  } },
620
+ // Required as well — see below.
621
+ optimizeDeps: { exclude: ["@rolldown/binding-wasm32-wasi"] },
620
622
  };
621
623
  ```
622
624
 
623
625
  Production hosting must return the same two headers. Without them SandboxedJS reports a direct
624
- configuration error when Vite/Rolldown starts. The compiler is loaded only when an installed
626
+ configuration error when Vite/Rolldown starts.
627
+
628
+ `optimizeDeps.exclude` matters just as much, and fails less obviously. The binding starts its
629
+ WASI worker with `new Worker(new URL("@rolldown/binding-wasm32-wasi/wasi-worker-browser.mjs",
630
+ import.meta.url))`. A bundler that pre-bundles the package rewrites that URL to a path inside its
631
+ own dependency cache, where the worker file does not exist — so the dev server answers with
632
+ `index.html` and the browser rejects it for its MIME type, several layers away from anything that
633
+ mentions Rolldown. Excluding the binding leaves it served from `node_modules`, where that URL
634
+ resolves. The compiler is loaded only when an installed
625
635
  project actually contains Rolldown, so ordinary container boot does not pay its WASM startup cost.
626
636
 
627
637
  **Not done — these things still stand between this and a complete browser IDE.**
@@ -758,6 +768,31 @@ Two caveats worth knowing:
758
768
  itself reports status correctly and can be relied on in `&&` chains.
759
769
  - **No hardware acceleration and no native codecs** beyond what the WebAssembly build ships.
760
770
 
771
+ ## Isolation
772
+
773
+ By default each guest program runs on its own thread, in a Worker. The volume, the kernel, the
774
+ coreutils and the process table stay on the thread that created the container, and the program
775
+ reaches them through a `SharedArrayBuffer` channel it can wait on synchronously.
776
+
777
+ Two things follow from that. Guest code no longer shares your page's realm, so it cannot reach
778
+ your application's globals. And `child_process.execSync`, `spawnSync` and `execFileSync` work —
779
+ they cannot be expressed any other way, because a synchronous call has to block its caller while
780
+ the child it is waiting for still makes progress, which is impossible when both are the same
781
+ thread.
782
+
783
+ It is chosen automatically and falls back on its own, so nothing that runs today stops running:
784
+
785
+ | Condition | What happens |
786
+ |---|---|
787
+ | `SharedArrayBuffer` unavailable, or the page is not cross-origin isolated | Falls back to the in-realm runtime |
788
+ | The guest bundle cannot be loaded (a bundler moved or rewrote it) | Falls back to the in-realm runtime |
789
+ | `modules` supplied by the host | Falls back — live JavaScript objects cannot cross a thread |
790
+ | The project has `rolldown` installed | *That process* runs in-realm; the rest still get a thread |
791
+
792
+ In a browser this needs the same COOP/COEP headers Rolldown does, which is the usual reason to
793
+ find yourself in the fallback. `createContainer({ isolation: "realm" })` opts out entirely, and
794
+ `workerUrl` points at the guest bundle when a bundler has moved it.
795
+
761
796
  ## Known limits
762
797
 
763
798
  Honest list of what does not work:
@@ -765,15 +800,25 @@ Honest list of what does not work:
765
800
  - **Compiled native addons.** A `.node` file cannot be loaded, so a package that ships one has to
766
801
  have a JavaScript or WebAssembly build to fall back on. `rollup` and `esbuild` do, and the
767
802
  runtime redirects those two names to `@rollup/wasm-node` and `esbuild-wasm` automatically when
768
- they are installed. Vite 8 is supported through Rolldown's official WASI build (with the browser
769
- isolation headers above). Express, Koa, Fastify-style apps and plain `http` servers also run.
803
+ they are installed. Vite 8 is supported through Rolldown's official WASI build **in a browser
804
+ host** (with the two configuration steps above). Express, Koa, Fastify-style apps and plain
805
+ `http` servers also run.
806
+ - **Vite 8 / Rolldown does not work when the host is Node.** The binding has two builds. The
807
+ browser one owns a `memfs` volume, which SandboxedJS mirrors the project into; the Node one
808
+ builds a `node:wasi` instance that preopens the *real* filesystem root, and there is no way to
809
+ hand it a different one. Rolldown therefore looks for `/app/my-app/index.html` on your actual
810
+ disk, does not find it, and the dev server answers every request with its fallback page. Vite 7
811
+ works on both hosts and is what the Node acceptance test pins.
770
812
  - **Concurrent browser Rolldown projects need distinct absolute working directories.** The
771
813
  official binding owns one WASI memfs per page; SandboxedJS mirrors each project into it before
772
814
  startup. Two live projects using the same path such as `/workspace` can overwrite that mirror.
773
- - **`child_process` is asynchronous only.** `spawn`, `exec` and `execFile` run through the kernel,
774
- so a child sees the same filesystem and coreutils as the shell. `execSync`, `spawnSync` and
775
- `execFileSync` throw `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM`: blocking the JavaScript thread on
776
- another process is not expressible here.
815
+ - **`child_process` is synchronous only under the Worker pod.** `spawn`, `exec` and `execFile`
816
+ always work and run through the kernel, so a child sees the same filesystem and coreutils as the
817
+ shell. `execSync`, `spawnSync` and `execFileSync` need the guest program to be on its own thread
818
+ see *Isolation* above. Where it is, they work; where it is not, they throw
819
+ `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM` naming the command they were asked to run, and the way
820
+ through is to answer **No** to a prompt like `npm create vite`'s "Install with npm and start
821
+ now?" and run `npm install && npm run dev` from the shell instead.
777
822
  - **No `net`, `tls`, `worker_threads` or `vm`.** `http` and `https` are served by a virtual stack
778
823
  that `request()` talks to directly, so servers work; raw sockets do not.
779
824
  - **Python is CPython via Pyodide.** The standard library is the real one. A C