Skip to content

Commit 2b68fe9

Browse files
authored
Add chidori-wasm: the engine + replay runtime in the browser (#147)
1 parent 941933c commit 2b68fe9

21 files changed

Lines changed: 2007 additions & 15 deletions

File tree

.github/workflows/docs.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ on:
1212
- "docs/**"
1313
- "website/**"
1414
- ".github/workflows/docs.yml"
15+
# The /playground page ships the wasm runtime + browser SDK.
16+
- "crates/chidori-wasm/**"
17+
- "crates/chidori-js/**"
18+
- "sdk/browser/**"
19+
- "scripts/build-wasm.sh"
1520
workflow_dispatch:
1621

1722
permissions:
@@ -35,6 +40,20 @@ jobs:
3540
node-version: 22
3641
cache: npm
3742
cache-dependency-path: website/package-lock.json
43+
# Build the /playground wasm assets (engine + browser SDK) into
44+
# website/public/chidori-wasm before the site build. wasm-bindgen-cli
45+
# must match the wasm-bindgen pin in crates/chidori-wasm/Cargo.toml.
46+
- uses: dtolnay/rust-toolchain@stable
47+
with:
48+
targets: wasm32-unknown-unknown
49+
- uses: Swatinem/rust-cache@v2
50+
with:
51+
key: docs-wasm
52+
- uses: taiki-e/install-action@v2
53+
with:
54+
tool: wasm-bindgen@0.2.126
55+
- name: Build wasm playground assets
56+
run: scripts/build-wasm.sh
3857
- name: Install dependencies
3958
run: npm ci
4059
working-directory: website

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
# Vendored Test262 conformance suite (fetched by scripts/test262.sh, ~56k files)
88
/vendor/test262/
99

10+
# wasm-bindgen output for the browser demo (regenerate with scripts/build-wasm.sh)
11+
/crates/chidori-wasm/www/pkg/
12+
1013
# macOS
1114
.DS_Store
1215

@@ -56,6 +59,8 @@ node_modules/
5659
/website/out/
5760
/website/.source/
5861
/website/next-env.d.ts
62+
# Playground runtime assets, mirrored from the wasm build by scripts/build-wasm.sh
63+
/website/public/chidori-wasm/
5964

6065
# Secrets / local env
6166
.env

Cargo.lock

Lines changed: 24 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
members = [
33
"crates/chidori",
44
"crates/chidori-js",
5+
"crates/chidori-wasm",
56
"crates/test262-runner",
67
]
78
# Bare `cargo run` / `cargo build` at the workspace root mean the CLI — the

crates/chidori-wasm/Cargo.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "chidori-wasm"
3+
version = "0.1.0"
4+
edition = "2021"
5+
# oxc 0.133 (via chidori-js) relies on `if let` guards, stabilized in Rust 1.95.
6+
rust-version = "1.95"
7+
description = "Browser embedding of the chidori-js engine and durable replay runtime, via wasm-bindgen."
8+
publish = false
9+
readme.workspace = true
10+
repository.workspace = true
11+
license.workspace = true
12+
13+
[lib]
14+
# cdylib for the wasm-bindgen artifact; rlib so the native workspace build and
15+
# `cargo test --workspace` can compile and run this crate's unit tests.
16+
crate-type = ["cdylib", "rlib"]
17+
18+
[dependencies]
19+
chidori-js = { path = "../chidori-js", version = "0.3.3" }
20+
# TypeScript stripping for browser-authored agents, mirroring the native
21+
# runtime's transpile defaults (crates/chidori/src/runtime/typescript). Same
22+
# version/features as chidori-js, so this adds no new crates to the build.
23+
oxc = { version = "0.133", features = ["semantic", "transformer", "codegen"] }
24+
serde_json = "1"
25+
# Kept in lockstep with the wasm-bindgen-cli version used by
26+
# scripts/build-wasm.sh — the CLI refuses to process a module built by a
27+
# different crate version.
28+
wasm-bindgen = "0.2.126"
29+
30+
# Workspace-wide lint levels (see [workspace.lints] in the root Cargo.toml).
31+
[lints]
32+
workspace = true

crates/chidori-wasm/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# chidori-wasm
2+
3+
The chidori-js engine — bytecode compiler, VM, GC, builtins, and the durable
4+
replay runtime — compiled to WebAssembly and driven from a browser page.
5+
6+
The engine crate is pure Rust (`#![forbid(unsafe_code)]`, no C, no threads, no
7+
filesystem), so it builds for `wasm32-unknown-unknown` unmodified. This crate
8+
adds only the boundary: a `wasm-bindgen` wrapper around
9+
`chidori_js::replay::ReplayRuntime` that exposes the record/replay pump to
10+
JavaScript.
11+
12+
## The pump protocol
13+
14+
The page owns the event loop and the host effects (fetch, time, randomness,
15+
prompts). The runtime is a pump:
16+
17+
```js
18+
const rt = new WasmRuntime(bundle, ['now', 'random', 'httpFetch']);
19+
for (;;) {
20+
const status = JSON.parse(rt.runUntilBlocked());
21+
if (status.status === 'completed') break;
22+
// status: { status: 'blocked', opId, name, args }
23+
const result = await host[status.name](...status.args); // e.g. fetch()
24+
rt.resolveOp(status.opId, JSON.stringify(result)); // journaled
25+
}
26+
const blob = rt.toBlob(); // durable artifact: bundle + effects + journal
27+
```
28+
29+
`WasmRuntime.fromBlob(blob)` restores in replay mode: journaled effects are
30+
served from the journal (no network, no reruns of anything non-deterministic),
31+
and the pump only surfaces ops past the recorded frontier — so a suspended run
32+
can resume in a fresh tab, or a completed run can replay with byte-identical
33+
output and zero live host calls. The blob is the same `DurableBlob` artifact
34+
the native runtime uses.
35+
36+
## Build and run the demo
37+
38+
```sh
39+
rustup target add wasm32-unknown-unknown
40+
cargo install wasm-bindgen-cli # version must match Cargo.toml's wasm-bindgen pin
41+
42+
scripts/build-wasm.sh
43+
python3 -m http.server -d crates/chidori-wasm/www 8080
44+
# open http://localhost:8080 — record a run, then replay it offline
45+
```
46+
47+
## What stays native
48+
49+
The `chidori` CLI crate is deliberately not part of the wasm build: it is the
50+
*host* side — tokio, reqwest, axum, SQLite session stores, OS sandboxing
51+
(seccomp/Landlock) — and in the browser those responsibilities belong to the
52+
page (fetch, IndexedDB/localStorage, the browser sandbox). The engine and the
53+
journal format are shared; the host is swapped.
54+
55+
## Tests
56+
57+
The driver core is plain Rust (`src/lib.rs`, `driver` module), so the full
58+
record → suspend → resolve → replay cycle runs under `cargo test -p
59+
chidori-wasm` on the native target; browser behavior is exercised by the demo
60+
page.

0 commit comments

Comments
 (0)