diff --git a/Cargo.lock b/Cargo.lock index 727ea70ea..972fe3366 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -734,6 +734,7 @@ dependencies = [ "bitwarden-fido", "bitwarden-generators", "bitwarden-send", + "bitwarden-state", "bitwarden-vault", "tsify", "uniffi", @@ -816,14 +817,6 @@ dependencies = [ "uniffi", ] -[[package]] -name = "bitwarden-state-migrations" -version = "1.0.0" -dependencies = [ - "bitwarden-state", - "bitwarden-vault", -] - [[package]] name = "bitwarden-test" version = "1.0.0" @@ -873,7 +866,6 @@ dependencies = [ "bitwarden-send", "bitwarden-ssh", "bitwarden-state", - "bitwarden-state-migrations", "bitwarden-uniffi-error", "bitwarden-vault", "chrono", @@ -960,7 +952,6 @@ dependencies = [ "bitwarden-pm", "bitwarden-ssh", "bitwarden-state", - "bitwarden-state-migrations", "bitwarden-threading", "bitwarden-vault", "console_error_panic_hook", diff --git a/Cargo.toml b/Cargo.toml index d7e9d3eb5..675ecfcdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ bitwarden-send = { path = "crates/bitwarden-send", version = "=1.0.0" } bitwarden-sm = { path = "bitwarden_license/bitwarden-sm", version = "=1.0.0" } bitwarden-ssh = { path = "crates/bitwarden-ssh", version = "=1.0.0" } bitwarden-state = { path = "crates/bitwarden-state", version = "=1.0.0" } -bitwarden-state-migrations = { path = "crates/bitwarden-state-migrations", version = "=1.0.0" } bitwarden-test = { path = "crates/bitwarden-test", version = "=1.0.0" } bitwarden-threading = { path = "crates/bitwarden-threading", version = "=1.0.0" } bitwarden-uniffi-error = { path = "crates/bitwarden-uniffi-error", version = "=1.0.0" } diff --git a/crates/bitwarden-pm/Cargo.toml b/crates/bitwarden-pm/Cargo.toml index 7a90980a5..b084522ae 100644 --- a/crates/bitwarden-pm/Cargo.toml +++ b/crates/bitwarden-pm/Cargo.toml @@ -24,6 +24,7 @@ uniffi = [ "bitwarden-fido/uniffi", "bitwarden-generators/uniffi", "bitwarden-send/uniffi", + "bitwarden-state/uniffi", "bitwarden-vault/uniffi", "dep:uniffi" ] # Uniffi bindings @@ -33,6 +34,7 @@ wasm = [ "bitwarden-core/wasm", "bitwarden-exporters/wasm", "bitwarden-generators/wasm", + "bitwarden-state/wasm", "bitwarden-vault/wasm", "dep:wasm-bindgen", "dep:wasm-bindgen-futures", @@ -48,6 +50,7 @@ bitwarden-exporters = { workspace = true } bitwarden-fido = { workspace = true } bitwarden-generators = { workspace = true } bitwarden-send = { workspace = true } +bitwarden-state = { workspace = true } bitwarden-vault = { workspace = true } tsify = { workspace = true, optional = true } diff --git a/crates/bitwarden-pm/src/lib.rs b/crates/bitwarden-pm/src/lib.rs index aeb23a24d..81e282dd7 100644 --- a/crates/bitwarden-pm/src/lib.rs +++ b/crates/bitwarden-pm/src/lib.rs @@ -27,6 +27,8 @@ pub mod clients { #[cfg(feature = "bitwarden-license")] pub use commercial::CommercialPasswordManagerClient; +pub mod migrations; + /// The main entry point for the Bitwarden Password Manager SDK pub struct PasswordManagerClient(pub bitwarden_core::Client); @@ -46,6 +48,11 @@ impl PasswordManagerClient { )) } + /// Platform operations + pub fn platform(&self) -> bitwarden_core::platform::PlatformClient { + self.0.platform() + } + /// Auth operations pub fn auth(&self) -> bitwarden_auth::AuthClient { self.0.auth_new() diff --git a/crates/bitwarden-pm/src/migrations.rs b/crates/bitwarden-pm/src/migrations.rs new file mode 100644 index 000000000..242ae87e3 --- /dev/null +++ b/crates/bitwarden-pm/src/migrations.rs @@ -0,0 +1,32 @@ +//! Manages repository migrations for the Bitwarden SDK. + +use bitwarden_state::repository::{RepositoryItem, RepositoryMigrationStep, RepositoryMigrations}; +use bitwarden_vault::{Cipher, Folder}; + +/// Returns a list of all SDK-managed repository migrations. +pub fn get_sdk_managed_migrations() -> RepositoryMigrations { + use RepositoryMigrationStep::*; + RepositoryMigrations::new(vec![ + // Add any new migrations here. Note that order matters, and that removing a repository + // requires a separate migration step using `Remove(...)`. + Add(Cipher::data()), + Add(Folder::data()), + ]) +} + +/// Macro to create the client managed repositories for the SDK. +/// To add a new repository, add it to the list in the macro invocation. +/// This is meant to be used by the final application crates (e.g., bitwarden-uniffi, +/// bitwarden-wasm-internal, bw). +#[macro_export] +macro_rules! create_client_managed_repositories { + ($container_name:ident, $macro:ident) => { + $macro! { + $container_name; + // List any SDK-managed repositories here. The format is: + // , , , + ::bitwarden_vault::Cipher, Cipher, cipher, CipherRepository; + ::bitwarden_vault::Folder, Folder, folder, FolderRepository; + } + }; +} diff --git a/crates/bitwarden-state-migrations/Cargo.toml b/crates/bitwarden-state-migrations/Cargo.toml deleted file mode 100644 index f0cadc8d0..000000000 --- a/crates/bitwarden-state-migrations/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "bitwarden-state-migrations" -version.workspace = true -authors.workspace = true -edition.workspace = true -rust-version.workspace = true -homepage.workspace = true -repository.workspace = true -license-file.workspace = true -keywords.workspace = true - -[features] -uniffi = ["bitwarden-vault/uniffi"] -wasm = ["bitwarden-vault/wasm"] - -[dependencies] -bitwarden-state = { workspace = true } -bitwarden-vault = { workspace = true } - -[lints] -workspace = true diff --git a/crates/bitwarden-state-migrations/README.md b/crates/bitwarden-state-migrations/README.md deleted file mode 100644 index a0fa7635f..000000000 --- a/crates/bitwarden-state-migrations/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# bitwarden-state-migrations - -This crate contains migrations for the SDK-managed state framework. It should only be imported by -the final application crates (`bitwarden-wasm-internal` and `bitwarden-uniffi`) diff --git a/crates/bitwarden-state-migrations/src/lib.rs b/crates/bitwarden-state-migrations/src/lib.rs deleted file mode 100644 index b6585cac2..000000000 --- a/crates/bitwarden-state-migrations/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![doc = include_str!("../README.md")] - -use bitwarden_state::repository::{RepositoryItem, RepositoryMigrationStep, RepositoryMigrations}; -use bitwarden_vault::{Cipher, Folder}; - -/// Returns a list of all SDK-managed repository migrations. -pub fn get_sdk_managed_migrations() -> RepositoryMigrations { - use RepositoryMigrationStep::*; - RepositoryMigrations::new(vec![ - // Add any new migrations here. Note that order matters, and that removing a repository - // requires a separate migration step using `Remove(...)`. - Add(Cipher::data()), - Add(Folder::data()), - ]) -} diff --git a/crates/bitwarden-state/README.md b/crates/bitwarden-state/README.md index bda45c114..f3f72dfca 100644 --- a/crates/bitwarden-state/README.md +++ b/crates/bitwarden-state/README.md @@ -39,21 +39,20 @@ need to define some functions in `bitwarden-wasm-internal` and `bitwarden-uniffi applications to provide their `Repository` implementations. The implementations themselves will be very simple as we provide macros that take care of the brunt of the work. -### Client-Managed State in WASM +To add support for a new `Repository`, add it to the list defined at the end of +`crates/bitwarden-pm/src/migrations.rs`. -For WASM, we need to define a new `Repository` for our type and provide a function that will accept -it. This is done in the file `crates/bitwarden-wasm-internal/src/platform/mod.rs`, you can check the -provided example: - -```rust,ignore -repository::create_wasm_repository!(CipherRepository, Cipher, "Repository"); - -#[wasm_bindgen] -impl StateClient { - pub fn register_cipher_repository(&self, store: CipherRepository) { - let store = store.into_channel_impl(); - self.0.platform().state().register_client_managed(store) - } +```rust +macro_rules! create_client_managed_repositories { + ($container_name:ident, $macro:ident) => { + $macro! { + $container_name; + // List any SDK-managed repositories here. The format is: + // , , , + ::bitwarden_vault::Cipher, Cipher, cipher, CipherRepository; + ::bitwarden_vault::Folder, Folder, folder, FolderRepository; + } + }; } ``` @@ -90,30 +89,9 @@ export async function initializeState( stateClient: StateClient, stateProvider: StateProvider, ): Promise { - await stateClient.register_cipher_repository( - new RepositoryRecord(userId, stateProvider, new CipherRecordMapper()), - ); -} -``` - -### Client-Managed State in UniFFI - -For UniFFI, we need to define a new `Repository` for our type and provide a function that will -accept it. This is done in the file `crates/bitwarden-uniffi/src/platform/mod.rs`, you can check the -provided example: - -```rust,ignore -repository::create_uniffi_repository!(CipherRepository, Cipher); - -#[uniffi::export] -impl StateClient { - pub fn register_cipher_repository(&self, store: Arc) { - let store_internal = UniffiRepositoryBridge::new(store); - self.0 - .platform() - .state() - .register_client_managed(store_internal) - } + stateClient.register_client_managed_repositories({ + cipher: new RepositoryRecord(userId, stateProvider, new CipherRecordMapper()), + }); } ``` @@ -187,8 +165,8 @@ SDK. To add support for an SDK managed `Repository`, a new migration step needs ### How to initialize SDK-Managed State -Go to `crates/bitwarden-state-migrations/src/lib.rs` and add a line with your type, as shown below. -In this example we're registering `Cipher` and `Folder` as SDK managed. +Go to `crates/bitwarden-pm/src/migrations.rs` and add a line with your type, as shown below. In this +example we're registering `Cipher` and `Folder` as SDK managed. ```rust,ignore /// Returns a list of all SDK-managed repository migrations. diff --git a/crates/bitwarden-uniffi/Cargo.toml b/crates/bitwarden-uniffi/Cargo.toml index ab7b6c60a..82aa7a7bb 100644 --- a/crates/bitwarden-uniffi/Cargo.toml +++ b/crates/bitwarden-uniffi/Cargo.toml @@ -31,7 +31,6 @@ bitwarden-pm = { workspace = true, features = ["uniffi"] } bitwarden-send = { workspace = true, features = ["uniffi"] } bitwarden-ssh = { workspace = true, features = ["uniffi"] } bitwarden-state = { workspace = true, features = ["uniffi"] } -bitwarden-state-migrations = { workspace = true, features = ["uniffi"] } bitwarden-uniffi-error = { workspace = true } bitwarden-vault = { workspace = true, features = ["uniffi"] } chrono = { workspace = true, features = ["std"] } diff --git a/crates/bitwarden-uniffi/src/platform/mod.rs b/crates/bitwarden-uniffi/src/platform/mod.rs index 8f71c5775..8dcdaeb4e 100644 --- a/crates/bitwarden-uniffi/src/platform/mod.rs +++ b/crates/bitwarden-uniffi/src/platform/mod.rs @@ -1,10 +1,11 @@ +#![allow(deprecated)] + use std::sync::Arc; use bitwarden_core::{Client, platform::FingerprintRequest}; use bitwarden_fido::ClientFido2Ext; use bitwarden_state::DatabaseConfiguration; -use bitwarden_vault::Cipher; -use repository::UniffiRepositoryBridge; +use repository::{UniffiRepositoryBridge, create_uniffi_repositories}; use crate::error::Result; @@ -45,24 +46,29 @@ impl PlatformClient { #[derive(uniffi::Object)] pub struct StateClient(Client); -repository::create_uniffi_repository!(CipherRepository, Cipher); - #[derive(uniffi::Record)] pub struct SqliteConfiguration { db_name: String, folder_path: String, } +bitwarden_pm::create_client_managed_repositories!(Repositories, create_uniffi_repositories); + #[uniffi::export] impl StateClient { + #[deprecated(note = "Use `register_client_managed_repositories` instead")] pub fn register_cipher_repository(&self, repository: Arc) { let cipher = UniffiRepositoryBridge::new(repository); self.0.platform().state().register_client_managed(cipher); } + pub fn register_client_managed_repositories(&self, repositories: Repositories) { + repositories.register_all(&self.0.platform().state()); + } + /// Initialize the database for SDK managed repositories. pub async fn initialize_state(&self, configuration: SqliteConfiguration) -> Result<()> { - let migrations = bitwarden_state_migrations::get_sdk_managed_migrations(); + let migrations = bitwarden_pm::migrations::get_sdk_managed_migrations(); self.0 .platform() diff --git a/crates/bitwarden-uniffi/src/platform/repository.rs b/crates/bitwarden-uniffi/src/platform/repository.rs index 7cee81918..973afd3a0 100644 --- a/crates/bitwarden-uniffi/src/platform/repository.rs +++ b/crates/bitwarden-uniffi/src/platform/repository.rs @@ -39,60 +39,82 @@ impl From for bitwarden_state::repository::RepositoryError { /// This macro creates a Uniffi repository trait and its implementation for the /// [bitwarden_state::repository::Repository] trait -macro_rules! create_uniffi_repository { - ($name:ident, $ty:ty) => { - #[uniffi::export(with_foreign)] - #[async_trait::async_trait] - pub trait $name: Send + Sync { - async fn get( - &self, - id: String, - ) -> Result, $crate::platform::repository::RepositoryError>; - async fn list(&self) - -> Result, $crate::platform::repository::RepositoryError>; - async fn set( - &self, - id: String, - value: $ty, - ) -> Result<(), $crate::platform::repository::RepositoryError>; - async fn remove( - &self, - id: String, - ) -> Result<(), $crate::platform::repository::RepositoryError>; +macro_rules! create_uniffi_repositories { + ( $container_name:ident ; $( $qualified_type_name:ty, $type_name:ident, $field_name:ident, $repo_name:ident );+ $(;)? ) => { - async fn has( - &self, - id: String, - ) -> Result; + #[derive(::uniffi::Record)] + pub struct $container_name { + $( + pub $field_name: Option<::std::sync::Arc>, + )+ } - #[async_trait::async_trait] - impl bitwarden_state::repository::Repository<$ty> - for $crate::platform::repository::UniffiRepositoryBridge> - { - async fn get( - &self, - key: String, - ) -> Result, bitwarden_state::repository::RepositoryError> { - self.0.get(key).await.map_err(Into::into) + impl $container_name { + pub fn register_all(self, client: &bitwarden_core::platform::StateClient) { + $( + if let Some(repo) = self.$field_name { + let bridge = $crate::platform::repository::UniffiRepositoryBridge::new(repo); + client.register_client_managed(bridge); + } + )+ } - async fn list(&self) -> Result, bitwarden_state::repository::RepositoryError> { - self.0.list().await.map_err(Into::into) - } - async fn set( - &self, - key: String, - value: $ty, - ) -> Result<(), bitwarden_state::repository::RepositoryError> { - self.0.set(key, value).await.map_err(Into::into) + } + + $( + #[::uniffi::export(with_foreign)] + #[::async_trait::async_trait] + pub trait $repo_name: Send + Sync { + async fn get( + &self, + id: String, + ) -> Result, $crate::platform::repository::RepositoryError>; + async fn list(&self) + -> Result, $crate::platform::repository::RepositoryError>; + async fn set( + &self, + id: String, + value: $qualified_type_name, + ) -> Result<(), $crate::platform::repository::RepositoryError>; + async fn remove( + &self, + id: String, + ) -> Result<(), $crate::platform::repository::RepositoryError>; + + async fn has( + &self, + id: String, + ) -> Result; } - async fn remove( - &self, - key: String, - ) -> Result<(), bitwarden_state::repository::RepositoryError> { - self.0.remove(key).await.map_err(Into::into) + + #[async_trait::async_trait] + impl bitwarden_state::repository::Repository<$qualified_type_name> + for $crate::platform::repository::UniffiRepositoryBridge> + { + async fn get( + &self, + key: String, + ) -> Result, bitwarden_state::repository::RepositoryError> { + self.0.get(key).await.map_err(Into::into) + } + async fn list(&self) -> Result, bitwarden_state::repository::RepositoryError> { + self.0.list().await.map_err(Into::into) + } + async fn set( + &self, + key: String, + value: $qualified_type_name, + ) -> Result<(), bitwarden_state::repository::RepositoryError> { + self.0.set(key, value).await.map_err(Into::into) + } + async fn remove( + &self, + key: String, + ) -> Result<(), bitwarden_state::repository::RepositoryError> { + self.0.remove(key).await.map_err(Into::into) + } } - } + )+ }; } -pub(super) use create_uniffi_repository; + +pub(super) use create_uniffi_repositories; diff --git a/crates/bitwarden-wasm-internal/Cargo.toml b/crates/bitwarden-wasm-internal/Cargo.toml index e5b25ccdd..27cc102a0 100644 --- a/crates/bitwarden-wasm-internal/Cargo.toml +++ b/crates/bitwarden-wasm-internal/Cargo.toml @@ -30,7 +30,6 @@ bitwarden-ipc = { workspace = true, features = ["wasm"] } bitwarden-pm = { workspace = true, features = ["wasm"] } bitwarden-ssh = { workspace = true, features = ["wasm"] } bitwarden-state = { workspace = true, features = ["wasm"] } -bitwarden-state-migrations = { workspace = true, features = ["wasm"] } bitwarden-threading = { workspace = true } bitwarden-vault = { workspace = true, features = ["wasm"] } console_error_panic_hook = "0.1.7" diff --git a/crates/bitwarden-wasm-internal/src/platform/mod.rs b/crates/bitwarden-wasm-internal/src/platform/mod.rs index daf85ac65..6953557af 100644 --- a/crates/bitwarden-wasm-internal/src/platform/mod.rs +++ b/crates/bitwarden-wasm-internal/src/platform/mod.rs @@ -1,10 +1,11 @@ use bitwarden_core::Client; use bitwarden_state::DatabaseConfiguration; -use bitwarden_vault::{Cipher, Folder}; use serde::{Deserialize, Serialize}; use tsify::Tsify; use wasm_bindgen::{JsValue, prelude::wasm_bindgen}; +use crate::platform::repository::create_wasm_repositories; + mod repository; pub mod token_provider; @@ -48,8 +49,7 @@ impl StateClient { } } -repository::create_wasm_repository!(CipherRepository, Cipher, "Repository"); -repository::create_wasm_repository!(FolderRepository, Folder, "Repository"); +bitwarden_pm::create_client_managed_repositories!(Repositories, create_wasm_repositories); #[derive(Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] @@ -59,22 +59,30 @@ pub struct IndexedDbConfiguration { #[wasm_bindgen] impl StateClient { + #[allow(deprecated)] + #[deprecated(note = "Use `register_client_managed_repositories` instead")] pub fn register_cipher_repository(&self, cipher_repository: CipherRepository) { let cipher = cipher_repository.into_channel_impl(); self.0.platform().state().register_client_managed(cipher); } + #[allow(deprecated)] + #[deprecated(note = "Use `register_client_managed_repositories` instead")] pub fn register_folder_repository(&self, store: FolderRepository) { let store = store.into_channel_impl(); self.0.platform().state().register_client_managed(store) } + pub fn register_client_managed_repositories(&self, repositories: Repositories) { + repositories.register_all(&self.0.platform().state()); + } + /// Initialize the database for SDK managed repositories. pub async fn initialize_state( &self, configuration: IndexedDbConfiguration, ) -> Result<(), bitwarden_state::registry::StateRegistryError> { - let sdk_managed_repositories = bitwarden_state_migrations::get_sdk_managed_migrations(); + let sdk_managed_repositories = bitwarden_pm::migrations::get_sdk_managed_migrations(); self.0 .platform() diff --git a/crates/bitwarden-wasm-internal/src/platform/repository.rs b/crates/bitwarden-wasm-internal/src/platform/repository.rs index 3ec4033f5..faa4db8a0 100644 --- a/crates/bitwarden-wasm-internal/src/platform/repository.rs +++ b/crates/bitwarden-wasm-internal/src/platform/repository.rs @@ -29,7 +29,7 @@ * use the existing [Repository] trait. * - It runs the calls in a thread-bound manner, so we can safely call the [WasmRepository] * methods from any thread. - * - The [create_wasm_repository] macro, defines the [::wasm_bindgen] interface and implements + * - The [create_wasm_repositories] macro, defines the [::wasm_bindgen] interface and implements * the [WasmRepository] trait for you. */ @@ -95,70 +95,106 @@ export interface Repository { /// This macro generates a [::wasm_bindgen] interface for a repository type, and provides the /// implementation of [WasmRepository] and a way to convert it into something that implements /// the [Repository] trait. -macro_rules! create_wasm_repository { - ($name:ident, $ty:ty, $typescript_ty:literal) => { +macro_rules! create_wasm_repositories { + ( $container_name:ident ; $( $qualified_type_name:ty, $type_name:ident, $field_name:ident, $repo_name:ident );+ $(;)? ) => { + + const _: () = { + #[wasm_bindgen(typescript_custom_section)] + const REPOSITORIES_CUSTOM_TS_TYPE: &'static str = concat!( + "export interface ", + stringify!($container_name), + "{\n", + $( stringify!($field_name), ": Repository<", stringify!($type_name), "> | null;\n", )+ + "}\n" + ); + }; + #[wasm_bindgen] extern "C" { - #[wasm_bindgen(js_name = $name, typescript_type = $typescript_ty)] - pub type $name; - - #[wasm_bindgen(method, catch)] - async fn get( - this: &$name, - id: String, - ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; - #[wasm_bindgen(method, catch)] - async fn list(this: &$name) - -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; - #[wasm_bindgen(method, catch)] - async fn set( - this: &$name, - id: String, - value: $ty, - ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; - #[wasm_bindgen(method, catch)] - async fn remove( - this: &$name, - id: String, - ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; + #[wasm_bindgen(typescript_type = $container_name)] + pub type $container_name; + + $( + #[wasm_bindgen(method, getter)] + pub fn $field_name(this: &$container_name) -> Option<$repo_name>; + )+ } - impl $crate::platform::repository::WasmRepository<$ty> for $name { - async fn get( - &self, - id: String, - ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { - self.get(id).await + impl $container_name { + pub fn register_all(self, client: &bitwarden_core::platform::StateClient) { + $( + if let Some(repo) = self.$field_name() { + let repo = repo.into_channel_impl(); + client.register_client_managed(repo); + } + )+ } - async fn list(&self) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { - self.list().await - } - async fn set( - &self, - id: String, - value: $ty, - ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { - self.set(id, value).await + } + + $( + #[wasm_bindgen] + extern "C" { + #[wasm_bindgen] + pub type $repo_name; + + #[wasm_bindgen(method, catch)] + async fn get( + this: &$repo_name, + id: String, + ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; + #[wasm_bindgen(method, catch)] + async fn list(this: &$repo_name) + -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; + #[wasm_bindgen(method, catch)] + async fn set( + this: &$repo_name, + id: String, + value: $qualified_type_name, + ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; + #[wasm_bindgen(method, catch)] + async fn remove( + this: &$repo_name, + id: String, + ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue>; } - async fn remove( - &self, - id: String, - ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { - self.remove(id).await + + impl $crate::platform::repository::WasmRepository<$qualified_type_name> for $repo_name { + async fn get( + &self, + id: String, + ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { + self.get(id).await + } + async fn list(&self) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { + self.list().await + } + async fn set( + &self, + id: String, + value: $qualified_type_name, + ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { + self.set(id, value).await + } + async fn remove( + &self, + id: String, + ) -> Result<::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue> { + self.remove(id).await + } } - } - impl $name { - pub fn into_channel_impl( - self, - ) -> ::std::sync::Arc> { - use $crate::platform::repository::WasmRepositoryChannel; - ::std::sync::Arc::new(WasmRepositoryChannel::new(self)) + impl $repo_name { + pub fn into_channel_impl( + self, + ) -> ::std::sync::Arc> { + use $crate::platform::repository::WasmRepositoryChannel; + ::std::sync::Arc::new(WasmRepositoryChannel::new(self)) + } } - } + )+ }; } -pub(crate) use create_wasm_repository; +pub(crate) use create_wasm_repositories; const UNIT: Result = Ok(JsValue::UNDEFINED);