From 46a031a91c0227c38083aeaa49061bb582dfc2a6 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 15 May 2026 15:41:18 +0100 Subject: [PATCH 1/3] docs: add RFC-0021 Route Relay Proposes host_route_get / host_route_set / host_route_changed so apps running in a Web host can publish their internal route to the address bar, restore deep-linked state at bootstrap, and react to Host back/forward without accessing the URL bar directly. --- docs/rfcs/0021-route-relay.md | 99 +++++++++++++++++++++++++++++++++++ docs/rfcs/_index.md | 1 + 2 files changed, 100 insertions(+) create mode 100644 docs/rfcs/0021-route-relay.md diff --git a/docs/rfcs/0021-route-relay.md b/docs/rfcs/0021-route-relay.md new file mode 100644 index 00000000..6b506538 --- /dev/null +++ b/docs/rfcs/0021-route-relay.md @@ -0,0 +1,99 @@ +# RFC-0021: Route Relay + +| | | +| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Start Date** | 2026-05-15 | +| **Description** | Host API surface that lets an app publish its internal route to the Host's address bar, read the current route, and observe back/forward navigation | +| **Authors** | @pgherveou | + +## Summary + +Add three host calls (`host_route_get`, `host_route_set`, `host_route_changed`) that relay an opaque per-app route string between the embedded app and the Host shell. This makes in-app navigation deep-linkable, shareable, and reload-stable, and lets the app react to Host back/forward, without giving the app any access to the Host's URL bar. + +## Motivation + +Apps that run inside a Web host are loaded in a webview / iframe. The visible address bar belongs to the Host, not to the app. Today this means: + +- An app can call `history.pushState` / mutate `window.location.hash` internally, but those changes are invisible to the user, are not shareable, and do not survive a reload — the Host re-launches the wrapper at `https://dot.li/` with no fragment preserved. +- At bootstrap the app cannot tell which sub-route the user intended to open. There is no way to deep-link into, say, a specific method in the TrUAPI Playground, a specific chat in a messenger app, or a specific item in a marketplace app. + We need a small, symmetric channel: the app owns its route format, the Host owns the address bar, and the two stay in sync. + +## Stakeholders + +- **Product developers** (consumers): want shareable deep links and reload-stable routes without re-implementing routing per host. +- **Host implementors**: own the address bar, history stack, and how routes are rendered to the user (path, fragment, query, etc.). +- **End users**: copy / share / reload URLs and expect them to land where they were. + +## Explanation + +### `host_route_get` + +```rust +fn host_route_get() -> Result + +struct HostRouteGetResponse { + /// The current route the Host holds for this app. + /// `None` if no route is set (app's home). + route: Option, +} +``` + +Returns the current route the Host holds for this app. At bootstrap this is the route the Host was launched with (e.g. `Permissions/host_device_permission`); afterwards it reflects the most recent `host_route_set` and any Host-driven changes (back/forward, pasted URL). The Host does not interpret the string; the app defines its own format. + +Typical use is one call at bootstrap to restore deep-linked state. + +### `host_route_set` + +```rust +fn host_route_set(req: HostRouteSetRequest) -> Result<(), GenericErr> + +struct HostRouteSetRequest { + /// Opaque route segment defined by the app. + route: String, + /// `true` replaces the current history entry (analog of `history.replaceState`). + /// `false` pushes a new entry (analog of `history.pushState`). + replace: bool, +} +``` + +Called whenever the app navigates internally. The Host renders `route` as part of the user-visible URL so it can be copied, shared, and reloaded. The exact rendering (path segment, fragment, query parameter) is the Host's choice; the protocol does not constrain it. + +Setting `route` to the empty string clears the route (app's "home"). + +### `host_route_changed` + +```rust +fn host_route_changed() -> Stream + +struct HostRouteChangedEvent { + /// New route. `None` when the user is at the app's home. + route: Option, +} +``` + +Emits when the route changes from outside the app: Host back/forward, or a pasted URL while the app is running. The Host MUST NOT emit for changes that originated from `host_route_set` in this app session (no echo loop). The stream does not emit the initial value; the app reads that from `host_route_get`. + +### Lifecycle + +1. App starts → calls `host_route_get` → restores deep-linked state. +2. App subscribes to `host_route_changed` → handles back/forward and pasted URLs. +3. On every internal navigation → calls `host_route_set` with `replace=false` (or `true` for redirects / non-history-worthy transitions). + +### Semantics + +- **Opaque.** The Host treats `route` as an opaque byte string and does not parse it. Apps define their own grammar. +- **Length / charset.** Routes MUST be valid UTF-8. Hosts MAY impose a maximum length (recommended: at least 2048 bytes) and MUST return `GenericErr` for over-long routes; apps should avoid stuffing application state into the route. +- **Permissioning.** No permission prompt. The route is information the app already has; relaying it to the address bar does not disclose anything new to the user. (The Host MAY still rate-limit `host_route_set` to mitigate history-stack abuse.) + +## Drawbacks + +- Hosts must implement the no-echo rule on `host_route_changed` correctly, or naive apps will loop. + +## Compatibility + +Purely additive. + +## Future Directions + +- `host_route_set_title` for per-route titles in the Host chrome. +- Fold `host_route_get` into the connection handshake to save a bootstrap round-trip. diff --git a/docs/rfcs/_index.md b/docs/rfcs/_index.md index 6f45a32e..06fb119c 100644 --- a/docs/rfcs/_index.md +++ b/docs/rfcs/_index.md @@ -21,3 +21,4 @@ created: 2026-03-13 | 0011 | [Simple Group Chat](0011-simple-group-chat.md) | draft | @filvecchiato | [#131](https://github.com/paritytech/triangle-js-sdks/pull/131) | | 0015 | [Get User Primary DotNS Name](0015-get-user-id.md) | draft | @valentunn | [#144](https://github.com/paritytech/triangle-js-sdks/pull/144) | | 0019 | [Scheduled Push Notifications](0019-scheduled-notifications.md) | draft | @johnthecat | | +| 0021 | [Route Relay](0021-route-relay.md) | draft | @pgherveou | | From cde73ed869630cee7e43300c02a9ecd6c03689e1 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 15 May 2026 15:45:31 +0100 Subject: [PATCH 2/3] truapi: add host_route_get / host_route_set / host_route_changed Wire IDs 134, 136 (unary) and 138 (stream) on the System trait. Adds the v0.1 types, versioned envelopes, and trait methods. Also documents the Web-host shim where these methods can be reached transparently via the standard history.pushState / popstate API. --- docs/rfcs/0021-route-relay.md | 4 ++ rust/crates/truapi/src/api/system.rs | 79 +++++++++++++++++++++- rust/crates/truapi/src/v01/system.rs | 20 ++++++ rust/crates/truapi/src/versioned/system.rs | 6 ++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/docs/rfcs/0021-route-relay.md b/docs/rfcs/0021-route-relay.md index 6b506538..045d747b 100644 --- a/docs/rfcs/0021-route-relay.md +++ b/docs/rfcs/0021-route-relay.md @@ -85,6 +85,10 @@ Emits when the route changes from outside the app: Host back/forward, or a paste - **Length / charset.** Routes MUST be valid UTF-8. Hosts MAY impose a maximum length (recommended: at least 2048 bytes) and MUST return `GenericErr` for over-long routes; apps should avoid stuffing application state into the route. - **Permissioning.** No permission prompt. The route is information the app already has; relaying it to the address bar does not disclose anything new to the user. (The Host MAY still rate-limit `host_route_set` to mitigate history-stack abuse.) +### Web-host shim + +A Web host MAY monkey-patch `history.pushState`, `history.replaceState`, and the `popstate` / `hashchange` events on the iframe's `window` to call these TrUAPI methods underneath. With that shim in place, apps written against the standard web History API "just work" — their existing router (Next.js, React Router, vanilla `pushState`, etc.) drives the Host address bar with no TrUAPI-specific code. The shim is a Host implementation detail, not part of the protocol; non-web hosts implement these methods natively. + ## Drawbacks - Hosts must implement the no-echo rule on `host_route_changed` correctly, or naive apps will loop. diff --git a/rust/crates/truapi/src/api/system.rs b/rust/crates/truapi/src/api/system.rs index 46d9bcda..b3681eec 100644 --- a/rust/crates/truapi/src/api/system.rs +++ b/rust/crates/truapi/src/api/system.rs @@ -4,10 +4,12 @@ use crate::versioned::system::{ HostFeatureSupportedError, HostFeatureSupportedRequest, HostFeatureSupportedResponse, HostHandshakeError, HostHandshakeRequest, HostHandshakeResponse, HostNavigateToError, HostNavigateToRequest, HostNavigateToResponse, HostPushNotificationError, - HostPushNotificationRequest, HostPushNotificationResponse, + HostPushNotificationRequest, HostPushNotificationResponse, HostRouteChangedItem, + HostRouteGetError, HostRouteGetResponse, HostRouteSetError, HostRouteSetRequest, + HostRouteSetResponse, }; use crate::wire; -use crate::{CallContext, CallError}; +use crate::{CallContext, CallError, Subscription}; /// General-purpose TrUAPI methods for handshake, feature detection, /// navigation, and notifications. @@ -102,4 +104,77 @@ pub trait System: Send + Sync { cx: &CallContext, request: HostNavigateToRequest, ) -> Result>; + + /// Read the route the host currently holds for this app. + /// + /// At bootstrap this returns the route the host was launched with, so the + /// app can restore deep-linked state. Returns `None` when the app is at + /// its home. + /// + /// ```ts + /// import { type Client } from "@parity/truapi"; + /// + /// export async function bootstrapRoute(truapi: Client): Promise { + /// const result = await truapi.system.routeGet(); + /// + /// if (result.isErr()) throw result.error; + /// return result.value.route ?? null; + /// } + /// ``` + #[wire(request_id = 134)] + async fn route_get( + &self, + cx: &CallContext, + ) -> Result>; + + /// Publish the app's current route to the host's address bar. + /// + /// The host renders `route` as part of the user-visible URL so it can be + /// copied, shared, and reloaded. The host treats the route as opaque. + /// + /// ```ts + /// import { type Client } from "@parity/truapi"; + /// + /// export async function pushRoute(truapi: Client): Promise { + /// const result = await truapi.system.routeSet({ + /// route: "Permissions/host_device_permission", + /// replace: false, + /// }); + /// + /// if (result.isErr()) throw result.error; + /// } + /// ``` + #[wire(request_id = 136)] + async fn route_set( + &self, + cx: &CallContext, + request: HostRouteSetRequest, + ) -> Result>; + + /// Subscribe to route changes that originated outside the app. + /// + /// Emits on host back/forward and pasted-URL navigation. The host MUST + /// NOT emit for changes that originated from `route_set` in this app + /// session. The stream does not emit the initial value; the app reads + /// that from `route_get`. + /// + /// ```ts + /// import { + /// type Client, + /// type Subscription, + /// type HostRouteChangedItem, + /// } from "@parity/truapi"; + /// + /// export function watchRoute(truapi: Client): Subscription { + /// return truapi.system.routeChanged().subscribe({ + /// next: (event: HostRouteChangedItem) => console.log(event.route), + /// error: (error: Error) => console.error(error), + /// complete: () => console.log("completed"), + /// }); + /// } + /// ``` + #[wire(start_id = 138)] + async fn route_changed(&self, _cx: &CallContext) -> Subscription { + Subscription::empty() + } } diff --git a/rust/crates/truapi/src/v01/system.rs b/rust/crates/truapi/src/v01/system.rs index f171af6d..0d449c77 100644 --- a/rust/crates/truapi/src/v01/system.rs +++ b/rust/crates/truapi/src/v01/system.rs @@ -48,3 +48,23 @@ pub struct HostNavigateToRequest { /// URL to open. pub url: String, } + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostRouteGetResponse { + /// Current route the host holds for this app, or `None` when the app is at its home. + pub route: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostRouteSetRequest { + /// Opaque route segment defined by the app. + pub route: String, + /// `true` replaces the current history entry; `false` pushes a new one. + pub replace: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostRouteChangedItem { + /// New route, or `None` when the user is at the app's home. + pub route: Option, +} diff --git a/rust/crates/truapi/src/versioned/system.rs b/rust/crates/truapi/src/versioned/system.rs index 06a46b93..cac1f779 100644 --- a/rust/crates/truapi/src/versioned/system.rs +++ b/rust/crates/truapi/src/versioned/system.rs @@ -15,4 +15,10 @@ versioned_type! { pub enum HostPushNotificationRequest { V1 => v01::HostPushNotificationRequest } pub enum HostPushNotificationResponse { V1 } pub enum HostPushNotificationError { V1 => v01::GenericError } + pub enum HostRouteGetResponse { V1 => v01::HostRouteGetResponse } + pub enum HostRouteGetError { V1 => v01::GenericError } + pub enum HostRouteSetRequest { V1 => v01::HostRouteSetRequest } + pub enum HostRouteSetResponse { V1 } + pub enum HostRouteSetError { V1 => v01::GenericError } + pub enum HostRouteChangedItem { V1 => v01::HostRouteChangedItem } } From d4e68df5d5ce0df3965cbc340d7e9879b182a3b2 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 15 May 2026 15:48:57 +0100 Subject: [PATCH 3/3] truapi: move route + navigate_to into a Navigation trait Splits the route surface and external-URL open out of System into a dedicated Navigation trait. Wire IDs are unchanged (6 for navigate_to, 134/136/138 for route_get/route_set/route_changed); only the trait membership and the v0.1 / versioned module layout move. --- rust/crates/truapi/src/api/mod.rs | 4 + rust/crates/truapi/src/api/navigation.rs | 105 +++++++++++++++++ rust/crates/truapi/src/api/system.rs | 106 +----------------- rust/crates/truapi/src/v01/mod.rs | 2 + rust/crates/truapi/src/v01/navigation.rs | 33 ++++++ rust/crates/truapi/src/v01/system.rs | 32 ------ rust/crates/truapi/src/versioned/mod.rs | 8 +- .../crates/truapi/src/versioned/navigation.rs | 15 +++ rust/crates/truapi/src/versioned/system.rs | 9 -- 9 files changed, 169 insertions(+), 145 deletions(-) create mode 100644 rust/crates/truapi/src/api/navigation.rs create mode 100644 rust/crates/truapi/src/v01/navigation.rs create mode 100644 rust/crates/truapi/src/versioned/navigation.rs diff --git a/rust/crates/truapi/src/api/mod.rs b/rust/crates/truapi/src/api/mod.rs index 9332e8ce..290559f3 100644 --- a/rust/crates/truapi/src/api/mod.rs +++ b/rust/crates/truapi/src/api/mod.rs @@ -6,6 +6,7 @@ pub mod chat; pub mod entropy; pub mod jsonrpc; pub mod local_storage; +pub mod navigation; pub mod payment; pub mod permissions; pub mod preimage; @@ -21,6 +22,7 @@ pub use chat::Chat; pub use entropy::Entropy; pub use jsonrpc::JsonRpc; pub use local_storage::LocalStorage; +pub use navigation::Navigation; pub use payment::Payment; pub use permissions::Permissions; pub use preimage::Preimage; @@ -38,6 +40,7 @@ pub trait TrUApi: + Entropy + JsonRpc + LocalStorage + + Navigation + Payment + Permissions + Preimage @@ -58,6 +61,7 @@ impl TrUApi for T where + Entropy + JsonRpc + LocalStorage + + Navigation + Payment + Permissions + Preimage diff --git a/rust/crates/truapi/src/api/navigation.rs b/rust/crates/truapi/src/api/navigation.rs new file mode 100644 index 00000000..b3daa5ef --- /dev/null +++ b/rust/crates/truapi/src/api/navigation.rs @@ -0,0 +1,105 @@ +//! Unified [`Navigation`] trait. + +use crate::versioned::navigation::{ + HostNavigateToError, HostNavigateToRequest, HostNavigateToResponse, HostRouteChangedItem, + HostRouteGetError, HostRouteGetResponse, HostRouteSetError, HostRouteSetRequest, + HostRouteSetResponse, +}; +use crate::wire; +use crate::{CallContext, CallError, Subscription}; + +/// Host navigation surface: external URL opens and the app's own route. +pub trait Navigation: Send + Sync { + /// Request the host to open a URL. + /// + /// ```ts + /// import { type Client } from "@parity/truapi"; + /// + /// export async function navigateToDocs(truapi: Client): Promise { + /// const result = await truapi.navigation.navigateTo({ + /// url: "https://example.com", + /// }); + /// + /// if (result.isErr()) throw result.error; + /// } + /// ``` + #[wire(request_id = 6)] + async fn navigate_to( + &self, + cx: &CallContext, + request: HostNavigateToRequest, + ) -> Result>; + + /// Read the route the host currently holds for this app. + /// + /// At bootstrap this returns the route the host was launched with, so the + /// app can restore deep-linked state. Returns `None` when the app is at + /// its home. + /// + /// ```ts + /// import { type Client } from "@parity/truapi"; + /// + /// export async function bootstrapRoute(truapi: Client): Promise { + /// const result = await truapi.navigation.routeGet(); + /// + /// if (result.isErr()) throw result.error; + /// return result.value.route ?? null; + /// } + /// ``` + #[wire(request_id = 134)] + async fn route_get( + &self, + cx: &CallContext, + ) -> Result>; + + /// Publish the app's current route to the host's address bar. + /// + /// The host renders `route` as part of the user-visible URL so it can be + /// copied, shared, and reloaded. The host treats the route as opaque. + /// + /// ```ts + /// import { type Client } from "@parity/truapi"; + /// + /// export async function pushRoute(truapi: Client): Promise { + /// const result = await truapi.navigation.routeSet({ + /// route: "Permissions/host_device_permission", + /// replace: false, + /// }); + /// + /// if (result.isErr()) throw result.error; + /// } + /// ``` + #[wire(request_id = 136)] + async fn route_set( + &self, + cx: &CallContext, + request: HostRouteSetRequest, + ) -> Result>; + + /// Subscribe to route changes that originated outside the app. + /// + /// Emits on host back/forward and pasted-URL navigation. The host MUST + /// NOT emit for changes that originated from `route_set` in this app + /// session. The stream does not emit the initial value; the app reads + /// that from `route_get`. + /// + /// ```ts + /// import { + /// type Client, + /// type Subscription, + /// type HostRouteChangedItem, + /// } from "@parity/truapi"; + /// + /// export function watchRoute(truapi: Client): Subscription { + /// return truapi.navigation.routeChanged().subscribe({ + /// next: (event: HostRouteChangedItem) => console.log(event.route), + /// error: (error: Error) => console.error(error), + /// complete: () => console.log("completed"), + /// }); + /// } + /// ``` + #[wire(start_id = 138)] + async fn route_changed(&self, _cx: &CallContext) -> Subscription { + Subscription::empty() + } +} diff --git a/rust/crates/truapi/src/api/system.rs b/rust/crates/truapi/src/api/system.rs index b3681eec..28271543 100644 --- a/rust/crates/truapi/src/api/system.rs +++ b/rust/crates/truapi/src/api/system.rs @@ -2,17 +2,14 @@ use crate::versioned::system::{ HostFeatureSupportedError, HostFeatureSupportedRequest, HostFeatureSupportedResponse, - HostHandshakeError, HostHandshakeRequest, HostHandshakeResponse, HostNavigateToError, - HostNavigateToRequest, HostNavigateToResponse, HostPushNotificationError, - HostPushNotificationRequest, HostPushNotificationResponse, HostRouteChangedItem, - HostRouteGetError, HostRouteGetResponse, HostRouteSetError, HostRouteSetRequest, - HostRouteSetResponse, + HostHandshakeError, HostHandshakeRequest, HostHandshakeResponse, HostPushNotificationError, + HostPushNotificationRequest, HostPushNotificationResponse, }; use crate::wire; -use crate::{CallContext, CallError, Subscription}; +use crate::{CallContext, CallError}; -/// General-purpose TrUAPI methods for handshake, feature detection, -/// navigation, and notifications. +/// General-purpose TrUAPI methods for handshake, feature detection, and +/// notifications. pub trait System: Send + Sync { /// Negotiate the wire codec version with the product. /// @@ -84,97 +81,4 @@ pub trait System: Send + Sync { cx: &CallContext, request: HostPushNotificationRequest, ) -> Result>; - - /// Request the host to open a URL. - /// - /// ```ts - /// import { type Client } from "@parity/truapi"; - /// - /// export async function navigateToDocs(truapi: Client): Promise { - /// const result = await truapi.system.navigateTo({ - /// url: "https://example.com", - /// }); - /// - /// if (result.isErr()) throw result.error; - /// } - /// ``` - #[wire(request_id = 6)] - async fn navigate_to( - &self, - cx: &CallContext, - request: HostNavigateToRequest, - ) -> Result>; - - /// Read the route the host currently holds for this app. - /// - /// At bootstrap this returns the route the host was launched with, so the - /// app can restore deep-linked state. Returns `None` when the app is at - /// its home. - /// - /// ```ts - /// import { type Client } from "@parity/truapi"; - /// - /// export async function bootstrapRoute(truapi: Client): Promise { - /// const result = await truapi.system.routeGet(); - /// - /// if (result.isErr()) throw result.error; - /// return result.value.route ?? null; - /// } - /// ``` - #[wire(request_id = 134)] - async fn route_get( - &self, - cx: &CallContext, - ) -> Result>; - - /// Publish the app's current route to the host's address bar. - /// - /// The host renders `route` as part of the user-visible URL so it can be - /// copied, shared, and reloaded. The host treats the route as opaque. - /// - /// ```ts - /// import { type Client } from "@parity/truapi"; - /// - /// export async function pushRoute(truapi: Client): Promise { - /// const result = await truapi.system.routeSet({ - /// route: "Permissions/host_device_permission", - /// replace: false, - /// }); - /// - /// if (result.isErr()) throw result.error; - /// } - /// ``` - #[wire(request_id = 136)] - async fn route_set( - &self, - cx: &CallContext, - request: HostRouteSetRequest, - ) -> Result>; - - /// Subscribe to route changes that originated outside the app. - /// - /// Emits on host back/forward and pasted-URL navigation. The host MUST - /// NOT emit for changes that originated from `route_set` in this app - /// session. The stream does not emit the initial value; the app reads - /// that from `route_get`. - /// - /// ```ts - /// import { - /// type Client, - /// type Subscription, - /// type HostRouteChangedItem, - /// } from "@parity/truapi"; - /// - /// export function watchRoute(truapi: Client): Subscription { - /// return truapi.system.routeChanged().subscribe({ - /// next: (event: HostRouteChangedItem) => console.log(event.route), - /// error: (error: Error) => console.error(error), - /// complete: () => console.log("completed"), - /// }); - /// } - /// ``` - #[wire(start_id = 138)] - async fn route_changed(&self, _cx: &CallContext) -> Subscription { - Subscription::empty() - } } diff --git a/rust/crates/truapi/src/v01/mod.rs b/rust/crates/truapi/src/v01/mod.rs index 73200903..eac2d860 100644 --- a/rust/crates/truapi/src/v01/mod.rs +++ b/rust/crates/truapi/src/v01/mod.rs @@ -7,6 +7,7 @@ mod common; mod entropy; mod jsonrpc; mod local_storage; +mod navigation; mod payment; mod permissions; mod preimage; @@ -24,6 +25,7 @@ pub use common::*; pub use entropy::*; pub use jsonrpc::*; pub use local_storage::*; +pub use navigation::*; pub use payment::*; pub use permissions::*; pub use preimage::*; diff --git a/rust/crates/truapi/src/v01/navigation.rs b/rust/crates/truapi/src/v01/navigation.rs new file mode 100644 index 00000000..5d3bc3ce --- /dev/null +++ b/rust/crates/truapi/src/v01/navigation.rs @@ -0,0 +1,33 @@ +use parity_scale_codec::{Decode, Encode}; + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub enum HostNavigateToError { + PermissionDenied, + Unknown { reason: String }, +} + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostNavigateToRequest { + /// URL to open. + pub url: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostRouteGetResponse { + /// Current route the host holds for this app, or `None` when the app is at its home. + pub route: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostRouteSetRequest { + /// Opaque route segment defined by the app. + pub route: String, + /// `true` replaces the current history entry; `false` pushes a new one. + pub replace: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct HostRouteChangedItem { + /// New route, or `None` when the user is at the app's home. + pub route: Option, +} diff --git a/rust/crates/truapi/src/v01/system.rs b/rust/crates/truapi/src/v01/system.rs index 0d449c77..281dfade 100644 --- a/rust/crates/truapi/src/v01/system.rs +++ b/rust/crates/truapi/src/v01/system.rs @@ -10,12 +10,6 @@ pub enum HostFeatureSupportedRequest { }, } -#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub enum HostNavigateToError { - PermissionDenied, - Unknown { reason: String }, -} - #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] pub struct HostPushNotificationRequest { /// Notification text. @@ -42,29 +36,3 @@ pub struct HostFeatureSupportedResponse { /// Whether the feature is supported. pub supported: bool, } - -#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct HostNavigateToRequest { - /// URL to open. - pub url: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct HostRouteGetResponse { - /// Current route the host holds for this app, or `None` when the app is at its home. - pub route: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct HostRouteSetRequest { - /// Opaque route segment defined by the app. - pub route: String, - /// `true` replaces the current history entry; `false` pushes a new one. - pub replace: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct HostRouteChangedItem { - /// New route, or `None` when the user is at the app's home. - pub route: Option, -} diff --git a/rust/crates/truapi/src/versioned/mod.rs b/rust/crates/truapi/src/versioned/mod.rs index 1e53a18a..3c541c7e 100644 --- a/rust/crates/truapi/src/versioned/mod.rs +++ b/rust/crates/truapi/src/versioned/mod.rs @@ -86,6 +86,7 @@ pub mod chat; pub mod entropy; pub mod jsonrpc; pub mod local_storage; +pub mod navigation; pub mod payment; pub mod permissions; pub mod preimage; @@ -109,9 +110,10 @@ mod tests { #[test] fn unit_response_roundtrip() { - let original = super::system::HostNavigateToResponse::V1; - let decoded = super::system::HostNavigateToResponse::decode(&mut &original.encode()[..]) - .expect("decode"); + let original = super::navigation::HostNavigateToResponse::V1; + let decoded = + super::navigation::HostNavigateToResponse::decode(&mut &original.encode()[..]) + .expect("decode"); assert_eq!(original, decoded); } diff --git a/rust/crates/truapi/src/versioned/navigation.rs b/rust/crates/truapi/src/versioned/navigation.rs new file mode 100644 index 00000000..0f3ac578 --- /dev/null +++ b/rust/crates/truapi/src/versioned/navigation.rs @@ -0,0 +1,15 @@ +//! Versioned wrappers for [`Navigation`](crate::api::Navigation) methods. + +use crate::v01; + +versioned_type! { + pub enum HostNavigateToRequest { V1 => v01::HostNavigateToRequest } + pub enum HostNavigateToResponse { V1 } + pub enum HostNavigateToError { V1 => v01::HostNavigateToError } + pub enum HostRouteGetResponse { V1 => v01::HostRouteGetResponse } + pub enum HostRouteGetError { V1 => v01::GenericError } + pub enum HostRouteSetRequest { V1 => v01::HostRouteSetRequest } + pub enum HostRouteSetResponse { V1 } + pub enum HostRouteSetError { V1 => v01::GenericError } + pub enum HostRouteChangedItem { V1 => v01::HostRouteChangedItem } +} diff --git a/rust/crates/truapi/src/versioned/system.rs b/rust/crates/truapi/src/versioned/system.rs index cac1f779..1b4ad1a7 100644 --- a/rust/crates/truapi/src/versioned/system.rs +++ b/rust/crates/truapi/src/versioned/system.rs @@ -9,16 +9,7 @@ versioned_type! { pub enum HostFeatureSupportedRequest { V1 => v01::HostFeatureSupportedRequest } pub enum HostFeatureSupportedResponse { V1 => v01::HostFeatureSupportedResponse } pub enum HostFeatureSupportedError { V1 => v01::GenericError } - pub enum HostNavigateToRequest { V1 => v01::HostNavigateToRequest } - pub enum HostNavigateToResponse { V1 } - pub enum HostNavigateToError { V1 => v01::HostNavigateToError } pub enum HostPushNotificationRequest { V1 => v01::HostPushNotificationRequest } pub enum HostPushNotificationResponse { V1 } pub enum HostPushNotificationError { V1 => v01::GenericError } - pub enum HostRouteGetResponse { V1 => v01::HostRouteGetResponse } - pub enum HostRouteGetError { V1 => v01::GenericError } - pub enum HostRouteSetRequest { V1 => v01::HostRouteSetRequest } - pub enum HostRouteSetResponse { V1 } - pub enum HostRouteSetError { V1 => v01::GenericError } - pub enum HostRouteChangedItem { V1 => v01::HostRouteChangedItem } }