Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 118 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,48 @@ This repo is the single source of truth for the TrUAPI protocol. It vendors `dot

```
rust/crates/
truapi/ Rust trait + type definitions for protocol versions v0.1 and v0.2
truapi/ Rust trait + type definitions for protocol versions v0.1 and v0.2 (canonical)
truapi-codegen/ rustdoc JSON → TypeScript client + Rust dispatcher
truapi-macros/ #[wire(id = N)] proc-macro
truapi-platform/ Host syscall traits (storage, navigation, consent, ...)
truapi-server/ Rust runtime hosts implement; ships as WASM (browser/node) and via UniFFI (iOS/Android)
uniffi-bindgen-cli/ Thin CLI wrapper around uniffi::uniffi_bindgen_main()
js/packages/
truapi/ @parity/truapi TS package; generated TS lives under ignored paths
playground/ Next.js interactive playground; deploys to truapi-playground.dot
hosts/dotli/ dotli submodule
docs/ design docs, RFCs, feature proposals
scripts/codegen.sh regenerate the TS client from the Rust crate
truapi/ @parity/truapi TS package; generated TS lives under ignored paths
truapi-host/ @parity/truapi-host host-side codegen + dispatcher (no shared core)
truapi-host-wasm/ @parity/truapi-host-wasm: WASM-backed host runtime. Subpath entries:
`.` (core Provider + dispatcher + node runtime), `/web` (iframe + Web
Worker), `/electron` (MessagePortMain), `/worker-runtime` (Worker entry).
WASM bundle (gitignored) under dist/wasm/{web,node}/, built via `make wasm`
android/
truapi-host/ io.parity:truapi-host-android Maven library (AAR + UniFFI Kotlin bindings)
ios/
truapi-host/ TrUAPIHost Swift Package (sources + UniFFI Swift bindings)
playground/ Next.js interactive playground; deploys to truapi-playground.dot
hosts/dotli/ dotli submodule
docs/ design docs, RFCs, feature proposals
scripts/codegen.sh regenerate the TS client from the Rust crate
```

### Crate + binding invariants

- `truapi` is canonical; runtime crates re-export rather than redefine. New
syscall traits and host-side runtime types live in `truapi-platform` and
`truapi-server`, not in `truapi`. Any additions to `truapi` itself are limited
to additive `Display` impls.
- All types exposed by `truapi-platform` and `truapi-server` come from
`truapi::versioned::*` and `truapi::v01::*`. The runtime crates re-export
rather than redefine.
- `truapi-server` WASM artifacts live under
`js/packages/truapi-host-wasm/dist/wasm/{web,node}/` and are gitignored.
Build them locally with `make wasm` (rerun whenever
`rust/crates/truapi-server/` changes); CI builds the bundle fresh from the
Rust source on every run.
- UniFFI bindings under `android/truapi-host/` and `ios/truapi-host/` are generated from the
`truapi-server` cdylib via `make uniffi`. The generated Swift modulemap may
need a one-time relocation into `Sources/truapi_serverFFI/include/`, the
`make uniffi` target prints a reminder.

## Code style

- Every `pub` Rust item (functions, methods, types, traits, modules, constants) carries a doc comment (`///` or `//!`).
Expand Down Expand Up @@ -116,6 +147,87 @@ submodule init + `bun install` and the per-pane `cd` discipline).
Alternatively, with a deployed Polkadot Desktop Host installed, navigate to
`https://dot.li/localhost:3000` from within it.

#### Local dotli + playground E2E notes

Use `make dev DEBUG=1` from the repo root for the local host stack. It prepares
the ignored WASM/build artifacts, verifies dotli can resolve
`@parity/truapi-host-wasm`, then starts dotli on `:5173` and the playground on
`:3000`. Open `http://localhost:5173/localhost:3000`.

When automating with Playwright, block service workers for smoke tests unless
the test is explicitly about SW behavior. Stale host/product bundles can mask
runtime fixes. Use a fresh cache-busting query string on
`http://localhost:5173/localhost:3000?...`, collect `pageerror` and
`console` messages, and fail on unexpected page errors.

