Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
8e0e71f
feat(truapi): add testing API and versioned wiring
pgherveou Jun 30, 2026
dea080a
fixup! feat(truapi): add testing API and versioned wiring
pgherveou Jul 1, 2026
3409152
fixup! feat(truapi): add testing API and versioned wiring
pgherveou Jul 1, 2026
0569aaf
fixup! feat(truapi): add testing API and versioned wiring
pgherveou Jul 2, 2026
8c93e99
feat(truapi-platform): add host capability traits
pgherveou Jun 30, 2026
97d0b79
fixup! feat(truapi-platform): add host capability traits
pgherveou Jul 2, 2026
d2e3674
fixup! feat(truapi-platform): add host capability traits
pgherveou Jul 3, 2026
c6f888c
feat(truapi-codegen): emit Rust dispatcher, wire table, and host call…
pgherveou Jun 30, 2026
a37abae
fixup! feat(truapi-codegen): emit Rust dispatcher, wire table, and ho…
pgherveou Jul 2, 2026
99d1b7e
fixup! feat(truapi-codegen): emit Rust dispatcher, wire table, and ho…
pgherveou Jul 2, 2026
1c46353
fixup! feat(truapi-codegen): emit Rust dispatcher, wire table, and ho…
pgherveou Jul 2, 2026
2c52262
fixup! feat(truapi-codegen): emit Rust dispatcher, wire table, and ho…
pgherveou Jul 3, 2026
7bd57b8
fixup! feat(truapi-codegen): emit Rust dispatcher, wire table, and ho…
pgherveou Jul 3, 2026
6964df3
feat(truapi-server): add host logic primitives
pgherveou Jul 1, 2026
c8c4595
fixup! feat(truapi-server): add host logic primitives
pgherveou Jul 1, 2026
88cf1a9
fixup! feat(truapi-server): add host logic primitives
pgherveou Jul 2, 2026
2d88bdf
fixup! feat(truapi-server): add host logic primitives
pgherveou Jul 3, 2026
e1f6790
feat(truapi-server): add wire and chain infrastructure
pgherveou Jul 1, 2026
d959726
fixup! feat(truapi-server): add wire and chain infrastructure
pgherveou Jul 3, 2026
fa642c1
fixup! feat(truapi-server): add host logic primitives
pgherveou Jul 3, 2026
176c6b1
feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 1, 2026
6aa9887
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 1, 2026
0f6e16c
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 2, 2026
80ff2c7
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 2, 2026
c6091f0
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 3, 2026
e4d9a0d
fixup! feat(truapi-server): add wire and chain infrastructure
pgherveou Jul 3, 2026
7ac562a
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 3, 2026
dab5395
Merge origin/main into rust-core/04-codegen
pgherveou Jul 3, 2026
15e1594
Merge branch 'rust-core/04-codegen' into rust-core/04a-server-host-logic
pgherveou Jul 3, 2026
54f0b20
docs(host-logic): link host-spec sections
pgherveou Jul 3, 2026
2da3da5
Merge branch 'rust-core/04a-server-host-logic' into rust-core/04b-ser…
pgherveou Jul 3, 2026
f7b2424
Merge branch 'rust-core/04b-server-wire-chain' into rust-core/03-serv…
pgherveou Jul 3, 2026
ac7992f
docs(runtime): link host-spec sections
pgherveou Jul 3, 2026
cda27e1
fixup! feat(truapi-server): add wire and chain infrastructure
pgherveou Jul 3, 2026
227f47c
Merge branch 'rust-core/04b-server-wire-chain' into rust-core/03-serv…
pgherveou Jul 3, 2026
8bd9085
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 3, 2026
ba2571a
Merge branch 'main' into rust-core/03-server-runtime
pgherveou Jul 3, 2026
b804d04
fix(server): enforce runtime permissions
pgherveou Jul 6, 2026
f22b4b5
feat(codegen): generate wasm bridge callbacks
pgherveou Jul 6, 2026
5de806e
fix(server): include runtime crate in workspace
pgherveou Jul 6, 2026
460dc77
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 6, 2026
0d304f8
docs(server): describe permission flow
pgherveou Jul 6, 2026
cddce3e
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 6, 2026
a253874
fix(codegen): satisfy wasm bridge clippy
pgherveou Jul 6, 2026
1735b8a
test(server): wait for auth sync callback
pgherveou Jul 6, 2026
01ddadc
Merge remote-tracking branch 'origin/rust-core/03-server-runtime' int…
pgherveou Jul 6, 2026
f421258
test(server): make pairing snapshot test deterministic
pgherveou Jul 6, 2026
2fc5be9
Merge remote-tracking branch 'origin/rust-core/03-server-runtime' int…
pgherveou Jul 6, 2026
7190552
chore(stack): move wasm bridge out of runtime layer
pgherveou Jul 6, 2026
c3c243b
Merge remote-tracking branch 'origin/rust-core/03-server-runtime' int…
pgherveou Jul 6, 2026
5fbf0b3
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
07a3a1c
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 6, 2026
95516f7
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
9f0a7ef
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 6, 2026
86ffc19
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
5f21721
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 6, 2026
98b1023
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
c4f7c02
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 6, 2026
b639cb7
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 7, 2026
ee797ed
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 7, 2026
95ce2e9
fixup! feat(codegen): generate wasm bridge callbacks
pgherveou Jul 7, 2026
4bdb9b5
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 8, 2026
9875241
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 8, 2026
4fb288e
fixup! feat(codegen): generate wasm bridge callbacks
pgherveou Jul 8, 2026
3a64291
refactor(platform): derive allowance Debug
pgherveou Jul 8, 2026
4757653
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 8, 2026
a99f0e5
fix(runtime): keep allowance signing in Rust
pgherveou Jul 8, 2026
e53b78e
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 8, 2026
80135ef
fix(runtime): harden pairing failures
pgherveou Jul 8, 2026
b24a693
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 8, 2026
3f775f3
fix(runtime): simplify pairing outcome
pgherveou Jul 8, 2026
defe071
Merge branch 'rust-core/03-server-runtime' into rust-core/04-wasm-bri…
pgherveou Jul 8, 2026
3c97ceb
ci: format generated Rust codegen output
pgherveou Jul 8, 2026
4132406
fixup! feat(codegen): generate wasm bridge callbacks
pgherveou Jul 8, 2026
747f412
Merge remote-tracking branch 'origin/main' into rust-core/04-wasm-bri…
pgherveou Jul 9, 2026
f90c233
ci: install rustfmt for codegen job
pgherveou Jul 9, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ jobs:
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: nightly
components: rustfmt

- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2

Expand Down
53 changes: 35 additions & 18 deletions rust/crates/truapi-codegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::PathBuf;
use std::str::FromStr;

mod platform;
mod platform_callbacks;
mod rust;
mod rustdoc;
mod ts;
Expand Down Expand Up @@ -72,6 +73,11 @@ struct Cli {
#[arg(long)]
platform_wasm_adapter_output: Option<String>,

/// Output directory for the generated Rust WASM platform bridge.
/// Only honored when `--platform-input` is also set.
#[arg(long)]
platform_rust_output: Option<PathBuf>,

/// Output directory for generated explorer metadata (optional). When set,
/// writes `codegen/types.ts` with the DataType list consumed by the
/// explorer site.
Expand Down Expand Up @@ -145,33 +151,44 @@ fn main() -> Result<()> {
.with_context(|| format!("writing Rust dispatcher to {}", path.display()))?;
println!("Wrote Rust dispatcher to {}", path.display());
}
if let (Some(input), Some(output)) = (&cli.platform_input, &cli.platform_ts_output) {
if let Some(input) = &cli.platform_input {
if cli.platform_wasm_adapter_output.is_some() && cli.platform_ts_output.is_none() {
anyhow::bail!("--platform-wasm-adapter-output requires --platform-ts-output");
}
let json = std::fs::read_to_string(input)
.with_context(|| format!("reading platform rustdoc JSON from {input}"))?;
let krate =
rustdoc::parse(&json).with_context(|| format!("parsing platform rustdoc {input}"))?;
let definition = platform::extract(&krate)
.with_context(|| format!("extracting platform definition from {input}"))?;
let codec_types = api
.types
.iter()
.filter(|t| !matches!(t.kind, rustdoc::TypeDefKind::Alias(_)))
.map(|t| t.name.clone())
.collect();
let adapter_output = cli
.platform_wasm_adapter_output
.as_deref()
.unwrap_or(output.as_str());
ts::generate_host_callbacks(&definition, &codec_types, output, adapter_output)
.with_context(|| format!("writing host callbacks TS to {output}"))?;
println!("Generated typed HostCallbacks TS surface in {output}");
println!("Generated WASM HostCallbacks adapter in {adapter_output}");
} else if cli.platform_input.is_some() != cli.platform_ts_output.is_some()
if let Some(output) = &cli.platform_ts_output {
let codec_types = api
.types
.iter()
.filter(|t| !matches!(t.kind, rustdoc::TypeDefKind::Alias(_)))
.map(|t| t.name.clone())
.collect();
let adapter_output = cli
.platform_wasm_adapter_output
.as_deref()
.unwrap_or(output.as_str());
ts::generate_host_callbacks(&definition, &codec_types, output, adapter_output)
.with_context(|| format!("writing host callbacks TS to {output}"))?;
println!("Generated typed HostCallbacks TS surface in {output}");
println!("Generated WASM HostCallbacks adapter in {adapter_output}");
}
if let Some(output) = &cli.platform_rust_output {
rust::generate_wasm_bridge_file(&definition, &api, output)
.with_context(|| format!("writing Rust WASM bridge to {}", output.display()))?;
println!("Generated Rust WASM bridge in {}", output.display());
}
} else if cli.platform_ts_output.is_some()
|| cli.platform_wasm_adapter_output.is_some()
|| cli.platform_rust_output.is_some()
{
anyhow::bail!(
"--platform-input and --platform-ts-output must be provided together; \
--platform-wasm-adapter-output additionally requires both"
"--platform-input is required for platform output; \
--platform-wasm-adapter-output additionally requires --platform-ts-output"
);
}
if let Some(path) = &cli.explorer_output {
Expand Down
181 changes: 181 additions & 0 deletions rust/crates/truapi-codegen/src/platform_callbacks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
//! Shared callback naming and selection rules for generated platform bridges.

use std::collections::BTreeSet;

use crate::platform::{PlatformDefinition, PlatformInner, PlatformMethod, PlatformTrait};
use crate::rustdoc::TypeRef;

pub(crate) fn composed_traits(definition: &PlatformDefinition) -> Vec<&PlatformTrait> {
let composed: BTreeSet<String> = match &definition.super_trait {
Some(s) => s.composes.iter().cloned().collect(),
None => definition.traits.iter().map(|t| t.name.clone()).collect(),
};
definition
.traits
.iter()
.filter(|t| composed.contains(&t.name))
.collect()
}

pub(crate) fn raw_callback_name(method: &PlatformMethod) -> String {
to_camel_case(&method.name)
}

pub(crate) fn platform_trait_names(definition: &PlatformDefinition) -> BTreeSet<String> {
definition.traits.iter().map(|t| t.name.clone()).collect()
}

pub(crate) fn trait_object_return_name<'a>(
method: &'a PlatformMethod,
platform_trait_names: &BTreeSet<String>,
) -> Option<&'a str> {
match &method.return_shape.inner {
PlatformInner::TraitObject(name) => Some(name.as_str()),
PlatformInner::Result { ok, .. } | PlatformInner::Plain(ok) => {
named_platform_trait(ok, platform_trait_names)
}
PlatformInner::Unit | PlatformInner::Stream(_) => None,
}
}

