> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spurdoverse.app/llms.txt
> Use this file to discover all available pages before exploring further.

# WASI

> Run WebAssembly command and reactor modules with WASI preview1.

`wasi_snapshot_preview1` for WebAssembly modules, shaped like Node's `node:wasi`. `WebAssembly` itself is
the standard global ([MDN](https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/JavaScript_interface)).

```ts theme={null}
import { WASI } from "@native/wasi";
```

<Note>
  Nothing is patched globally. Create a `WASI`, pass its imports to `WebAssembly.instantiate`, then
  `start()` a command or `initialize()` a reactor.
</Note>

***

## WASI

### constructor

<br />

```ts theme={null}
new WASI(options?: WASIOptions)
```

Creates one WASI environment.

| Option | Default | |
| :- | :- | :- |
| `args` | `[]` | argv, including `argv[0]` |
| `env` | `{}` | environment variables |
| `preopens` | `{ "/": data/ }` | guest directory → host directory; relative host paths start at `data/` |
| `returnOnExit` | `true` | `proc_exit(code)` ends `start()`, which returns `code`; `false` makes it throw instead |
| `version` | `"preview1"` | the only one |

A host directory outside `data/` needs the `filesystem` [permission](/api/manifest#permissions) and
must exist.

```ts theme={null}
const wasi = new WASI({
    args: ["app", "--fast"],
    env: { MODE: "demo" },
    preopens: { "/": ".", "/assets": "assets" },
});
```

### getImportObject

<br />

```ts theme={null}
wasi.getImportObject(): { wasi_snapshot_preview1: Readonly<Record<string, WasiSyscall>> }
```

The imports to pass to `WebAssembly.instantiate`. `wasi.wasiImport` is the same syscall table on its own,
for merging with your own imports.

```ts theme={null}
const { instance } = await WebAssembly.instantiate(bytes, wasi.getImportObject());

const imports = { wasi_snapshot_preview1: wasi.wasiImport, env: { log: (n: number) => console.log(n) } };
```

### start

<br />

```ts theme={null}
wasi.start(instance: WebAssembly.Instance): number
```

Runs a command: calls `_start()` and returns the exit code (0 when `_start` returns). Call `start()` or
`initialize()` once per `WASI`.

```ts theme={null}
const code = wasi.start(instance);
```

With `returnOnExit: false`, `proc_exit` throws an `Error` with `exitCode`.

### initialize

<br />

```ts theme={null}
wasi.initialize(instance: WebAssembly.Instance): void
```

Sets up a reactor (a module without `_start`): calls `_initialize()` if it's exported. Then call its
exports yourself.

```ts theme={null}
wasi.initialize(instance);
const add = instance.exports.add as (a: number, b: number) => number;
add(2, 3);
```

### dispose

<br />

```ts theme={null}
wasi.dispose(): void
```

Closes every file the guest opened. Happens on unload anyway. `alive` is `false` afterwards, and `using`
disposes at the end of the block.

***

## Guest environment

| | |
| :- | :- |
| argv / environ | exactly `args` / `env` |
| Filesystem | only the preopens, no `..` out of them |
| stdin | empty |
| stdout / stderr | the script log, stderr as errors |
| `sleep()` | returns immediately |
| Sockets | none |

***

## Example

Run a WASI command from `data/app.wasm`.

```ts theme={null}
import { WASI } from "@native/wasi";
import fs from "@native/fs";

async function runApp(args: string[]): Promise<number> {
    using wasi = new WASI({ args: ["app", ...args], env: { MODE: "demo" } });
    const bytes = await fs.readFile("app.wasm");
    const { instance } = await WebAssembly.instantiate(bytes, wasi.getImportObject());
    return wasi.start(instance);
}

const code = await runApp(["--fast"]);
console.log("exit", code);
```
