1# WebAssembly System Interface (WASI) 2 3<!--introduced_in=v12.16.0--> 4 5> Stability: 1 - Experimental 6 7<!-- source_link=lib/wasi.js --> 8 9The WASI API provides an implementation of the [WebAssembly System Interface][] 10specification. WASI gives sandboxed WebAssembly applications access to the 11underlying operating system via a collection of POSIX-like functions. 12 13```js 14'use strict'; 15const fs = require('fs'); 16const { WASI } = require('wasi'); 17const wasi = new WASI({ 18 args: process.argv, 19 env: process.env, 20 preopens: { 21 '/sandbox': '/some/real/path/that/wasm/can/access' 22 } 23}); 24const importObject = { wasi_snapshot_preview1: wasi.wasiImport }; 25 26(async () => { 27 const wasm = await WebAssembly.compile(fs.readFileSync('./demo.wasm')); 28 const instance = await WebAssembly.instantiate(wasm, importObject); 29 30 wasi.start(instance); 31})(); 32``` 33 34To run the above example, create a new WebAssembly text format file named 35`demo.wat`: 36 37```text 38(module 39 ;; Import the required fd_write WASI function which will write the given io vectors to stdout 40 ;; The function signature for fd_write is: 41 ;; (File Descriptor, *iovs, iovs_len, nwritten) -> Returns number of bytes written 42 (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) 43 44 (memory 1) 45 (export "memory" (memory 0)) 46 47 ;; Write 'hello world\n' to memory at an offset of 8 bytes 48 ;; Note the trailing newline which is required for the text to appear 49 (data (i32.const 8) "hello world\n") 50 51 (func $main (export "_start") 52 ;; Creating a new io vector within linear memory 53 (i32.store (i32.const 0) (i32.const 8)) ;; iov.iov_base - This is a pointer to the start of the 'hello world\n' string 54 (i32.store (i32.const 4) (i32.const 12)) ;; iov.iov_len - The length of the 'hello world\n' string 55 56 (call $fd_write 57 (i32.const 1) ;; file_descriptor - 1 for stdout 58 (i32.const 0) ;; *iovs - The pointer to the iov array, which is stored at memory location 0 59 (i32.const 1) ;; iovs_len - We're printing 1 string stored in an iov - so one. 60 (i32.const 20) ;; nwritten - A place in memory to store the number of bytes written 61 ) 62 drop ;; Discard the number of bytes written from the top of the stack 63 ) 64) 65``` 66 67Use [wabt](https://github.com/WebAssembly/wabt) to compile `.wat` to `.wasm` 68 69```console 70$ wat2wasm demo.wat 71``` 72 73The `--experimental-wasi-unstable-preview1` and `--experimental-wasm-bigint` 74CLI arguments are needed for this example to run. 75 76## Class: `WASI` 77<!-- YAML 78added: v12.16.0 79--> 80 81The `WASI` class provides the WASI system call API and additional convenience 82methods for working with WASI-based applications. Each `WASI` instance 83represents a distinct sandbox environment. For security purposes, each `WASI` 84instance must have its command line arguments, environment variables, and 85sandbox directory structure configured explicitly. 86 87### `new WASI([options])` 88<!-- YAML 89added: v12.16.0 90--> 91 92* `options` {Object} 93 * `args` {Array} An array of strings that the WebAssembly application will 94 see as command line arguments. The first argument is the virtual path to the 95 WASI command itself. **Default:** `[]`. 96 * `env` {Object} An object similar to `process.env` that the WebAssembly 97 application will see as its environment. **Default:** `{}`. 98 * `preopens` {Object} This object represents the WebAssembly application's 99 sandbox directory structure. The string keys of `preopens` are treated as 100 directories within the sandbox. The corresponding values in `preopens` are 101 the real paths to those directories on the host machine. 102 * `returnOnExit` {boolean} By default, WASI applications terminate the Node.js 103 process via the `__wasi_proc_exit()` function. Setting this option to `true` 104 causes `wasi.start()` to return the exit code rather than terminate the 105 process. **Default:** `false`. 106 * `stdin` {integer} The file descriptor used as standard input in the 107 WebAssembly application. **Default:** `0`. 108 * `stdout` {integer} The file descriptor used as standard output in the 109 WebAssembly application. **Default:** `1`. 110 * `stderr` {integer} The file descriptor used as standard error in the 111 WebAssembly application. **Default:** `2`. 112 113### `wasi.start(instance)` 114<!-- YAML 115added: v12.16.0 116--> 117 118* `instance` {WebAssembly.Instance} 119 120Attempt to begin execution of `instance` as a WASI command by invoking its 121`_start()` export. If `instance` does not contain a `_start()` export, or if 122`instance` contains an `_initialize()` export, then an exception is thrown. 123 124`start()` requires that `instance` exports a [`WebAssembly.Memory`][] named 125`memory`. If `instance` does not have a `memory` export an exception is thrown. 126 127If `start()` is called more than once, an exception is thrown. 128 129### `wasi.initialize(instance)` 130<!-- YAML 131added: 132 - v12.19.0 133--> 134 135* `instance` {WebAssembly.Instance} 136 137Attempt to initialize `instance` as a WASI reactor by invoking its 138`_initialize()` export, if it is present. If `instance` contains a `_start()` 139export, then an exception is thrown. 140 141`initialize()` requires that `instance` exports a [`WebAssembly.Memory`][] named 142`memory`. If `instance` does not have a `memory` export an exception is thrown. 143 144If `initialize()` is called more than once, an exception is thrown. 145 146### `wasi.wasiImport` 147<!-- YAML 148added: v12.16.0 149--> 150 151* {Object} 152 153`wasiImport` is an object that implements the WASI system call API. This object 154should be passed as the `wasi_snapshot_preview1` import during the instantiation 155of a [`WebAssembly.Instance`][]. 156 157[WebAssembly System Interface]: https://wasi.dev/ 158[`WebAssembly.Instance`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance 159[`WebAssembly.Memory`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory 160