pub(crate) fn raw_callback_wire_name(
trait_def: &PlatformTrait,
method: &PlatformMethod,
platform_trait_names: &BTreeSet<String>,
) -> String {
let raw = raw_callback_name(method);
if trait_object_return_name(method, platform_trait_names).is_some() {
return format!(
"{}{}",
callback_namespace(&trait_def.name),
upper_first(&raw)
);
}
raw
}

pub(crate) fn raw_callback_field_name(
trait_def: &PlatformTrait,
method: &PlatformMethod,
platform_trait_names: &BTreeSet<String>,
) -> String {
snake_case(&raw_callback_wire_name(
trait_def,
method,
platform_trait_names,
))
}

pub(crate) fn raw_callback_type_name(
trait_def: &PlatformTrait,
method: &PlatformMethod,
platform_trait_names: &BTreeSet<String>,
) -> String {
upper_first(&raw_callback_wire_name(
trait_def,
method,
platform_trait_names,
))
}

pub(crate) fn raw_callback_adapter_name(
trait_def: &PlatformTrait,
method: &PlatformMethod,
platform_trait_names: &BTreeSet<String>,
) -> String {
format!(
"{}Adapter",
raw_callback_wire_name(trait_def, method, platform_trait_names)
)
}

pub(crate) fn callback_namespace(trait_name: &str) -> String {
let stem = ["Provider", "Presenter", "Host"]
Comment thread
pgherveou marked this conversation as resolved.
.into_iter()
.find_map(|suffix| trait_name.strip_suffix(suffix))
.unwrap_or(trait_name);
lower_pascal_case(stem)
}