For interactive SSO checks, prefer a persistent headed Chrome profile and reuse
the same browser context across checks. SSO pairing needs a real phone QR scan,
and signing/resource-allocation flows may need web or mobile confirmation; if
the human or companion app is unavailable, skip those methods and record the
skip instead of treating it as a protocol failure. Non-interactive checks should
still verify that the playground renders, the TrUAPI debug panel receives
host/product events, generated examples can call non-confirmation methods, and
logout/relogin does not restore a stale session.

The dotli Playwright e2e suite under `hosts/dotli/apps/host/tests/e2e/`
pairs through the signer-bot service. It requires `SIGNER_BOT_SVC_TOKEN`;
`SIGNER_BOT_BASE_URL` and `SIGNER_BOT_NETWORK` default to dotli CI's
`https://signing-bot-dev.novasama-tech.org/` and `paseo-next-v2`. Without the
token, do not treat the full suite as locally runnable. Use
`E2E_DOTLI_SMOKE=1 make e2e-dotli` for the no-phone QR smoke path.

For a fully automated local playground diagnosis run, use:

```bash
SIGNER_BOT_SVC_TOKEN=... \
make e2e-dotli
```

`make e2e-dotli` starts dotli preview and the playground, signs out any
restored host session, signs in through signer-bot by extracting the QR payload,
runs the playground Diagnosis screen, auto-accepts host-side Allow/Sign modals,
and writes `hosts/dotli/test-results/e2e-dotli/diagnosis-report.md`.

Root CI runs the same target when it can read the private dotli submodule. It
needs `DOTLI_CHECKOUT_TOKEN` for submodule checkout; without that token, the
job warns and skips dotli e2e rather than failing unrelated PR checks. With
dotli access but without `SIGNER_BOT_SVC_TOKEN`, CI runs the no-phone smoke
path only.

A useful no-phone smoke assertion is:

```bash
E2E_DOTLI_SMOKE=1 make e2e-dotli
```

For manual debugging of that smoke path:

1. Start `make dev DEBUG=1`.
2. Open `http://localhost:5173/localhost:3000?debug=truapi&cachebust=<ts>` with
service workers blocked.
3. Wait for `globalThis.__truapi?.setLogLevel`, call
`__truapi.setLogLevel("debug")`, and confirm the console logs
`[truapi worker] logLevel=debug providers=0`.
4. Click `#auth-button`, wait for `#auth-modal-backdrop.open`, and confirm:
the modal shows `Login with Polkadot Mobile`, `__truapi.getProviderCount()`
is greater than zero, worker frame/callback logs appear, and there are no
page errors.

If `make dev` reports `EADDRINUSE` on `:5173` or the playground moves from
`:3000` to `:3001`, kill stale `preview-server.ts` / `next dev` processes and
restart the tmux session. Port drift causes false-negative local e2e results.

Useful debug signals:

```bash
localStorage.setItem("truapi:logLevel", "debug")
sessionStorage.setItem("dotli:truapi-debug", "1")
```

Reload after setting them. Watch for `Unknown wire discriminant`, missing
`@parity/truapi-host-wasm` imports, worker WASM instantiation failures, and
debug-panel traffic disappearing when the login popup opens.

## Deployment

