Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 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
5de806e
fix(server): include runtime crate in workspace
pgherveou Jul 6, 2026
0d304f8
docs(server): describe permission flow
pgherveou Jul 6, 2026
1735b8a
test(server): wait for auth sync callback
pgherveou Jul 6, 2026
f421258
test(server): make pairing snapshot test deterministic
pgherveou Jul 6, 2026
7190552
chore(stack): move wasm bridge out of runtime layer
pgherveou Jul 6, 2026
5fbf0b3
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
95516f7
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
86ffc19
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
98b1023
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 6, 2026
b639cb7
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 7, 2026
4bdb9b5
fixup! feat(truapi-server): add platform runtime and host bridge
pgherveou Jul 8, 2026
3a64291
refactor(platform): derive allowance Debug
pgherveou Jul 8, 2026
a99f0e5
fix(runtime): keep allowance signing in Rust
pgherveou Jul 8, 2026
80135ef
fix(runtime): harden pairing failures
pgherveou Jul 8, 2026
3f775f3
fix(runtime): simplify pairing outcome
pgherveou Jul 8, 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
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[workspace]
resolver = "2"
members = ["rust/crates/*"]
exclude = ["rust/crates/truapi-server"]

[workspace.package]
edition = "2024"
Expand Down
2 changes: 2 additions & 0 deletions rust/crates/truapi-codegen/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,8 @@ fn should_skip_type_name(name: &str) -> bool {
"Subscription"
| "CallContext"
| "CallError"
| "CancellationFuture"
| "CancellationReason"
| "CancellationToken"
| "FrameworkOnlyError"
| "Infallible"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
NotificationId,
} from "@parity/truapi";
import {
BulletinAllowanceSigner,
CoreStorageKey,
UserConfirmationReview,
} from "./host-callbacks.js";
Expand All @@ -41,7 +42,7 @@ export interface RawCallbacks {
cancelNotification(id: NotificationId): Promise<void>;
devicePermission(request: Uint8Array): Promise<Uint8Array>;
remotePermission(request: Uint8Array): Promise<Uint8Array>;
submitPreimage(value: Uint8Array): Promise<Uint8Array>;
submitPreimage(value: Uint8Array, bulletinAllowanceSigner: Uint8Array): Promise<Uint8Array>;
lookupPreimage(key: Uint8Array, sendItem: (item?: Uint8Array) => void): (() => void) | void;
read(key: string): Promise<Uint8Array | null | undefined>;
write(key: string, value: Uint8Array): Promise<void>;
Expand All @@ -67,7 +68,7 @@ export function createWasmRawCallbacks(
cancelNotification: async (id) => await host.cancelNotification(id),
devicePermission: async (request) => HostDevicePermissionResponse.enc(await host.devicePermission(HostDevicePermissionRequest.dec(request))),
remotePermission: async (request) => RemotePermissionResponse.enc(await host.remotePermission(RemotePermissionRequest.dec(request))),
submitPreimage: async (value) => await host.submitPreimage(value),
submitPreimage: async (value, bulletinAllowanceSigner) => await host.submitPreimage(value, BulletinAllowanceSigner.dec(bulletinAllowanceSigner)),
lookupPreimage: (key, sendItem) => driveResultStream(host.lookupPreimage(key), sendItem),
read: async (key) => await host.read(key),
write: async (key, value) => await host.write(key, value),
Expand Down
94 changes: 85 additions & 9 deletions rust/crates/truapi-codegen/tests/golden/host-callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ import type {
ThemeVariant,
} from "@parity/truapi";

/**
* Review shown before a product asks to access another product account.
*/
export interface AccountAccessReview {
/**
* Product currently handling the request.
*/
requestingProductId: string;

/**
* Product whose account is being requested.
*/
targetProductId: string;
}

/**
* Review shown before a product asks to alias another product account.
*/
Expand Down Expand Up @@ -71,9 +86,19 @@ export type AuthState =
*/
| { tag: "LoginFailed"; value: { reason: string } };

/**
* Host-facing signer for Bulletin preimage submission.
*/
export interface BulletinAllowanceSigner {

}

/**
* Core-owned host-private storage slots. Products never address these slots;
* the host chooses the backing store for each slot.
*
* Storage is host-local; `storage.md` records the current status quo:
* <https://github.com/paritytech/host-spec/blob/adb3989208ae1c2107dbf0159611353e6989422c/storage.md?plain=1#L1-L7>
*/
export type CoreStorageKey =
/**
Expand All @@ -87,7 +112,15 @@ export type CoreStorageKey =
/**
* Persisted authorization for one product-scoped permission request.
*/
| { tag: "PermissionAuthorization"; value: { productId: string; request: PermissionAuthorizationRequest } };
| { tag: "PermissionAuthorization"; value: { productId: string; request: PermissionAuthorizationRequest } }
/**
* Persisted allowance-slot keys for one paired SSO session.
*/
| { tag: "AllowanceKeys"; value: { sessionId: string } }
/**
* Last processed SSO pairing response statement for the pairing device.
*/
| { tag: "LastProcessedPairingStatement"; value?: undefined };

/**
* Review shown before a transaction-creation request is sent to the paired wallet.
Expand All @@ -102,6 +135,16 @@ export type CreateTransactionReview =
*/
| { tag: "LegacyAccount"; value: LegacyAccountTxPayload };

/**
* Review shown before a product learns the user's primary identity.
*/
export interface IdentityDisclosureReview {
/**
* Product currently handling the request.
*/
productId: string;
}

/**
* Permission request whose authorization status can be inspected or updated
* by host administration UI.
Expand All @@ -114,7 +157,11 @@ export type PermissionAuthorizationRequest =
/**
* Remote/product-scoped permission such as chain submit or HTTP access.
*/
| { tag: "Remote"; value: RemotePermissionRequest };
| { tag: "Remote"; value: RemotePermissionRequest }
/**
* Product-scoped permission to disclose the user's primary identity.
*/
| { tag: "IdentityDisclosure"; value?: undefined };

/**
* Authorization status for a permission request.
Expand Down Expand Up @@ -206,36 +253,62 @@ export type UserConfirmationReview =
* Allow a product to request another product account alias.
*/
| { tag: "AccountAlias"; value: AccountAliasReview }
/**
* Allow a product to learn the user's primary identity.
*/
| { tag: "IdentityDisclosure"; value: IdentityDisclosureReview }
/**
* Allocate resources for the requesting product.
*/
| { tag: "ResourceAllocation"; value: HostRequestResourceAllocationRequest }
/**
* Submit a preimage to the host-selected backend.
*/
| { tag: "PreimageSubmit"; value: PreimageSubmitReview };
| { tag: "PreimageSubmit"; value: PreimageSubmitReview }
/**
* Allow a product to access another product account.
*/
| { tag: "AccountAccess"; value: AccountAccessReview };

/**
* Review shown before a product asks to access another product account.
*/
export const AccountAccessReview: S.Codec<AccountAccessReview> = S.lazy((): S.Codec<AccountAccessReview> => S.Struct({requestingProductId: S.str, targetProductId: S.str}) as S.Codec<AccountAccessReview>);

/**
* Review shown before a product asks to alias another product account.
*/
export const AccountAliasReview: S.Codec<AccountAliasReview> = S.lazy((): S.Codec<AccountAliasReview> => S.Struct({requestingProductId: S.str, targetProductId: S.str}) as S.Codec<AccountAliasReview>);

/**
* Host-facing signer for Bulletin preimage submission.
*/
export const BulletinAllowanceSigner: S.Codec<BulletinAllowanceSigner> = S.lazy((): S.Codec<BulletinAllowanceSigner> => S.Struct({}) as S.Codec<BulletinAllowanceSigner>);

/**
* Core-owned host-private storage slots. Products never address these slots;
* the host chooses the backing store for each slot.
*
* Storage is host-local; `storage.md` records the current status quo:
* <https://github.com/paritytech/host-spec/blob/adb3989208ae1c2107dbf0159611353e6989422c/storage.md?plain=1#L1-L7>
*/
export const CoreStorageKey: S.Codec<CoreStorageKey> = S.lazy((): S.Codec<CoreStorageKey> => S.TaggedUnion({AuthSession: S._void, PairingDeviceIdentity: S._void, PermissionAuthorization: S.Struct({productId: S.str, request: PermissionAuthorizationRequest}) as S.Codec<{ productId: string; request: PermissionAuthorizationRequest }>}));
export const CoreStorageKey: S.Codec<CoreStorageKey> = S.lazy((): S.Codec<CoreStorageKey> => S.TaggedUnion({AuthSession: S._void, PairingDeviceIdentity: S._void, PermissionAuthorization: S.Struct({productId: S.str, request: PermissionAuthorizationRequest}) as S.Codec<{ productId: string; request: PermissionAuthorizationRequest }>, AllowanceKeys: S.Struct({sessionId: S.str}) as S.Codec<{ sessionId: string }>, LastProcessedPairingStatement: S._void}));

/**
* Review shown before a transaction-creation request is sent to the paired wallet.
*/
export const CreateTransactionReview: S.Codec<CreateTransactionReview> = S.lazy((): S.Codec<CreateTransactionReview> => S.TaggedUnion({Product: ProductAccountTxPayload, LegacyAccount: LegacyAccountTxPayload}));

/**
* Review shown before a product learns the user's primary identity.
*/
export const IdentityDisclosureReview: S.Codec<IdentityDisclosureReview> = S.lazy((): S.Codec<IdentityDisclosureReview> => S.Struct({productId: S.str}) as S.Codec<IdentityDisclosureReview>);

/**
* Permission request whose authorization status can be inspected or updated
* by host administration UI.
*/
export const PermissionAuthorizationRequest: S.Codec<PermissionAuthorizationRequest> = S.lazy((): S.Codec<PermissionAuthorizationRequest> => S.TaggedUnion({Device: HostDevicePermissionRequest, Remote: RemotePermissionRequest}));
export const PermissionAuthorizationRequest: S.Codec<PermissionAuthorizationRequest> = S.lazy((): S.Codec<PermissionAuthorizationRequest> => S.TaggedUnion({Device: HostDevicePermissionRequest, Remote: RemotePermissionRequest, IdentityDisclosure: S._void}));

/**
* Authorization status for a permission request.
Expand Down Expand Up @@ -263,7 +336,7 @@ export const SignRawReview: S.Codec<SignRawReview> = S.lazy((): S.Codec<SignRawR
/**
* Review shown before a user-confirmed core action continues.
*/
export const UserConfirmationReview: S.Codec<UserConfirmationReview> = S.lazy((): S.Codec<UserConfirmationReview> => S.TaggedUnion({SignPayload: SignPayloadReview, SignRaw: SignRawReview, CreateTransaction: CreateTransactionReview, AccountAlias: AccountAliasReview, ResourceAllocation: HostRequestResourceAllocationRequest, PreimageSubmit: PreimageSubmitReview}));
export const UserConfirmationReview: S.Codec<UserConfirmationReview> = S.lazy((): S.Codec<UserConfirmationReview> => S.TaggedUnion({SignPayload: SignPayloadReview, SignRaw: SignRawReview, CreateTransaction: CreateTransactionReview, AccountAlias: AccountAliasReview, IdentityDisclosure: IdentityDisclosureReview, ResourceAllocation: HostRequestResourceAllocationRequest, PreimageSubmit: PreimageSubmitReview, AccountAccess: AccountAccessReview}));

/**
* Host auth UI driven by core-owned `AuthState` transitions.
Expand All @@ -282,6 +355,9 @@ export interface AuthPresenter {
*
* The platform provides a way to get a JSON-RPC connection for a given chain.
* The server runtime manages the chainHead v1 state machine on top of this.
* Host-spec N.6 requires products to access chains through host-mediated
* providers:
* <https://github.com/paritytech/host-spec/blob/adb3989208ae1c2107dbf0159611353e6989422c/spec/N-shared-infrastructure.md?plain=1#L91-L102>
*/
export interface ChainProvider {
/**
Expand Down Expand Up @@ -449,7 +525,7 @@ export interface PreimageHost {
/**
* Submit the preimage and return its key.
*/
submitPreimage?(value: Uint8Array): Promise<Uint8Array>;
submitPreimage?(value: Uint8Array, bulletinAllowanceSigner: BulletinAllowanceSigner): Promise<Uint8Array>;

/**
* Emits current value/miss immediately, then future updates.
Expand Down Expand Up @@ -491,11 +567,11 @@ export interface ThemeHost {
}

/**
* Local user confirmation UI for session-channel operations.
* Local user confirmation UI for sensitive core-owned operations.
*/
export interface UserConfirmation {
/**
* Confirm a reviewed action before the core asks the SSO peer.
* Confirm a reviewed action before the core continues.
*/
confirmUserAction(review: UserConfirmationReview): Promise<boolean>;
}
Expand Down
4 changes: 2 additions & 2 deletions rust/crates/truapi-codegen/tests/golden/worker-callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ function rawCallbacks(bridge: WorkerCallbackBridge): Required<Pick<RawCallbacks,
bridge.callbackRequest("devicePermission", [request]) as ReturnType<RawCallbacks["devicePermission"]>,
remotePermission: (request) =>
bridge.callbackRequest("remotePermission", [request]) as ReturnType<RawCallbacks["remotePermission"]>,
submitPreimage: (value) =>
bridge.callbackRequest("submitPreimage", [value]) as ReturnType<RawCallbacks["submitPreimage"]>,
submitPreimage: (value, bulletinAllowanceSigner) =>
bridge.callbackRequest("submitPreimage", [value, bulletinAllowanceSigner]) as ReturnType<RawCallbacks["submitPreimage"]>,
read: (key) =>
bridge.callbackRequest("read", [key]) as ReturnType<RawCallbacks["read"]>,
write: (key, value) =>
Expand Down
57 changes: 0 additions & 57 deletions rust/crates/truapi-codegen/tests/golden_rust_emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,6 @@ use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn quoted_strings_in_const_array(src: &str, const_name: &str) -> Vec<String> {
let marker = format!("export const {const_name} = [");
let start = src
.find(&marker)
.unwrap_or_else(|| panic!("missing {const_name}"));
let rest = &src[start + marker.len()..];
let end = rest
.find("] as const")
.unwrap_or_else(|| panic!("unterminated {const_name}"));
rest[..end]
.lines()
.filter_map(|line| {
let trimmed = line.trim().trim_end_matches(',');
trimmed
.strip_prefix('"')
.and_then(|s| s.strip_suffix('"'))
.map(str::to_string)
})
.collect()
}

fn wasm_optional_callback_names(workspace: &Path) -> Vec<String> {
let wasm_rs = workspace.join("rust/crates/truapi-server/src/wasm.rs");
if !wasm_rs.exists() {
return Vec::new();
}
let src = fs::read_to_string(wasm_rs).expect("read wasm.rs");
let mut names = src
.lines()
.filter_map(|line| {
let line = line.trim();
let start = line.find("get_optional_function(callbacks, \"")?;
let quoted = &line[start + "get_optional_function(callbacks, \"".len()..];
let end = quoted.find('"')?;
let name = &quoted[..end];
match name {
"chainConnect" | "dispose" => None,
_ => Some(name.to_string()),
}
})
.collect::<Vec<_>>();
names.sort();
names
}

/// Run `cargo +nightly rustdoc -p truapi --output-format json` into the
/// given `target_dir` and return the path to the produced JSON file.
/// Panics with a clear message if nightly is unavailable so CI cannot
Expand Down Expand Up @@ -271,16 +226,4 @@ fn golden_host_callbacks_ts() {
!worker_actual.contains("OPTIONAL_CALLBACK_NAMES"),
"worker callback generation should not expose an optional callback manifest"
);
let mut generated_names = quoted_strings_in_const_array(&worker_actual, "CALLBACK_NAMES");
generated_names.extend(quoted_strings_in_const_array(
&worker_actual,
"SUBSCRIPTION_NAMES",
));
let wasm_optional = wasm_optional_callback_names(&workspace);
for name in wasm_optional {
assert!(
generated_names.contains(&name),
"generated worker names must include JsBridge optional callback `{name}`"
);
}
}
2 changes: 1 addition & 1 deletion rust/crates/truapi-platform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
[dependencies]
truapi = { path = "../truapi" }
async-trait = "0.1"
derive_more = { version = "2", features = ["display"] }
derive_more = { version = "2", features = ["debug", "display", "error"] }
futures = "0.3"
parity-scale-codec = { version = "3", features = ["derive"] }
unicode-normalization = "0.1"
Expand Down
Loading