fn named_platform_trait<'a>(
ty: &'a TypeRef,
platform_trait_names: &BTreeSet<String>,
) -> Option<&'a str> {
let TypeRef::Named { name, args } = ty else {
return None;
};
if args.is_empty() && platform_trait_names.contains(name) {
return Some(name.as_str());
}
None
}

/// Unwrap a `Result<T, E>` stream item to its `T`; other item types pass
/// through. Streams carry `Result`s on the Rust side but the JS raw bridge
/// already unwraps them before handing each item to the WASM callback sink.
pub(crate) fn stream_item(item: &TypeRef) -> &TypeRef {
if let TypeRef::Named { name, args } = item
&& name == "Result"
&& let Some(ok) = args.first()
{
return ok;
}
item
}

pub(crate) fn to_camel_case(name: &str) -> String {
let mut out = String::with_capacity(name.len());
let mut upper_next = false;
for (idx, ch) in name.chars().enumerate() {
if ch == '_' {
upper_next = idx != 0;
continue;
}
if upper_next {
out.extend(ch.to_uppercase());
upper_next = false;
} else {
out.push(ch);
}
}
out
}

fn lower_pascal_case(name: &str) -> String {
let mut chars = name.chars();
let Some(first) = chars.next() else {
return String::new();
};
format!(
"{}{}",
first.to_ascii_lowercase(),
chars.collect::<String>()
)
}

fn upper_first(name: &str) -> String {
let mut chars = name.chars();
let Some(first) = chars.next() else {
return String::new();
};
format!(
"{}{}",
first.to_ascii_uppercase(),
chars.collect::<String>()
)
}

pub(crate) fn snake_case(name: &str) -> String {
let mut out = String::with_capacity(name.len() + 4);
for (idx, ch) in name.chars().enumerate() {
if ch.is_ascii_uppercase() {
if idx != 0 {
out.push('_');
}
out.push(ch.to_ascii_lowercase());
} else {
out.push(ch);
}
}
out
}
17 changes: 17 additions & 0 deletions rust/crates/truapi-codegen/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ use anyhow::Result;

use convert_case::{Case, Casing};

use crate::platform::PlatformDefinition;
use crate::rustdoc::*;

mod dispatcher;
mod wasm_bridge;
mod wire_table;

pub use dispatcher::generate_dispatcher;
pub use wasm_bridge::generate_wasm_bridge;
pub use wire_table::generate_wire_table;

/// Generates the Rust wire dispatcher and wire-table sources into `output_dir`.
Expand All @@ -29,6 +32,20 @@ pub fn generate(api: &ApiDefinition, output_dir: &Path) -> Result<()> {
Ok(())
}

/// Generates the Rust wasm-bindgen platform bridge source into `output_dir`.
pub fn generate_wasm_bridge_file(
definition: &PlatformDefinition,
api: &ApiDefinition,
output_dir: &Path,
) -> Result<()> {
fs::create_dir_all(output_dir)?;
fs::write(
output_dir.join("generated_bridge.rs"),
generate_wasm_bridge(definition, api)?,
)?;
Ok(())
}

/// Trait -> versioned-module mapping. Trait names are PascalCase
/// (`JsonRpc`, `LocalStorage`); module names are snake_case
/// (`jsonrpc`, `local_storage`). The mapping is irregular enough
Expand Down
Loading