Pushes to `main` trigger `.github/workflows/deploy-playground.yml`, which builds `playground/` and publishes the static export to `truapi-playground.dot` via `bulletin-deploy`.
Expand Down
50 changes: 42 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,47 @@ rust/crates/
truapi/ Rust trait and type definitions (v01, v02)
truapi-codegen/ rustdoc JSON to TypeScript client + Rust dispatcher
truapi-macros/ #[wire(id = N)] proc-macro
truapi-platform/ Host syscall traits used by truapi-server (storage, navigation, consent, ...)
truapi-server/ Rust runtime that hosts implement: dispatcher, frames, SCALE, WASM + UniFFI surfaces
uniffi-bindgen-cli/ Thin CLI wrapper around uniffi::uniffi_bindgen_main() for the workspace
js/packages/
truapi/ @parity/truapi TypeScript client
playground/ Interactive Next.js playground (truapi-playground.dot)
hosts/dotli/ dotli host, vendored as a submodule
docs/ Design docs, RFCs, feature proposals
scripts/codegen.sh Regenerate the TS client from the Rust source
truapi/ @parity/truapi TypeScript client
truapi-host/ @parity/truapi-host host-side codegen and dispatcher (no shared core)
truapi-host-wasm/ @parity/truapi-host-wasm: WASM-backed host runtime; entries `.` (core),
`/web` (iframe + Web Worker), `/electron` (MessagePortMain), `/worker-runtime`
android/
truapi-host/ io.parity:truapi-host-android Maven library (AAR + UniFFI Kotlin bindings)
ios/
truapi-host/ TrUAPIHost Swift Package (sources + UniFFI Swift bindings)
playground/ Interactive Next.js playground (truapi-playground.dot)
hosts/dotli/ dotli host, vendored as a submodule
docs/ Design docs, RFCs, feature proposals
scripts/codegen.sh Regenerate the TS client from the Rust source
```

### Native + JS host SDKs

JS hosts integrate the Rust core through [`@parity/truapi-host-wasm`](js/packages/truapi-host-wasm),
a single package with tree-shakeable subpath entries (the separate
`@parity/truapi-host`, with no shared core, is for hosts that bring their own runtime):

- `@parity/truapi-host-wasm` (the `.` entry) ships the `truapi-server` WASM bundle, the
`Provider` factories that drive it, the dispatcher adapter, and `createNodeWasmProvider`.
- `@parity/truapi-host-wasm/web` wires the WASM provider into a browser host: the iframe
MessageChannel handshake (`createIframeHost`) plus `createWebWorkerProvider`.
- `@parity/truapi-host-wasm/electron` wraps an Electron `MessagePortMain` as a `Provider`.
- `@parity/truapi-host-wasm/worker-runtime` is the Web Worker entrypoint so the WASM core can
run off the page main thread.

Native shells sit one level under `android/` and `ios/` and ship as versioned packages from git tags:

- [`android/truapi-host/`](android/truapi-host) builds the `io.parity:truapi-host-android` Maven artifact (AAR + POM + sources jar). Distributed via JitPack as `com.github.paritytech.truapi:truapi-host:<tag>`.
- [`ios/truapi-host/`](ios/truapi-host) is a Swift Package consumed via `.package(url:)` or `.package(path:)`.

The nested layout leaves room for additional packages alongside (e.g. `android/widgets/`, `ios/something-else/`) without re-shaping the top-level directories.

Both link the `truapi-server` cdylib via UniFFI-generated bindings. The bindings are regenerated from the same Rust source via `make uniffi`.

## How it works

1. The protocol is defined as Rust traits in [`rust/crates/truapi/`](rust/crates/truapi/), with each method tagged `#[wire(id = N)]` for a stable byte-level dispatch table. Every method's doc comment must carry a ` ```ts ` example, which codegen extracts into the playground's EXAMPLE tab; the build fails if any method is missing one.
Expand All @@ -80,9 +113,11 @@ Common tasks are wrapped in the top-level `Makefile`. Run `make help` for the fu

```bash
make setup # submodules + JS dependencies
make build # Rust workspace + TypeScript client
make test # Rust + TypeScript client tests
make build # Rust workspace + TypeScript client + @parity/truapi-host-* packages
make test # Rust + TypeScript client + @parity/truapi-host-* tests
make check # full suite: build, fmt, clippy, test, TS tests, playground build + lint
make wasm # rebuild truapi-server WASM artifacts under js/packages/truapi-host-wasm/dist/wasm/
make uniffi # regenerate UniFFI Kotlin + Swift bindings under android/truapi-host/ and ios/truapi-host/
```

To run the playground locally:
Expand Down Expand Up @@ -129,4 +164,3 @@ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for issue reports, feature proposals, a
## License

[MIT](./LICENSE)

Loading
Loading