diff --git a/component-model/book.toml b/component-model/book.toml
index 74f0eaf2..047ccfbf 100644
--- a/component-model/book.toml
+++ b/component-model/book.toml
@@ -8,7 +8,8 @@ title = "The WebAssembly Component Model"
[output.html]
git-repository-url = "https://github.com/bytecodealliance/component-docs/tree/main/component-model"
edit-url-template = "https://github.com/bytecodealliance/component-docs/tree/main/component-model/{path}"
-additional-css = ["theme/head.hbs"]
+additional-css = ["theme/head.hbs", "theme/tabs.css", "theme/version-notice.css"]
+additional-js = ["theme/tabs.js"]
[output.html.fold]
enable = true
@@ -34,4 +35,6 @@ level = 1
[preprocessor.alerts]
+[preprocessor.tabs]
+
[output.linkcheck]
diff --git a/component-model/src/running-components/wasmtime.md b/component-model/src/running-components/wasmtime.md
index 4272725c..79bb781d 100644
--- a/component-model/src/running-components/wasmtime.md
+++ b/component-model/src/running-components/wasmtime.md
@@ -1,9 +1,25 @@
# Wasmtime
+
+
+This page has content for both **WASI P2** and **WASI P3**. Use the tabs below to switch between versions where they differ.
+
+
+
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI P2" }}
[Wasmtime](https://github.com/bytecodealliance/wasmtime/) is the reference implementation of the Component Model.
-It supports running components that implement the [`wasi:cli/command` world](https://github.com/WebAssembly/wasi-cli/blob/main/wit/command.wit)
-and serving components that implement the [`wasi:http/proxy` world](https://github.com/WebAssembly/wasi-http/blob/main/wit/proxy.wit).
+It supports running components that implement the [`wasi:cli/command` world](https://github.com/WebAssembly/WASI/blob/main/proposals/cli/wit/command.wit)
+and serving components that implement the [`wasi:http/proxy` world](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit/proxy.wit).
Wasmtime can also invoke functions exported from a component.
+{{#endtab }}
+{{#tab name="WASI P3" }}
+[Wasmtime](https://github.com/bytecodealliance/wasmtime/) is the reference implementation of the Component Model. WASI P3 runtime support is available in Wasmtime 43 and later, which implements the WASI 0.3 ABI (`async func`, `stream`, `future`).
+
+It supports running components that implement the [`wasi:cli/command` world](https://github.com/WebAssembly/WASI/blob/main/proposals/cli/wit-0.3.0-draft/command.wit). Support for serving components in the [`wasi:http/service` world](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit-0.3.0-draft/worlds.wit) and the new [`wasi:http/middleware` world](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit-0.3.0-draft/worlds.wit), which both imports and exports the HTTP handler interface, is in development. See [the tracking issue](https://github.com/bytecodealliance/wit-bindgen/issues/1554) for current status.
+Wasmtime can also invoke functions exported from a component.
+{{#endtab }}
+{{#endtabs }}
## Running command components with Wasmtime
To run a command component with Wasmtime, execute:
@@ -21,8 +37,10 @@ See the [Wasmtime guide](https://docs.wasmtime.dev/) for information on granting
## Running HTTP components with Wasmtime
-You can execute components that implement the [HTTP proxy world](https://github.com/WebAssembly/wasi-http/blob/main/wit/proxy.wit) with the `wasmtime serve` subcommand.
-[The Wasmtime CLI](https://github.com/bytecodealliance/wasmtime) supports serving these components as of `v14.0.3`.
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI P2" }}
+You can execute components that implement the [HTTP proxy world](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit/proxy.wit) with the `wasmtime serve` subcommand.
+[The Wasmtime CLI](https://github.com/bytecodealliance/wasmtime) supports serving these components as of `v18.0.0`.
To run a HTTP component with Wasmtime, execute:
```sh
@@ -34,6 +52,13 @@ Try out building and running HTTP components with one of these tutorials
1. [Hello WASI HTTP tutorial](https://github.com/sunfishcode/hello-wasi-http) - build and serve a simple Rust-based HTTP component
2. [HTTP Auth Middleware tutorial](https://github.com/fermyon/http-auth-middleware#running-with-wasmtime) - compose a HTTP authentication middleware component with a business logic component
+{{#endtab }}
+{{#tab name="WASI P3" }}
+Wasmtime 43 and later provide runtime support for the WASI P3 ABI. The `wasmtime serve` subcommand currently targets the [`wasi:http/proxy` world](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit/proxy.wit) from WASI P2; support for serving components in the WASI P3 [`wasi:http/service`](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit-0.3.0-draft/worlds.wit) and [`wasi:http/middleware`](https://github.com/WebAssembly/WASI/blob/main/proposals/http/wit-0.3.0-draft/worlds.wit) worlds is in progress. See [the tracking issue](https://github.com/bytecodealliance/wit-bindgen/issues/1554) for current status.
+
+For an overview of the WASI P3 HTTP interfaces, see [WASI 0.3](https://wasi.dev/releases/wasi-p3) on WASI.dev.
+{{#endtab }}
+{{#endtabs }}
## Running components with custom exports
diff --git a/component-model/theme/tabs.css b/component-model/theme/tabs.css
new file mode 100644
index 00000000..61cda923
--- /dev/null
+++ b/component-model/theme/tabs.css
@@ -0,0 +1,52 @@
+.mdbook-tabs {
+ display: flex;
+ border-bottom: 1px solid var(--table-border-color);
+}
+
+.mdbook-tab {
+ background-color: var(--table-alternate-bg);
+ color: var(--fg);
+ padding: 0.5rem 1rem;
+ cursor: pointer;
+ border: none;
+ border-bottom: 2px solid transparent;
+ font-size: 1.6rem;
+ line-height: 1.45em;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .mdbook-tab {
+ transition: color 120ms ease, border-color 120ms ease;
+ }
+}
+
+.mdbook-tab:hover:not(.active) {
+ color: var(--sidebar-active, var(--fg));
+}
+
+.mdbook-tab.active {
+ background-color: var(--table-header-bg);
+ color: var(--sidebar-active, var(--fg));
+ border-bottom-color: var(--sidebar-active, var(--fg));
+ font-weight: bold;
+}
+
+/* Rust theme: --sidebar-active (#e69f67) has low contrast against the warm
+ tan tab backgrounds. Fall back to --fg for the label text; the accent
+ color still carries the active signal via the bottom border. */
+.rust .mdbook-tab.active {
+ color: var(--fg);
+}
+
+.rust .mdbook-tab:hover:not(.active) {
+ color: var(--fg);
+ border-bottom-color: var(--sidebar-active, var(--fg));
+}
+
+.mdbook-tab-content {
+ padding: 1rem 0rem;
+}
+
+.mdbook-tab-content table {
+ margin: unset;
+}
diff --git a/component-model/theme/tabs.js b/component-model/theme/tabs.js
new file mode 100644
index 00000000..8d335667
--- /dev/null
+++ b/component-model/theme/tabs.js
@@ -0,0 +1,75 @@
+/**
+ * Change active tab of tabs.
+ *
+ * @param {Element} container
+ * @param {string} name
+ */
+const changeTab = (container, name) => {
+ for (const child of container.children) {
+ if (!(child instanceof HTMLElement)) {
+ continue;
+ }
+
+ if (child.classList.contains('mdbook-tabs')) {
+ for (const tab of child.children) {
+ if (!(tab instanceof HTMLElement)) {
+ continue;
+ }
+
+ if (tab.dataset.tabname === name) {
+ tab.classList.add('active');
+ } else {
+ tab.classList.remove('active');
+ }
+ }
+ } else if (child.classList.contains('mdbook-tab-content')) {
+ if (child.dataset.tabname === name) {
+ child.classList.remove('hidden');
+ } else {
+ child.classList.add('hidden');
+ }
+ }
+ }
+};
+
+document.addEventListener('DOMContentLoaded', () => {
+ const tabs = document.querySelectorAll('.mdbook-tab');
+ for (const tab of tabs) {
+ tab.addEventListener('click', () => {
+ if (!(tab instanceof HTMLElement)) {
+ return;
+ }
+
+ if (!tab.parentElement || !tab.parentElement.parentElement) {
+ return;
+ }
+
+ const container = tab.parentElement.parentElement;
+ const name = tab.dataset.tabname;
+ const global = container.dataset.tabglobal;
+
+ changeTab(container, name);
+
+ if (global) {
+ localStorage.setItem(`mdbook-tabs-${global}`, name);
+
+ const globalContainers = document.querySelectorAll(
+ `.mdbook-tabs-container[data-tabglobal="${global}"]`
+ );
+ for (const globalContainer of globalContainers) {
+ changeTab(globalContainer, name);
+ }
+ }
+ });
+ }
+
+ const containers = document.querySelectorAll('.mdbook-tabs-container[data-tabglobal]');
+ for (const container of containers) {
+ const global = container.dataset.tabglobal;
+
+ const name = localStorage.getItem(`mdbook-tabs-${global}`);
+ if (name && document.querySelector(`.mdbook-tab[data-tabname="${name}"]`)) {
+ changeTab(container, name);
+ }
+ }
+});
diff --git a/component-model/theme/version-notice.css b/component-model/theme/version-notice.css
new file mode 100644
index 00000000..5ae986dd
--- /dev/null
+++ b/component-model/theme/version-notice.css
@@ -0,0 +1,37 @@
+.version-notice {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.75rem;
+ padding: 0.75rem 1rem 0.75rem 1.25rem;
+ margin: 0 0 1.5rem 0;
+ background-color: var(--quote-bg);
+ border-left: 4px solid var(--sidebar-active, var(--fg));
+ border-radius: 0 4px 4px 0;
+ font-size: 0.95em;
+ line-height: 1.5;
+}
+
+.version-notice::before {
+ content: "";
+ flex-shrink: 0;
+ width: 1.15em;
+ height: 1.15em;
+ margin-top: 0.15em;
+ background-color: var(--sidebar-active, var(--fg));
+ -webkit-mask-image: url("data:image/svg+xml;utf8,");
+ mask-image: url("data:image/svg+xml;utf8,");
+ -webkit-mask-size: contain;
+ mask-size: contain;
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ mask-position: center;
+}
+
+.version-notice > *:first-child {
+ margin-top: 0;
+}
+
+.version-notice > *:last-child {
+ margin-bottom: 0;
+}