diff --git a/.gitignore b/.gitignore
index d59c72e..af2286b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,8 +12,11 @@ examples/http/.spin
examples/http/http.wasm
examples/http/proxy
examples/http/poll_loop.py
+examples/tcp-p3/tcp.wasm
examples/tcp/tcp.wasm
examples/tcp/command
+examples/tls-p3/tls.wasm
+examples/cli-p3/cli.wasm
examples/cli/cli.wasm
examples/cli/command
examples/sandbox/sandbox
diff --git a/Cargo.lock b/Cargo.lock
index 8bfb5fe..fe89d03 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -477,7 +477,7 @@ dependencies = [
[[package]]
name = "componentize-py"
-version = "0.20.0"
+version = "0.21.0"
dependencies = [
"anyhow",
"assert_cmd",
diff --git a/examples/cli-p3/app.py b/examples/cli-p3/app.py
index fd4184e..caf22c7 100644
--- a/examples/cli-p3/app.py
+++ b/examples/cli-p3/app.py
@@ -1,5 +1,5 @@
from wit_world import exports
class Run(exports.Run):
- async def run(self):
+ async def run(self) -> None:
print("Hello, world!")
diff --git a/examples/tcp-p3/README.md b/examples/tcp-p3/README.md
new file mode 100644
index 0000000..3e744b3
--- /dev/null
+++ b/examples/tcp-p3/README.md
@@ -0,0 +1,45 @@
+# Example: `tcp-p3`
+
+This is an example of how to use [componentize-py] and [Wasmtime] to build and
+run a Python-based component targetting version `0.3.0-rc-2026-01-06` of the
+[wasi-cli] `command` world and making an outbound TCP request using [wasi-sockets].
+
+[componentize-py]: https://github.com/bytecodealliance/componentize-py
+[Wasmtime]: https://github.com/bytecodealliance/wasmtime
+[wasi-cli]: https://github.com/WebAssembly/WASI/tree/v0.3.0-rc-2026-01-06/proposals/cli/wit-0.3.0-draft
+[wasi-sockets]: https://github.com/WebAssembly/WASI/tree/v0.3.0-rc-2026-01-06/proposals/sockets/wit-0.3.0-draft
+
+## Prerequisites
+
+* `Wasmtime` 41.0.3
+* `componentize-py` 0.21.0
+
+Below, we use [Rust](https://rustup.rs/)'s `cargo` to install `Wasmtime`. If
+you don't have `cargo`, you can download and install from
+https://github.com/bytecodealliance/wasmtime/releases/tag/v41.0.3.
+
+```
+cargo install --version 41.0.3 wasmtime-cli
+pip install componentize-py==0.21.0
+```
+
+## Running the demo
+
+First, in a separate terminal, run `netcat`, telling it to listen for incoming
+TCP connections. You can choose any port you like.
+
+```
+nc -l 127.0.0.1 3456
+```
+
+Now, build and run the example, using the same port you gave to `netcat`.
+
+```
+componentize-py -d ../../wit -w wasi:cli/command@0.3.0-rc-2026-01-06 componentize app -o tcp.wasm
+wasmtime run -Sp3 -Sinherit-network -Wcomponent-model-async tcp.wasm 127.0.0.1:3456
+```
+
+The program will open a TCP connection, send a message, and wait to receive a
+response before exiting. You can give it a response by typing anything you like
+into the terminal where `netcat` is running and then pressing the `Enter` key on
+your keyboard.
diff --git a/examples/tcp-p3/app.py b/examples/tcp-p3/app.py
new file mode 100644
index 0000000..33e74c9
--- /dev/null
+++ b/examples/tcp-p3/app.py
@@ -0,0 +1,81 @@
+import sys
+import asyncio
+import ipaddress
+from ipaddress import IPv4Address, IPv6Address
+import wit_world
+from wit_world import exports
+from wit_world.imports.wasi_sockets_types import (
+ TcpSocket,
+ IpSocketAddress_Ipv4,
+ IpSocketAddress_Ipv6,
+ Ipv4SocketAddress,
+ Ipv6SocketAddress,
+ IpAddressFamily,
+)
+from typing import Tuple
+
+
+IPAddress = IPv4Address | IPv6Address
+
+class Run(exports.Run):
+ async def run(self) -> None:
+ args = sys.argv[1:]
+ if len(args) != 1:
+ print("usage: tcp-p3
:", file=sys.stderr)
+ exit(-1)
+
+ address, port = parse_address_and_port(args[0])
+ await send_and_receive(address, port)
+
+
+def parse_address_and_port(address_and_port: str) -> Tuple[IPAddress, int]:
+ ip, separator, port = address_and_port.rpartition(":")
+ assert separator
+ return (ipaddress.ip_address(ip.strip("[]")), int(port))
+
+
+def make_socket_address(address: IPAddress, port: int) -> IpSocketAddress_Ipv4 | IpSocketAddress_Ipv6:
+ if isinstance(address, IPv4Address):
+ octets = address.packed
+ return IpSocketAddress_Ipv4(Ipv4SocketAddress(
+ port=port,
+ address=(octets[0], octets[1], octets[2], octets[3]),
+ ))
+ else:
+ b = address.packed
+ return IpSocketAddress_Ipv6(Ipv6SocketAddress(
+ port=port,
+ flow_info=0,
+ address=(
+ (b[0] << 8) | b[1],
+ (b[2] << 8) | b[3],
+ (b[4] << 8) | b[5],
+ (b[6] << 8) | b[7],
+ (b[8] << 8) | b[9],
+ (b[10] << 8) | b[11],
+ (b[12] << 8) | b[13],
+ (b[14] << 8) | b[15],
+ ),
+ scope_id=0,
+ ))
+
+
+async def send_and_receive(address: IPAddress, port: int) -> None:
+ family = IpAddressFamily.IPV4 if isinstance(address, IPv4Address) else IpAddressFamily.IPV6
+
+ sock = TcpSocket.create(family)
+
+ await sock.connect(make_socket_address(address, port))
+
+ send_tx, send_rx = wit_world.byte_stream()
+ async def write() -> None:
+ with send_tx:
+ await send_tx.write_all(b"hello, world!")
+ await asyncio.gather(sock.send(send_rx), write())
+
+ recv_rx, recv_fut = sock.receive()
+ async def read() -> None:
+ with recv_rx:
+ data = await recv_rx.read(1024)
+ print(f"received: {str(data)}")
+ await asyncio.gather(recv_fut.read(), read())
diff --git a/examples/tls-p3/README.md b/examples/tls-p3/README.md
new file mode 100644
index 0000000..09f9122
--- /dev/null
+++ b/examples/tls-p3/README.md
@@ -0,0 +1,38 @@
+# Example: `tls-p3`
+
+This is an example of how to use [componentize-py] and [Wasmtime] to build and
+run a Python-based TLS client component targetting version `0.3.0-rc-2026-02-09`
+of the [wasi-cli] `command` world with [wasi-tls] and [wasi-sockets] support.
+
+[componentize-py]: https://github.com/bytecodealliance/componentize-py
+[Wasmtime]: https://github.com/bytecodealliance/wasmtime
+[wasi-cli]: https://github.com/WebAssembly/WASI/tree/v0.3.0-rc-2026-02-09/proposals/cli/wit-0.3.0-draft
+[wasi-sockets]: https://github.com/WebAssembly/WASI/tree/v0.3.0-rc-2026-02-09/proposals/sockets/wit-0.3.0-draft
+[wasi-tls]: https://github.com/WebAssembly/wasi-tls
+
+## Prerequisites
+
+* `Wasmtime` 43.0.0
+* `componentize-py` 0.21.0
+
+Below, we use [Rust](https://rustup.rs/)'s `cargo` to install `Wasmtime`. If
+you don't have `cargo`, you can download and install from
+https://github.com/bytecodealliance/wasmtime/releases/tag/v43.0.0.
+
+```
+cargo install --version 43.0.0 wasmtime-cli
+pip install componentize-py==0.21.0
+```
+
+## Running the demo
+
+```
+componentize-py -d ../../wit -w tls-p3 componentize app -o tls.wasm
+wasmtime run -Sp3,inherit-network,tls,allow-ip-name-lookup -Wcomponent-model-async tls.wasm
+```
+
+For example, to connect to `api.github.com` over TLS:
+
+```
+wasmtime run -Sp3,inherit-network,tls,allow-ip-name-lookup -Wcomponent-model-async tls.wasm api.github.com
+```
diff --git a/examples/tls-p3/app.py b/examples/tls-p3/app.py
new file mode 100644
index 0000000..ca6aead
--- /dev/null
+++ b/examples/tls-p3/app.py
@@ -0,0 +1,76 @@
+import sys
+import asyncio
+import wit_world
+from wit_world import exports
+from wit_world.imports.wasi_sockets_types import (
+ TcpSocket,
+ IpSocketAddress_Ipv4,
+ IpSocketAddress_Ipv6,
+ Ipv4SocketAddress,
+ Ipv6SocketAddress,
+ IpAddressFamily,
+ IpAddress_Ipv4,
+ IpAddress_Ipv6,
+)
+from wit_world.imports.ip_name_lookup import resolve_addresses
+from wit_world.imports.client import Connector
+
+
+class Run(exports.Run):
+ async def run(self) -> None:
+ args = sys.argv[1:]
+ if len(args) != 1:
+ print("usage: tls-p3 ", file=sys.stderr)
+ exit(-1)
+
+ server_name = args[0]
+ await send_and_receive(server_name)
+
+
+async def send_and_receive(server_name: str) -> None:
+ port = 443
+ addresses = await resolve_addresses(server_name)
+ address = addresses[0]
+
+ if isinstance(address, IpAddress_Ipv4):
+ family = IpAddressFamily.IPV4
+ sock_addr: IpSocketAddress_Ipv4 | IpSocketAddress_Ipv6 = IpSocketAddress_Ipv4(
+ Ipv4SocketAddress(port=port, address=address.value)
+ )
+ else:
+ family = IpAddressFamily.IPV6
+ sock_addr = IpSocketAddress_Ipv6(
+ Ipv6SocketAddress(port=port, flow_info=0, address=address.value, scope_id=0)
+ )
+
+ sock = TcpSocket.create(family)
+ await sock.connect(sock_addr)
+
+ tls = Connector()
+
+ data_send_tx, data_send_rx = wit_world.byte_stream()
+ tls_send_rx, tls_send_fut = tls.send(data_send_rx)
+ sock_send_fut = sock.send(tls_send_rx)
+
+ tls_recv_rx, sock_recv_fut = sock.receive()
+ data_recv_rx, tls_recv_fut = tls.receive(tls_recv_rx)
+
+ async def write() -> None:
+ with data_send_tx:
+ await data_send_tx.write_all(f"GET / HTTP/1.1\r\nHost: {server_name}\r\nUser-Agent: wasmtime-wasi-rust\r\nConnection: close\r\n\r\n".encode())
+
+ async def read() -> None:
+ with data_recv_rx:
+ while not data_recv_rx.writer_dropped:
+ buf = await data_recv_rx.read(1024)
+ sys.stdout.buffer.write(buf)
+
+ await asyncio.gather(
+ Connector.connect(tls, server_name),
+ write(),
+ read(),
+ sock_send_fut.read(),
+ sock_recv_fut.read(),
+ tls_send_fut.read(),
+ tls_recv_fut.read(),
+ )
diff --git a/tests/bindings.rs b/tests/bindings.rs
index 2b583d8..fadcf85 100644
--- a/tests/bindings.rs
+++ b/tests/bindings.rs
@@ -29,6 +29,27 @@ fn lint_cli_bindings() -> anyhow::Result<()> {
Ok(())
}
+#[test]
+fn lint_cli_p3_bindings() -> anyhow::Result<()> {
+ let dir = tempfile::tempdir()?;
+ fs_extra::copy_items(
+ &["./examples/cli-p3", "./wit"],
+ dir.path(),
+ &CopyOptions::new(),
+ )?;
+ let path = dir.path().join("cli-p3");
+
+ generate_bindings(&path, "wasi:cli/command@0.3.0-rc-2026-01-06")?;
+
+ assert!(predicate::path::is_dir().eval(&path.join("wit_world")));
+
+ _ = dir.keep();
+
+ mypy_check(&path, ["--strict", "-m", "app"]);
+
+ Ok(())
+}
+
#[test]
fn lint_http_bindings() -> anyhow::Result<()> {
let dir = tempfile::tempdir()?;
@@ -150,6 +171,44 @@ fn lint_tcp_bindings() -> anyhow::Result<()> {
Ok(())
}
+#[test]
+fn lint_tcp_p3_bindings() -> anyhow::Result<()> {
+ let dir = tempfile::tempdir()?;
+ fs_extra::copy_items(
+ &["./examples/tcp-p3", "./wit"],
+ dir.path(),
+ &CopyOptions::new(),
+ )?;
+ let path = dir.path().join("tcp-p3");
+
+ generate_bindings(&path, "wasi:cli/command@0.3.0-rc-2026-01-06")?;
+
+ assert!(predicate::path::is_dir().eval(&path.join("wit_world")));
+
+ mypy_check(&path, ["--strict", "-m", "app"]);
+
+ Ok(())
+}
+
+#[test]
+fn lint_tls_p3_bindings() -> anyhow::Result<()> {
+ let dir = tempfile::tempdir()?;
+ fs_extra::copy_items(
+ &["./examples/tls-p3", "./wit"],
+ dir.path(),
+ &CopyOptions::new(),
+ )?;
+ let path = dir.path().join("tls-p3");
+
+ generate_bindings(&path, "tls-p3")?;
+
+ assert!(predicate::path::is_dir().eval(&path.join("wit_world")));
+
+ mypy_check(&path, ["--strict", "-m", "app"]);
+
+ Ok(())
+}
+
fn generate_bindings(path: &Path, world: &str) -> Result {
Ok(cargo::cargo_bin_cmd!("componentize-py")
.current_dir(path)
diff --git a/tests/componentize.rs b/tests/componentize.rs
index e1fa63c..bcf2bf4 100644
--- a/tests/componentize.rs
+++ b/tests/componentize.rs
@@ -1,3 +1,4 @@
+use core::net::Ipv4Addr;
use std::{
io::Write,
path::{Path, PathBuf},
@@ -14,13 +15,22 @@ use tar::Archive;
#[test]
fn cli_example() -> anyhow::Result<()> {
+ test_cli_example("cli", "wasi:cli/command@0.2.0")
+}
+
+#[test]
+fn cli_p3_example() -> anyhow::Result<()> {
+ test_cli_example("cli-p3", "wasi:cli/command@0.3.0-rc-2026-01-06")
+}
+
+fn test_cli_example(name: &str, world: &str) -> anyhow::Result<()> {
let dir = tempfile::tempdir()?;
fs_extra::copy_items(
- &["./examples/cli", "./wit"],
+ &[format!("./examples/{name}").as_str(), "./wit"],
dir.path(),
&CopyOptions::new(),
)?;
- let path = dir.path().join("cli");
+ let path = dir.path().join(name);
cargo::cargo_bin_cmd!("componentize-py")
.current_dir(&path)
@@ -28,7 +38,7 @@ fn cli_example() -> anyhow::Result<()> {
"-d",
"../wit",
"-w",
- "wasi:cli/command@0.2.0",
+ world,
"componentize",
"app",
"-o",
@@ -40,7 +50,7 @@ fn cli_example() -> anyhow::Result<()> {
Command::new("wasmtime")
.current_dir(&path)
- .args(["run", "cli.wasm"])
+ .args(["run", "-Sp3", "-Wcomponent-model-async", "cli.wasm"])
.assert()
.success()
.stdout("Hello, world!\n");
@@ -232,13 +242,22 @@ fn sandbox_example() -> anyhow::Result<()> {
#[test]
fn tcp_example() -> anyhow::Result<()> {
+ test_tcp_example("tcp", "wasi:cli/command@0.2.0")
+}
+
+#[test]
+fn tcp_p3_example() -> anyhow::Result<()> {
+ test_tcp_example("tcp-p3", "wasi:cli/command@0.3.0-rc-2026-01-06")
+}
+
+fn test_tcp_example(name: &str, world: &str) -> anyhow::Result<()> {
let dir = tempfile::tempdir()?;
fs_extra::copy_items(
- &["./examples/tcp", "./wit"],
+ &[format!("./examples/{name}").as_str(), "./wit"],
dir.path(),
&CopyOptions::new(),
)?;
- let path = dir.path().join("tcp");
+ let path = dir.path().join(name);
cargo::cargo_bin_cmd!("componentize-py")
.current_dir(&path)
@@ -246,7 +265,7 @@ fn tcp_example() -> anyhow::Result<()> {
"-d",
"../wit",
"-w",
- "wasi:cli/command@0.2.0",
+ world,
"componentize",
"app",
"-o",
@@ -256,16 +275,17 @@ fn tcp_example() -> anyhow::Result<()> {
.success()
.stdout("Component built successfully\n");
- let listener = std::net::TcpListener::bind("127.0.0.1:3456")?;
+ let listener = std::net::TcpListener::bind((Ipv4Addr::LOCALHOST, 0))?;
+ let port = listener.local_addr()?.port();
let tcp_handle = std::process::Command::new("wasmtime")
.current_dir(&path)
.args([
"run",
- "--wasi",
- "inherit-network",
+ "-Sp3,inherit-network",
+ "-Wcomponent-model-async",
"tcp.wasm",
- "127.0.0.1:3456",
+ &format!("127.0.0.1:{port}"),
])
.stdout(Stdio::piped())
.spawn()?;
@@ -283,6 +303,48 @@ fn tcp_example() -> anyhow::Result<()> {
Ok(())
}
+#[test]
+fn tls_p3_example() -> anyhow::Result<()> {
+ let dir = tempfile::tempdir()?;
+ fs_extra::copy_items(
+ &["./examples/tls-p3", "./wit"],
+ dir.path(),
+ &CopyOptions::new(),
+ )?;
+ let path = dir.path().join("tls-p3");
+
+ cargo::cargo_bin_cmd!("componentize-py")
+ .current_dir(&path)
+ .args([
+ "-d",
+ "../wit",
+ "-w",
+ "tls-p3",
+ "componentize",
+ "app",
+ "-o",
+ "tls.wasm",
+ ])
+ .assert()
+ .success()
+ .stdout("Component built successfully\n");
+
+ Command::new("wasmtime")
+ .current_dir(&path)
+ .args([
+ "run",
+ "-Sp3,inherit-network,tls,allow-ip-name-lookup",
+ "-Wcomponent-model-async",
+ "tls.wasm",
+ "api.github.com",
+ ])
+ .assert()
+ .success()
+ .stdout(predicate::str::starts_with("HTTP/1.1 200 OK"));
+
+ Ok(())
+}
+
fn retry(mut func: impl FnMut() -> anyhow::Result) -> anyhow::Result {
let times = 10;
for i in 0..times {
diff --git a/wit/deps/cli-0.3.0-rc-2026-01-06.wit b/wit/deps/cli.wit
similarity index 60%
rename from wit/deps/cli-0.3.0-rc-2026-01-06.wit
rename to wit/deps/cli.wit
index 0f987bf..4f8bbf8 100644
--- a/wit/deps/cli-0.3.0-rc-2026-01-06.wit
+++ b/wit/deps/cli.wit
@@ -1,6 +1,6 @@
-package wasi:cli@0.3.0-rc-2026-01-06;
+package wasi:cli@0.3.0-rc-2026-02-09;
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface environment {
/// Get the POSIX-style environment variables.
///
@@ -10,23 +10,23 @@ interface environment {
/// Morally, these are a value import, but until value imports are available
/// in the component model, this import function should return the same
/// values each time it is called.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-environment: func() -> list>;
/// Get the POSIX-style arguments to the program.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-arguments: func() -> list;
/// Return a path that programs should use as their initial current working
/// directory, interpreting `.` as shorthand for this.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-initial-cwd: func() -> option;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface exit {
/// Exit the current instance and any linked instances.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
exit: func(status: result);
/// Exit the current instance and any linked instances, reporting the
@@ -41,16 +41,16 @@ interface exit {
exit-with-code: func(status-code: u8);
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface run {
/// Run the program.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
run: async func() -> result;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface types {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
enum error-code {
/// Input/output error
io,
@@ -61,7 +61,7 @@ interface types {
}
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface stdin {
use types.{error-code};
@@ -78,11 +78,11 @@ interface stdin {
///
/// Multiple streams may be active at the same time. The behavior of concurrent
/// reads is implementation-specific.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
read-via-stream: func() -> tuple, future>>;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface stdout {
use types.{error-code};
@@ -94,11 +94,11 @@ interface stdout {
///
/// Otherwise if there is an error the readable end of the stream will be
/// dropped and this function will return an error-code.
- @since(version = 0.3.0-rc-2026-01-06)
- write-via-stream: async func(data: stream) -> result<_, error-code>;
+ @since(version = 0.3.0-rc-2026-02-09)
+ write-via-stream: func(data: stream) -> future>;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface stderr {
use types.{error-code};
@@ -110,8 +110,8 @@ interface stderr {
///
/// Otherwise if there is an error the readable end of the stream will be
/// dropped and this function will return an error-code.
- @since(version = 0.3.0-rc-2026-01-06)
- write-via-stream: async func(data: stream) -> result<_, error-code>;
+ @since(version = 0.3.0-rc-2026-02-09)
+ write-via-stream: func(data: stream) -> future>;
}
/// Terminal input.
@@ -119,10 +119,10 @@ interface stderr {
/// In the future, this may include functions for disabling echoing,
/// disabling input buffering so that keyboard events are sent through
/// immediately, querying supported features, and so on.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface terminal-input {
/// The input side of a terminal.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
resource terminal-input;
}
@@ -131,126 +131,126 @@ interface terminal-input {
/// In the future, this may include functions for querying the terminal
/// size, being notified of terminal size changes, querying supported
/// features, and so on.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface terminal-output {
/// The output side of a terminal.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
resource terminal-output;
}
/// An interface providing an optional `terminal-input` for stdin as a
/// link-time authority.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface terminal-stdin {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
use terminal-input.{terminal-input};
/// If stdin is connected to a terminal, return a `terminal-input` handle
/// allowing further interaction with it.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-terminal-stdin: func() -> option;
}
/// An interface providing an optional `terminal-output` for stdout as a
/// link-time authority.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface terminal-stdout {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
use terminal-output.{terminal-output};
/// If stdout is connected to a terminal, return a `terminal-output` handle
/// allowing further interaction with it.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-terminal-stdout: func() -> option;
}
/// An interface providing an optional `terminal-output` for stderr as a
/// link-time authority.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface terminal-stderr {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
use terminal-output.{terminal-output};
/// If stderr is connected to a terminal, return a `terminal-output` handle
/// allowing further interaction with it.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-terminal-stderr: func() -> option;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
world imports {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import environment;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import exit;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import types;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import stdin;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import stdout;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import stderr;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-input;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-output;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-stdin;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-stdout;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-stderr;
- import wasi:clocks/types@0.3.0-rc-2026-01-06;
- import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
- import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
+ import wasi:clocks/types@0.3.0-rc-2026-02-09;
+ import wasi:clocks/monotonic-clock@0.3.0-rc-2026-02-09;
+ import wasi:clocks/system-clock@0.3.0-rc-2026-02-09;
@unstable(feature = clocks-timezone)
- import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
- import wasi:filesystem/types@0.3.0-rc-2026-01-06;
- import wasi:filesystem/preopens@0.3.0-rc-2026-01-06;
- import wasi:sockets/types@0.3.0-rc-2026-01-06;
- import wasi:sockets/ip-name-lookup@0.3.0-rc-2026-01-06;
- import wasi:random/random@0.3.0-rc-2026-01-06;
- import wasi:random/insecure@0.3.0-rc-2026-01-06;
- import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
+ import wasi:clocks/timezone@0.3.0-rc-2026-02-09;
+ import wasi:filesystem/types@0.3.0-rc-2026-02-09;
+ import wasi:filesystem/preopens@0.3.0-rc-2026-02-09;
+ import wasi:sockets/types@0.3.0-rc-2026-02-09;
+ import wasi:sockets/ip-name-lookup@0.3.0-rc-2026-02-09;
+ import wasi:random/random@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure-seed@0.3.0-rc-2026-02-09;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
world command {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import environment;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import exit;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import types;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import stdin;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import stdout;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import stderr;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-input;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-output;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-stdin;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-stdout;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import terminal-stderr;
- import wasi:clocks/types@0.3.0-rc-2026-01-06;
- import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
- import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
+ import wasi:clocks/types@0.3.0-rc-2026-02-09;
+ import wasi:clocks/monotonic-clock@0.3.0-rc-2026-02-09;
+ import wasi:clocks/system-clock@0.3.0-rc-2026-02-09;
@unstable(feature = clocks-timezone)
- import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
- import wasi:filesystem/types@0.3.0-rc-2026-01-06;
- import wasi:filesystem/preopens@0.3.0-rc-2026-01-06;
- import wasi:sockets/types@0.3.0-rc-2026-01-06;
- import wasi:sockets/ip-name-lookup@0.3.0-rc-2026-01-06;
- import wasi:random/random@0.3.0-rc-2026-01-06;
- import wasi:random/insecure@0.3.0-rc-2026-01-06;
- import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
+ import wasi:clocks/timezone@0.3.0-rc-2026-02-09;
+ import wasi:filesystem/types@0.3.0-rc-2026-02-09;
+ import wasi:filesystem/preopens@0.3.0-rc-2026-02-09;
+ import wasi:sockets/types@0.3.0-rc-2026-02-09;
+ import wasi:sockets/ip-name-lookup@0.3.0-rc-2026-02-09;
+ import wasi:random/random@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure-seed@0.3.0-rc-2026-02-09;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
export run;
}
diff --git a/wit/deps/clocks-0.3.0-rc-2026-01-06.wit b/wit/deps/clocks.wit
similarity index 89%
rename from wit/deps/clocks-0.3.0-rc-2026-01-06.wit
rename to wit/deps/clocks.wit
index fc59f5a..71986ba 100644
--- a/wit/deps/clocks-0.3.0-rc-2026-01-06.wit
+++ b/wit/deps/clocks.wit
@@ -1,10 +1,10 @@
-package wasi:clocks@0.3.0-rc-2026-01-06;
+package wasi:clocks@0.3.0-rc-2026-02-09;
/// This interface common types used throughout wasi:clocks.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface types {
/// A duration of time, in nanoseconds.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
type duration = u64;
}
@@ -16,14 +16,14 @@ interface types {
///
/// A monotonic clock is a clock which has an unspecified initial value, and
/// successive reads of the clock will produce non-decreasing values.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface monotonic-clock {
use types.{duration};
/// A mark on a monotonic clock is a number of nanoseconds since an
/// unspecified initial value, and can only be compared to instances from
/// the same monotonic-clock.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
type mark = u64;
/// Read the current value of the clock.
@@ -35,20 +35,20 @@ interface monotonic-clock {
/// the value of the clock in a `mark`. Consequently, implementations
/// should ensure that the starting time is low enough to avoid the
/// possibility of overflow in practice.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
now: func() -> mark;
/// Query the resolution of the clock. Returns the duration of time
/// corresponding to a clock tick.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-resolution: func() -> duration;
/// Wait until the specified mark has occurred.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
wait-until: async func(when: mark);
/// Wait for the specified duration to elapse.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
wait-for: async func(how-long: duration);
}
@@ -62,7 +62,7 @@ interface monotonic-clock {
/// monotonic, making it unsuitable for measuring elapsed time.
///
/// It is intended for reporting the current date and time for humans.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface system-clock {
use types.{duration};
@@ -82,7 +82,7 @@ interface system-clock {
///
/// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
/// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
record instant {
seconds: s64,
nanoseconds: u32,
@@ -94,12 +94,12 @@ interface system-clock {
/// will not necessarily produce a sequence of non-decreasing values.
///
/// The nanoseconds field of the output is always less than 1000000000.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
now: func() -> instant;
/// Query the resolution of the clock. Returns the smallest duration of time
/// that the implementation permits distinguishing.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-resolution: func() -> duration;
}
@@ -148,13 +148,13 @@ interface timezone {
to-debug-string: func() -> string;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
world imports {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import types;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import monotonic-clock;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import system-clock;
@unstable(feature = clocks-timezone)
import timezone;
diff --git a/wit/deps/filesystem-0.3.0-rc-2026-01-06.wit b/wit/deps/filesystem.wit
similarity index 87%
rename from wit/deps/filesystem-0.3.0-rc-2026-01-06.wit
rename to wit/deps/filesystem.wit
index 0ac149c..8fb8304 100644
--- a/wit/deps/filesystem-0.3.0-rc-2026-01-06.wit
+++ b/wit/deps/filesystem.wit
@@ -1,12 +1,9 @@
-package wasi:filesystem@0.3.0-rc-2026-01-06;
+package wasi:filesystem@0.3.0-rc-2026-02-09;
/// WASI filesystem is a filesystem API primarily intended to let users run WASI
/// programs that access their files on their existing filesystems, without
/// significant overhead.
///
-/// It is intended to be roughly portable between Unix-family platforms and
-/// Windows, though it does not hide many of the major differences.
-///
/// Paths are passed as interface-type `string`s, meaning they must consist of
/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain
/// paths which are not accessible by this API.
@@ -23,20 +20,34 @@ package wasi:filesystem@0.3.0-rc-2026-01-06;
/// For more information about WASI path resolution and sandboxing, see
/// [WASI filesystem path resolution].
///
+/// Though this package presents a portable interface modelled on POSIX, it
+/// prioritizes compatibility over portability: allowing users to access their
+/// files on their machine is more important than exposing a single semantics
+/// across all platforms. Notably, depending on the underlying operating system
+/// and file system:
+/// * Paths may be case-folded or not.
+/// * Deleting (unlinking) a file may fail if there are other file descriptors
+/// open.
+/// * Durability and atomicity of changes to underlying files when there are
+/// concurrent writers.
+///
+/// Users that need well-defined, portable semantics should use a key-value
+/// store or a database instead.
+///
/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface types {
- @since(version = 0.3.0-rc-2026-01-06)
- use wasi:clocks/system-clock@0.3.0-rc-2026-01-06.{instant};
+ @since(version = 0.3.0-rc-2026-02-09)
+ use wasi:clocks/system-clock@0.3.0-rc-2026-02-09.{instant};
/// File size or length of a region within a file.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
type filesize = u64;
/// The type of a filesystem object referenced by a descriptor.
///
/// Note: This was called `filetype` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
enum descriptor-type {
/// The type of the descriptor or file is unknown or is different from
/// any of the other types specified.
@@ -60,7 +71,7 @@ interface types {
/// Descriptor flags.
///
/// Note: This was called `fdflags` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
flags descriptor-flags {
/// Read mode: Data can be read.
read,
@@ -102,7 +113,7 @@ interface types {
}
/// Flags determining the method of how paths are resolved.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
flags path-flags {
/// As long as the resolved path corresponds to a symbolic link, it is
/// expanded.
@@ -110,7 +121,7 @@ interface types {
}
/// Open flags used by `open-at`.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
flags open-flags {
/// Create file if it does not exist, similar to `O_CREAT` in POSIX.
create,
@@ -123,13 +134,13 @@ interface types {
}
/// Number of hard links to an inode.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
type link-count = u64;
/// File attributes.
///
/// Note: This was called `filestat` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
record descriptor-stat {
/// File type.
%type: descriptor-type,
@@ -156,7 +167,7 @@ interface types {
}
/// When setting a timestamp, this gives the value to set it to.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
variant new-timestamp {
/// Leave the timestamp set to its previous value.
no-change,
@@ -168,6 +179,7 @@ interface types {
}
/// A directory entry.
+ @since(version = 0.3.0-rc-2026-02-09)
record directory-entry {
/// The type of the file referred to by this directory entry.
%type: descriptor-type,
@@ -179,6 +191,7 @@ interface types {
/// Not all of these error codes are returned by the functions provided by this
/// API; some are used in higher-level library layers, and others are provided
/// merely for alignment with POSIX.
+ @since(version = 0.3.0-rc-2026-02-09)
enum error-code {
/// Permission denied, similar to `EACCES` in POSIX.
access,
@@ -255,7 +268,7 @@ interface types {
}
/// File or memory access pattern advisory information.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
enum advice {
/// The application has no advice to give on its behavior with respect
/// to the specified data.
@@ -279,7 +292,7 @@ interface types {
/// A 128-bit hash value, split into parts because wasm doesn't have a
/// 128-bit integer type.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
record metadata-hash-value {
/// 64 bits of a 128-bit hash value.
lower: u64,
@@ -290,7 +303,7 @@ interface types {
/// A descriptor is a reference to a filesystem object, which may be a file,
/// directory, named pipe, special file, or other object on which filesystem
/// calls may be made.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
resource descriptor {
/// Return a stream for reading from a file.
///
@@ -308,7 +321,7 @@ interface types {
/// resolves to `err` with an `error-code`.
///
/// Note: This is similar to `pread` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
read-via-stream: func(offset: filesize) -> tuple, future>>;
/// Return a stream for writing to a file, if available.
///
@@ -322,8 +335,8 @@ interface types {
/// written or an error is encountered.
///
/// Note: This is similar to `pwrite` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
- write-via-stream: async func(data: stream, offset: filesize) -> result<_, error-code>;
+ @since(version = 0.3.0-rc-2026-02-09)
+ write-via-stream: func(data: stream, offset: filesize) -> future>;
/// Return a stream for appending to a file, if available.
///
/// May fail with an error-code describing why the file cannot be appended.
@@ -332,12 +345,12 @@ interface types {
/// written or an error is encountered.
///
/// Note: This is similar to `write` with `O_APPEND` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
- append-via-stream: async func(data: stream) -> result<_, error-code>;
+ @since(version = 0.3.0-rc-2026-02-09)
+ append-via-stream: func(data: stream) -> future>;
/// Provide file advisory information on a descriptor.
///
/// This is similar to `posix_fadvise` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
advise: async func(offset: filesize, length: filesize, advice: advice) -> result<_, error-code>;
/// Synchronize the data of a file to disk.
///
@@ -345,7 +358,7 @@ interface types {
/// opened for writing.
///
/// Note: This is similar to `fdatasync` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
sync-data: async func() -> result<_, error-code>;
/// Get flags associated with a descriptor.
///
@@ -353,7 +366,7 @@ interface types {
///
/// Note: This returns the value that was the `fs_flags` value returned
/// from `fdstat_get` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-flags: async func() -> result;
/// Get the dynamic type of a descriptor.
///
@@ -365,20 +378,20 @@ interface types {
///
/// Note: This returns the value that was the `fs_filetype` value returned
/// from `fdstat_get` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-type: async func() -> result;
/// Adjust the size of an open file. If this increases the file's size, the
/// extra bytes are filled with zeros.
///
/// Note: This was called `fd_filestat_set_size` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-size: async func(size: filesize) -> result<_, error-code>;
/// Adjust the timestamps of an open file or directory.
///
/// Note: This is similar to `futimens` in POSIX.
///
/// Note: This was called `fd_filestat_set_times` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-times: async func(data-access-timestamp: new-timestamp, data-modification-timestamp: new-timestamp) -> result<_, error-code>;
/// Read directory entries from a directory.
///
@@ -392,20 +405,20 @@ interface types {
///
/// This function returns a future, which will resolve to an error code if
/// reading full contents of the directory fails.
- @since(version = 0.3.0-rc-2026-01-06)
- read-directory: async func() -> tuple, future>>;
+ @since(version = 0.3.0-rc-2026-02-09)
+ read-directory: func() -> tuple, future>>;
/// Synchronize the data and metadata of a file to disk.
///
/// This function succeeds with no effect if the file descriptor is not
/// opened for writing.
///
/// Note: This is similar to `fsync` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
sync: async func() -> result<_, error-code>;
/// Create a directory.
///
/// Note: This is similar to `mkdirat` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
create-directory-at: async func(path: string) -> result<_, error-code>;
/// Return the attributes of an open file or directory.
///
@@ -416,7 +429,7 @@ interface types {
/// modified, use `metadata-hash`.
///
/// Note: This was called `fd_filestat_get` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
stat: async func() -> result;
/// Return the attributes of a file or directory.
///
@@ -425,7 +438,7 @@ interface types {
/// discussion of alternatives.
///
/// Note: This was called `path_filestat_get` in earlier versions of WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
stat-at: async func(path-flags: path-flags, path: string) -> result;
/// Adjust the timestamps of a file or directory.
///
@@ -433,7 +446,7 @@ interface types {
///
/// Note: This was called `path_filestat_set_times` in earlier versions of
/// WASI.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-times-at: async func(path-flags: path-flags, path: string, data-access-timestamp: new-timestamp, data-modification-timestamp: new-timestamp) -> result<_, error-code>;
/// Create a hard link.
///
@@ -442,7 +455,7 @@ interface types {
/// `error-code::not-permitted` if the old path is not a file.
///
/// Note: This is similar to `linkat` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
link-at: async func(old-path-flags: path-flags, old-path: string, new-descriptor: borrow, new-path: string) -> result<_, error-code>;
/// Open a file or directory.
///
@@ -456,7 +469,7 @@ interface types {
/// `error-code::read-only`.
///
/// Note: This is similar to `openat` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
open-at: async func(path-flags: path-flags, path: string, open-flags: open-flags, %flags: descriptor-flags) -> result;
/// Read the contents of a symbolic link.
///
@@ -464,19 +477,19 @@ interface types {
/// filesystem, this function fails with `error-code::not-permitted`.
///
/// Note: This is similar to `readlinkat` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
readlink-at: async func(path: string) -> result;
/// Remove a directory.
///
/// Return `error-code::not-empty` if the directory is not empty.
///
/// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
remove-directory-at: async func(path: string) -> result<_, error-code>;
/// Rename a filesystem object.
///
/// Note: This is similar to `renameat` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
rename-at: async func(old-path: string, new-descriptor: borrow, new-path: string) -> result<_, error-code>;
/// Create a symbolic link (also known as a "symlink").
///
@@ -484,13 +497,13 @@ interface types {
/// `error-code::not-permitted`.
///
/// Note: This is similar to `symlinkat` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
symlink-at: async func(old-path: string, new-path: string) -> result<_, error-code>;
/// Unlink a filesystem object that is not a directory.
///
/// Return `error-code::is-directory` if the path refers to a directory.
/// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
unlink-file-at: async func(path: string) -> result<_, error-code>;
/// Test whether two descriptors refer to the same filesystem object.
///
@@ -498,7 +511,7 @@ interface types {
/// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers.
/// wasi-filesystem does not expose device and inode numbers, so this function
/// may be used instead.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
is-same-object: async func(other: borrow) -> bool;
/// Return a hash of the metadata associated with a filesystem object referred
/// to by a descriptor.
@@ -519,35 +532,35 @@ interface types {
/// computed hash.
///
/// However, none of these is required.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
metadata-hash: async func() -> result;
/// Return a hash of the metadata associated with a filesystem object referred
/// to by a directory descriptor and a relative path.
///
/// This performs the same hash computation as `metadata-hash`.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
metadata-hash-at: async func(path-flags: path-flags, path: string) -> result;
}
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface preopens {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
use types.{descriptor};
/// Return the set of preopened directories, and their paths.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-directories: func() -> list>;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
world imports {
- @since(version = 0.3.0-rc-2026-01-06)
- import wasi:clocks/types@0.3.0-rc-2026-01-06;
- @since(version = 0.3.0-rc-2026-01-06)
- import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
+ import wasi:clocks/types@0.3.0-rc-2026-02-09;
+ @since(version = 0.3.0-rc-2026-02-09)
+ import wasi:clocks/system-clock@0.3.0-rc-2026-02-09;
+ @since(version = 0.3.0-rc-2026-02-09)
import types;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import preopens;
}
diff --git a/wit/deps/http-0.3.0-rc-2026-01-06.wit b/wit/deps/http.wit
similarity index 90%
rename from wit/deps/http-0.3.0-rc-2026-01-06.wit
rename to wit/deps/http.wit
index 3860af7..442b18e 100644
--- a/wit/deps/http-0.3.0-rc-2026-01-06.wit
+++ b/wit/deps/http.wit
@@ -1,11 +1,13 @@
-package wasi:http@0.3.0-rc-2026-01-06;
+package wasi:http@0.3.0-rc-2026-02-09;
/// This interface defines all of the types and methods for implementing HTTP
/// Requests and Responses, as well as their headers, trailers, and bodies.
+@since(version = 0.3.0-rc-2026-02-09)
interface types {
- use wasi:clocks/types@0.3.0-rc-2026-01-06.{duration};
+ use wasi:clocks/types@0.3.0-rc-2026-02-09.{duration};
/// This type corresponds to HTTP standard Methods.
+ @since(version = 0.3.0-rc-2026-02-09)
variant method {
get,
head,
@@ -20,6 +22,7 @@ interface types {
}
/// This type corresponds to HTTP standard Related Schemes.
+ @since(version = 0.3.0-rc-2026-02-09)
variant scheme {
HTTP,
HTTPS,
@@ -27,18 +30,21 @@ interface types {
}
/// Defines the case payload type for `DNS-error` above:
+ @since(version = 0.3.0-rc-2026-02-09)
record DNS-error-payload {
rcode: option,
info-code: option,
}
/// Defines the case payload type for `TLS-alert-received` above:
+ @since(version = 0.3.0-rc-2026-02-09)
record TLS-alert-received-payload {
alert-id: option,
alert-message: option,
}
/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
+ @since(version = 0.3.0-rc-2026-02-09)
record field-size-payload {
field-name: option,
field-size: option,
@@ -46,6 +52,7 @@ interface types {
/// These cases are inspired by the IANA HTTP Proxy Error Types:
///
+ @since(version = 0.3.0-rc-2026-02-09)
variant error-code {
DNS-timeout,
DNS-error(DNS-error-payload),
@@ -95,6 +102,7 @@ interface types {
/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
+ @since(version = 0.3.0-rc-2026-02-09)
variant header-error {
/// This error indicates that a `field-name` or `field-value` was
/// syntactically invalid when used with an operation that sets headers in a
@@ -110,6 +118,7 @@ interface types {
/// This type enumerates the different kinds of errors that may occur when
/// setting fields of a `request-options` resource.
+ @since(version = 0.3.0-rc-2026-02-09)
variant request-options-error {
/// Indicates the specified field is not supported by this implementation.
not-supported,
@@ -122,11 +131,13 @@ interface types {
///
/// Field names should always be treated as case insensitive by the `fields`
/// resource for the purposes of equality checking.
+ @since(version = 0.3.0-rc-2026-02-09)
type field-name = string;
/// Field values should always be ASCII strings. However, in
/// reality, HTTP implementations often have to interpret malformed values,
/// so they are provided as a list of bytes.
+ @since(version = 0.3.0-rc-2026-02-09)
type field-value = list;
/// This following block defines the `fields` resource which corresponds to
@@ -144,6 +155,7 @@ interface types {
/// original casing used to construct or mutate the `fields` resource. The `fields`
/// resource should use that original casing when serializing the fields for
/// transport or when returning them from a method.
+ @since(version = 0.3.0-rc-2026-02-09)
resource fields {
/// Construct an empty HTTP Fields.
///
@@ -212,12 +224,15 @@ interface types {
}
/// Headers is an alias for Fields.
+ @since(version = 0.3.0-rc-2026-02-09)
type headers = fields;
/// Trailers is an alias for Fields.
+ @since(version = 0.3.0-rc-2026-02-09)
type trailers = fields;
/// Represents an HTTP Request.
+ @since(version = 0.3.0-rc-2026-02-09)
resource request {
/// Construct a new `request` with a default `method` of `GET`, and
/// `none` values for `path-with-query`, `scheme`, and `authority`.
@@ -304,6 +319,7 @@ interface types {
///
/// These timeouts are separate from any the user may use to bound an
/// asynchronous call.
+ @since(version = 0.3.0-rc-2026-02-09)
resource request-options {
/// Construct a default `request-options` value.
constructor();
@@ -332,9 +348,11 @@ interface types {
}
/// This type corresponds to the HTTP standard Status Code.
+ @since(version = 0.3.0-rc-2026-02-09)
type status-code = u16;
/// Represents an HTTP Response.
+ @since(version = 0.3.0-rc-2026-02-09)
resource response {
/// Construct a new `response`, with a default `status-code` of `200`.
/// If a different `status-code` is needed, it must be set via the
@@ -383,6 +401,7 @@ interface types {
///
/// In `wasi:http/middleware` this interface is both exported and imported as
/// the "downstream" and "upstream" directions of the middleware chain.
+@since(version = 0.3.0-rc-2026-02-09)
interface handler {
use types.{request, response, error-code};
@@ -401,6 +420,7 @@ interface handler {
/// (including WIT itself) is unable to represent a component importing two
/// instances of the same interface. A `client.send` import may be linked
/// directly to a `handler.handle` export to bypass the network.
+@since(version = 0.3.0-rc-2026-02-09)
interface client {
use types.{request, response, error-code};
@@ -412,21 +432,22 @@ interface client {
/// The `wasi:http/service` world captures a broad category of HTTP services
/// including web applications, API servers, and proxies. It may be `include`d
/// in more specific worlds such as `wasi:http/middleware`.
+@since(version = 0.3.0-rc-2026-02-09)
world service {
- import wasi:cli/types@0.3.0-rc-2026-01-06;
- import wasi:cli/stdout@0.3.0-rc-2026-01-06;
- import wasi:cli/stderr@0.3.0-rc-2026-01-06;
- import wasi:cli/stdin@0.3.0-rc-2026-01-06;
- import wasi:clocks/types@0.3.0-rc-2026-01-06;
+ import wasi:cli/types@0.3.0-rc-2026-02-09;
+ import wasi:cli/stdout@0.3.0-rc-2026-02-09;
+ import wasi:cli/stderr@0.3.0-rc-2026-02-09;
+ import wasi:cli/stdin@0.3.0-rc-2026-02-09;
+ import wasi:clocks/types@0.3.0-rc-2026-02-09;
import types;
import client;
- import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
- import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
+ import wasi:clocks/monotonic-clock@0.3.0-rc-2026-02-09;
+ import wasi:clocks/system-clock@0.3.0-rc-2026-02-09;
@unstable(feature = clocks-timezone)
- import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
- import wasi:random/random@0.3.0-rc-2026-01-06;
- import wasi:random/insecure@0.3.0-rc-2026-01-06;
- import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
+ import wasi:clocks/timezone@0.3.0-rc-2026-02-09;
+ import wasi:random/random@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure-seed@0.3.0-rc-2026-02-09;
export handler;
}
@@ -436,22 +457,23 @@ world service {
/// Components may implement this world to allow them to participate in handler
/// "chains" where a `request` flows through handlers on its way to some terminal
/// `service` and corresponding `response` flows in the opposite direction.
+@since(version = 0.3.0-rc-2026-02-09)
world middleware {
- import wasi:clocks/types@0.3.0-rc-2026-01-06;
+ import wasi:clocks/types@0.3.0-rc-2026-02-09;
import types;
import handler;
- import wasi:cli/types@0.3.0-rc-2026-01-06;
- import wasi:cli/stdout@0.3.0-rc-2026-01-06;
- import wasi:cli/stderr@0.3.0-rc-2026-01-06;
- import wasi:cli/stdin@0.3.0-rc-2026-01-06;
+ import wasi:cli/types@0.3.0-rc-2026-02-09;
+ import wasi:cli/stdout@0.3.0-rc-2026-02-09;
+ import wasi:cli/stderr@0.3.0-rc-2026-02-09;
+ import wasi:cli/stdin@0.3.0-rc-2026-02-09;
import client;
- import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
- import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
+ import wasi:clocks/monotonic-clock@0.3.0-rc-2026-02-09;
+ import wasi:clocks/system-clock@0.3.0-rc-2026-02-09;
@unstable(feature = clocks-timezone)
- import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
- import wasi:random/random@0.3.0-rc-2026-01-06;
- import wasi:random/insecure@0.3.0-rc-2026-01-06;
- import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
+ import wasi:clocks/timezone@0.3.0-rc-2026-02-09;
+ import wasi:random/random@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure@0.3.0-rc-2026-02-09;
+ import wasi:random/insecure-seed@0.3.0-rc-2026-02-09;
export handler;
}
diff --git a/wit/deps/random-0.3.0-rc-2026-01-06.wit b/wit/deps/random.wit
similarity index 85%
rename from wit/deps/random-0.3.0-rc-2026-01-06.wit
rename to wit/deps/random.wit
index 8bb8731..521df6e 100644
--- a/wit/deps/random-0.3.0-rc-2026-01-06.wit
+++ b/wit/deps/random.wit
@@ -1,10 +1,10 @@
-package wasi:random@0.3.0-rc-2026-01-06;
+package wasi:random@0.3.0-rc-2026-02-09;
/// The insecure-seed interface for seeding hash-map DoS resistance.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface insecure-seed {
/// Return a 128-bit value that may contain a pseudo-random value.
///
@@ -23,7 +23,7 @@ interface insecure-seed {
/// This will likely be changed to a value import, to prevent it from being
/// called multiple times and potentially used for purposes other than DoS
/// protection.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-insecure-seed: func() -> tuple;
}
@@ -31,7 +31,7 @@ interface insecure-seed {
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface insecure {
/// Return `len` insecure pseudo-random bytes.
///
@@ -41,14 +41,14 @@ interface insecure {
/// There are no requirements on the values of the returned bytes, however
/// implementations are encouraged to return evenly distributed values with
/// a long period.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-insecure-random-bytes: func(len: u64) -> list;
/// Return an insecure pseudo-random `u64` value.
///
/// This function returns the same type of pseudo-random data as
/// `get-insecure-random-bytes`, represented as a `u64`.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-insecure-random-u64: func() -> u64;
}
@@ -56,7 +56,7 @@ interface insecure {
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface random {
/// Return `len` cryptographically-secure random or pseudo-random bytes.
///
@@ -70,23 +70,23 @@ interface random {
/// This function must always return fresh data. Deterministic environments
/// must omit this function, rather than implementing it with deterministic
/// data.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-random-bytes: func(len: u64) -> list;
/// Return a cryptographically-secure random or pseudo-random `u64` value.
///
/// This function returns the same type of data as `get-random-bytes`,
/// represented as a `u64`.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-random-u64: func() -> u64;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
world imports {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import random;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import insecure;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import insecure-seed;
}
diff --git a/wit/deps/sockets-0.3.0-rc-2026-01-06.wit b/wit/deps/sockets.wit
similarity index 92%
rename from wit/deps/sockets-0.3.0-rc-2026-01-06.wit
rename to wit/deps/sockets.wit
index d7ebe15..aa9d4d7 100644
--- a/wit/deps/sockets-0.3.0-rc-2026-01-06.wit
+++ b/wit/deps/sockets.wit
@@ -1,9 +1,9 @@
-package wasi:sockets@0.3.0-rc-2026-01-06;
+package wasi:sockets@0.3.0-rc-2026-02-09;
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface types {
- @since(version = 0.3.0-rc-2026-01-06)
- use wasi:clocks/types@0.3.0-rc-2026-01-06.{duration};
+ @since(version = 0.3.0-rc-2026-02-09)
+ use wasi:clocks/types@0.3.0-rc-2026-02-09.{duration};
/// Error codes.
///
@@ -16,7 +16,7 @@ interface types {
/// - `out-of-memory`
///
/// See each individual API for what the POSIX equivalents are. They sometimes differ per API.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
enum error-code {
/// Unknown error
unknown,
@@ -57,7 +57,7 @@ interface types {
datagram-too-large,
}
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
enum ip-address-family {
/// Similar to `AF_INET` in POSIX.
ipv4,
@@ -65,19 +65,19 @@ interface types {
ipv6,
}
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
type ipv4-address = tuple;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
type ipv6-address = tuple;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
variant ip-address {
ipv4(ipv4-address),
ipv6(ipv6-address),
}
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
record ipv4-socket-address {
/// sin_port
port: u16,
@@ -85,7 +85,7 @@ interface types {
address: ipv4-address,
}
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
record ipv6-socket-address {
/// sin6_port
port: u16,
@@ -97,7 +97,7 @@ interface types {
scope-id: u32,
}
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
variant ip-socket-address {
ipv4(ipv4-socket-address),
ipv6(ipv6-socket-address),
@@ -122,7 +122,7 @@ interface types {
/// In addition to the general error codes documented on the
/// `types::error-code` type, TCP socket methods may always return
/// `error(invalid-state)` when in the `closed` state.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
resource tcp-socket {
/// Create a new TCP socket.
///
@@ -138,7 +138,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
create: static func(address-family: ip-address-family) -> result;
/// Bind the socket to the provided IP address and port.
///
@@ -171,7 +171,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
bind: func(local-address: ip-socket-address) -> result<_, error-code>;
/// Connect to a remote endpoint.
///
@@ -202,7 +202,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
connect: async func(remote-address: ip-socket-address) -> result<_, error-code>;
/// Start listening and return a stream of new inbound connections.
///
@@ -259,6 +259,12 @@ interface types {
/// In either case, the stream returned by this `listen` method remains
/// operational.
///
+ /// WASI requires `listen` to perform an implicit bind if the socket
+ /// has not already been bound. Not all platforms (notably Windows)
+ /// exhibit this behavior out of the box. On platforms that require it,
+ /// the WASI implementation can emulate this behavior by performing
+ /// the bind itself if the guest hasn't already done so.
+ ///
/// # References
/// -
/// -
@@ -268,7 +274,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
listen: func() -> result, error-code>;
/// Transmit data to peer.
///
@@ -290,8 +296,8 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
- send: async func(data: stream) -> result<_, error-code>;
+ @since(version = 0.3.0-rc-2026-02-09)
+ send: func(data: stream) -> future>;
/// Read data from peer.
///
/// This function returns a `stream` which provides the data received from the
@@ -323,7 +329,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
receive: func() -> tuple, future>>;
/// Get the bound local address.
///
@@ -341,7 +347,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-local-address: func() -> result;
/// Get the remote address.
///
@@ -353,19 +359,19 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-remote-address: func() -> result;
/// Whether the socket is in the `listening` state.
///
/// Equivalent to the SO_ACCEPTCONN socket option.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-is-listening: func() -> bool;
/// Whether this is a IPv4 or IPv6 socket.
///
/// This is the value passed to the constructor.
///
/// Equivalent to the SO_DOMAIN socket option.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-address-family: func() -> ip-address-family;
/// Hints the desired listen queue size. Implementations are free to ignore this.
///
@@ -376,7 +382,7 @@ interface types {
/// - `not-supported`: (set) The platform does not support changing the backlog size after the initial listen.
/// - `invalid-argument`: (set) The provided value was 0.
/// - `invalid-state`: (set) The socket is in the `connecting` or `connected` state.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-listen-backlog-size: func(value: u64) -> result<_, error-code>;
/// Enables or disables keepalive.
///
@@ -387,9 +393,9 @@ interface types {
/// These properties can be configured while `keep-alive-enabled` is false, but only come into effect when `keep-alive-enabled` is true.
///
/// Equivalent to the SO_KEEPALIVE socket option.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-keep-alive-enabled: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-keep-alive-enabled: func(value: bool) -> result<_, error-code>;
/// Amount of time the connection has to be idle before TCP starts sending keepalive packets.
///
@@ -401,9 +407,9 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The provided value was 0.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-keep-alive-idle-time: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>;
/// The time between keepalive packets.
///
@@ -415,9 +421,9 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The provided value was 0.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-keep-alive-interval: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-keep-alive-interval: func(value: duration) -> result<_, error-code>;
/// The maximum amount of keepalive packets TCP should send before aborting the connection.
///
@@ -429,9 +435,9 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The provided value was 0.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-keep-alive-count: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-keep-alive-count: func(value: u32) -> result<_, error-code>;
/// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options.
///
@@ -439,9 +445,9 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The TTL value must be 1 or higher.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-hop-limit: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-hop-limit: func(value: u8) -> result<_, error-code>;
/// The kernel buffer space reserved for sends/receives on this socket.
///
@@ -453,18 +459,18 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The provided value was 0.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-receive-buffer-size: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-send-buffer-size: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-send-buffer-size: func(value: u64) -> result<_, error-code>;
}
/// A UDP socket handle.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
resource udp-socket {
/// Create a new UDP socket.
///
@@ -480,7 +486,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
create: static func(address-family: ip-address-family) -> result;
/// Bind the socket to the provided IP address and port.
///
@@ -500,7 +506,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
bind: func(local-address: ip-socket-address) -> result<_, error-code>;
/// Associate this socket with a specific peer address.
///
@@ -538,7 +544,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
connect: func(remote-address: ip-socket-address) -> result<_, error-code>;
/// Dissociate this socket from its peer address.
///
@@ -555,7 +561,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
disconnect: func() -> result<_, error-code>;
/// Send a message on the socket to a particular peer.
///
@@ -588,7 +594,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
send: async func(data: list, remote-address: option) -> result<_, error-code>;
/// Receive a message on the socket.
///
@@ -613,7 +619,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
receive: async func() -> result, ip-socket-address>, error-code>;
/// Get the current bound address.
///
@@ -631,7 +637,7 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-local-address: func() -> result;
/// Get the address the socket is currently "connected" to.
///
@@ -643,14 +649,14 @@ interface types {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-remote-address: func() -> result;
/// Whether this is a IPv4 or IPv6 socket.
///
/// This is the value passed to the constructor.
///
/// Equivalent to the SO_DOMAIN socket option.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-address-family: func() -> ip-address-family;
/// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options.
///
@@ -658,9 +664,9 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The TTL value must be 1 or higher.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-unicast-hop-limit: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-unicast-hop-limit: func(value: u8) -> result<_, error-code>;
/// The kernel buffer space reserved for sends/receives on this socket.
///
@@ -672,24 +678,24 @@ interface types {
///
/// # Typical errors
/// - `invalid-argument`: (set) The provided value was 0.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-receive-buffer-size: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
get-send-buffer-size: func() -> result;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
set-send-buffer-size: func(value: u64) -> result<_, error-code>;
}
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
interface ip-name-lookup {
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
use types.{ip-address};
/// Lookup error codes.
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
enum error-code {
/// Unknown error
unknown,
@@ -737,16 +743,16 @@ interface ip-name-lookup {
/// -
/// -
/// -
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
resolve-addresses: async func(name: string) -> result, error-code>;
}
-@since(version = 0.3.0-rc-2026-01-06)
+@since(version = 0.3.0-rc-2026-02-09)
world imports {
- @since(version = 0.3.0-rc-2026-01-06)
- import wasi:clocks/types@0.3.0-rc-2026-01-06;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
+ import wasi:clocks/types@0.3.0-rc-2026-02-09;
+ @since(version = 0.3.0-rc-2026-02-09)
import types;
- @since(version = 0.3.0-rc-2026-01-06)
+ @since(version = 0.3.0-rc-2026-02-09)
import ip-name-lookup;
}
diff --git a/wit/deps/tls-0.3.0-draft/client.wit b/wit/deps/tls-0.3.0-draft/client.wit
new file mode 100644
index 0000000..8f282db
--- /dev/null
+++ b/wit/deps/tls-0.3.0-draft/client.wit
@@ -0,0 +1,22 @@
+interface client {
+ use types.{error};
+
+ resource connector {
+ constructor();
+
+ /// Set up the encryption stream transform.
+ /// This takes an unprotected `cleartext` application data stream and
+ /// returns an encrypted data stream, ready to be sent out over the network.
+ /// Closing the `cleartext` stream will cause a `close_notify` packet to be emitted on the returned output stream.
+ send: func(cleartext: stream) -> tuple, future>>;
+
+ /// Set up the decryption stream transform.
+ /// This takes an encrypted data stream, as received via e.g. the network,
+ /// and returns a decrypted application data stream.
+ receive: func(ciphertext: stream) -> tuple, future>>;
+
+ /// Perform the handshake.
+ /// The `send` & `receive` streams must be set up before calling this method.
+ connect: static async func(this: connector, server-name: string) -> result<_, error>;
+ }
+}
diff --git a/wit/deps/tls-0.3.0-draft/types.wit b/wit/deps/tls-0.3.0-draft/types.wit
new file mode 100644
index 0000000..fc6c4b1
--- /dev/null
+++ b/wit/deps/tls-0.3.0-draft/types.wit
@@ -0,0 +1,5 @@
+interface types {
+ resource error {
+ to-debug-string: func() -> string;
+ }
+}
diff --git a/wit/deps/tls-0.3.0-draft/world.wit b/wit/deps/tls-0.3.0-draft/world.wit
new file mode 100644
index 0000000..599d496
--- /dev/null
+++ b/wit/deps/tls-0.3.0-draft/world.wit
@@ -0,0 +1,6 @@
+package wasi:tls@0.3.0-draft;
+
+world imports {
+ import client;
+ import types;
+}
diff --git a/wit/tls.wit b/wit/tls.wit
new file mode 100644
index 0000000..7a85dd1
--- /dev/null
+++ b/wit/tls.wit
@@ -0,0 +1,4 @@
+world tls-p3 {
+ include wasi:cli/command@0.3.0-rc-2026-02-09;
+ include wasi:tls/imports@0.3.0-draft;
+}