diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md index 50e0d9db94..bf373ffa41 100644 --- a/bindings/wasm/README.md +++ b/bindings/wasm/README.md @@ -67,7 +67,7 @@ const client = identity.Client.fromConfig(config) // Publish the DID Document to the IOTA Tangle // The message can be viewed at https://explorer.iota.org/<mainnet|devnet>/transaction/<messageId> -client.publishDocument(doc.toJSON()) +client.publishDocument(doc) .then((receipt) => { console.log("Tangle Message Receipt: ", receipt) console.log("Tangle Message Url:", doc.id.network.messageURL(receipt.messageId)) diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index 70ea91936e..4af8471601 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -27,6 +27,8 @@ <dd></dd> <dt><a href="#Network">Network</a></dt> <dd></dd> +<dt><a href="#Receipt">Receipt</a></dt> +<dd></dd> <dt><a href="#Service">Service</a></dt> <dd></dd> <dt><a href="#Timestamp">Timestamp</a></dt> @@ -67,12 +69,12 @@ * [new Client()](#new_Client_new) * _instance_ * [.network()](#Client+network) ⇒ [<code>Network</code>](#Network) - * [.publishDocument(document)](#Client+publishDocument) ⇒ <code>Promise.<any></code> - * [.publishDiff(message_id, diff)](#Client+publishDiff) ⇒ <code>Promise.<any></code> - * [.publishJSON(index, data)](#Client+publishJSON) ⇒ <code>Promise.<any></code> - * [.resolve(did)](#Client+resolve) ⇒ <code>Promise.<any></code> - * [.resolveHistory(did)](#Client+resolveHistory) ⇒ <code>Promise.<any></code> - * [.resolveDiffHistory(document)](#Client+resolveDiffHistory) ⇒ <code>Promise.<any></code> + * [.publishDocument(document)](#Client+publishDocument) ⇒ [<code>Promise.<Receipt></code>](#Receipt) + * [.publishDiff(message_id, diff)](#Client+publishDiff) ⇒ [<code>Promise.<Receipt></code>](#Receipt) + * [.publishJSON(index, data)](#Client+publishJSON) ⇒ [<code>Promise.<Receipt></code>](#Receipt) + * [.resolve(did)](#Client+resolve) ⇒ [<code>Promise.<Document></code>](#Document) + * [.resolveHistory(did)](#Client+resolveHistory) ⇒ [<code>Promise.<DocumentHistory></code>](#DocumentHistory) + * [.resolveDiffHistory(document)](#Client+resolveDiffHistory) ⇒ [<code>Promise.<DiffChainHistory></code>](#DiffChainHistory) * [.checkCredential(data)](#Client+checkCredential) ⇒ <code>Promise.<any></code> * [.checkPresentation(data)](#Client+checkPresentation) ⇒ <code>Promise.<any></code> * _static_ @@ -92,18 +94,18 @@ Returns the `Client` Tangle network. **Kind**: instance method of [<code>Client</code>](#Client) <a name="Client+publishDocument"></a> -### client.publishDocument(document) ⇒ <code>Promise.<any></code> +### client.publishDocument(document) ⇒ [<code>Promise.<Receipt></code>](#Receipt) Publishes an `IotaDocument` to the Tangle. **Kind**: instance method of [<code>Client</code>](#Client) | Param | Type | | --- | --- | -| document | <code>any</code> | +| document | [<code>Document</code>](#Document) | <a name="Client+publishDiff"></a> -### client.publishDiff(message_id, diff) ⇒ <code>Promise.<any></code> +### client.publishDiff(message_id, diff) ⇒ [<code>Promise.<Receipt></code>](#Receipt) Publishes a `DocumentDiff` to the Tangle. **Kind**: instance method of [<code>Client</code>](#Client) @@ -115,7 +117,7 @@ Publishes a `DocumentDiff` to the Tangle. <a name="Client+publishJSON"></a> -### client.publishJSON(index, data) ⇒ <code>Promise.<any></code> +### client.publishJSON(index, data) ⇒ [<code>Promise.<Receipt></code>](#Receipt) Publishes arbitrary JSON data to the specified index on the Tangle. **Kind**: instance method of [<code>Client</code>](#Client) @@ -127,7 +129,7 @@ Publishes arbitrary JSON data to the specified index on the Tangle. <a name="Client+resolve"></a> -### client.resolve(did) ⇒ <code>Promise.<any></code> +### client.resolve(did) ⇒ [<code>Promise.<Document></code>](#Document) **Kind**: instance method of [<code>Client</code>](#Client) | Param | Type | @@ -136,7 +138,7 @@ Publishes arbitrary JSON data to the specified index on the Tangle. <a name="Client+resolveHistory"></a> -### client.resolveHistory(did) ⇒ <code>Promise.<any></code> +### client.resolveHistory(did) ⇒ [<code>Promise.<DocumentHistory></code>](#DocumentHistory) Returns the message history of the given DID. **Kind**: instance method of [<code>Client</code>](#Client) @@ -147,7 +149,7 @@ Returns the message history of the given DID. <a name="Client+resolveDiffHistory"></a> -### client.resolveDiffHistory(document) ⇒ <code>Promise.<any></code> +### client.resolveDiffHistory(document) ⇒ [<code>Promise.<DiffChainHistory></code>](#DiffChainHistory) Returns the `DiffChainHistory` of a diff chain starting from a document on the integration chain. @@ -608,24 +610,24 @@ Parses a `DIDUrl` from the input string. * [DiffChainHistory](#DiffChainHistory) * _instance_ - * [.chainData()](#DiffChainHistory+chainData) ⇒ <code>Array.<any></code> - * [.spam()](#DiffChainHistory+spam) ⇒ <code>Array.<any></code> + * [.chainData()](#DiffChainHistory+chainData) ⇒ [<code>Array.<DocumentDiff></code>](#DocumentDiff) + * [.spam()](#DiffChainHistory+spam) ⇒ <code>Array.<string></code> * [.toJSON()](#DiffChainHistory+toJSON) ⇒ <code>any</code> * _static_ * [.fromJSON(json)](#DiffChainHistory.fromJSON) ⇒ [<code>DiffChainHistory</code>](#DiffChainHistory) <a name="DiffChainHistory+chainData"></a> -### diffChainHistory.chainData() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of the chain objects. +### diffChainHistory.chainData() ⇒ [<code>Array.<DocumentDiff></code>](#DocumentDiff) +Returns an `Array` of the diff chain `DocumentDiffs`. NOTE: this clones the field. **Kind**: instance method of [<code>DiffChainHistory</code>](#DiffChainHistory) <a name="DiffChainHistory+spam"></a> -### diffChainHistory.spam() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of `MessageIds` as strings. +### diffChainHistory.spam() ⇒ <code>Array.<string></code> +Returns an `Array` of `MessageIds` as strings. NOTE: this clones the field. @@ -1161,26 +1163,26 @@ A DID Document's history and current state. * [DocumentHistory](#DocumentHistory) * _instance_ - * [.integrationChainData()](#DocumentHistory+integrationChainData) ⇒ <code>Array.<any></code> - * [.integrationChainSpam()](#DocumentHistory+integrationChainSpam) ⇒ <code>Array.<any></code> - * [.diffChainData()](#DocumentHistory+diffChainData) ⇒ <code>Array.<any></code> - * [.diffChainSpam()](#DocumentHistory+diffChainSpam) ⇒ <code>Array.<any></code> + * [.integrationChainData()](#DocumentHistory+integrationChainData) ⇒ [<code>Array.<Document></code>](#Document) + * [.integrationChainSpam()](#DocumentHistory+integrationChainSpam) ⇒ <code>Array.<string></code> + * [.diffChainData()](#DocumentHistory+diffChainData) ⇒ [<code>Array.<DocumentDiff></code>](#DocumentDiff) + * [.diffChainSpam()](#DocumentHistory+diffChainSpam) ⇒ <code>Array.<string></code> * [.toJSON()](#DocumentHistory+toJSON) ⇒ <code>any</code> * _static_ * [.fromJSON(json)](#DocumentHistory.fromJSON) ⇒ [<code>DocumentHistory</code>](#DocumentHistory) <a name="DocumentHistory+integrationChainData"></a> -### documentHistory.integrationChainData() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of integration chain `Documents`. +### documentHistory.integrationChainData() ⇒ [<code>Array.<Document></code>](#Document) +Returns an `Array` of integration chain `Documents`. NOTE: clones the data. **Kind**: instance method of [<code>DocumentHistory</code>](#DocumentHistory) <a name="DocumentHistory+integrationChainSpam"></a> -### documentHistory.integrationChainSpam() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of message id strings for "spam" messages on the same index +### documentHistory.integrationChainSpam() ⇒ <code>Array.<string></code> +Returns an `Array` of message id strings for "spam" messages on the same index as the integration chain. NOTE: clones the data. @@ -1188,16 +1190,16 @@ NOTE: clones the data. **Kind**: instance method of [<code>DocumentHistory</code>](#DocumentHistory) <a name="DocumentHistory+diffChainData"></a> -### documentHistory.diffChainData() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of diff chain `DocumentDiffs`. +### documentHistory.diffChainData() ⇒ [<code>Array.<DocumentDiff></code>](#DocumentDiff) +Returns an `Array` of diff chain `DocumentDiffs`. NOTE: clones the data. **Kind**: instance method of [<code>DocumentHistory</code>](#DocumentHistory) <a name="DocumentHistory+diffChainSpam"></a> -### documentHistory.diffChainSpam() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of message id strings for "spam" messages on the same index +### documentHistory.diffChainSpam() ⇒ <code>Array.<string></code> +Returns an `Array` of message id strings for "spam" messages on the same index as the diff chain. NOTE: clones the data. @@ -1227,24 +1229,24 @@ Deserializes `DocumentHistory` from a JSON object. * [IntegrationChainHistory](#IntegrationChainHistory) * _instance_ - * [.chainData()](#IntegrationChainHistory+chainData) ⇒ <code>Array.<any></code> - * [.spam()](#IntegrationChainHistory+spam) ⇒ <code>Array.<any></code> + * [.chainData()](#IntegrationChainHistory+chainData) ⇒ [<code>Array.<Document></code>](#Document) + * [.spam()](#IntegrationChainHistory+spam) ⇒ <code>Array.<string></code> * [.toJSON()](#IntegrationChainHistory+toJSON) ⇒ <code>any</code> * _static_ * [.fromJSON(json)](#IntegrationChainHistory.fromJSON) ⇒ [<code>IntegrationChainHistory</code>](#IntegrationChainHistory) <a name="IntegrationChainHistory+chainData"></a> -### integrationChainHistory.chainData() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of the chain objects. +### integrationChainHistory.chainData() ⇒ [<code>Array.<Document></code>](#Document) +Returns an `Array` of the integration chain `Documents`. NOTE: this clones the field. **Kind**: instance method of [<code>IntegrationChainHistory</code>](#IntegrationChainHistory) <a name="IntegrationChainHistory+spam"></a> -### integrationChainHistory.spam() ⇒ <code>Array.<any></code> -Returns a `js_sys::Array` of `MessageIds` as strings. +### integrationChainHistory.spam() ⇒ <code>Array.<string></code> +Returns an `Array` of `MessageIds` as strings. NOTE: this clones the field. @@ -1506,6 +1508,62 @@ Parses the provided string to a `Network`. ### Network.devnet() ⇒ [<code>Network</code>](#Network) **Kind**: static method of [<code>Network</code>](#Network) +<a name="Receipt"></a> + +## Receipt +**Kind**: global class + +* [Receipt](#Receipt) + * _instance_ + * [.network](#Receipt+network) ⇒ [<code>Network</code>](#Network) + * [.messageId](#Receipt+messageId) ⇒ <code>string</code> + * [.networkId](#Receipt+networkId) ⇒ <code>string</code> + * [.nonce](#Receipt+nonce) ⇒ <code>string</code> + * [.toJSON()](#Receipt+toJSON) ⇒ <code>any</code> + * _static_ + * [.fromJSON(json)](#Receipt.fromJSON) ⇒ [<code>Receipt</code>](#Receipt) + +<a name="Receipt+network"></a> + +### receipt.network ⇒ [<code>Network</code>](#Network) +Returns the associated IOTA Tangle `Network`. + +**Kind**: instance property of [<code>Receipt</code>](#Receipt) +<a name="Receipt+messageId"></a> + +### receipt.messageId ⇒ <code>string</code> +Returns the message `id`. + +**Kind**: instance property of [<code>Receipt</code>](#Receipt) +<a name="Receipt+networkId"></a> + +### receipt.networkId ⇒ <code>string</code> +Returns the message `network_id`. + +**Kind**: instance property of [<code>Receipt</code>](#Receipt) +<a name="Receipt+nonce"></a> + +### receipt.nonce ⇒ <code>string</code> +Returns the message `nonce`. + +**Kind**: instance property of [<code>Receipt</code>](#Receipt) +<a name="Receipt+toJSON"></a> + +### receipt.toJSON() ⇒ <code>any</code> +Serializes a `Receipt` as a JSON object. + +**Kind**: instance method of [<code>Receipt</code>](#Receipt) +<a name="Receipt.fromJSON"></a> + +### Receipt.fromJSON(json) ⇒ [<code>Receipt</code>](#Receipt) +Deserializes a `Receipt` from a JSON object. + +**Kind**: static method of [<code>Receipt</code>](#Receipt) + +| Param | Type | +| --- | --- | +| json | <code>any</code> | + <a name="Service"></a> ## Service diff --git a/bindings/wasm/examples/src/create_did.js b/bindings/wasm/examples/src/create_did.js index ef630ccb7b..d2f9556b74 100644 --- a/bindings/wasm/examples/src/create_did.js +++ b/bindings/wasm/examples/src/create_did.js @@ -29,7 +29,7 @@ async function createIdentity(clientConfig) { const client = Client.fromConfig(config); // Publish the Identity to the IOTA Network, this may take a few seconds to complete Proof-of-Work. - const receipt = await client.publishDocument(doc.toJSON()); + const receipt = await client.publishDocument(doc); doc.messageId = receipt.messageId; // Log the results. diff --git a/bindings/wasm/examples/src/manipulate_did.js b/bindings/wasm/examples/src/manipulate_did.js index b23d0606a3..99afbe41ca 100644 --- a/bindings/wasm/examples/src/manipulate_did.js +++ b/bindings/wasm/examples/src/manipulate_did.js @@ -51,7 +51,7 @@ async function manipulateIdentity(clientConfig) { doc.signSelf(key, doc.defaultSigningMethod().id.toString()); // Publish the Identity to the IOTA Network, this may take a few seconds to complete Proof-of-Work. - const updateReceipt = await client.publishDocument(doc.toJSON()); + const updateReceipt = await client.publishDocument(doc); // Log the results. logExplorerUrl("Identity Update:", clientConfig.network.toString(), updateReceipt.messageId); diff --git a/bindings/wasm/examples/src/merkle_key.js b/bindings/wasm/examples/src/merkle_key.js index c863f1d235..5234c9bed9 100644 --- a/bindings/wasm/examples/src/merkle_key.js +++ b/bindings/wasm/examples/src/merkle_key.js @@ -46,7 +46,7 @@ async function merkleKey(clientConfig) { // Publish the Identity to the IOTA Network and log the results. // This may take a few seconds to complete proof-of-work. - const receipt = await client.publishDocument(issuer.doc.toJSON()); + const receipt = await client.publishDocument(issuer.doc); logExplorerUrl("Identity Update:", clientConfig.network.toString(), receipt.messageId); // Prepare a credential subject indicating the degree earned by Alice @@ -84,7 +84,7 @@ async function merkleKey(clientConfig) { issuer.doc.previousMessageId = receipt.messageId; issuer.doc.updated = Timestamp.nowUTC(); issuer.doc.signSelf(issuer.key, issuer.doc.defaultSigningMethod().id.toString()); - const nextReceipt = await client.publishDocument(issuer.doc.toJSON()); + const nextReceipt = await client.publishDocument(issuer.doc); logExplorerUrl("Identity Update:", clientConfig.network.toString(), nextReceipt.messageId); // Check the verifiable credential is revoked diff --git a/bindings/wasm/examples/src/private_tangle.js b/bindings/wasm/examples/src/private_tangle.js index 07f86e7171..ad1d6b1622 100644 --- a/bindings/wasm/examples/src/private_tangle.js +++ b/bindings/wasm/examples/src/private_tangle.js @@ -39,7 +39,7 @@ async function createIdentityPrivateTangle(restURL, networkName) { const client = Client.fromConfig(config); // Publish the Identity to the IOTA Network, this may take a few seconds to complete Proof-of-Work. - const receipt = await client.publishDocument(doc.toJSON()); + const receipt = await client.publishDocument(doc); // Make sure the DID can be resolved on the private tangle const resolved = await client.resolve(doc.id.toString()); diff --git a/bindings/wasm/examples/src/resolve_history.js b/bindings/wasm/examples/src/resolve_history.js index 8e7235b0d3..460ef775f1 100644 --- a/bindings/wasm/examples/src/resolve_history.js +++ b/bindings/wasm/examples/src/resolve_history.js @@ -71,7 +71,7 @@ async function resolveHistory(clientConfig) { // Publish the updated DID Document to the Tangle, updating the integration chain. // This may take a few seconds to complete proof-of-work. - const intReceipt1 = await client.publishDocument(intDoc1.toJSON()); + const intReceipt1 = await client.publishDocument(intDoc1); // Log the results. logExplorerUrl("Int. Chain Update (1):", clientConfig.network.toString(), intReceipt1.messageId); @@ -175,7 +175,7 @@ async function resolveHistory(clientConfig) { intDoc2.previousMessageId = intReceipt1.messageId; intDoc2.updated = Timestamp.nowUTC(); intDoc2.signSelf(key, intDoc2.defaultSigningMethod().id.toString()); - const intReceipt2 = await client.publishDocument(intDoc2.toJSON()); + const intReceipt2 = await client.publishDocument(intDoc2); // Log the results. logExplorerUrl("Int. Chain Update (2):", clientConfig.network.toString(), intReceipt2.messageId); diff --git a/bindings/wasm/examples/src/revoke_vc.js b/bindings/wasm/examples/src/revoke_vc.js index 8c8ea1db1e..3b98b9dbc8 100644 --- a/bindings/wasm/examples/src/revoke_vc.js +++ b/bindings/wasm/examples/src/revoke_vc.js @@ -37,7 +37,7 @@ async function revokeVC(clientConfig) { issuer.doc.updated = Timestamp.nowUTC(); issuer.doc.signSelf(issuer.key, issuer.doc.defaultSigningMethod().id.toString()); // This is an integration chain update, so we publish the full document. - const {messageId} = await client.publishDocument(issuer.doc.toJSON()); + const {messageId} = await client.publishDocument(issuer.doc); // Log the resulting Identity update logExplorerUrl("Issuer Identity Update:", clientConfig.network.toString(), messageId); diff --git a/bindings/wasm/src/chain/document_history.rs b/bindings/wasm/src/chain/document_history.rs index b86d4095cc..5ba8f02777 100644 --- a/bindings/wasm/src/chain/document_history.rs +++ b/bindings/wasm/src/chain/document_history.rs @@ -6,6 +6,7 @@ use identity::iota::DocumentDiff; use identity::iota::DocumentHistory; use identity::iota::IotaDocument; use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; use crate::did::WasmDocument; use crate::did::WasmDocumentDiff; @@ -17,13 +18,35 @@ use crate::error::WasmResult; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct WasmDocumentHistory(DocumentHistory); +// Workaround for Typescript type annotations on async function returns and arrays. +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "Promise<DocumentHistory>")] + pub type PromiseDocumentHistory; + + #[wasm_bindgen(typescript_type = "Promise<IntegrationChainHistory>")] + pub type PromiseIntegrationChainHistory; + + #[wasm_bindgen(typescript_type = "Promise<DiffChainHistory>")] + pub type PromiseDiffChainHistory; + + #[wasm_bindgen(typescript_type = "Array<string>")] + pub type ArrayString; + + #[wasm_bindgen(typescript_type = "Array<Document>")] + pub type ArrayDocument; + + #[wasm_bindgen(typescript_type = "Array<DocumentDiff>")] + pub type ArrayDocumentDiff; +} + #[wasm_bindgen(js_class = DocumentHistory)] impl WasmDocumentHistory { - /// Returns a `js_sys::Array` of integration chain `Documents`. + /// Returns an `Array` of integration chain `Documents`. /// /// NOTE: clones the data. #[wasm_bindgen(js_name = integrationChainData)] - pub fn integration_chain_data(&self) -> js_sys::Array { + pub fn integration_chain_data(&self) -> ArrayDocument { self .0 .integration_chain_data @@ -31,15 +54,16 @@ impl WasmDocumentHistory { .cloned() .map(WasmDocument::from) .map(JsValue::from) - .collect() + .collect::<js_sys::Array>() + .unchecked_into::<ArrayDocument>() } - /// Returns a `js_sys::Array` of message id strings for "spam" messages on the same index + /// Returns an `Array` of message id strings for "spam" messages on the same index /// as the integration chain. /// /// NOTE: clones the data. #[wasm_bindgen(js_name = integrationChainSpam)] - pub fn integration_chain_spam(&self) -> js_sys::Array { + pub fn integration_chain_spam(&self) -> ArrayString { self .0 .integration_chain_spam @@ -47,14 +71,15 @@ impl WasmDocumentHistory { .cloned() .map(|message_id| message_id.to_string()) .map(JsValue::from) - .collect() + .collect::<js_sys::Array>() + .unchecked_into::<ArrayString>() } - /// Returns a `js_sys::Array` of diff chain `DocumentDiffs`. + /// Returns an `Array` of diff chain `DocumentDiffs`. /// /// NOTE: clones the data. #[wasm_bindgen(js_name = diffChainData)] - pub fn diff_chain_data(&self) -> js_sys::Array { + pub fn diff_chain_data(&self) -> ArrayDocumentDiff { self .0 .diff_chain_data @@ -62,15 +87,16 @@ impl WasmDocumentHistory { .cloned() .map(WasmDocumentDiff::from) .map(JsValue::from) - .collect() + .collect::<js_sys::Array>() + .unchecked_into::<ArrayDocumentDiff>() } - /// Returns a `js_sys::Array` of message id strings for "spam" messages on the same index + /// Returns an `Array` of message id strings for "spam" messages on the same index /// as the diff chain. /// /// NOTE: clones the data. #[wasm_bindgen(js_name = diffChainSpam)] - pub fn diff_chain_spam(&self) -> js_sys::Array { + pub fn diff_chain_spam(&self) -> ArrayString { self .0 .diff_chain_spam @@ -78,7 +104,8 @@ impl WasmDocumentHistory { .cloned() .map(|message_id| message_id.to_string()) .map(JsValue::from) - .collect() + .collect::<js_sys::Array>() + .unchecked_into::<ArrayString>() } /// Serializes `DocumentHistory` as a JSON object. @@ -108,30 +135,53 @@ pub struct IntegrationChainHistory(ChainHistory<IotaDocument>); #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DiffChainHistory(ChainHistory<DocumentDiff>); +#[wasm_bindgen] +impl IntegrationChainHistory { + /// Returns an `Array` of the integration chain `Documents`. + /// + /// NOTE: this clones the field. + #[wasm_bindgen(js_name = chainData)] + pub fn chain_data(&self) -> ArrayDocument { + self + .0 + .chain_data + .iter() + .cloned() + .map(WasmDocument::from) + .map(JsValue::from) + .collect::<js_sys::Array>() + .unchecked_into::<ArrayDocument>() + } +} + +#[wasm_bindgen] +impl DiffChainHistory { + /// Returns an `Array` of the diff chain `DocumentDiffs`. + /// + /// NOTE: this clones the field. + #[wasm_bindgen(js_name = chainData)] + pub fn chain_data(&self) -> ArrayDocumentDiff { + self + .0 + .chain_data + .iter() + .cloned() + .map(WasmDocumentDiff::from) + .map(JsValue::from) + .collect::<js_sys::Array>() + .unchecked_into::<ArrayDocumentDiff>() + } +} + macro_rules! impl_wasm_chain_history { ($ident:ident, $ty:ty, $wasm_ty:ty) => { #[wasm_bindgen] impl $ident { - /// Returns a `js_sys::Array` of the chain objects. - /// - /// NOTE: this clones the field. - #[wasm_bindgen(js_name = chainData)] - pub fn chain_data(&self) -> js_sys::Array { - self - .0 - .chain_data - .iter() - .cloned() - .map(<$wasm_ty>::from) - .map(JsValue::from) - .collect() - } - - /// Returns a `js_sys::Array` of `MessageIds` as strings. + /// Returns an `Array` of `MessageIds` as strings. /// /// NOTE: this clones the field. #[wasm_bindgen] - pub fn spam(&self) -> js_sys::Array { + pub fn spam(&self) -> ArrayString { self .0 .spam @@ -139,7 +189,8 @@ macro_rules! impl_wasm_chain_history { .cloned() .map(|message_id| message_id.to_string()) .map(JsValue::from) - .collect() + .collect::<js_sys::Array>() + .unchecked_into::<ArrayString>() } /// Serializes as a JSON object. diff --git a/bindings/wasm/src/chain/mod.rs b/bindings/wasm/src/chain/mod.rs index 3f287468bb..c566b05bb0 100644 --- a/bindings/wasm/src/chain/mod.rs +++ b/bindings/wasm/src/chain/mod.rs @@ -1,8 +1,6 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -pub use document_history::DiffChainHistory; -pub use document_history::IntegrationChainHistory; -pub use document_history::WasmDocumentHistory; +pub use document_history::*; mod document_history; diff --git a/bindings/wasm/src/did/mod.rs b/bindings/wasm/src/did/mod.rs index 255413f5cf..3691801aa3 100644 --- a/bindings/wasm/src/did/mod.rs +++ b/bindings/wasm/src/did/mod.rs @@ -1,14 +1,15 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -mod wasm_did; -mod wasm_did_url; -mod wasm_document; -mod wasm_document_diff; -mod wasm_verification_method; - pub use self::wasm_did::WasmDID; pub use self::wasm_did_url::WasmDIDUrl; +pub use self::wasm_document::PromiseDocument; pub use self::wasm_document::WasmDocument; pub use self::wasm_document_diff::WasmDocumentDiff; pub use self::wasm_verification_method::WasmVerificationMethod; + +mod wasm_did; +mod wasm_did_url; +mod wasm_document; +mod wasm_document_diff; +mod wasm_verification_method; diff --git a/bindings/wasm/src/did/wasm_document.rs b/bindings/wasm/src/did/wasm_document.rs index d4c6eaa2a0..21066f9443 100644 --- a/bindings/wasm/src/did/wasm_document.rs +++ b/bindings/wasm/src/did/wasm_document.rs @@ -39,6 +39,13 @@ use crate::service::Service; #[derive(Clone, Debug, PartialEq)] pub struct WasmDocument(pub(crate) IotaDocument); +// Workaround for Typescript type annotations on async function returns. +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "Promise<Document>")] + pub type PromiseDocument; +} + #[wasm_bindgen(js_class = Document)] impl WasmDocument { /// Creates a new DID Document from the given `KeyPair`, network, and verification method diff --git a/bindings/wasm/src/tangle/client.rs b/bindings/wasm/src/tangle/client.rs index 432591ba41..fefd72b596 100644 --- a/bindings/wasm/src/tangle/client.rs +++ b/bindings/wasm/src/tangle/client.rs @@ -17,16 +17,22 @@ use identity::iota::MessageId; use identity::iota::TangleResolve; use js_sys::Promise; use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; use wasm_bindgen_futures::future_to_promise; use crate::chain::DiffChainHistory; +use crate::chain::PromiseDiffChainHistory; +use crate::chain::PromiseDocumentHistory; use crate::chain::WasmDocumentHistory; +use crate::did::PromiseDocument; use crate::did::WasmDocument; use crate::did::WasmDocumentDiff; use crate::error::Result; use crate::error::WasmResult; use crate::tangle::Config; +use crate::tangle::PromiseReceipt; use crate::tangle::WasmNetwork; +use crate::tangle::WasmReceipt; #[wasm_bindgen] #[derive(Debug)] @@ -74,24 +80,26 @@ impl Client { /// Publishes an `IotaDocument` to the Tangle. #[wasm_bindgen(js_name = publishDocument)] - pub fn publish_document(&self, document: &JsValue) -> Result<Promise> { - let document: IotaDocument = document.into_serde().wasm_result()?; + pub fn publish_document(&self, document: &WasmDocument) -> Result<PromiseReceipt> { + let document: IotaDocument = document.0.clone(); let client: Rc<IotaClient> = self.client.clone(); let promise: Promise = future_to_promise(async move { client .publish_document(&document) .await + .map(WasmReceipt) + .map(Into::into) .wasm_result() - .and_then(|receipt| JsValue::from_serde(&receipt).wasm_result()) }); - Ok(promise) + // WARNING: this does not validate the return type. Check carefully. + Ok(promise.unchecked_into::<PromiseReceipt>()) } /// Publishes a `DocumentDiff` to the Tangle. #[wasm_bindgen(js_name = publishDiff)] - pub fn publish_diff(&self, message_id: &str, diff: WasmDocumentDiff) -> Result<Promise> { + pub fn publish_diff(&self, message_id: &str, diff: WasmDocumentDiff) -> Result<PromiseReceipt> { let message: MessageId = MessageId::from_str(message_id).wasm_result()?; let client: Rc<IotaClient> = self.client.clone(); @@ -99,16 +107,18 @@ impl Client { client .publish_diff(&message, diff.deref()) .await + .map(WasmReceipt) + .map(Into::into) .wasm_result() - .and_then(|receipt| JsValue::from_serde(&receipt).wasm_result()) }); - Ok(promise) + // WARNING: this does not validate the return type. Check carefully. + Ok(promise.unchecked_into::<PromiseReceipt>()) } /// Publishes arbitrary JSON data to the specified index on the Tangle. #[wasm_bindgen(js_name = publishJSON)] - pub fn publish_json(&self, index: &str, data: &JsValue) -> Result<Promise> { + pub fn publish_json(&self, index: &str, data: &JsValue) -> Result<PromiseReceipt> { let client: Rc<IotaClient> = self.client.clone(); let index = index.to_owned(); @@ -117,22 +127,17 @@ impl Client { client .publish_json(&index, &value) .await + .map(WasmReceipt) + .map(Into::into) .wasm_result() - .and_then(|receipt| JsValue::from_serde(&receipt).wasm_result()) }); - Ok(promise) + // WARNING: this does not validate the return type. Check carefully. + Ok(promise.unchecked_into::<PromiseReceipt>()) } #[wasm_bindgen] - pub fn resolve(&self, did: &str) -> Result<Promise> { - #[derive(Serialize)] - pub struct DocWrapper<'a> { - document: &'a IotaDocument, - #[serde(rename = "messageId")] - message_id: &'a MessageId, - } - + pub fn resolve(&self, did: &str) -> Result<PromiseDocument> { let client: Rc<IotaClient> = self.client.clone(); let did: IotaDID = did.parse().wasm_result()?; @@ -141,16 +146,17 @@ impl Client { .resolve(&did) .await .map(WasmDocument::from) - .map(JsValue::from) + .map(Into::into) .wasm_result() }); - Ok(promise) + // WARNING: this does not validate the return type. Check carefully. + Ok(promise.unchecked_into::<PromiseDocument>()) } /// Returns the message history of the given DID. #[wasm_bindgen(js_name = resolveHistory)] - pub fn resolve_history(&self, did: &str) -> Result<Promise> { + pub fn resolve_history(&self, did: &str) -> Result<PromiseDocumentHistory> { let did: IotaDID = did.parse().wasm_result()?; let client: Rc<IotaClient> = self.client.clone(); @@ -159,11 +165,12 @@ impl Client { .resolve_history(&did) .await .map(WasmDocumentHistory::from) - .map(JsValue::from) + .map(Into::into) .wasm_result() }); - Ok(promise) + // WARNING: this does not validate the return type. Check carefully. + Ok(promise.unchecked_into::<PromiseDocumentHistory>()) } /// Returns the `DiffChainHistory` of a diff chain starting from a document on the @@ -172,7 +179,7 @@ impl Client { /// NOTE: the document must have been published to the tangle and have a valid message id and /// capability invocation method. #[wasm_bindgen(js_name = resolveDiffHistory)] - pub fn resolve_diff_history(&self, document: &WasmDocument) -> Result<Promise> { + pub fn resolve_diff_history(&self, document: &WasmDocument) -> Result<PromiseDiffChainHistory> { let client: Rc<IotaClient> = self.client.clone(); let iota_document: IotaDocument = document.0.clone(); @@ -181,11 +188,12 @@ impl Client { .resolve_diff_history(&iota_document) .await .map(DiffChainHistory::from) - .map(JsValue::from) + .map(Into::into) .wasm_result() }); - Ok(promise) + // WARNING: this does not validate the return type. Check carefully. + Ok(promise.unchecked_into::<PromiseDiffChainHistory>()) } /// Validates a credential with the DID Document from the Tangle. diff --git a/bindings/wasm/src/tangle/mod.rs b/bindings/wasm/src/tangle/mod.rs index 4014aeef58..deead3ff35 100644 --- a/bindings/wasm/src/tangle/mod.rs +++ b/bindings/wasm/src/tangle/mod.rs @@ -5,8 +5,10 @@ pub use self::client::*; pub use self::config::*; pub use self::message::*; pub use self::network::*; +pub use self::receipt::*; mod client; mod config; mod message; mod network; +mod receipt; diff --git a/bindings/wasm/src/tangle/network.rs b/bindings/wasm/src/tangle/network.rs index c5fd1928f4..76d7f48efa 100644 --- a/bindings/wasm/src/tangle/network.rs +++ b/bindings/wasm/src/tangle/network.rs @@ -1,7 +1,7 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity::iota::Network as IotaNetwork; +use identity::iota::Network; use wasm_bindgen::prelude::*; use crate::error::Result; @@ -9,24 +9,24 @@ use crate::error::WasmResult; #[wasm_bindgen(js_name = Network)] #[derive(Clone, Debug)] -pub struct WasmNetwork(IotaNetwork); +pub struct WasmNetwork(Network); #[wasm_bindgen(js_class = Network)] impl WasmNetwork { /// Parses the provided string to a `Network`. #[wasm_bindgen] pub fn try_from_name(name: String) -> Result<WasmNetwork> { - IotaNetwork::try_from_name(name).map(Self).wasm_result() + Network::try_from_name(name).map(Self).wasm_result() } #[wasm_bindgen] pub fn mainnet() -> WasmNetwork { - Self(IotaNetwork::Mainnet) + Self(Network::Mainnet) } #[wasm_bindgen] pub fn devnet() -> WasmNetwork { - Self(IotaNetwork::Devnet) + Self(Network::Devnet) } /// Returns the node URL of the Tangle network. @@ -56,18 +56,18 @@ impl WasmNetwork { impl Default for WasmNetwork { fn default() -> Self { - IotaNetwork::default().into() + Network::default().into() } } -impl From<WasmNetwork> for IotaNetwork { +impl From<WasmNetwork> for Network { fn from(other: WasmNetwork) -> Self { other.0 } } -impl From<IotaNetwork> for WasmNetwork { - fn from(other: IotaNetwork) -> Self { +impl From<Network> for WasmNetwork { + fn from(other: Network) -> Self { Self(other) } } diff --git a/bindings/wasm/src/tangle/receipt.rs b/bindings/wasm/src/tangle/receipt.rs new file mode 100644 index 0000000000..0b4efb2c17 --- /dev/null +++ b/bindings/wasm/src/tangle/receipt.rs @@ -0,0 +1,73 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use identity::iota::Receipt; +use wasm_bindgen::prelude::*; + +use crate::error::Result; +use crate::error::WasmResult; +use crate::tangle::WasmNetwork; + +#[wasm_bindgen(js_name = Receipt, inspectable)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct WasmReceipt(pub(crate) Receipt); + +// Workaround for Typescript type annotations on async function returns. +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "Promise<Receipt>")] + pub type PromiseReceipt; +} + +#[wasm_bindgen(js_class = Receipt)] +impl WasmReceipt { + /// Returns the associated IOTA Tangle `Network`. + #[wasm_bindgen(getter)] + pub fn network(&self) -> WasmNetwork { + WasmNetwork::from(self.0.network()) + } + + /// Returns the message `id`. + #[wasm_bindgen(getter = messageId)] + pub fn message_id(&self) -> String { + self.0.message_id().to_string() + } + + /// Returns the message `network_id`. + #[wasm_bindgen(getter = networkId)] + pub fn network_id(&self) -> String { + // NOTE: do not return u64 to avoid BigInt64Array/BigUint64Array compatibility issues. + self.0.network_id().to_string() + } + + /// Returns the message `nonce`. + #[wasm_bindgen(getter)] + pub fn nonce(&self) -> String { + // NOTE: do not return u64 to avoid BigInt64Array/BigUint64Array compatibility issues. + self.0.nonce().to_string() + } + + /// Serializes a `Receipt` as a JSON object. + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result<JsValue> { + JsValue::from_serde(&self.0).wasm_result() + } + + /// Deserializes a `Receipt` from a JSON object. + #[wasm_bindgen(js_name = fromJSON)] + pub fn from_json(json: &JsValue) -> Result<WasmReceipt> { + json.into_serde().map(Self).wasm_result() + } +} + +impl From<Receipt> for WasmReceipt { + fn from(receipt: Receipt) -> Self { + Self(receipt) + } +} + +impl From<WasmReceipt> for Receipt { + fn from(receipt: WasmReceipt) -> Self { + receipt.0 + } +}