From b22b4349e79f2f421e48f6f5ef941d59b9cf8c93 Mon Sep 17 00:00:00 2001 From: 8e8b2c <138928994+8e8b2c@users.noreply.github.com> Date: Mon, 9 Sep 2024 17:16:01 +0100 Subject: [PATCH] feat: self list as publisher (#115) * feat: all publishers links; convert to Uint8Arrays in coordinator results; more concise link validation * chore: add publisher listing to example --- .../src/oracle_document.rs | 37 ++ .../src/link_types.rs | 162 ++----- .../username_registry_validation/src/lib.rs | 2 + .../src/publisher.rs | 35 ++ examples/emissions/co2-sensor/co2-sensor.ts | 26 ++ packages/client/src/utils.ts | 16 +- .../agents_can_list_as_publishers.test.ts | 24 + .../types/scripts/extract-fn-bindings.mjs | 102 +++-- packages/types/src/index.ts | 1 + .../UsernameRegistryIntegrity.ts | 11 +- packages/types/src/utils.ts | 40 ++ .../src/zome-functions/PingCoordinator.ts | 18 +- .../src/zome-functions/RecordsCoordinator.ts | 18 +- .../src/zome-functions/SignerCoordinator.ts | 18 +- .../UsernameRegistryCoordinator.ts | 418 ++++++------------ .../src/zome-functions/VersionCoordinator.ts | 18 +- 16 files changed, 438 insertions(+), 508 deletions(-) create mode 100644 crates/username_registry_validation/src/publisher.rs create mode 100644 packages/tryorama/src/oracle/agents_can_list_as_publishers.test.ts create mode 100644 packages/types/src/utils.ts diff --git a/crates/username_registry_coordinator/src/oracle_document.rs b/crates/username_registry_coordinator/src/oracle_document.rs index 343da96..396f57a 100644 --- a/crates/username_registry_coordinator/src/oracle_document.rs +++ b/crates/username_registry_coordinator/src/oracle_document.rs @@ -1,3 +1,5 @@ +use core::str; + use hdk::prelude::*; use holoom_types::{DocumentRelationTag, OracleDocument}; use username_registry_integrity::{EntryTypes, LinkTypes}; @@ -124,3 +126,38 @@ pub fn get_relation_link_ahs(relation_name: String) -> ExternResult ExternResult { + create_link( + hash_identifier("all_publishers".into())?, + agent_info()?.agent_initial_pubkey, + LinkTypes::Publisher, + tag, + ) +} + +/// Gets a list of `(agent, tag)` pairs representing all globally listed publishers. +/// +/// The `agent` is the publisher, and the `tag` is a `String` intended to indicate the type of +/// content they publish. +#[hdk_extern] +pub fn get_all_publishers(_: ()) -> ExternResult> { + let pairs = get_links( + GetLinksInputBuilder::try_new( + hash_identifier("all_publishers".into())?, + LinkTypes::Publisher, + )? + .build(), + )? + .into_iter() + .filter_map(|link| { + let agent = AgentPubKey::try_from(link.target).ok()?; + let tag = str::from_utf8(&link.tag.into_inner()).ok()?.to_string(); + Some((agent, tag)) + }) + .collect(); + Ok(pairs) +} diff --git a/crates/username_registry_integrity/src/link_types.rs b/crates/username_registry_integrity/src/link_types.rs index efe895f..3aaa48e 100644 --- a/crates/username_registry_integrity/src/link_types.rs +++ b/crates/username_registry_integrity/src/link_types.rs @@ -9,6 +9,7 @@ pub enum LinkTypes { AgentToWalletAttestations, AgentToExternalIdAttestation, ExternalIdToAttestation, + Publisher, NameToOracleDocument, RelateOracleDocumentName, NameToRecipe, @@ -24,72 +25,28 @@ impl LinkTypes { target_address: AnyLinkableHash, tag: LinkTag, ) -> ExternResult { - match self { + let validate_fn = match self { LinkTypes::AgentToUsernameAttestations => { - validate_create_link_agent_to_username_attestations( - action, - base_address, - target_address, - tag, - ) - } - LinkTypes::AgentMetadata => { - validate_create_link_user_metadata(action, base_address, target_address, tag) + validate_create_link_agent_to_username_attestations } + LinkTypes::AgentMetadata => validate_create_link_user_metadata, LinkTypes::AgentToWalletAttestations => { - validate_create_link_agent_to_wallet_attestations( - action, - base_address, - target_address, - tag, - ) + validate_create_link_agent_to_wallet_attestations } LinkTypes::AgentToExternalIdAttestation => { - validate_create_link_agent_to_external_id_attestations( - action, - base_address, - target_address, - tag, - ) - } - LinkTypes::ExternalIdToAttestation => validate_create_link_external_id_to_attestation( - action, - base_address, - target_address, - tag, - ), - LinkTypes::NameToOracleDocument => validate_create_link_name_to_oracle_document( - action, - base_address, - target_address, - tag, - ), - LinkTypes::RelateOracleDocumentName => { - validate_create_link_relate_oracle_document_name( - action, - base_address, - target_address, - tag, - ) - } - LinkTypes::NameToRecipe => { - validate_create_link_name_to_recipe(action, base_address, target_address, tag) + validate_create_link_agent_to_external_id_attestations } - LinkTypes::NameToSigningOffer => validate_create_link_name_to_evm_signing_offer( - action, - base_address, - target_address, - tag, - ), + LinkTypes::ExternalIdToAttestation => validate_create_link_external_id_to_attestation, + LinkTypes::Publisher => validate_create_link_publisher, + LinkTypes::NameToOracleDocument => validate_create_link_name_to_oracle_document, + LinkTypes::RelateOracleDocumentName => validate_create_link_relate_oracle_document_name, + LinkTypes::NameToRecipe => validate_create_link_name_to_recipe, + LinkTypes::NameToSigningOffer => validate_create_link_name_to_evm_signing_offer, LinkTypes::EvmAddressToSigningOffer => { - validate_create_link_evm_address_to_signing_offer( - action, - base_address, - target_address, - tag, - ) + validate_create_link_evm_address_to_signing_offer } - } + }; + validate_fn(action, base_address, target_address, tag) } pub fn validate_delete( @@ -100,88 +57,27 @@ impl LinkTypes { target_address: AnyLinkableHash, tag: LinkTag, ) -> ExternResult { - match self { + let validate_fn = match self { LinkTypes::AgentToUsernameAttestations => { - validate_delete_link_agent_to_username_attestations( - action, - original_action, - base_address, - target_address, - tag, - ) + validate_delete_link_agent_to_username_attestations } - LinkTypes::AgentMetadata => validate_delete_link_user_metadata( - action, - original_action, - base_address, - target_address, - tag, - ), + LinkTypes::AgentMetadata => validate_delete_link_user_metadata, LinkTypes::AgentToWalletAttestations => { - validate_delete_link_agent_to_wallet_attestations( - action, - original_action, - base_address, - target_address, - tag, - ) + validate_delete_link_agent_to_wallet_attestations } LinkTypes::AgentToExternalIdAttestation => { - validate_delete_link_agent_to_external_id_attestations( - action, - original_action, - base_address, - target_address, - tag, - ) + validate_delete_link_agent_to_external_id_attestations } - LinkTypes::ExternalIdToAttestation => validate_delete_link_external_id_to_attestation( - action, - original_action, - base_address, - target_address, - tag, - ), - LinkTypes::NameToOracleDocument => validate_delete_link_name_to_oracle_document( - action, - original_action, - base_address, - target_address, - tag, - ), - LinkTypes::RelateOracleDocumentName => { - validate_delete_link_relate_oracle_document_name( - action, - original_action, - base_address, - target_address, - tag, - ) - } - - LinkTypes::NameToRecipe => validate_delete_link_name_to_recipe( - action, - original_action, - base_address, - target_address, - tag, - ), - LinkTypes::NameToSigningOffer => validate_delete_link_name_to_evm_signing_offer( - action, - original_action, - base_address, - target_address, - tag, - ), + LinkTypes::ExternalIdToAttestation => validate_delete_link_external_id_to_attestation, + LinkTypes::Publisher => validate_delete_link_publisher, + LinkTypes::NameToOracleDocument => validate_delete_link_name_to_oracle_document, + LinkTypes::RelateOracleDocumentName => validate_delete_link_relate_oracle_document_name, + LinkTypes::NameToRecipe => validate_delete_link_name_to_recipe, + LinkTypes::NameToSigningOffer => validate_delete_link_name_to_evm_signing_offer, LinkTypes::EvmAddressToSigningOffer => { - validate_delete_link_evm_address_to_signing_offer( - action, - original_action, - base_address, - target_address, - tag, - ) + validate_delete_link_evm_address_to_signing_offer } - } + }; + validate_fn(action, original_action, base_address, target_address, tag) } } diff --git a/crates/username_registry_validation/src/lib.rs b/crates/username_registry_validation/src/lib.rs index a39669d..e05caca 100644 --- a/crates/username_registry_validation/src/lib.rs +++ b/crates/username_registry_validation/src/lib.rs @@ -32,3 +32,5 @@ pub mod name_to_evm_signing_offer; pub use name_to_evm_signing_offer::*; pub mod evm_address_to_signing_offer; pub use evm_address_to_signing_offer::*; +pub mod publisher; +pub use publisher::*; diff --git a/crates/username_registry_validation/src/publisher.rs b/crates/username_registry_validation/src/publisher.rs new file mode 100644 index 0000000..ffc4e9b --- /dev/null +++ b/crates/username_registry_validation/src/publisher.rs @@ -0,0 +1,35 @@ +use core::str; + +use hdi::prelude::*; + +pub fn validate_create_link_publisher( + action: CreateLink, + _base_address: AnyLinkableHash, + target_address: AnyLinkableHash, + tag: LinkTag, +) -> ExternResult { + if AnyLinkableHash::from(action.author) != target_address { + return Ok(ValidateCallbackResult::Invalid( + "Target of publisher link must author".to_string(), + )); + } + + if str::from_utf8(&tag.into_inner()).is_err() { + return Ok(ValidateCallbackResult::Invalid( + "Tag must be a valid utf-8 string".to_string(), + )); + } + + Ok(ValidateCallbackResult::Valid) +} +pub fn validate_delete_link_publisher( + _action: DeleteLink, + _original_action: CreateLink, + _base: AnyLinkableHash, + _target: AnyLinkableHash, + _tag: LinkTag, +) -> ExternResult { + Ok(ValidateCallbackResult::Invalid(String::from( + "Publisher links cannot be deleted", + ))) +} diff --git a/examples/emissions/co2-sensor/co2-sensor.ts b/examples/emissions/co2-sensor/co2-sensor.ts index 99f4421..3830332 100644 --- a/examples/emissions/co2-sensor/co2-sensor.ts +++ b/examples/emissions/co2-sensor/co2-sensor.ts @@ -6,6 +6,7 @@ import { ensureAndConnectToHapp } from "@holoom/sandbox"; import { UsernameRegistryCoordinator } from "@holoom/types"; +import { AgentPubKey } from "@holochain/client"; async function main() { // Create a conductor sandbox (with holoom installed) at the specified @@ -22,9 +23,34 @@ async function main() { ); const usernameRegistryCoordinator = new UsernameRegistryCoordinator(appWs); + await ensureListedAsPublisher(appWs.myPubKey, usernameRegistryCoordinator); + setInterval(() => publishMeasurement(usernameRegistryCoordinator), 1_000); } +async function ensureListedAsPublisher( + myPubkey: AgentPubKey, + usernameRegistryCoordinator: UsernameRegistryCoordinator +) { + const publishers = await usernameRegistryCoordinator.getAllPublishers(); + for (const [agent] of publishers) { + if (arrEqual(agent, myPubkey)) { + console.log("Already listed as publisher"); + return; + } + } + console.log("Listing self as publisher"); + await usernameRegistryCoordinator.registerAsPublisher("co2-sensor"); +} + +function arrEqual(arr1: Uint8Array, arr2: Uint8Array): boolean { + if (arr1.length !== arr2.length) return false; + for (let i = 0; i < arr1.length; i++) { + if (arr1![i] !== arr2[i]) return false; + } + return true; +} + async function publishMeasurement( usernameRegistryCoordinator: UsernameRegistryCoordinator ) { diff --git a/packages/client/src/utils.ts b/packages/client/src/utils.ts index 5071085..eb1bb73 100644 --- a/packages/client/src/utils.ts +++ b/packages/client/src/utils.ts @@ -1,23 +1,9 @@ import type { Record } from "@holochain/client"; +import { convertBuffersToUint8Arrays } from "@holoom/types"; import { decode } from "@msgpack/msgpack"; import { bytesToHex, Hex, hexToBytes } from "viem"; -function convertBuffersToUint8Arrays(obj: unknown): unknown { - if (Buffer.isBuffer(obj)) { - return new Uint8Array(obj); - } else if (Array.isArray(obj)) { - return obj.map(convertBuffersToUint8Arrays); - } else if (obj !== null && typeof obj === "object") { - for (const key in obj) { - type O = typeof obj; - type K = keyof O; - obj[key as K] = convertBuffersToUint8Arrays(obj[key as K]) as O[K]; - } - } - return obj; -} - export function decodeAppEntry(record: Record): T { if (!("Present" in record.entry)) { throw new Error("Empty Record"); diff --git a/packages/tryorama/src/oracle/agents_can_list_as_publishers.test.ts b/packages/tryorama/src/oracle/agents_can_list_as_publishers.test.ts new file mode 100644 index 0000000..b6b9678 --- /dev/null +++ b/packages/tryorama/src/oracle/agents_can_list_as_publishers.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from "vitest"; +import { dhtSync, runScenario } from "@holochain/tryorama"; + +import { setupPlayer } from "../utils/setup-happ.js"; + +test("Agents can list as publishers", async () => { + await runScenario(async (scenario) => { + const [alice, aliceCoordinators] = await setupPlayer(scenario); + const [bob, bobCoordinators] = await setupPlayer(scenario); + await scenario.shareAllAgents(); + + // Authority creates a external_id Attestation + await expect( + aliceCoordinators.usernameRegistry.registerAsPublisher("some-topic") + ).resolves.not.toThrow(); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Authority gets the external_id Attestation + await expect( + bobCoordinators.usernameRegistry.getAllPublishers() + ).resolves.toEqual([[alice.agentPubKey, "some-topic"]]); + }); +}); diff --git a/packages/types/scripts/extract-fn-bindings.mjs b/packages/types/scripts/extract-fn-bindings.mjs index e82d6f3..e71abde 100644 --- a/packages/types/scripts/extract-fn-bindings.mjs +++ b/packages/types/scripts/extract-fn-bindings.mjs @@ -72,22 +72,13 @@ async function extractFnBindingsForCrate(name, typesTransform) { const methodStrs = bindings.map((binding) => { if (binding.inputType === "void") { return `async ${snakeToCamel(binding.fnName)}(): Promise<${binding.outputType}> { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "${binding.fnName}", - payload: null, - }) - }`; + return this.callZomeFn("${binding.fnName}") + }`; } else { - return `async ${snakeToCamel(binding.fnName)}(payload: ${binding.inputType}): Promise<${binding.outputType}> { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "${binding.fnName}", - payload, - }) - }`; + const inputName = snakeToCamel(binding.inputName); + return `async ${snakeToCamel(binding.fnName)}(${inputName}: ${binding.inputType}): Promise<${binding.outputType}> { + return this.callZomeFn("${binding.fnName}", ${inputName}) + }`; } }); @@ -97,7 +88,10 @@ async function extractFnBindingsForCrate(name, typesTransform) { splitDeps[location].push(name); } - let classFile = `import {${splitDeps.holochain.sort().join(", ")}} from '@holochain/client';\n`; + let classFile = ` + import { callZomeFnHelper } from '../utils'; + import {${splitDeps.holochain.sort().join(", ")}} from '@holochain/client'; + `; if (splitDeps.holoom.length) { classFile += `import {${splitDeps.holoom.sort().join(", ")}} from '../types';\n`; } @@ -109,6 +103,16 @@ async function extractFnBindingsForCrate(name, typesTransform) { private readonly roleName = 'holoom', private readonly zomeName = '${name.replace("_coordinator", "")}', ) {} + + callZomeFn(fnName:string, payload?: unknown) { + return callZomeFnHelper( + this.client, + this.roleName, + this.zomeName, + fnName, + payload, + ); + } ${methodStrs.join("\n\n")} } @@ -142,53 +146,52 @@ class TypeTransform { } transform(rustType) { - const withDelimiters = rustType.replace(/([a-z0-9]+|[^\w])/gi, "$1†"); - const parts = withDelimiters - .split("†") + const tokens = rustType + .split(/(\w+|[^\w])/gi) .map((str) => str.trim()) .filter((str) => !!str); - // console.log("parts", parts, rustType, withDelimiters); - if (parts.length === 0) { + // console.log("tokens", tokens, rustType); + if (tokens.length === 0) { throw Error("Empty rust type"); } - if (parts.length === 1) { + if (tokens.length === 1) { return this.transformShallow(rustType); } // Type is complex - if (parts[0] === "(") { + if (tokens[0] === "(") { // Found a tuple or Unit type - if (parts[parts.length - 1] !== ")") { + if (tokens[tokens.length - 1] !== ")") { throw new Error(`Invalid type ${rustType}`); } - if (parts.length === 2) { + if (tokens.length === 2) { // Rust unit type return { type: "void", deps: new Set() }; } // Found tuple - const { types, deps } = this.transformElemsFromParts(parts.slice(1, -1)); + const { types, deps } = this.transformElemsFromParts(tokens.slice(1, -1)); return { type: `[${types.join(", ")}]`, deps }; } - if (parts[1] === "<") { + if (tokens[1] === "<") { // Found a generic - if (parts[parts.length - 1] !== ">") { + if (tokens[tokens.length - 1] !== ">") { throw new Error(`Invalid type ${rustType}`); } - const { types, deps } = this.transformElemsFromParts(parts.slice(2, -1)); + const { types, deps } = this.transformElemsFromParts(tokens.slice(2, -1)); - if (parts[0] === "Vec") { + if (tokens[0] === "Vec") { if (types.length !== 1) { throw new Error(`Invalid Vec '${rustType}'`); } return { type: `${types[0]}[]`, deps }; - } else if (parts[0] === "Option") { + } else if (tokens[0] === "Option") { if (types.length !== 1) { throw new Error(`Invalid Option '${rustType}'`); } return { type: `(${types[0]}) | null`, deps }; - } else if (parts[0] === "HashMap") { + } else if (tokens[0] === "HashMap") { if (types.length !== 2) { throw new Error(`Invalid HashMap '${rustType}'`); } @@ -201,11 +204,8 @@ class TypeTransform { throw new Error(`Type not determined for '${rustType}'`); } - transformElemsFromParts(parts) { - const rustElems = parts - .join("") - .split(/,\s*?/) - .filter((str) => !!str); // Protects against trailing comma + transformElemsFromParts(tokens) { + const rustElems = flattenTokens(tokens); const tsElems = rustElems.map((elem) => this.transform(elem)); const deps = tsElems.reduce( (acc, elem) => new Set([...elem.deps, ...acc]), @@ -244,4 +244,32 @@ class TypeTransform { } } +// Joins any tokens that are part of an opened scope +function flattenTokens(tokens) { + let openBrackets = 0; + let openArrows = 0; + const parts = []; + let activePart = ""; + for (const token of tokens) { + if (token === "(") { + openBrackets++; + } else if (token === ")") { + openBrackets--; + } else if (token === "<") { + openArrows++; + } else if (token === ">") { + openArrows--; + } + + if (token === "," && openBrackets === 0 && openArrows === 0) { + parts.push(activePart); + activePart = ""; + } else { + activePart += token; + } + } + if (activePart) parts.push(activePart); + return parts; +} + main().catch(console.error); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 94c610c..f76ab5a 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,2 +1,3 @@ export * from "./types"; export * from "./zome-functions"; +export * from "./utils"; diff --git a/packages/types/src/integrity-enums/UsernameRegistryIntegrity.ts b/packages/types/src/integrity-enums/UsernameRegistryIntegrity.ts index 5c4fc8d..0ded43b 100644 --- a/packages/types/src/integrity-enums/UsernameRegistryIntegrity.ts +++ b/packages/types/src/integrity-enums/UsernameRegistryIntegrity.ts @@ -18,9 +18,10 @@ export enum UsernameRegistryIntegrityLinkTypeIndex { AgentToWalletAttestations = 2, AgentToExternalIdAttestation = 3, ExternalIdToAttestation = 4, - NameToOracleDocument = 5, - RelateOracleDocumentName = 6, - NameToRecipe = 7, - NameToSigningOffer = 8, - EvmAddressToSigningOffer = 9, + Publisher = 5, + NameToOracleDocument = 6, + RelateOracleDocumentName = 7, + NameToRecipe = 8, + NameToSigningOffer = 9, + EvmAddressToSigningOffer = 10, } diff --git a/packages/types/src/utils.ts b/packages/types/src/utils.ts new file mode 100644 index 0000000..c82c7de --- /dev/null +++ b/packages/types/src/utils.ts @@ -0,0 +1,40 @@ +import { AppClient } from "@holochain/client"; + +/** + * Recursively traverses an object replacing any node.js `Buffer`s with + * `Uint8Array`s. This is mostly for the benefit of having a consistent + * behaviour when testing in node vs the browser. + * + * @param obj Any input is valid + * @returns The equivalent to the input with all buffers replaced. + */ +export function convertBuffersToUint8Arrays(obj: T): T { + if (Buffer.isBuffer(obj)) { + return new Uint8Array(obj) as T; + } else if (Array.isArray(obj)) { + return obj.map(convertBuffersToUint8Arrays) as T; + } else if (obj !== null && typeof obj === "object") { + for (const key in obj) { + type O = typeof obj; + type K = keyof O; + obj[key as K] = convertBuffersToUint8Arrays(obj[key as K]) as O[K]; + } + } + return obj; +} + +export async function callZomeFnHelper( + client: AppClient, + role_name: string, + zome_name: string, + fn_name: string, + payload: unknown +) { + const result = await client.callZome({ + role_name, + zome_name, + fn_name, + payload, + }); + return convertBuffersToUint8Arrays(result) as any; +} diff --git a/packages/types/src/zome-functions/PingCoordinator.ts b/packages/types/src/zome-functions/PingCoordinator.ts index af9c334..c1a426d 100644 --- a/packages/types/src/zome-functions/PingCoordinator.ts +++ b/packages/types/src/zome-functions/PingCoordinator.ts @@ -1,3 +1,4 @@ +import { callZomeFnHelper } from "../utils"; import { AppClient } from "@holochain/client"; export class PingCoordinator { @@ -7,12 +8,17 @@ export class PingCoordinator { private readonly zomeName = "ping", ) {} + callZomeFn(fnName: string, payload?: unknown) { + return callZomeFnHelper( + this.client, + this.roleName, + this.zomeName, + fnName, + payload, + ); + } + async ping(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "ping", - payload: null, - }); + return this.callZomeFn("ping"); } } diff --git a/packages/types/src/zome-functions/RecordsCoordinator.ts b/packages/types/src/zome-functions/RecordsCoordinator.ts index e8f1f02..75ddddd 100644 --- a/packages/types/src/zome-functions/RecordsCoordinator.ts +++ b/packages/types/src/zome-functions/RecordsCoordinator.ts @@ -1,3 +1,4 @@ +import { callZomeFnHelper } from "../utils"; import { ActionHash, AppClient, Record } from "@holochain/client"; export class RecordsCoordinator { @@ -7,12 +8,17 @@ export class RecordsCoordinator { private readonly zomeName = "records", ) {} - async getRecord(payload: ActionHash): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_record", + callZomeFn(fnName: string, payload?: unknown) { + return callZomeFnHelper( + this.client, + this.roleName, + this.zomeName, + fnName, payload, - }); + ); + } + + async getRecord(actionHash: ActionHash): Promise { + return this.callZomeFn("get_record", actionHash); } } diff --git a/packages/types/src/zome-functions/SignerCoordinator.ts b/packages/types/src/zome-functions/SignerCoordinator.ts index 8427917..e9ea52b 100644 --- a/packages/types/src/zome-functions/SignerCoordinator.ts +++ b/packages/types/src/zome-functions/SignerCoordinator.ts @@ -1,3 +1,4 @@ +import { callZomeFnHelper } from "../utils"; import { AppClient, Signature } from "@holochain/client"; import { SignableBytes } from "../types"; @@ -8,12 +9,17 @@ export class SignerCoordinator { private readonly zomeName = "signer", ) {} - async signMessage(payload: SignableBytes): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "sign_message", + callZomeFn(fnName: string, payload?: unknown) { + return callZomeFnHelper( + this.client, + this.roleName, + this.zomeName, + fnName, payload, - }); + ); + } + + async signMessage(message: SignableBytes): Promise { + return this.callZomeFn("sign_message", message); } } diff --git a/packages/types/src/zome-functions/UsernameRegistryCoordinator.ts b/packages/types/src/zome-functions/UsernameRegistryCoordinator.ts index c54f0af..d12642b 100644 --- a/packages/types/src/zome-functions/UsernameRegistryCoordinator.ts +++ b/packages/types/src/zome-functions/UsernameRegistryCoordinator.ts @@ -1,3 +1,4 @@ +import { callZomeFnHelper } from "../utils"; import { ActionHash, AgentPubKey, AppClient, Record } from "@holochain/client"; import { ChainWalletSignature, @@ -33,446 +34,275 @@ export class UsernameRegistryCoordinator { private readonly zomeName = "username_registry", ) {} - async attestWalletSignature(payload: ChainWalletSignature): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "attest_wallet_signature", + callZomeFn(fnName: string, payload?: unknown) { + return callZomeFnHelper( + this.client, + this.roleName, + this.zomeName, + fnName, payload, - }); + ); + } + + async attestWalletSignature( + chainWalletSignature: ChainWalletSignature, + ): Promise { + return this.callZomeFn("attest_wallet_signature", chainWalletSignature); } async confirmExternalIdRequest( payload: ConfirmExternalIdRequestPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "confirm_external_id_request", - payload, - }); + return this.callZomeFn("confirm_external_id_request", payload); } async createExternalIdAttestation( - payload: ExternalIdAttestation, + attestation: ExternalIdAttestation, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_external_id_attestation", - payload, - }); + return this.callZomeFn("create_external_id_attestation", attestation); } - async createOracleDocument(payload: OracleDocument): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_oracle_document", - payload, - }); + async createOracleDocument(oracleDocument: OracleDocument): Promise { + return this.callZomeFn("create_oracle_document", oracleDocument); } - async createRecipe(payload: Recipe): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_recipe", - payload, - }); + async createRecipe(recipe: Recipe): Promise { + return this.callZomeFn("create_recipe", recipe); } - async createRecipeExecution(payload: RecipeExecution): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_recipe_execution", - payload, - }); + async createRecipeExecution( + recipeExecution: RecipeExecution, + ): Promise { + return this.callZomeFn("create_recipe_execution", recipeExecution); } async createSignedEvmSigningOffer( payload: CreateEvmSigningOfferPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_signed_evm_signing_offer", - payload, - }); + return this.callZomeFn("create_signed_evm_signing_offer", payload); } async createUsernameAttestation( - payload: UsernameAttestation, + usernameAttestation: UsernameAttestation, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_username_attestation", - payload, - }); + return this.callZomeFn("create_username_attestation", usernameAttestation); } - async createWalletAttestation(payload: WalletAttestation): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "create_wallet_attestation", - payload, - }); + async createWalletAttestation( + walletAttestation: WalletAttestation, + ): Promise { + return this.callZomeFn("create_wallet_attestation", walletAttestation); } - async deleteExternalIdAttestation(payload: ActionHash): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "delete_external_id_attestation", - payload, - }); + async deleteExternalIdAttestation( + originalAttestationHash: ActionHash, + ): Promise { + return this.callZomeFn( + "delete_external_id_attestation", + originalAttestationHash, + ); } - async deleteUsernameAttestation(payload: ActionHash): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "delete_username_attestation", - payload, - }); + async deleteUsernameAttestation( + originalUsernameAttestationHash: ActionHash, + ): Promise { + return this.callZomeFn( + "delete_username_attestation", + originalUsernameAttestationHash, + ); } - async doesAgentHaveUsername(payload: AgentPubKey): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "does_agent_have_username", - payload, - }); + async doesAgentHaveUsername(agent: AgentPubKey): Promise { + return this.callZomeFn("does_agent_have_username", agent); } async evmSignatureProviderSetup(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "evm_signature_provider_setup", - payload: null, - }); + return this.callZomeFn("evm_signature_provider_setup"); } async executeRecipe(payload: ExecuteRecipePayload): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "execute_recipe", - payload, - }); + return this.callZomeFn("execute_recipe", payload); } async externalIdAuthoritySetup(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "external_id_authority_setup", - payload: null, - }); + return this.callZomeFn("external_id_authority_setup"); } async getAllAuthoredExternalIdAhs(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_all_authored_external_id_ahs", - payload: null, - }); + return this.callZomeFn("get_all_authored_external_id_ahs"); } async getAllAuthoredUsernameAttestations(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_all_authored_username_attestations", - payload: null, - }); + return this.callZomeFn("get_all_authored_username_attestations"); + } + + async getAllPublishers(): Promise<[AgentPubKey, string][]> { + return this.callZomeFn("get_all_publishers"); } async getAttestationForExternalId( payload: GetAttestationForExternalIdPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_attestation_for_external_id", - payload, - }); + return this.callZomeFn("get_attestation_for_external_id", payload); } - async getEvmWalletBindingMessage(payload: Uint8Array): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_evm_wallet_binding_message", - payload, - }); + async getEvmWalletBindingMessage(evmAddress: Uint8Array): Promise { + return this.callZomeFn("get_evm_wallet_binding_message", evmAddress); } - async getExternalIdAttestation(payload: ActionHash): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_external_id_attestation", - payload, - }); + async getExternalIdAttestation( + externalIdAh: ActionHash, + ): Promise { + return this.callZomeFn("get_external_id_attestation", externalIdAh); } async getExternalIdAttestationsForAgent( payload: GetExternalIdAttestationsForAgentPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_external_id_attestations_for_agent", - payload, - }); + return this.callZomeFn("get_external_id_attestations_for_agent", payload); } async getLatestEvmSigningOfferAhForName( - payload: string, + name: string, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_latest_evm_signing_offer_ah_for_name", - payload, - }); + return this.callZomeFn("get_latest_evm_signing_offer_ah_for_name", name); } - async getMetadata(payload: AgentPubKey): Promise<{ [key: string]: string }> { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_metadata", - payload, - }); + async getMetadata( + agentPubkey: AgentPubKey, + ): Promise<{ [key: string]: string }> { + return this.callZomeFn("get_metadata", agentPubkey); } async getMetadataItemValue( payload: GetMetadataItemValuePayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_metadata_item_value", - payload, - }); + return this.callZomeFn("get_metadata_item_value", payload); } - async getOracleDocumentLinkAhsForName( - payload: string, - ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_oracle_document_link_ahs_for_name", - payload, - }); + async getOracleDocumentLinkAhsForName(name: string): Promise { + return this.callZomeFn("get_oracle_document_link_ahs_for_name", name); } - async getRelatedOracleDocumentNames(payload: string): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_related_oracle_document_names", - payload, - }); + async getRelatedOracleDocumentNames(relationName: string): Promise { + return this.callZomeFn("get_related_oracle_document_names", relationName); } - async getRelationLinkAhs(payload: string): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_relation_link_ahs", - payload, - }); + async getRelationLinkAhs(relationName: string): Promise { + return this.callZomeFn("get_relation_link_ahs", relationName); } async getSigningOfferAhsForEvmAddress( - payload: Uint8Array, + evmAddress: Uint8Array, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_signing_offer_ahs_for_evm_address", - payload, - }); + return this.callZomeFn("get_signing_offer_ahs_for_evm_address", evmAddress); } - async getSolanaWalletBindingMessage(payload: Uint8Array): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_solana_wallet_binding_message", - payload, - }); + async getSolanaWalletBindingMessage( + solanaAddress: Uint8Array, + ): Promise { + return this.callZomeFn("get_solana_wallet_binding_message", solanaAddress); } - async getUsernameAttestation(payload: ActionHash): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_username_attestation", - payload, - }); + async getUsernameAttestation( + usernameAttestationHash: ActionHash, + ): Promise { + return this.callZomeFn("get_username_attestation", usernameAttestationHash); } async getUsernameAttestationForAgent( payload: GetUsernameAttestationForAgentPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_username_attestation_for_agent", - payload, - }); + return this.callZomeFn("get_username_attestation_for_agent", payload); } - async getWalletAttestation(payload: ActionHash): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_wallet_attestation", - payload, - }); + async getWalletAttestation( + walletAttestationHash: ActionHash, + ): Promise { + return this.callZomeFn("get_wallet_attestation", walletAttestationHash); } - async getWalletAttestationsForAgent(payload: AgentPubKey): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "get_wallet_attestations_for_agent", - payload, - }); + async getWalletAttestationsForAgent(agent: AgentPubKey): Promise { + return this.callZomeFn("get_wallet_attestations_for_agent", agent); } async ingestEvmSignatureOverRecipeExecutionRequest( payload: EvmSignatureOverRecipeExecutionRequest, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "ingest_evm_signature_over_recipe_execution_request", + return this.callZomeFn( + "ingest_evm_signature_over_recipe_execution_request", payload, - }); + ); } async ingestExternalIdAttestationRequest( payload: IngestExternalIdAttestationRequestPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "ingest_external_id_attestation_request", - payload, - }); + return this.callZomeFn("ingest_external_id_attestation_request", payload); } - async ingestSignedUsername(payload: SignedUsername): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "ingest_signed_username", - payload, - }); + async ingestSignedUsername(signedUsername: SignedUsername): Promise { + return this.callZomeFn("ingest_signed_username", signedUsername); + } + + async registerAsPublisher(tag: string): Promise { + return this.callZomeFn("register_as_publisher", tag); } async rejectEvmSignatureOverRecipeExecutionRequest( payload: RejectEvmSignatureOverRecipeExecutionRequestPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "reject_evm_signature_over_recipe_execution_request", + return this.callZomeFn( + "reject_evm_signature_over_recipe_execution_request", payload, - }); + ); } async rejectExternalIdRequest( payload: RejectExternalIdRequestPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "reject_external_id_request", - payload, - }); + return this.callZomeFn("reject_external_id_request", payload); } - async relateOracleDocument(payload: DocumentRelationTag): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "relate_oracle_document", - payload, - }); + async relateOracleDocument(relationTag: DocumentRelationTag): Promise { + return this.callZomeFn("relate_oracle_document", relationTag); } async resolveEvmSignatureOverRecipeExecutionRequest( payload: ResolveEvmSignatureOverRecipeExecutionRequestPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "resolve_evm_signature_over_recipe_execution_request", + return this.callZomeFn( + "resolve_evm_signature_over_recipe_execution_request", payload, - }); + ); } async sendExternalIdAttestationRequest( payload: SendExternalIdAttestationRequestPayload, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "send_external_id_attestation_request", - payload, - }); + return this.callZomeFn("send_external_id_attestation_request", payload); } async sendRequestForEvmSignatureOverRecipeExecution( - payload: EvmSignatureOverRecipeExecutionRequest, + request: EvmSignatureOverRecipeExecutionRequest, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "send_request_for_evm_signature_over_recipe_execution", - payload, - }); + return this.callZomeFn( + "send_request_for_evm_signature_over_recipe_execution", + request, + ); } async signUsernameAndRequestAttestation( - payload: SignUsernameAndRequestAttestationInput, + input: SignUsernameAndRequestAttestationInput, ): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "sign_username_and_request_attestation", - payload, - }); + return this.callZomeFn("sign_username_and_request_attestation", input); } async updateMetadataItem(payload: UpdateMetadataItemPayload): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "update_metadata_item", - payload, - }); + return this.callZomeFn("update_metadata_item", payload); } async usernameAuthoritySetup(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "username_authority_setup", - payload: null, - }); + return this.callZomeFn("username_authority_setup"); } } diff --git a/packages/types/src/zome-functions/VersionCoordinator.ts b/packages/types/src/zome-functions/VersionCoordinator.ts index da9a1b6..6c1c545 100644 --- a/packages/types/src/zome-functions/VersionCoordinator.ts +++ b/packages/types/src/zome-functions/VersionCoordinator.ts @@ -1,3 +1,4 @@ +import { callZomeFnHelper } from "../utils"; import { AppClient } from "@holochain/client"; export class VersionCoordinator { @@ -7,12 +8,17 @@ export class VersionCoordinator { private readonly zomeName = "version", ) {} + callZomeFn(fnName: string, payload?: unknown) { + return callZomeFnHelper( + this.client, + this.roleName, + this.zomeName, + fnName, + payload, + ); + } + async gitRev(): Promise { - return this.client.callZome({ - role_name: this.roleName, - zome_name: this.zomeName, - fn_name: "git_rev", - payload: null, - }); + return this.callZomeFn("git_rev"); } }