first commit
This commit is contained in:
79
docs/api-stack/api/api-sandbox-wasm/src/sandbox/sandbox.md
Normal file
79
docs/api-stack/api/api-sandbox-wasm/src/sandbox/sandbox.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# sandbox
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Top-level entry point for the WASM sandbox host. `createWasmSandbox`
|
||||
compiles (or accepts a pre-compiled) WASM module, validates its WASI
|
||||
imports against the supported-version allowlist, builds the preopen
|
||||
table and outbound allowlist from the `PermissionPolicy`, wraps every
|
||||
capability import in the permission checker, and instantiates the
|
||||
guest under those constraints.
|
||||
|
||||
The returned `WasmSandboxHandle` exposes the WebAssembly instance plus
|
||||
the policy bindings (`preopens`, `outbound`) for diagnostic consumers,
|
||||
and a `dispose()` method that is idempotent — calling it twice is a
|
||||
no-op. Memory is bound automatically when the guest exports a `memory`
|
||||
of type `WebAssembly.Memory`.
|
||||
|
||||
## Features
|
||||
|
||||
- Accepts a pre-compiled `WebAssembly.Module` or raw bytes.
|
||||
- WASI version pre-check via `detectWasiVersion`.
|
||||
- Wraps `WebAssembly.compile` / `WebAssembly.instantiate` failures
|
||||
in `SAND_WASM_INSTANTIATION_FAILED`, preserving the underlying
|
||||
`cause` for operator triage.
|
||||
- Idempotent `dispose()` — the WebAssembly instance becomes eligible
|
||||
for GC once the handle is released.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
const handle = await createWasmSandbox({
|
||||
pluginName: "stripe-checkout",
|
||||
policy,
|
||||
capabilities: [],
|
||||
checker,
|
||||
wasmBytes: await readFile("./plugin.wasm"),
|
||||
});
|
||||
try {
|
||||
(handle.instance.exports._start as () => void)();
|
||||
} finally {
|
||||
handle.dispose();
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
// Hot-reload path: re-use the compiled module across reloads.
|
||||
const module = await WebAssembly.compile(bytes);
|
||||
let handle = await createWasmSandbox({ ..., wasmModule: module });
|
||||
hotReloadBus.on("reload", async () => {
|
||||
handle.dispose();
|
||||
handle = await createWasmSandbox({ ..., wasmModule: module });
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `createWasmSandbox(options): Promise<WasmSandboxHandle>`
|
||||
- `CreateWasmSandboxOptions.{pluginName, policy, capabilities, checker, wasmModule | wasmBytes, wasiDeps?, instruments?}`
|
||||
- `WasmSandboxHandle.{instance, preopens, outbound, wasi, instruments, dispose(), disposed}`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The pre-compiled-vs-bytes split exists because hot-reload paths cache
|
||||
the `WebAssembly.Module` across reloads to avoid re-paying the
|
||||
validator cost on every cycle. Compilation is significantly more
|
||||
expensive than instantiation, and operators have explicitly asked for
|
||||
the option.
|
||||
|
||||
`dispose()` does NOT call any `fd_close` on the preopens because the
|
||||
preopen layer in this minimal snapshot does not hold open file
|
||||
descriptors — each `path_open` is a fresh `stat` against the host
|
||||
filesystem. A richer WASI implementation that holds open fds would
|
||||
need to track them in the handle and close them in `dispose()`.
|
||||
Reference in New Issue
Block a user