From 15ddf44ef7c54e7e587ef99d202c1f6c3e96ba32 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Mon, 22 Jun 2026 19:56:00 +0200 Subject: [PATCH] feat(js): add wRPC codec package Add `js/` (`@bytecodealliance/wrpc`), a dependency-free, transport-agnostic JavaScript codec for the wRPC wire format, mirroring `wrpc-transport`'s `value.rs` and default framing: - `t`/`types` build the structural WIT type tree; - `value` encodes/decodes component-model values (a jco-compatible mapping); - `wit` parses inlined WIT text back into the type tree; - `frame` builds an invocation's request bytes and decodes its results. The ESM source runs directly in the browser and is publishable to npm; it ships a hand-written `.d.ts`, JSDoc, `node --test` round-trip tests and a `tsc` typecheck. Use the codec in the `wasi:keyvalue` web example: the UI imports it from `/wrpc` (served via `ServeDir`) and drops the hand-rolled byte encoding, removing the 127-byte request/response size limits. Assisted-by: claude:claude-opus-4-8 --- .github/workflows/wrpc.yml | 18 ++ examples/web/rust/src/main.rs | 6 + examples/web/ui/index.html | 369 ++++++------------------------- js/.gitignore | 2 + js/README.md | 145 +++++++++++++ js/package-lock.json | 33 +++ js/package.json | 45 ++++ js/src/index.d.ts | 188 ++++++++++++++++ js/src/index.js | 15 ++ js/src/io.js | 315 +++++++++++++++++++++++++++ js/src/mux.js | 200 +++++++++++++++++ js/src/session.js | 323 +++++++++++++++++++++++++++ js/src/types.js | 110 ++++++++++ js/src/value.js | 395 ++++++++++++++++++++++++++++++++++ js/test/session.test.js | 201 +++++++++++++++++ js/test/value.test.js | 151 +++++++++++++ js/tsconfig.json | 14 ++ 17 files changed, 2230 insertions(+), 300 deletions(-) create mode 100644 js/.gitignore create mode 100644 js/README.md create mode 100644 js/package-lock.json create mode 100644 js/package.json create mode 100644 js/src/index.d.ts create mode 100644 js/src/index.js create mode 100644 js/src/io.js create mode 100644 js/src/mux.js create mode 100644 js/src/session.js create mode 100644 js/src/types.js create mode 100644 js/src/value.js create mode 100644 js/test/session.test.js create mode 100644 js/test/value.test.js create mode 100644 js/tsconfig.json diff --git a/.github/workflows/wrpc.yml b/.github/workflows/wrpc.yml index 7a7b7305c..82a88ee36 100644 --- a/.github/workflows/wrpc.yml +++ b/.github/workflows/wrpc.yml @@ -200,6 +200,24 @@ jobs: if: ${{ matrix.check == 'nextest' }} - run: nix build -L .#checks.x86_64-linux.${{ matrix.check }} + js: + if: ${{ !startsWith(github.ref, 'refs/tags/go/') }} + name: js + runs-on: ubuntu-24.04 + defaults: + run: + working-directory: ./js + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: 22 + cache: npm + cache-dependency-path: js/package-lock.json + - run: npm ci + - run: npm run check + - run: npm test + crates: if: ${{ !startsWith(github.ref, 'refs/tags/go/') }} strategy: diff --git a/examples/web/rust/src/main.rs b/examples/web/rust/src/main.rs index 0fe03d401..97d93748f 100644 --- a/examples/web/rust/src/main.rs +++ b/examples/web/rust/src/main.rs @@ -23,6 +23,7 @@ use rustls::{DigitallySignedStruct, SignatureScheme}; use tokio::sync::{Notify, RwLock}; use tokio::task::JoinSet; use tokio::{select, signal}; +use tower_http::services::ServeDir; use tower_http::trace::TraceLayer; use tracing::{debug, error, info, instrument, trace, warn}; use tracing_subscriber::layer::SubscriberExt as _; @@ -616,6 +617,11 @@ export const PORT = "{port}" ), )), ) + // Serve the `@bytecodealliance/wrpc` client the UI imports. + .nest_service( + "/wrpc", + ServeDir::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../../../js/src")), + ) .fallback(index) .layer(TraceLayer::new_for_http()), ); diff --git a/examples/web/ui/index.html b/examples/web/ui/index.html index db3c43de2..b24a4e9b4 100644 --- a/examples/web/ui/index.html +++ b/examples/web/ui/index.html @@ -32,12 +32,54 @@ }