diff --git a/README.md b/README.md
index 623189bb5b..fd8744ae33 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ See [Supported Features](https://credo.js.org/guides/features) on the Credo webs
- 🏃 **Platform agnostic** - out of the box support for Node.JS and React Native
- 🔒 **DIDComm and AIP** - Support for [DIDComm v1](https://hyperledger.github.io/aries-rfcs/latest/concepts/0005-didcomm/), and both v1 and v2 of the [Aries Interop Profile](https://github.com/hyperledger/aries-rfcs/blob/main/concepts/0302-aries-interop-profile/README.md).
-- 🛂 **Extendable [DID](https://www.w3.org/TR/did-core/) resolver and registrar** - out of the box support for `did:web`, `did:key`, `did:jwk`, `did:peer`, `did:sov`, `did:indy` and `did:cheqd`.
+- 🛂 **Extendable [DID](https://www.w3.org/TR/did-core/) resolver and registrar** - out of the box support for `did:web`, `did:key`, `did:jwk`, `did:peer`, `did:sov`, `did:indy`, `did:cheqd` and `did:hedera`.
- 🔑 **[OpenID4VC](https://openid.net/sg/openid4vc/)** - support for [OpenID for Verifiable Credential Issuance](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html), [OpenID for Verifiable Presentations](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html) and [Self-Issued OpenID Provider v2](https://openid.net/specs/openid-connect-self-issued-v2-1_0.html).
- 🪪 **Multiple credential formats** - [W3C Verifiable Credential Data Model v1.1](https://www.w3.org/TR/vc-data-model/), [SD-JWT VCs](https://www.ietf.org/archive/id/draft-ietf-oauth-sd-jwt-vc-03.html), and [AnonCreds](https://hyperledger.github.io/anoncreds-spec/).
- 🏢 **Multi-tenant** - Optional multi-tenant module for managing multiple tenants under a single agent.
@@ -158,6 +158,14 @@ See [Supported Features](https://credo.js.org/guides/features) on the Credo webs
+
@aries-framework/indy-sdk (deprecated, unmaintained after 0.4.x) |
diff --git a/demo/package.json b/demo/package.json
index 17cc3b3caf..ecb205d9a7 100644
--- a/demo/package.json
+++ b/demo/package.json
@@ -13,19 +13,21 @@
"faber": "ts-node src/FaberInquirer.ts"
},
"dependencies": {
- "@hyperledger/indy-vdr-nodejs": "catalog:",
"@hyperledger/anoncreds-nodejs": "catalog:",
+ "@hyperledger/indy-vdr-nodejs": "catalog:",
"@openwallet-foundation/askar-nodejs": "catalog:",
"inquirer": "^8.2.5"
},
"devDependencies": {
"@credo-ts/anoncreds": "workspace:*",
"@credo-ts/askar": "workspace:*",
+ "@credo-ts/cheqd": "workspace:*",
"@credo-ts/core": "workspace:*",
"@credo-ts/didcomm": "workspace:*",
+ "@credo-ts/hedera": "workspace:*",
"@credo-ts/indy-vdr": "workspace:*",
- "@credo-ts/cheqd": "workspace:*",
"@credo-ts/node": "workspace:*",
+ "@hiero-did-sdk/client": "0.1.3",
"@types/figlet": "^1.5.4",
"@types/inquirer": "^8.2.6",
"clear": "^0.1.0",
diff --git a/demo/src/BaseAgent.ts b/demo/src/BaseAgent.ts
index 0f19b2fadd..837b79722a 100644
--- a/demo/src/BaseAgent.ts
+++ b/demo/src/BaseAgent.ts
@@ -1,7 +1,3 @@
-import type { InitConfig } from '@credo-ts/core'
-import type { DidCommModuleConfigOptions } from '@credo-ts/didcomm'
-import type { IndyVdrPoolConfig } from '@credo-ts/indy-vdr'
-
import {
AnonCredsCredentialFormatService,
AnonCredsModule,
@@ -19,7 +15,9 @@ import {
CheqdModule,
CheqdModuleConfig,
} from '@credo-ts/cheqd'
+import type { InitConfig } from '@credo-ts/core'
import { Agent, DidsModule } from '@credo-ts/core'
+import type { DidCommModuleConfigOptions } from '@credo-ts/didcomm'
import {
AutoAcceptCredential,
AutoAcceptProof,
@@ -31,13 +29,16 @@ import {
V2ProofProtocol,
getDefaultDidcommModules,
} from '@credo-ts/didcomm'
+import type { IndyVdrPoolConfig } from '@credo-ts/indy-vdr'
import { IndyVdrAnonCredsRegistry, IndyVdrIndyDidResolver, IndyVdrModule } from '@credo-ts/indy-vdr'
import { HttpInboundTransport, agentDependencies } from '@credo-ts/node'
+import { HederaNetwork } from '@hiero-did-sdk/client'
import { anoncreds } from '@hyperledger/anoncreds-nodejs'
import { indyVdr } from '@hyperledger/indy-vdr-nodejs'
import { askar } from '@openwallet-foundation/askar-nodejs'
import { AskarModuleConfigStoreOptions } from '@credo-ts/askar'
+import { HederaAnonCredsRegistry, HederaDidRegistrar, HederaDidResolver, HederaModule } from '@credo-ts/hedera'
import { greenText } from './OutputClass'
const bcovrin = `{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"138.197.138.255","client_port":9702,"node_ip":"138.197.138.255","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"}
@@ -121,7 +122,7 @@ function getAskarAnonCredsIndyModules(
],
}),
anoncreds: new AnonCredsModule({
- registries: [new IndyVdrAnonCredsRegistry(), new CheqdAnonCredsRegistry()],
+ registries: [new IndyVdrAnonCredsRegistry(), new CheqdAnonCredsRegistry(), new HederaAnonCredsRegistry()],
anoncreds,
}),
indyVdr: new IndyVdrModule({
@@ -140,12 +141,23 @@ function getAskarAnonCredsIndyModules(
})
),
dids: new DidsModule({
- resolvers: [new IndyVdrIndyDidResolver(), new CheqdDidResolver()],
- registrars: [new CheqdDidRegistrar()],
+ resolvers: [new IndyVdrIndyDidResolver(), new CheqdDidResolver(), new HederaDidResolver()],
+ registrars: [new CheqdDidRegistrar(), new HederaDidRegistrar()],
}),
askar: new AskarModule({
askar,
store: askarStoreConfig,
}),
+ hedera: new HederaModule({
+ networks: [
+ {
+ network: (process.env.HEDERA_NETWORK as HederaNetwork) ?? 'testnet',
+ operatorId: process.env.HEDERA_OPERATOR_ID ?? '0.0.5489553',
+ operatorKey:
+ process.env.HEDERA_OPERATOR_KEY ??
+ '302e020100300506032b6570042204209f54b75b6238ced43e41b1463999cb40bf2f7dd2c9fd4fd3ef780027c016a138',
+ },
+ ],
+ }),
} as const
}
diff --git a/demo/src/Faber.ts b/demo/src/Faber.ts
index b6523610cb..0ea91b03d7 100644
--- a/demo/src/Faber.ts
+++ b/demo/src/Faber.ts
@@ -14,6 +14,7 @@ import { Color, Output, greenText, purpleText, redText } from './OutputClass'
export enum RegistryOptions {
indy = 'did:indy',
cheqd = 'did:cheqd',
+ hedera = 'did:hedera',
}
export class Faber extends BaseAgent {
@@ -38,11 +39,22 @@ export class Faber extends BaseAgent {
// and store the existing did in the wallet
// indy did is based on private key (seed)
const unqualifiedIndyDid = '2jEvRuKmfBJTRa7QowDpNN'
- const cheqdDid = 'did:cheqd:testnet:d37eba59-513d-42d3-8f9f-d1df0548b675'
- const indyDid = `did:indy:${indyNetworkConfig.indyNamespace}:${unqualifiedIndyDid}`
- const didDocumentRelativeKeyId = registry === RegistryOptions.indy ? '#verkey' : '#key-1'
- const did = registry === RegistryOptions.indy ? indyDid : cheqdDid
+ const rootKeyIds: Record = {
+ [RegistryOptions.indy]: '#verkey',
+ [RegistryOptions.cheqd]: '#key-1',
+ [RegistryOptions.hedera]: '#did-root-key',
+ }
+
+ const Dids: Record = {
+ [RegistryOptions.indy]: `did:indy:${indyNetworkConfig.indyNamespace}:${unqualifiedIndyDid}`,
+ [RegistryOptions.cheqd]: 'did:cheqd:testnet:d37eba59-513d-42d3-8f9f-d1df0548b675',
+ [RegistryOptions.hedera]: 'did:hedera:testnet:44eesExqdsUvLZ35FpnBPErqRGRnYbzzyG3wgCCYxkmq_0.0.6231121',
+ }
+
+ const didDocumentRelativeKeyId = rootKeyIds[registry]
+ const did = Dids[registry]
+
const { privateJwk } = transformPrivateKeyToPrivateJwk({
type: {
crv: 'Ed25519',
diff --git a/demo/src/FaberInquirer.ts b/demo/src/FaberInquirer.ts
index 31d9958776..ac5fb6118e 100644
--- a/demo/src/FaberInquirer.ts
+++ b/demo/src/FaberInquirer.ts
@@ -90,7 +90,9 @@ export class FaberInquirer extends BaseInquirer {
}
public async credential() {
- const registry = await prompt([this.inquireOptions([RegistryOptions.indy, RegistryOptions.cheqd])])
+ const registry = await prompt([
+ this.inquireOptions([RegistryOptions.indy, RegistryOptions.cheqd, RegistryOptions.hedera]),
+ ])
await this.faber.importDid(registry.options)
await this.faber.issueCredential()
const title = 'Is the credential offer accepted?'
diff --git a/packages/hedera/CHANGELOG.md b/packages/hedera/CHANGELOG.md
new file mode 100644
index 0000000000..cb65216ef8
--- /dev/null
+++ b/packages/hedera/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+
+## 0.5.13
+
+### Patch Changes
+
+- Added Hedera module
+
diff --git a/packages/hedera/README.md b/packages/hedera/README.md
new file mode 100644
index 0000000000..0f0db816da
--- /dev/null
+++ b/packages/hedera/README.md
@@ -0,0 +1,31 @@
+
+
+
+
+Credo Hedera Module
+
+
+
+
+
+
+
+
+Credo hedera provides integration of the Hedera network into Credo. See the [Hedera Setup](https://credo.js.org/guides/getting-started/set-up/hedera) for installation instructions.
diff --git a/packages/hedera/jest.config.ts b/packages/hedera/jest.config.ts
new file mode 100644
index 0000000000..d91513a189
--- /dev/null
+++ b/packages/hedera/jest.config.ts
@@ -0,0 +1,14 @@
+import type { Config } from '@jest/types'
+
+import base from '../../jest.config.base'
+
+import packageJson from './package.json'
+
+const config: Config.InitialOptions = {
+ ...base,
+ displayName: packageJson.name,
+ setupFilesAfterEnv: ['./tests/setup.ts'],
+ coveragePathIgnorePatterns: ['../tests'],
+}
+
+export default config
diff --git a/packages/hedera/package.json b/packages/hedera/package.json
new file mode 100644
index 0000000000..8532870728
--- /dev/null
+++ b/packages/hedera/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@credo-ts/hedera",
+ "main": "src/index",
+ "types": "src/index",
+ "version": "0.5.13",
+ "files": ["build"],
+ "license": "Apache-2.0",
+ "publishConfig": {
+ "access": "public"
+ },
+ "homepage": "https://github.com/openwallet-foundation/credo-ts/tree/main/packages/hedera",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/openwallet-foundation/credo-ts",
+ "directory": "packages/hedera"
+ },
+ "scripts": {
+ "build": "pnpm run clean && pnpm run compile",
+ "clean": "rimraf ./build",
+ "compile": "tsc -p tsconfig.build.json",
+ "prepublishOnly": "pnpm run build",
+ "test": "jest",
+ "test:coverage": "jest --coverage",
+ "style:check": "biome check --unsafe",
+ "style:fix": "biome check --write --unsafe"
+ },
+ "dependencies": {
+ "@credo-ts/anoncreds": "workspace:*",
+ "@credo-ts/core": "workspace:*",
+ "@hashgraph/sdk": "^2.72.0",
+ "@hiero-did-sdk/anoncreds": "^0.1.3",
+ "@hiero-did-sdk/client": "^0.1.3",
+ "@hiero-did-sdk/core": "^0.1.3",
+ "@hiero-did-sdk/hcs": "^0.1.3",
+ "@hiero-did-sdk/publisher-internal": "^0.1.3",
+ "@hiero-did-sdk/registrar": "^0.1.3",
+ "@hiero-did-sdk/resolver": "^0.1.3"
+ },
+ "devDependencies": {
+ "@credo-ts/node": "workspace:*",
+ "@hyperledger/anoncreds-nodejs": "^0.3.1",
+ "rimraf": "^4.4.0",
+ "zstd-napi": "^0.0.10"
+ }
+}
diff --git a/packages/hedera/src/HederaModule.ts b/packages/hedera/src/HederaModule.ts
new file mode 100644
index 0000000000..c3ce218400
--- /dev/null
+++ b/packages/hedera/src/HederaModule.ts
@@ -0,0 +1,32 @@
+import { DependencyManager, Module } from '@credo-ts/core'
+
+import { AgentConfig, Buffer } from '@credo-ts/core'
+
+import { HederaModuleConfig, HederaModuleConfigOptions } from './HederaModuleConfig'
+import { HederaLedgerService } from './ledger/HederaLedgerService'
+
+export class HederaModule implements Module {
+ public readonly config: HederaModuleConfig
+
+ public constructor(config: HederaModuleConfigOptions) {
+ this.config = new HederaModuleConfig(config)
+ }
+
+ public register(dependencyManager: DependencyManager) {
+ // Warn about experimental module
+ dependencyManager
+ .resolve(AgentConfig)
+ .logger.warn(
+ "The '@credo-ts/hedera' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages."
+ )
+
+ // Register config
+ dependencyManager.registerInstance(HederaModuleConfig, this.config)
+ dependencyManager.registerSingleton(HederaLedgerService)
+
+ // Hedera module needs Buffer to be available globally
+ // If it is not available yet, we overwrite it with the
+ // Buffer implementation from Credo
+ global.Buffer = global.Buffer || Buffer
+ }
+}
diff --git a/packages/hedera/src/HederaModuleConfig.ts b/packages/hedera/src/HederaModuleConfig.ts
new file mode 100644
index 0000000000..4b5aa6fab5
--- /dev/null
+++ b/packages/hedera/src/HederaModuleConfig.ts
@@ -0,0 +1,11 @@
+import { HederaAnoncredsRegistryConfiguration } from '@hiero-did-sdk/anoncreds'
+
+export interface HederaModuleConfigOptions extends HederaAnoncredsRegistryConfiguration {}
+
+export class HederaModuleConfig {
+ public readonly options: HederaModuleConfigOptions
+
+ public constructor(options: HederaModuleConfigOptions) {
+ this.options = options
+ }
+}
diff --git a/packages/hedera/src/anoncreds/HederaAnonCredsRegistry.ts b/packages/hedera/src/anoncreds/HederaAnonCredsRegistry.ts
new file mode 100644
index 0000000000..cff195cfd5
--- /dev/null
+++ b/packages/hedera/src/anoncreds/HederaAnonCredsRegistry.ts
@@ -0,0 +1,239 @@
+import type {
+ AnonCredsRegistry,
+ GetCredentialDefinitionReturn,
+ GetRevocationRegistryDefinitionReturn,
+ GetRevocationStatusListReturn,
+ GetSchemaReturn,
+ RegisterCredentialDefinitionOptions,
+ RegisterCredentialDefinitionReturn,
+ RegisterRevocationRegistryDefinitionOptions,
+ RegisterRevocationRegistryDefinitionReturn,
+ RegisterRevocationStatusListOptions,
+ RegisterRevocationStatusListReturn,
+ RegisterSchemaOptions,
+ RegisterSchemaReturn,
+} from '@credo-ts/anoncreds'
+import type { AgentContext } from '@credo-ts/core'
+import { HederaLedgerService } from '../ledger/HederaLedgerService'
+
+export class HederaAnonCredsRegistry implements AnonCredsRegistry {
+ public readonly methodName = 'hedera'
+ public readonly supportedIdentifier = /^did:hedera:.*$/
+
+ public async registerSchema(
+ agentContext: AgentContext,
+ options: RegisterSchemaOptions
+ ): Promise {
+ try {
+ agentContext.config.logger.trace('Registering schema on Hedera ledger')
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.registerSchema(agentContext, options)
+ } catch (error) {
+ agentContext.config.logger.debug(`Error registering schema for did '${options.schema.issuerId}'`, {
+ error,
+ did: options.schema.issuerId,
+ schema: options,
+ })
+ return {
+ schemaMetadata: {},
+ registrationMetadata: {},
+ schemaState: {
+ state: 'failed',
+ schema: options.schema,
+ reason: `Unable to register schema: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ public async getSchema(agentContext: AgentContext, schemaId: string): Promise {
+ try {
+ agentContext.config.logger.trace(`Resolving schema '${schemaId}' from Hedera ledger`)
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.getSchema(agentContext, schemaId)
+ } catch (error) {
+ agentContext.config.logger.error(`Error retrieving schema '${schemaId}'`, {
+ error,
+ schemaId,
+ })
+ return {
+ schemaId,
+ resolutionMetadata: {
+ error: 'notFound',
+ message: `Unable to resolve schema: ${error.message}`,
+ },
+ schemaMetadata: {},
+ }
+ }
+ }
+
+ public async registerCredentialDefinition(
+ agentContext: AgentContext,
+ options: RegisterCredentialDefinitionOptions
+ ): Promise {
+ try {
+ agentContext.config.logger.trace('Registering credential definition on Hedera ledger')
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.registerCredentialDefinition(agentContext, options)
+ } catch (error) {
+ agentContext.config.logger.error(
+ `Error registering credential definition for did '${options.credentialDefinition.issuerId}'`,
+ {
+ error,
+ did: options.credentialDefinition.issuerId,
+ schema: options,
+ }
+ )
+ return {
+ credentialDefinitionMetadata: {},
+ registrationMetadata: {},
+ credentialDefinitionState: {
+ state: 'failed',
+ credentialDefinition: options.credentialDefinition,
+ reason: `Unable to register credential definition: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ public async getCredentialDefinition(
+ agentContext: AgentContext,
+ credentialDefinitionId: string
+ ): Promise {
+ try {
+ agentContext.config.logger.trace(`Resolving credential definition '${credentialDefinitionId}' from Hedera ledger`)
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.getCredentialDefinition(agentContext, credentialDefinitionId)
+ } catch (error) {
+ agentContext.config.logger.error(`Error retrieving credential definition '${credentialDefinitionId}'`, {
+ error,
+ credentialDefinitionId,
+ })
+ return {
+ credentialDefinitionId,
+ resolutionMetadata: {
+ error: 'notFound',
+ message: `Unable to resolve credential definition: ${error.message}`,
+ },
+ credentialDefinitionMetadata: {},
+ }
+ }
+ }
+
+ public async registerRevocationRegistryDefinition(
+ agentContext: AgentContext,
+ options: RegisterRevocationRegistryDefinitionOptions
+ ): Promise {
+ try {
+ agentContext.config.logger.trace(
+ `Registering revocation registry definition for '${options.revocationRegistryDefinition.credDefId}' on Hedera ledger`
+ )
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.registerRevocationRegistryDefinition(agentContext, options)
+ } catch (error) {
+ agentContext.config.logger.error(
+ `Error registering revocation registry definition for did '${options.revocationRegistryDefinition.issuerId}'`,
+ {
+ error,
+ did: options.revocationRegistryDefinition.issuerId,
+ options,
+ }
+ )
+ return {
+ revocationRegistryDefinitionMetadata: {},
+ registrationMetadata: {},
+ revocationRegistryDefinitionState: {
+ state: 'failed',
+ revocationRegistryDefinition: options.revocationRegistryDefinition,
+ reason: `Unable to register revocation registry definition: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ public async getRevocationRegistryDefinition(
+ agentContext: AgentContext,
+ revocationRegistryDefinitionId: string
+ ): Promise {
+ try {
+ agentContext.config.logger.trace(
+ `Resolving revocation registry definition for '${revocationRegistryDefinitionId}' from Hedera ledger`
+ )
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.getRevocationRegistryDefinition(agentContext, revocationRegistryDefinitionId)
+ } catch (error) {
+ agentContext.config.logger.error(
+ `Error retrieving revocation registry definition '${revocationRegistryDefinitionId}'`,
+ {
+ error,
+ revocationRegistryDefinitionId,
+ }
+ )
+ return {
+ revocationRegistryDefinitionId,
+ resolutionMetadata: {
+ error: 'notFound',
+ message: `Unable to resolve revocation registry definition: ${error.message}`,
+ },
+ revocationRegistryDefinitionMetadata: {},
+ }
+ }
+ }
+
+ public async registerRevocationStatusList(
+ agentContext: AgentContext,
+ options: RegisterRevocationStatusListOptions
+ ): Promise {
+ try {
+ agentContext.config.logger.trace(
+ `Registering revocation status list for '${options.revocationStatusList.revRegDefId}' on Hedera ledger`
+ )
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.registerRevocationStatusList(agentContext, options)
+ } catch (error) {
+ agentContext.config.logger.error(
+ `Error registering revocation status list for did '${options.revocationStatusList.issuerId}'`,
+ {
+ error,
+ did: options.revocationStatusList.issuerId,
+ options,
+ }
+ )
+ return {
+ revocationStatusListMetadata: {},
+ registrationMetadata: {},
+ revocationStatusListState: {
+ state: 'failed',
+ revocationStatusList: options.revocationStatusList,
+ reason: `Unable to register revocation status list: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ public async getRevocationStatusList(
+ agentContext: AgentContext,
+ revocationRegistryId: string,
+ timestamp: number
+ ): Promise {
+ try {
+ agentContext.config.logger.trace(
+ `Resolving revocation status for for '${revocationRegistryId}' from Hedera ledger`
+ )
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ return await ledgerService.getRevocationStatusList(agentContext, revocationRegistryId, timestamp * 1000)
+ } catch (error) {
+ agentContext.config.logger.error(`Error retrieving revocation registry status list '${revocationRegistryId}'`, {
+ error,
+ revocationRegistryId,
+ })
+ return {
+ resolutionMetadata: {
+ error: 'notFound',
+ message: `Unable to resolve revocation registry status list: ${error.message}`,
+ },
+ revocationStatusListMetadata: {},
+ }
+ }
+ }
+}
diff --git a/packages/hedera/src/anoncreds/index.ts b/packages/hedera/src/anoncreds/index.ts
new file mode 100644
index 0000000000..886cabd90b
--- /dev/null
+++ b/packages/hedera/src/anoncreds/index.ts
@@ -0,0 +1 @@
+export { HederaAnonCredsRegistry } from './HederaAnonCredsRegistry'
diff --git a/packages/hedera/src/dids/HederaDidRegistrar.ts b/packages/hedera/src/dids/HederaDidRegistrar.ts
new file mode 100644
index 0000000000..f68a5a234a
--- /dev/null
+++ b/packages/hedera/src/dids/HederaDidRegistrar.ts
@@ -0,0 +1,182 @@
+import {
+ AgentContext,
+ DidCreateResult,
+ DidDeactivateResult,
+ DidDocument,
+ DidDocumentKey,
+ DidDocumentRole,
+ DidDocumentService,
+ DidRecord,
+ DidRegistrar,
+ DidRepository,
+ DidUpdateResult,
+ JsonTransformer,
+} from '@credo-ts/core'
+import {
+ HederaDidCreateOptions,
+ HederaDidDeactivateOptions,
+ HederaDidUpdateOptions,
+ HederaLedgerService,
+} from '../ledger/HederaLedgerService'
+
+export class HederaDidRegistrar implements DidRegistrar {
+ public readonly supportedMethods = ['hedera']
+
+ async create(agentContext: AgentContext, options: HederaDidCreateOptions): Promise {
+ try {
+ const didRepository = agentContext.dependencyManager.resolve(DidRepository)
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+
+ const { did, didDocument, rootKey } = await ledgerService.createDid(agentContext, options)
+
+ const credoDidDocument = new DidDocument({
+ ...didDocument,
+ service: didDocument.service?.map((s) => new DidDocumentService(s)),
+ })
+
+ await didRepository.save(
+ agentContext,
+ new DidRecord({
+ did,
+ role: DidDocumentRole.Created,
+ didDocument: credoDidDocument,
+ keys: [rootKey],
+ })
+ )
+
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'finished',
+ did,
+ didDocument: credoDidDocument,
+ },
+ }
+ } catch (error) {
+ agentContext.config.logger.debug('Error creating DID', {
+ error,
+ })
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'failed',
+ reason: `Unable to register Did: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ async update(agentContext: AgentContext, options: HederaDidUpdateOptions): Promise {
+ const didRepository = agentContext.dependencyManager.resolve(DidRepository)
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+
+ try {
+ const { did } = options
+ const { didDocument, didDocumentMetadata } = await ledgerService.resolveDid(agentContext, did)
+ const didRecord = await didRepository.findCreatedDid(agentContext, did)
+ if (!didDocument || didDocumentMetadata.deactivated || !didRecord) {
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'failed',
+ reason: 'Did not found',
+ },
+ }
+ }
+
+ const keys = this.concatKeys(didRecord.keys, options.secret?.keys)
+ const { didDocument: updatedDidDocument } = await ledgerService.updateDid(agentContext, {
+ ...options,
+ secret: { keys },
+ })
+
+ didRecord.didDocument = JsonTransformer.fromJSON(updatedDidDocument, DidDocument)
+ didRecord.keys = keys
+ await didRepository.update(agentContext, didRecord)
+
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'finished',
+ did,
+ didDocument: didRecord.didDocument,
+ },
+ }
+ } catch (error) {
+ agentContext.config.logger.error('Error updating DID', error)
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'failed',
+ reason: `Unable update DID: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ async deactivate(
+ agentContext: AgentContext,
+ options: Omit
+ ): Promise {
+ const didRepository = agentContext.dependencyManager.resolve(DidRepository)
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+
+ const did = options.did
+
+ try {
+ const { didDocument, didDocumentMetadata } = await ledgerService.resolveDid(agentContext, did)
+
+ const didRecord = await didRepository.findCreatedDid(agentContext, did)
+
+ if (!didDocument || didDocumentMetadata.deactivated || !didRecord) {
+ return {
+ didDocumentMetadata,
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'failed',
+ reason: 'Did not found',
+ },
+ }
+ }
+ const { didDocument: deactivatedDidDocument } = await ledgerService.deactivateDid(agentContext, {
+ ...options,
+ secret: { keys: didRecord.keys },
+ })
+
+ didRecord.didDocument = JsonTransformer.fromJSON(deactivatedDidDocument, DidDocument)
+ await didRepository.update(agentContext, didRecord)
+
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'finished',
+ did,
+ didDocument: didRecord.didDocument,
+ },
+ }
+ } catch (error) {
+ agentContext.config.logger.error('Error deactivating DID', error)
+ return {
+ didDocumentMetadata: {},
+ didRegistrationMetadata: {},
+ didState: {
+ state: 'failed',
+ reason: `Unable deactivating DID: ${error.message}`,
+ },
+ }
+ }
+ }
+
+ private concatKeys(keys1: DidDocumentKey[] = [], keys2: DidDocumentKey[] = []): DidDocumentKey[] {
+ return [
+ ...keys1,
+ ...keys2.filter((k2) => !keys1.some((k1) => k1.didDocumentRelativeKeyId === k2.didDocumentRelativeKeyId)),
+ ]
+ }
+}
diff --git a/packages/hedera/src/dids/HederaDidResolver.ts b/packages/hedera/src/dids/HederaDidResolver.ts
new file mode 100644
index 0000000000..1a0a241bdb
--- /dev/null
+++ b/packages/hedera/src/dids/HederaDidResolver.ts
@@ -0,0 +1,48 @@
+import {
+ type AgentContext,
+ DidDocument,
+ type DidResolutionOptions,
+ type DidResolutionResult,
+ type DidResolver,
+ JsonTransformer,
+ type ParsedDid,
+} from '@credo-ts/core'
+import { HederaLedgerService } from '../ledger/HederaLedgerService'
+
+export class HederaDidResolver implements DidResolver {
+ public readonly supportedMethods = ['hedera']
+ public readonly allowsCaching = true
+ public readonly allowsLocalDidRecord = true
+
+ async resolve(
+ agentContext: AgentContext,
+ did: string,
+ _parsed: ParsedDid,
+ _didResolutionOptions: DidResolutionOptions
+ ): Promise {
+ try {
+ agentContext.config.logger.trace('Try to resolve a did document from ledger')
+ const ledgerService = agentContext.dependencyManager.resolve(HederaLedgerService)
+ const resolveDidResult = await ledgerService.resolveDid(agentContext, did)
+ const didDocument = JsonTransformer.fromJSON(resolveDidResult.didDocument, DidDocument)
+ return {
+ didDocument,
+ didDocumentMetadata: resolveDidResult.didDocumentMetadata,
+ didResolutionMetadata: resolveDidResult.didResolutionMetadata,
+ }
+ } catch (error) {
+ agentContext.config.logger.debug('Error resolving the did', {
+ error,
+ did,
+ })
+ return {
+ didDocument: null,
+ didDocumentMetadata: {},
+ didResolutionMetadata: {
+ error: 'notFound',
+ message: `Unable to resolve did '${did}': ${error}`,
+ },
+ }
+ }
+ }
+}
diff --git a/packages/hedera/src/dids/index.ts b/packages/hedera/src/dids/index.ts
new file mode 100644
index 0000000000..960467c6ea
--- /dev/null
+++ b/packages/hedera/src/dids/index.ts
@@ -0,0 +1,2 @@
+export { HederaDidRegistrar } from './HederaDidRegistrar'
+export { HederaDidResolver } from './HederaDidResolver'
diff --git a/packages/hedera/src/index.ts b/packages/hedera/src/index.ts
new file mode 100644
index 0000000000..47a772c75f
--- /dev/null
+++ b/packages/hedera/src/index.ts
@@ -0,0 +1,4 @@
+export * from './dids'
+export * from './anoncreds'
+export * from './HederaModule'
+export * from './HederaModuleConfig'
diff --git a/packages/hedera/src/ledger/HederaLedgerService.ts b/packages/hedera/src/ledger/HederaLedgerService.ts
new file mode 100644
index 0000000000..eac07c60c3
--- /dev/null
+++ b/packages/hedera/src/ledger/HederaLedgerService.ts
@@ -0,0 +1,537 @@
+import {
+ GetCredentialDefinitionReturn,
+ GetRevocationRegistryDefinitionReturn,
+ GetRevocationStatusListReturn,
+ GetSchemaReturn,
+ RegisterCredentialDefinitionOptions,
+ RegisterCredentialDefinitionReturn,
+ RegisterRevocationRegistryDefinitionOptions,
+ RegisterRevocationRegistryDefinitionReturn,
+ RegisterRevocationStatusListOptions,
+ RegisterRevocationStatusListReturn,
+ RegisterSchemaOptions,
+ RegisterSchemaReturn,
+} from '@credo-ts/anoncreds'
+import {
+ type AgentContext,
+ DidCreateOptions,
+ DidDeactivateOptions,
+ type DidDocument,
+ DidDocumentKey,
+ DidRepository,
+ DidUpdateOptions,
+ Kms,
+ injectable,
+} from '@credo-ts/core'
+import { KeyManagementApi } from '@credo-ts/core/src/modules/kms'
+import { Client, PrivateKey } from '@hashgraph/sdk'
+import { HederaAnoncredsRegistry } from '@hiero-did-sdk/anoncreds'
+import { HederaClientService, HederaNetwork } from '@hiero-did-sdk/client'
+import { DIDResolution, DID_ROOT_KEY_ID, Service, VerificationMethod, parseDID } from '@hiero-did-sdk/core'
+import {
+ CreateDIDResult,
+ DIDUpdateBuilder,
+ DeactivateDIDResult,
+ UpdateDIDResult,
+ generateCreateDIDRequest,
+ generateDeactivateDIDRequest,
+ generateUpdateDIDRequest,
+ submitCreateDIDRequest,
+ submitDeactivateDIDRequest,
+ submitUpdateDIDRequest,
+} from '@hiero-did-sdk/registrar'
+import { TopicReaderHederaHcs, resolveDID } from '@hiero-did-sdk/resolver'
+import { HederaModuleConfig } from '../HederaModuleConfig'
+import { CredoCache } from './cache/CredoCache'
+import { KmsPublisher } from './publisher/KmsPublisher'
+import { createOrGetKey, getMultibasePublicKey } from './utils'
+
+export interface HederaDidCreateOptions extends DidCreateOptions {
+ method: 'hedera'
+ options?: {
+ network?: HederaNetwork | string
+ }
+ secret?: {
+ rootKeyId?: string
+ keys?: DidDocumentKey[]
+ }
+}
+
+export interface HederaCreateDIDResult extends CreateDIDResult {
+ rootKey: DidDocumentKey
+}
+
+export interface HederaDidUpdateOptions extends DidUpdateOptions {
+ secret?: {
+ keys?: DidDocumentKey[]
+ }
+}
+
+export interface HederaDidDeactivateOptions extends DidDeactivateOptions {
+ secret?: {
+ keys?: DidDocumentKey[]
+ }
+}
+
+@injectable()
+export class HederaLedgerService {
+ private readonly clientService: HederaClientService
+
+ public constructor(private readonly config: HederaModuleConfig) {
+ this.clientService = new HederaClientService(config.options)
+ }
+
+ public async resolveDid(agentContext: AgentContext, did: string): Promise {
+ const topicReader = this.getHederaHcsTopicReader(agentContext)
+ return await resolveDID(did, 'application/ld+json;profile="https://w3id.org/did-resolution"', { topicReader })
+ }
+
+ public async createDid(agentContext: AgentContext, props: HederaDidCreateOptions): Promise {
+ const { options, secret, didDocument } = props
+ return this.clientService.withClient({ networkName: options?.network }, async (client: Client) => {
+ const topicReader = this.getHederaHcsTopicReader(agentContext)
+
+ const controller =
+ typeof didDocument?.controller === 'string'
+ ? didDocument?.controller
+ : Array.isArray(didDocument?.controller)
+ ? didDocument?.controller[0]
+ : undefined
+
+ const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
+
+ const { keyId, publicJwk } = await createOrGetKey(kms, secret?.rootKeyId)
+ const rootKey = { kmsKeyId: keyId, didDocumentRelativeKeyId: DID_ROOT_KEY_ID }
+
+ const publisher = await this.getPublisher(agentContext, client, keyId)
+
+ const { state, signingRequest } = await generateCreateDIDRequest(
+ {
+ controller,
+ multibasePublicKey: getMultibasePublicKey(publicJwk),
+ topicReader,
+ },
+ {
+ client,
+ publisher,
+ }
+ )
+
+ const signatureResult = await kms.sign({ keyId, data: signingRequest.serializedPayload, algorithm: 'EdDSA' })
+ const createDidDocumentResult = await submitCreateDIDRequest(
+ { state, signature: signatureResult.signature, topicReader },
+ {
+ client,
+ publisher,
+ }
+ )
+
+ if (didDocument) {
+ const keys = [...(secret?.keys ?? []), ...[rootKey]]
+ const updateDidDocumentResult = await this.updateDid(agentContext, {
+ did: createDidDocumentResult.did,
+ didDocumentOperation: 'setDidDocument',
+ didDocument,
+ options: { ...options },
+ secret: { keys },
+ })
+ return {
+ ...updateDidDocumentResult,
+ rootKey,
+ }
+ }
+
+ return {
+ ...createDidDocumentResult,
+ rootKey,
+ }
+ })
+ }
+
+ public async updateDid(agentContext: AgentContext, props: HederaDidUpdateOptions): Promise {
+ const { did, didDocumentOperation, didDocument, secret } = props
+ const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
+
+ if (!didDocumentOperation) {
+ throw new Error('DidDocumentOperation is required')
+ }
+
+ const rootKey = secret?.keys?.find((key) => key.didDocumentRelativeKeyId === DID_ROOT_KEY_ID)
+ if (!rootKey?.kmsKeyId) {
+ throw new Error('The root key not found in the KMS')
+ }
+
+ this.validateDidUpdateKeys(didDocument, secret?.keys ?? [])
+
+ const { network: networkName } = parseDID(did)
+ return this.clientService.withClient({ networkName }, async (client: Client) => {
+ const topicReader = this.getHederaHcsTopicReader(agentContext)
+
+ const currentDidDocumentResolution = await resolveDID(
+ did,
+ 'application/ld+json;profile="https://w3id.org/did-resolution"',
+ { topicReader }
+ )
+ if (!currentDidDocumentResolution.didDocument) {
+ throw new Error(`DID ${did} not found`)
+ }
+
+ const didUpdates = this.prepareDidUpdates(
+ currentDidDocumentResolution.didDocument,
+ didDocument,
+ didDocumentOperation
+ )
+
+ const publisher = await this.getPublisher(agentContext, client, rootKey.kmsKeyId)
+
+ const { states, signingRequests } = await generateUpdateDIDRequest(
+ {
+ did,
+ updates: didUpdates.build(),
+ topicReader,
+ },
+ {
+ client,
+ publisher,
+ }
+ )
+
+ const signatures = await this.signRequests(signingRequests, kms, rootKey.kmsKeyId)
+ return await submitUpdateDIDRequest(
+ {
+ states,
+ signatures,
+ topicReader,
+ },
+ {
+ client,
+ publisher,
+ }
+ )
+ })
+ }
+
+ public async deactivateDid(
+ agentContext: AgentContext,
+ props: HederaDidDeactivateOptions
+ ): Promise {
+ const { did, secret } = props
+
+ const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
+
+ const rootKey = secret?.keys?.find((key) => key.didDocumentRelativeKeyId === DID_ROOT_KEY_ID)
+ if (!rootKey?.kmsKeyId) {
+ throw new Error('The root key not found in the KMS')
+ }
+
+ const { network: networkName } = parseDID(props.did)
+ return this.clientService.withClient({ networkName }, async (client: Client) => {
+ const topicReader = this.getHederaHcsTopicReader(agentContext)
+
+ const publisher = await this.getPublisher(agentContext, client, rootKey.kmsKeyId)
+
+ const { state, signingRequest } = await generateDeactivateDIDRequest(
+ {
+ did,
+ topicReader,
+ },
+ {
+ client,
+ publisher,
+ }
+ )
+ const signatureResult = await kms.sign({
+ keyId: rootKey.kmsKeyId,
+ data: signingRequest.serializedPayload,
+ algorithm: 'EdDSA',
+ })
+ return await submitDeactivateDIDRequest(
+ {
+ state,
+ signature: signatureResult.signature,
+ topicReader,
+ },
+ {
+ client,
+ publisher,
+ }
+ )
+ })
+ }
+
+ getSchema(agentContext: AgentContext, schemaId: string): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ return registry.getSchema(schemaId)
+ }
+
+ async registerSchema(agentContext: AgentContext, options: RegisterSchemaOptions): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ const issuerPrivateKey = await this.getIssuerPrivateKey(agentContext, options.schema.issuerId)
+ return registry.registerSchema({ ...options, issuerKeyDer: issuerPrivateKey.toStringDer() })
+ }
+
+ getCredentialDefinition(
+ agentContext: AgentContext,
+ credentialDefinitionId: string
+ ): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ return registry.getCredentialDefinition(credentialDefinitionId)
+ }
+
+ async registerCredentialDefinition(
+ agentContext: AgentContext,
+ options: RegisterCredentialDefinitionOptions
+ ): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ const issuerPrivateKey = await this.getIssuerPrivateKey(agentContext, options.credentialDefinition.issuerId)
+ return await registry.registerCredentialDefinition({
+ ...options,
+ issuerKeyDer: issuerPrivateKey.toStringDer(),
+ options: {
+ supportRevocation: !!options.options?.supportRevocation,
+ },
+ })
+ }
+
+ getRevocationRegistryDefinition(
+ agentContext: AgentContext,
+ revocationRegistryDefinitionId: string
+ ): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ return registry.getRevocationRegistryDefinition(revocationRegistryDefinitionId)
+ }
+
+ async registerRevocationRegistryDefinition(
+ agentContext: AgentContext,
+ options: RegisterRevocationRegistryDefinitionOptions
+ ): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ const issuerPrivateKey = await this.getIssuerPrivateKey(agentContext, options.revocationRegistryDefinition.issuerId)
+ return await registry.registerRevocationRegistryDefinition({
+ ...options,
+ issuerKeyDer: issuerPrivateKey.toStringDer(),
+ })
+ }
+
+ getRevocationStatusList(
+ agentContext: AgentContext,
+ revocationRegistryId: string,
+ timestamp: number
+ ): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ return registry.getRevocationStatusList(revocationRegistryId, timestamp)
+ }
+
+ async registerRevocationStatusList(
+ agentContext: AgentContext,
+ options: RegisterRevocationStatusListOptions
+ ): Promise {
+ const registry = this.getHederaAnonCredsRegistry(agentContext)
+ const issuerPrivateKey = await this.getIssuerPrivateKey(agentContext, options.revocationStatusList.issuerId)
+ return await registry.registerRevocationStatusList({
+ ...options,
+ issuerKeyDer: issuerPrivateKey.toStringDer(),
+ })
+ }
+
+ private getHederaHcsTopicReader(agentContext: AgentContext): TopicReaderHederaHcs {
+ const cache = this.config.options.cache ?? new CredoCache(agentContext)
+ return new TopicReaderHederaHcs({ ...this.config.options, cache })
+ }
+
+ private async getPublisher(agentContext: AgentContext, client: Client, keyId: string): Promise {
+ const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
+ const key = await createOrGetKey(kms, keyId)
+ return new KmsPublisher(agentContext, client, key)
+ }
+
+ private getHederaAnonCredsRegistry(agentContext: AgentContext): HederaAnoncredsRegistry {
+ const cache = this.config.options.cache ?? new CredoCache(agentContext)
+ return new HederaAnoncredsRegistry({ ...this.config.options, cache })
+ }
+
+ private getDidDocumentEntryId(item: { id: string } | string): string {
+ const id = typeof item === 'string' ? item : item.id
+ return id.includes('#') ? `#${id.split('#').pop()}` : id
+ }
+
+ private getDidDocumentPropertyDiff(
+ originalEntries: Array = [],
+ updatedEntries: Array = []
+ ) {
+ const originalIds = new Set(originalEntries.map((item) => this.getDidDocumentEntryId(item)))
+ const updatedIds = new Set(updatedEntries.map((item) => this.getDidDocumentEntryId(item)))
+
+ const unchangedEntries = updatedEntries.filter((item) => originalIds.has(this.getDidDocumentEntryId(item)))
+ const newEntries = updatedEntries.filter((item) => !originalIds.has(this.getDidDocumentEntryId(item)))
+ const removedEntries = originalEntries.filter((item) => !updatedIds.has(this.getDidDocumentEntryId(item)))
+
+ return { unchangedEntries, newEntries, removedEntries }
+ }
+
+ private async signRequests(
+ signingRequests: Record,
+ kms: KeyManagementApi,
+ keyId: string
+ ): Promise> {
+ const result: Record = {}
+
+ for (const [key, request] of Object.entries(signingRequests)) {
+ const { signature } = await kms.sign({
+ keyId,
+ data: request.serializedPayload,
+ algorithm: 'EdDSA',
+ })
+ result[key] = signature
+ }
+
+ return result
+ }
+
+ private validateDidUpdateKeys(didDocument: DidDocument | Partial, keys: DidDocumentKey[]) {
+ const verificationRelationships = [
+ 'verificationMethod',
+ 'assertionMethod',
+ 'authentication',
+ 'capabilityDelegation',
+ 'capabilityInvocation',
+ 'keyAgreement',
+ ] as const
+
+ for (const relationship of verificationRelationships) {
+ const entries = didDocument[relationship]
+ if (!entries) continue
+
+ for (const entry of entries) {
+ const id = this.getDidDocumentEntryId(entry)
+ if (!keys.some((key) => key.didDocumentRelativeKeyId === id)) {
+ throw new Error(
+ `Key ${id} is present in updated DID Document, but missing from DID record keys and DID update arguments`
+ )
+ }
+ }
+ }
+ }
+
+ private prepareDidUpdates(
+ originalDocument: DidDocument | Partial,
+ newDocument: DidDocument | Partial,
+ operation: string
+ ): DIDUpdateBuilder {
+ const builder = new DIDUpdateBuilder()
+ const properties = [
+ 'service',
+ 'verificationMethod',
+ 'assertionMethod',
+ 'authentication',
+ 'capabilityDelegation',
+ 'capabilityInvocation',
+ 'keyAgreement',
+ ] as const
+
+ for (const property of properties) {
+ const { unchangedEntries, newEntries, removedEntries } = this.getDidDocumentPropertyDiff(
+ originalDocument[property],
+ newDocument[property]
+ )
+
+ if (operation === 'setDidDocument') {
+ for (const entry of removedEntries) {
+ const entryId = this.getDidDocumentEntryId(entry)
+ if (entryId === DID_ROOT_KEY_ID) continue
+ const builderMethod = this.getUpdateMethod(builder, property, 'remove')
+ builderMethod(entryId)
+ }
+
+ for (const entry of newEntries) {
+ if (this.getDidDocumentEntryId(entry) === DID_ROOT_KEY_ID) continue
+ const builderMethod = this.getUpdateMethod(builder, property, 'add')
+ builderMethod(entry)
+ }
+ }
+
+ if (operation === 'addToDidDocument') {
+ for (const entry of newEntries) {
+ if (this.getDidDocumentEntryId(entry) === DID_ROOT_KEY_ID) continue
+ const builderMethod = this.getUpdateMethod(builder, property, 'add')
+ builderMethod(entry)
+ }
+ }
+
+ if (operation === 'removeFromDidDocument') {
+ for (const entry of unchangedEntries) {
+ const entryId = this.getDidDocumentEntryId(entry)
+ if (entryId === DID_ROOT_KEY_ID) continue
+ const builderMethod = this.getUpdateMethod(builder, property, 'remove')
+ builderMethod(entryId)
+ }
+ }
+ }
+
+ return builder
+ }
+
+ private getUpdateMethod(
+ builder: DIDUpdateBuilder,
+ property: string,
+ action: 'add' | 'remove'
+ // biome-ignore lint/suspicious/noExplicitAny:
+ ): (item: any) => DIDUpdateBuilder {
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const methodMap: Record DIDUpdateBuilder>> = {
+ service: {
+ add: (item: Service) => builder.addService(item),
+ remove: (id: string) => builder.removeService(id),
+ },
+ verificationMethod: {
+ add: (item: VerificationMethod | string) => builder.addVerificationMethod(item),
+ remove: (id: string) => builder.removeVerificationMethod(id),
+ },
+ assertionMethod: {
+ add: (item: VerificationMethod | string) => builder.addAssertionMethod(item),
+ remove: (id: string) => builder.removeAssertionMethod(id),
+ },
+ authentication: {
+ add: (item: VerificationMethod | string) => builder.addAuthenticationMethod(item),
+ remove: (id: string) => builder.removeAuthenticationMethod(id),
+ },
+ capabilityDelegation: {
+ add: (item: VerificationMethod | string) => builder.addCapabilityDelegationMethod(item),
+ remove: (id: string) => builder.removeCapabilityDelegationMethod(id),
+ },
+ capabilityInvocation: {
+ add: (item: VerificationMethod | string) => builder.addCapabilityInvocationMethod(item),
+ remove: (id: string) => builder.removeCapabilityInvocationMethod(id),
+ },
+ keyAgreement: {
+ add: (item: VerificationMethod | string) => builder.addKeyAgreementMethod(item),
+ remove: (id: string) => builder.removeKeyAgreementMethod(id),
+ },
+ }
+
+ const propertyMethods = methodMap[property]
+ if (!propertyMethods) {
+ return () => builder
+ }
+
+ return propertyMethods[action]
+ }
+
+ private async getIssuerPrivateKey(agentContext: AgentContext, issuerId: string): Promise {
+ const didRepository = agentContext.dependencyManager.resolve(DidRepository)
+ const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
+
+ const didRecord = await didRepository.findCreatedDid(agentContext, issuerId)
+ const rootKey = didRecord?.keys?.find((key) => key.didDocumentRelativeKeyId === DID_ROOT_KEY_ID)
+ if (!rootKey?.kmsKeyId) {
+ throw new Error('The root key not found in the KMS')
+ }
+
+ // @ts-ignore
+ const keyManagementService = kms.getKms(agentContext, 'askar')
+ // @ts-ignore
+ const keyInfo = await keyManagementService.getKeyAsserted(agentContext, rootKey.kmsKeyId)
+
+ return PrivateKey.fromBytesED25519(keyInfo.key.secretBytes)
+ }
+}
diff --git a/packages/hedera/src/ledger/cache/CredoCache.ts b/packages/hedera/src/ledger/cache/CredoCache.ts
new file mode 100644
index 0000000000..bd6a2a634e
--- /dev/null
+++ b/packages/hedera/src/ledger/cache/CredoCache.ts
@@ -0,0 +1,34 @@
+import { AgentContext, CacheModuleConfig, CredoError } from '@credo-ts/core'
+import { Cache as CoreCredoCache } from '@credo-ts/core'
+import { Cache } from '@hiero-did-sdk/core'
+
+export class CredoCache implements Cache {
+ private readonly credoCache: CoreCredoCache
+
+ constructor(private readonly agentContext: AgentContext) {
+ this.credoCache = agentContext.dependencyManager.resolve(CacheModuleConfig).cache
+ if (!this.credoCache) {
+ throw new CredoError('Failed to initialize cache: Credo cache instance is not found in dependency manager')
+ }
+ }
+
+ async get(key: string): Promise {
+ return await this.credoCache.get(this.agentContext, key)
+ }
+
+ async set(key: string, value: CacheValue, _expiresInSeconds?: number): Promise {
+ await this.credoCache.set(this.agentContext, key, value)
+ }
+
+ async remove(key: string): Promise {
+ await this.credoCache.remove(this.agentContext, key)
+ }
+
+ async clear(): Promise {
+ // no-op
+ }
+
+ async cleanupExpired(): Promise {
+ // no-op
+ }
+}
diff --git a/packages/hedera/src/ledger/publisher/KmsPublisher.ts b/packages/hedera/src/ledger/publisher/KmsPublisher.ts
new file mode 100644
index 0000000000..9de25caca5
--- /dev/null
+++ b/packages/hedera/src/ledger/publisher/KmsPublisher.ts
@@ -0,0 +1,55 @@
+import { AgentContext, Kms, TypedArrayEncoder } from '@credo-ts/core'
+import { KeyManagementApi, KmsJwkPublicOkp } from '@credo-ts/core/src/modules/kms'
+import { Client, PublicKey, Transaction, TransactionReceipt } from '@hashgraph/sdk'
+import { KeysUtility } from '@hiero-did-sdk/core'
+import { Publisher as ClientPublisher } from '@hiero-did-sdk/publisher-internal'
+import { createOrGetKey } from '../utils'
+
+export class KmsPublisher extends ClientPublisher {
+ private readonly kms: KeyManagementApi
+
+ private keyId: string
+ private submitPublicKey: PublicKey
+
+ constructor(
+ agentContext: AgentContext,
+ client: Client,
+ key: { keyId: string; publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' } }
+ ) {
+ super(client)
+
+ this.kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
+
+ this.keyId = key.keyId
+ this.submitPublicKey = KeysUtility.fromBytes(
+ Uint8Array.from(TypedArrayEncoder.fromBase64(key.publicJwk.x))
+ ).toPublicKey()
+ }
+
+ async setKeyId(keyId: string) {
+ this.keyId = keyId
+
+ const { publicJwk } = await createOrGetKey(this.kms, keyId)
+
+ this.submitPublicKey = KeysUtility.fromBytes(
+ Uint8Array.from(TypedArrayEncoder.fromBase64(publicJwk.x))
+ ).toPublicKey()
+ }
+
+ publicKey(): PublicKey {
+ return this.submitPublicKey
+ }
+
+ async publish(transaction: Transaction): Promise {
+ const frozenTransaction = transaction.freezeWith(this.client)
+
+ await frozenTransaction.signWith(this.submitPublicKey, async (message) => {
+ const signatureResult = await this.kms.sign({ keyId: this.keyId, data: message, algorithm: 'EdDSA' })
+ return signatureResult.signature
+ })
+
+ const response = await transaction.execute(this.client)
+
+ return response.getReceipt(this.client)
+ }
+}
diff --git a/packages/hedera/src/ledger/utils/index.ts b/packages/hedera/src/ledger/utils/index.ts
new file mode 100644
index 0000000000..3d99837ae8
--- /dev/null
+++ b/packages/hedera/src/ledger/utils/index.ts
@@ -0,0 +1,41 @@
+import { Kms, TypedArrayEncoder } from '@credo-ts/core'
+import { KeyManagementApi, KmsJwkPublicOkp } from '@credo-ts/core/src/modules/kms'
+
+export const getMultibasePublicKey = (publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' }): string => {
+ return `z${TypedArrayEncoder.toBase58(Uint8Array.from(TypedArrayEncoder.fromBase64(publicJwk.x)))}`
+}
+
+export const createOrGetKey = async (
+ kms: KeyManagementApi,
+ keyId?: string
+): Promise<{ keyId: string; publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' } }> => {
+ if (!keyId) {
+ const createKeyResult = await kms.createKey({
+ type: {
+ crv: 'Ed25519',
+ kty: 'OKP',
+ },
+ })
+ return {
+ publicJwk: createKeyResult.publicJwk,
+ keyId: createKeyResult.keyId,
+ }
+ }
+
+ const publicJwk = await kms.getPublicKey({ keyId })
+ if (!publicJwk) {
+ throw new Error(`Key with key id '${keyId}' not found`)
+ }
+ if (publicJwk.kty !== 'OKP' || publicJwk.crv !== 'Ed25519') {
+ throw new Error(
+ `Key with key id '${keyId}' uses unsupported ${Kms.getJwkHumanDescription(publicJwk)} for did:hedera`
+ )
+ }
+ return {
+ keyId,
+ publicJwk: {
+ ...publicJwk,
+ crv: publicJwk.crv,
+ },
+ }
+}
diff --git a/packages/hedera/tests/integration/hedera-anoncreds-registry.e2e.test.ts b/packages/hedera/tests/integration/hedera-anoncreds-registry.e2e.test.ts
new file mode 100644
index 0000000000..83d828163a
--- /dev/null
+++ b/packages/hedera/tests/integration/hedera-anoncreds-registry.e2e.test.ts
@@ -0,0 +1,168 @@
+import { Agent, ConsoleLogger, InMemoryLruCache, LogLevel, utils } from '@credo-ts/core'
+import { HederaDidCreateOptions } from '../../src/ledger/HederaLedgerService'
+import { getHederaAgent } from './utils'
+
+describe('Hedera AnonCreds support', () => {
+ let agent: Agent
+ let issuerId: string
+
+ const logger = new ConsoleLogger(LogLevel.fatal)
+ const cache = new InMemoryLruCache({ limit: 10 })
+
+ beforeAll(async () => {
+ agent = getHederaAgent({
+ label: 'alice',
+ logger,
+ cache,
+ })
+ await agent.initialize()
+
+ const didRegistrarResult = await agent.dids.create({
+ method: 'hedera',
+ })
+ if (!didRegistrarResult.didState?.didDocument?.id) throw new Error('DidRegistrarError')
+
+ issuerId = didRegistrarResult.didState.didDocument.id
+ logger.debug('issuerId', [issuerId])
+ })
+
+ beforeEach(() => {
+ cache.clear()
+ })
+
+ afterAll(async () => {
+ // Wait for messages to flush out
+ await new Promise((r) => setTimeout(r, 1000))
+
+ if (agent) {
+ await agent.shutdown()
+ }
+ })
+
+ describe('Hedera Anoncreds Registry', () => {
+ it('should execute the full workflow (register and resolve schema, credential definition, revocation registry definition, revocation status list)', async () => {
+ const schemaResult = await agent.modules.anoncreds.registerSchema({
+ schema: {
+ name: utils.uuid(),
+ version: '1',
+ issuerId: issuerId,
+ attrNames: ['field1'],
+ },
+ options: {},
+ })
+ logger.debug('RegisterSchema', [schemaResult])
+
+ const schemaId = schemaResult?.schemaState?.schemaId
+ expect(schemaId).toBeDefined()
+
+ const credDefResult = await agent.modules.anoncreds.registerCredentialDefinition({
+ credentialDefinition: {
+ tag: 'default',
+ issuerId: issuerId,
+ schemaId: schemaId,
+ },
+ options: {
+ supportRevocation: true,
+ },
+ })
+
+ logger.debug('credDefResult', [credDefResult])
+ expect(credDefResult?.credentialDefinitionState?.state).toEqual('finished')
+
+ const credentialDefinitionId = credDefResult.credentialDefinitionState.credentialDefinitionId ?? ''
+
+ const revRegDefRegResult = await agent.modules.anoncreds.registerRevocationRegistryDefinition({
+ revocationRegistryDefinition: {
+ issuerId: issuerId,
+ credentialDefinitionId,
+ maximumCredentialNumber: 10,
+ tag: 'default',
+ },
+ options: {},
+ })
+ logger.debug('revRegDefRegResult', [revRegDefRegResult])
+ const revocationRegistryDefinitionId =
+ revRegDefRegResult?.revocationRegistryDefinitionState?.revocationRegistryDefinitionId ?? ''
+ expect(revocationRegistryDefinitionId).toBeDefined()
+
+ const resolvedRevRegDef =
+ await agent.modules.anoncreds.getRevocationRegistryDefinition(revocationRegistryDefinitionId)
+ expect(resolvedRevRegDef.revocationRegistryDefinitionId).toEqual(revocationRegistryDefinitionId)
+
+ const registerRevocationStatusListResponse = await agent.modules.anoncreds.registerRevocationStatusList({
+ options: {},
+ revocationStatusList: {
+ issuerId: issuerId,
+ revocationRegistryDefinitionId,
+ },
+ })
+ logger.debug('registerRevocationStatusListResponse', [registerRevocationStatusListResponse])
+ const revocationStatusList = registerRevocationStatusListResponse?.revocationStatusListState.revocationStatusList
+ expect(revocationStatusList).toBeDefined()
+
+ const revocationStatusListResponse = await agent.modules.anoncreds.getRevocationStatusList(
+ revocationRegistryDefinitionId,
+ Date.now() / 1000
+ )
+ logger.debug('revocationStatusListResponse', [revocationStatusListResponse])
+
+ expect(revocationStatusListResponse?.revocationStatusList?.revRegDefId).toEqual(revocationRegistryDefinitionId)
+ expect(revocationStatusListResponse?.revocationStatusList?.issuerId).toEqual(issuerId)
+ expect(revocationStatusListResponse?.revocationStatusList?.revocationList).toEqual([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+
+ // Update revocation status list - Revoke indexes
+ const revokeUpdateRevocationStatusListResponse = await agent.modules.anoncreds.updateRevocationStatusList({
+ options: {},
+ revocationStatusList: {
+ revocationRegistryDefinitionId: revocationRegistryDefinitionId,
+ issuedCredentialIndexes: undefined,
+ revokedCredentialIndexes: [1, 3, 5, 9],
+ },
+ })
+ logger.debug('revokeUpdateRevocationStatusListResponse', [revokeUpdateRevocationStatusListResponse])
+ const revokeRevocationStatusList =
+ revokeUpdateRevocationStatusListResponse?.revocationStatusListState.revocationStatusList
+ expect(revokeRevocationStatusList).toBeDefined()
+
+ const revokeRevocationStatusListResponse = await agent.modules.anoncreds.getRevocationStatusList(
+ revocationRegistryDefinitionId,
+ Date.now() / 1000
+ )
+ logger.debug('revokeRevocationStatusListResponse', [revokeRevocationStatusListResponse])
+ expect(revokeRevocationStatusListResponse?.revocationStatusList?.revRegDefId).toEqual(
+ revocationRegistryDefinitionId
+ )
+ expect(revokeRevocationStatusListResponse?.revocationStatusList?.issuerId).toEqual(issuerId)
+ expect(revokeRevocationStatusListResponse?.revocationStatusList?.revocationList).toEqual([
+ 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
+ ])
+
+ // Update revocation status list - Revoke/Issue indexes
+ const issueUpdateRevocationStatusListResponse = await agent.modules.anoncreds.updateRevocationStatusList({
+ options: {},
+ revocationStatusList: {
+ revocationRegistryDefinitionId: revocationRegistryDefinitionId,
+ issuedCredentialIndexes: [3, 5],
+ revokedCredentialIndexes: [4],
+ },
+ })
+ logger.debug('issueUpdateRevocationStatusListResponse', [issueUpdateRevocationStatusListResponse])
+ const issueRevocationStatusList =
+ issueUpdateRevocationStatusListResponse?.revocationStatusListState.revocationStatusList
+ expect(issueRevocationStatusList).toBeDefined()
+
+ const issueRevocationStatusListResponse = await agent.modules.anoncreds.getRevocationStatusList(
+ revocationRegistryDefinitionId,
+ Date.now() / 1000
+ )
+ logger.debug('issueRevocationStatusListResponse', [issueRevocationStatusListResponse])
+ expect(issueRevocationStatusListResponse?.revocationStatusList?.revRegDefId).toEqual(
+ revocationRegistryDefinitionId
+ )
+ expect(issueRevocationStatusListResponse?.revocationStatusList?.issuerId).toEqual(issuerId)
+ expect(issueRevocationStatusListResponse?.revocationStatusList?.revocationList).toEqual([
+ 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
+ ])
+ })
+ })
+})
diff --git a/packages/hedera/tests/integration/hedera-did-registrar.e2e.test.ts b/packages/hedera/tests/integration/hedera-did-registrar.e2e.test.ts
new file mode 100644
index 0000000000..f6c8b7d2fb
--- /dev/null
+++ b/packages/hedera/tests/integration/hedera-did-registrar.e2e.test.ts
@@ -0,0 +1,368 @@
+import {
+ Agent,
+ ConsoleLogger,
+ DidDocument,
+ DidDocumentKey,
+ DidDocumentService,
+ LogLevel,
+ VerificationMethod,
+} from '@credo-ts/core'
+import { HederaDidCreateOptions, HederaDidUpdateOptions } from '../../src/ledger/HederaLedgerService'
+import { getMultibasePublicKey } from '../../src/ledger/utils'
+import { getHederaAgent } from './utils'
+
+const validDid = 'did:hedera:testnet:44eesExqdsUvLZ35FpnBPErqRGRnYbzzyG3wgCCYxkmq_0.0.6226170'
+
+const validService = new DidDocumentService({
+ id: '#service-1',
+ type: 'CustomType',
+ serviceEndpoint: ['https://rand.io'],
+})
+
+function getValidVerificationMethod(publicKeyMultibase?: string) {
+ return new VerificationMethod({
+ id: '#key-1',
+ type: 'Ed25519VerificationKey2020',
+ controller: validDid,
+ publicKeyMultibase: publicKeyMultibase ?? 'z44eesExqdsUvLZ35FpnBPErqRGRnYbzzyG3wgCCYxkmq',
+ })
+}
+
+function getValidDidDocument(publicKeyMultibase?: string) {
+ return new DidDocument({
+ id: validDid,
+ verificationMethod: [getValidVerificationMethod(publicKeyMultibase)],
+ service: [validService],
+ })
+}
+
+describe('Hedera DID registrar', () => {
+ const logger = new ConsoleLogger(LogLevel.error)
+ let agent: Agent
+
+ beforeAll(async () => {
+ agent = getHederaAgent({
+ logger,
+ label: 'alice',
+ })
+ await agent.initialize()
+ })
+
+ afterAll(async () => {
+ await agent.shutdown()
+ })
+
+ it('should create a did:hedera did document', async () => {
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ options: { network: 'testnet' },
+ })
+
+ expect(didResult).toMatchObject({
+ didState: {
+ state: 'finished',
+ didDocument: {
+ verificationMethod: [
+ {
+ type: 'Ed25519VerificationKey2020',
+ publicKeyMultibase: expect.any(String),
+ },
+ ],
+ },
+ },
+ })
+ })
+
+ it('should create a did:hedera did document with document presets', async () => {
+ const { keyId, publicJwk } = await agent.kms.createKey({
+ type: {
+ crv: 'Ed25519',
+ kty: 'OKP',
+ },
+ })
+ const multibasePublicKey = getMultibasePublicKey(publicJwk)
+ const keys: DidDocumentKey[] = [
+ {
+ kmsKeyId: keyId,
+ didDocumentRelativeKeyId: '#key-1',
+ },
+ ]
+
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ didDocument: getValidDidDocument(multibasePublicKey),
+ options: { network: 'testnet' },
+ secret: { keys },
+ })
+ expect(didResult.didState.state).toEqual('finished')
+
+ const verificationMethod = getValidVerificationMethod(multibasePublicKey)
+ expect(didResult.didState.didDocument?.verificationMethod).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ id: expect.stringContaining('#did-root-key'),
+ type: expect.any(String),
+ controller: didResult.didState.didDocument?.id,
+ publicKeyMultibase: expect.any(String),
+ }),
+ expect.objectContaining({
+ id: expect.stringContaining(verificationMethod.id),
+ type: verificationMethod.type,
+ controller: verificationMethod.controller,
+ publicKeyMultibase: verificationMethod.publicKeyMultibase,
+ }),
+ ])
+ )
+
+ expect(didResult.didState.didDocument?.service).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ id: expect.stringContaining(validService.id),
+ type: validService.type,
+ serviceEndpoint: validService.serviceEndpoint,
+ }),
+ ])
+ )
+ })
+
+ it('should create a did:hedera did document, add and remove service', async () => {
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ options: {
+ network: 'testnet',
+ },
+ })
+ expect(didResult).toMatchObject({ didState: { state: 'finished' } })
+
+ const did = didResult.didState.did ?? ''
+ const didDocument = didResult.didState.didDocument as DidDocument
+ didDocument.service = [validService]
+
+ const addUpdateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+
+ expect(addUpdateResult.didState.state).toEqual('finished')
+ expect(addUpdateResult.didState.didDocument?.id).toEqual(did)
+
+ const resolvedDocument = await agent.dids.resolve(did, {
+ useLocalCreatedDidRecord: false,
+ })
+ expect(resolvedDocument.didDocument?.id).toEqual(did)
+
+ expect(resolvedDocument.didDocument?.service).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ id: expect.stringContaining(validService.id),
+ type: validService.type,
+ serviceEndpoint: validService.serviceEndpoint,
+ }),
+ ])
+ )
+
+ const removeUpdateResult = await agent.dids.update({
+ did,
+ didDocument: {
+ ...didDocument,
+ verificationMethod: undefined,
+ },
+ didDocumentOperation: 'removeFromDidDocument',
+ })
+
+ expect(removeUpdateResult.didState.state).toEqual('finished')
+ expect(removeUpdateResult.didState.didDocument?.id).toEqual(did)
+
+ const removeResolvedDocument = await agent.dids.resolve(did, {
+ useLocalCreatedDidRecord: false,
+ })
+ expect(removeResolvedDocument.didDocument?.id).toEqual(did)
+ expect(removeResolvedDocument.didDocument?.service ?? []).toHaveLength(0)
+ })
+
+ it('should create a did:hedera did document, add and remove verification method', async () => {
+ const { keyId, publicJwk } = await agent.kms.createKey({
+ type: {
+ crv: 'Ed25519',
+ kty: 'OKP',
+ },
+ })
+ const multibasePublicKey = getMultibasePublicKey(publicJwk)
+ const keys: DidDocumentKey[] = [
+ {
+ kmsKeyId: keyId,
+ didDocumentRelativeKeyId: '#key-1',
+ },
+ ]
+
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ options: { network: 'testnet' },
+ })
+ expect(didResult).toMatchObject({ didState: { state: 'finished' } })
+
+ const did = didResult.didState.did ?? ''
+ const didDocument = didResult.didState.didDocument as DidDocument
+
+ const validVerificationMethod = getValidVerificationMethod(multibasePublicKey)
+ didDocument.verificationMethod = [validVerificationMethod]
+
+ const addUpdateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ secret: {
+ keys,
+ },
+ })
+ expect(addUpdateResult.didState.didDocument?.id).toEqual(did)
+ expect(addUpdateResult.didState.state).toEqual('finished')
+
+ const addResolvedDocument = await agent.dids.resolve(did, {
+ useLocalCreatedDidRecord: false,
+ })
+
+ expect(addResolvedDocument.didDocument?.id).toEqual(did)
+ expect(addResolvedDocument.didDocument?.verificationMethod).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ id: expect.stringContaining(validVerificationMethod.id),
+ type: validVerificationMethod.type,
+ controller: validVerificationMethod.controller,
+ publicKeyMultibase: validVerificationMethod.publicKeyMultibase,
+ }),
+ ])
+ )
+
+ const removeUpdateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'removeFromDidDocument',
+ secret: {
+ keys,
+ },
+ })
+ expect(removeUpdateResult.didState.didDocument?.id).toEqual(did)
+ expect(removeUpdateResult.didState.state).toEqual('finished')
+
+ const removeResolvedDocument = await agent.dids.resolve(did, {
+ useLocalCreatedDidRecord: false,
+ })
+
+ expect(removeResolvedDocument.didDocument?.id).toEqual(did)
+ expect(removeResolvedDocument.didDocument?.service ?? []).toHaveLength(0)
+ })
+
+ it('should create a did:hedera did document, but should not add verification method without required keys', async () => {
+ const { publicJwk } = await agent.kms.createKey({
+ type: {
+ crv: 'Ed25519',
+ kty: 'OKP',
+ },
+ })
+ const multibasePublicKey = getMultibasePublicKey(publicJwk)
+
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ options: { network: 'testnet' },
+ })
+ expect(didResult).toMatchObject({ didState: { state: 'finished' } })
+
+ const did = didResult.didState.did ?? ''
+ const didDocument = didResult.didState.didDocument as DidDocument
+
+ const validVerificationMethod = getValidVerificationMethod(multibasePublicKey)
+ didDocument.verificationMethod = [validVerificationMethod]
+
+ const expectedFailureReason =
+ 'Unable update DID: Key #key-1 is present in updated DID Document, but missing from DID record keys and DID update arguments'
+
+ let updateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+ expect(updateResult.didState.state).toEqual('failed')
+ if (updateResult.didState.state === 'failed') expect(updateResult.didState.reason).toEqual(expectedFailureReason)
+
+ didDocument.verificationMethod = undefined
+ didDocument.assertionMethod = [validVerificationMethod]
+
+ updateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+ expect(updateResult.didState.state).toEqual('failed')
+ if (updateResult.didState.state === 'failed') expect(updateResult.didState.reason).toEqual(expectedFailureReason)
+
+ didDocument.assertionMethod = undefined
+ didDocument.authentication = [validVerificationMethod]
+
+ updateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+ expect(updateResult.didState.state).toEqual('failed')
+ if (updateResult.didState.state === 'failed') expect(updateResult.didState.reason).toEqual(expectedFailureReason)
+
+ didDocument.authentication = undefined
+ didDocument.capabilityDelegation = [validVerificationMethod]
+
+ updateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+ expect(updateResult.didState.state).toEqual('failed')
+ if (updateResult.didState.state === 'failed') expect(updateResult.didState.reason).toEqual(expectedFailureReason)
+
+ didDocument.capabilityDelegation = undefined
+ didDocument.capabilityInvocation = [validVerificationMethod]
+
+ updateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+ expect(updateResult.didState.state).toEqual('failed')
+ if (updateResult.didState.state === 'failed') expect(updateResult.didState.reason).toEqual(expectedFailureReason)
+
+ didDocument.capabilityInvocation = undefined
+ didDocument.keyAgreement = [validVerificationMethod]
+
+ updateResult = await agent.dids.update({
+ did,
+ didDocument,
+ didDocumentOperation: 'addToDidDocument',
+ })
+ expect(updateResult.didState.state).toEqual('failed')
+ if (updateResult.didState.state === 'failed') expect(updateResult.didState.reason).toEqual(expectedFailureReason)
+ })
+
+ it('should create and deactivate a did:hedera did', async () => {
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ options: {
+ network: 'testnet',
+ },
+ })
+ expect(didResult).toMatchObject({ didState: { state: 'finished' } })
+
+ const did = didResult.didState.did ?? ''
+
+ const deactivateResult = await agent.dids.deactivate({
+ did,
+ })
+
+ expect(deactivateResult.didState.didDocument?.id).toEqual(did)
+ expect(deactivateResult.didState.state).toEqual('finished')
+
+ const resolvedDocument = await agent.dids.resolve(did, {
+ useLocalCreatedDidRecord: false,
+ })
+ expect(resolvedDocument.didDocumentMetadata.deactivated).toBe(true)
+ })
+})
diff --git a/packages/hedera/tests/integration/hedera-did-resolver.e2e.test.ts b/packages/hedera/tests/integration/hedera-did-resolver.e2e.test.ts
new file mode 100644
index 0000000000..cac437d51a
--- /dev/null
+++ b/packages/hedera/tests/integration/hedera-did-resolver.e2e.test.ts
@@ -0,0 +1,52 @@
+import { Agent, ConsoleLogger, JsonTransformer, LogLevel } from '@credo-ts/core'
+import { HederaDidCreateOptions } from '../../src/ledger/HederaLedgerService'
+import { getHederaAgent } from './utils'
+
+describe('Hedera DID resolver', () => {
+ const logger = new ConsoleLogger(LogLevel.error)
+
+ let agent: Agent
+ let did: string
+
+ beforeAll(async () => {
+ agent = getHederaAgent({
+ logger,
+ label: 'alice',
+ })
+ await agent.initialize()
+
+ const didResult = await agent.dids.create({
+ method: 'hedera',
+ })
+ if (!didResult.didState.did) {
+ throw new Error('No DID created')
+ }
+ did = didResult.didState.did
+ })
+
+ afterAll(async () => {
+ await agent.shutdown()
+ })
+
+ it('should resolve a did:hedera did from testnet', async () => {
+ const resolveResult = await agent.dids.resolve(did)
+
+ expect(JsonTransformer.toJSON(resolveResult)).toMatchObject({
+ didDocument: {
+ '@context': ['https://www.w3.org/ns/did/v1'],
+ id: did,
+ controller: did,
+ verificationMethod: [
+ {
+ controller: did,
+ id: `${did}#did-root-key`,
+ type: 'Ed25519VerificationKey2020',
+ publicKeyMultibase: expect.any(String),
+ },
+ ],
+ },
+ didDocumentMetadata: {},
+ didResolutionMetadata: {},
+ })
+ })
+})
diff --git a/packages/hedera/tests/integration/utils/hederaModule.ts b/packages/hedera/tests/integration/utils/hederaModule.ts
new file mode 100644
index 0000000000..833c6bb2ea
--- /dev/null
+++ b/packages/hedera/tests/integration/utils/hederaModule.ts
@@ -0,0 +1,69 @@
+import { AnonCredsModule } from '@credo-ts/anoncreds'
+import { AskarModule } from '@credo-ts/askar'
+import { Agent, Cache, CacheModule, DidsModule, Logger, ModulesMap, utils } from '@credo-ts/core'
+import {
+ HederaAnonCredsRegistry,
+ HederaDidRegistrar,
+ HederaDidResolver,
+ HederaModule,
+ HederaModuleConfigOptions,
+} from '@credo-ts/hedera'
+import { agentDependencies } from '@credo-ts/node'
+import { HederaNetwork } from '@hiero-did-sdk/client'
+import { anoncreds } from '@hyperledger/anoncreds-nodejs'
+import { askar } from '@openwallet-foundation/askar-nodejs'
+import { InMemoryTailsFileService } from '../../../../anoncreds/tests/InMemoryTailsFileService'
+
+export const getHederaModuleConfig = (props: {
+ network?: HederaNetwork
+ operatorId?: string
+ operatorKey?: string
+}): HederaModuleConfigOptions => {
+ return {
+ networks: [
+ {
+ network: props.network ?? (process.env.HEDERA_NETWORK as HederaNetwork) ?? 'testnet',
+ operatorId: props.operatorId ?? process.env.HEDERA_OPERATOR_ID ?? '0.0.5489553',
+ operatorKey:
+ props.operatorKey ??
+ process.env.HEDERA_OPERATOR_KEY ??
+ '302e020100300506032b6570042204209f54b75b6238ced43e41b1463999cb40bf2f7dd2c9fd4fd3ef780027c016a138',
+ },
+ ],
+ }
+}
+
+export const getHederaAgent = (props: {
+ operatorId?: string
+ operatorKey?: string
+ label?: string
+ logger?: Logger
+ cache?: Cache
+}) => {
+ const label = props.label ?? utils.uuid()
+ const logger = props.logger
+ const cache = props.cache
+
+ let modules: ModulesMap = {
+ askar: new AskarModule({ askar, store: { id: label, key: label } }),
+ anoncreds: new AnonCredsModule({
+ anoncreds,
+ registries: [new HederaAnonCredsRegistry()],
+ tailsFileService: new InMemoryTailsFileService(),
+ }),
+ dids: new DidsModule({
+ resolvers: [new HederaDidResolver()],
+ registrars: [new HederaDidRegistrar()],
+ }),
+ hedera: new HederaModule(getHederaModuleConfig(props)),
+ }
+ if (cache) {
+ modules = { ...modules, cache: new CacheModule({ cache }) }
+ }
+
+ return new Agent({
+ config: { label, logger },
+ dependencies: agentDependencies,
+ modules,
+ })
+}
diff --git a/packages/hedera/tests/integration/utils/index.ts b/packages/hedera/tests/integration/utils/index.ts
new file mode 100644
index 0000000000..bb406f518b
--- /dev/null
+++ b/packages/hedera/tests/integration/utils/index.ts
@@ -0,0 +1 @@
+export * from './hederaModule'
diff --git a/packages/hedera/tests/setup.ts b/packages/hedera/tests/setup.ts
new file mode 100644
index 0000000000..cc76304a17
--- /dev/null
+++ b/packages/hedera/tests/setup.ts
@@ -0,0 +1 @@
+jest.setTimeout(100000)
diff --git a/packages/hedera/tests/unit/credo-cache.test.ts b/packages/hedera/tests/unit/credo-cache.test.ts
new file mode 100644
index 0000000000..b9927933ad
--- /dev/null
+++ b/packages/hedera/tests/unit/credo-cache.test.ts
@@ -0,0 +1,100 @@
+import { AgentContext, CacheModuleConfig, CredoError } from '@credo-ts/core'
+import { Cache as CoreCredoCache } from '@credo-ts/core'
+import { CredoCache } from '../../src/ledger/cache/CredoCache'
+
+describe('CredoCache', () => {
+ let mockAgentContext: AgentContext
+ let mockDependencyManagerResolve: jest.Mock
+ let mockCredoCache: jest.Mocked
+
+ beforeEach(() => {
+ mockCredoCache = {
+ get: jest.fn(),
+ set: jest.fn(),
+ remove: jest.fn(),
+ }
+
+ mockDependencyManagerResolve = jest.fn().mockReturnValue({ cache: mockCredoCache })
+
+ mockAgentContext = {
+ dependencyManager: {
+ resolve: mockDependencyManagerResolve,
+ },
+ } as unknown as AgentContext
+ })
+
+ it('should throw CredoError if cache not found in constructor', () => {
+ mockDependencyManagerResolve.mockReturnValue({ cache: null })
+
+ expect(() => new CredoCache(mockAgentContext)).toThrowError(CredoError)
+ })
+
+ it('should initialize credoCache from dependency manager', () => {
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ expect(mockDependencyManagerResolve).toHaveBeenCalledWith(CacheModuleConfig)
+ // @ts-ignore
+ expect(credoCacheInstance.credoCache).toBe(mockCredoCache)
+ })
+
+ describe('get', () => {
+ it('should call credoCache.get with correct parameters and return value', async () => {
+ const testKey = 'test-key'
+ const returnedValue = { foo: 'bar' }
+ mockCredoCache.get.mockResolvedValue(returnedValue)
+
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ const result = await credoCacheInstance.get(testKey)
+
+ expect(mockCredoCache.get).toHaveBeenCalledWith(mockAgentContext, testKey)
+ expect(result).toBe(returnedValue)
+ })
+
+ it('should return null if credoCache.get resolves null', async () => {
+ mockCredoCache.get.mockResolvedValue(null)
+
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ const result = await credoCacheInstance.get('missing')
+
+ expect(result).toBeNull()
+ })
+ })
+
+ describe('set', () => {
+ it('should call credoCache.set with correct parameters', async () => {
+ const key = 'key'
+ const value = { a: 1 }
+ mockCredoCache.set.mockResolvedValue(undefined)
+
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ await credoCacheInstance.set(key, value, 123)
+
+ expect(mockCredoCache.set).toHaveBeenCalledWith(mockAgentContext, key, value)
+ })
+ })
+
+ describe('remove', () => {
+ it('should call credoCache.remove with correct parameters', async () => {
+ const key = 'keyToRemove'
+ mockCredoCache.remove.mockResolvedValue(undefined)
+
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ await credoCacheInstance.remove(key)
+
+ expect(mockCredoCache.remove).toHaveBeenCalledWith(mockAgentContext, key)
+ })
+ })
+
+ describe('clear', () => {
+ it('should throw error when called', async () => {
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ await expect(credoCacheInstance.clear()).resolves.not.toThrow()
+ })
+ })
+
+ describe('cleanupExpired', () => {
+ it('should throw error when called', async () => {
+ const credoCacheInstance = new CredoCache(mockAgentContext)
+ await expect(credoCacheInstance.cleanupExpired()).resolves.not.toThrow()
+ })
+ })
+})
diff --git a/packages/hedera/tests/unit/fixtures/did-document.ts b/packages/hedera/tests/unit/fixtures/did-document.ts
new file mode 100644
index 0000000000..723b1b2cad
--- /dev/null
+++ b/packages/hedera/tests/unit/fixtures/did-document.ts
@@ -0,0 +1,28 @@
+import { ParsedDid, parseDid } from '@credo-ts/core'
+import { DIDResolutionMetadata, JsonLdDIDDocument } from '@hiero-did-sdk/core'
+
+export const did = 'did:hedera:testnet:4BGybF4yCeYNi8RFVowK3zHc1xs2psYdkbiEvETrp3HL_0.0.1000001'
+export const parsedDid: ParsedDid = parseDid(did)
+
+export const didDocument: Required> & JsonLdDIDDocument = {
+ '@context': [
+ 'https://w3.org/ns/did/v1',
+ 'https://w3id.org/security/suites/ed25519-2018/v1',
+ 'https://w3id.org/security/suites/ed25519-2020/v1',
+ ],
+ id: did,
+ controller: did,
+ service: [{ id: 'mock-service', type: 'MockService', serviceEndpoint: 'https://example.com/mock-service/' }],
+ verificationMethod: [
+ {
+ id: `${did}#did-root-key`,
+ controller: did,
+ type: 'Ed25519VerificationKey2020' as const,
+ publicKeyMultibase: 'z6MkhdY2BVKQYC2qpdFxBNu9u5qbqY8tEknzScdAkWRsjG4i',
+ },
+ ],
+}
+
+export const didResolutionMetadata: DIDResolutionMetadata = {
+ contentType: 'application/ld+json;profile="https://w3id.org/did-resolution"',
+}
diff --git a/packages/hedera/tests/unit/hedera-anoncres-registry.test.ts b/packages/hedera/tests/unit/hedera-anoncres-registry.test.ts
new file mode 100644
index 0000000000..0b2344449a
--- /dev/null
+++ b/packages/hedera/tests/unit/hedera-anoncres-registry.test.ts
@@ -0,0 +1,439 @@
+import {
+ GetCredentialDefinitionReturn,
+ GetRevocationRegistryDefinitionReturn,
+ GetRevocationStatusListReturn,
+ GetSchemaReturn,
+ RegisterCredentialDefinitionOptions,
+ RegisterCredentialDefinitionReturn,
+ RegisterRevocationRegistryDefinitionOptions,
+ RegisterRevocationRegistryDefinitionReturn,
+ RegisterRevocationStatusListOptions,
+ RegisterRevocationStatusListReturn,
+ RegisterSchemaOptions,
+ RegisterSchemaReturn,
+} from '@credo-ts/anoncreds'
+import { AgentContext } from '@credo-ts/core'
+import { HederaAnonCredsRegistry } from '@credo-ts/hedera'
+import { mockFunction } from '../../../core/tests/helpers'
+import { HederaLedgerService } from '../../src/ledger/HederaLedgerService'
+
+const mockLedgerService = {
+ registerSchema: jest.fn(),
+ getSchema: jest.fn(),
+ registerCredentialDefinition: jest.fn(),
+ getCredentialDefinition: jest.fn(),
+ registerRevocationRegistryDefinition: jest.fn(),
+ getRevocationRegistryDefinition: jest.fn(),
+ registerRevocationStatusList: jest.fn(),
+ getRevocationStatusList: jest.fn(),
+} as unknown as HederaLedgerService
+
+const mockAgentContext = {
+ dependencyManager: {
+ resolve: jest.fn().mockImplementation((cls) => {
+ if (cls === HederaLedgerService) return mockLedgerService
+ }),
+ },
+ config: {
+ logger: {
+ trace: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ },
+ },
+} as unknown as AgentContext
+
+describe('HederaAnonCredsRegistry', () => {
+ const registry: HederaAnonCredsRegistry = new HederaAnonCredsRegistry()
+
+ describe('registerSchema', () => {
+ const options: RegisterSchemaOptions = {
+ schema: {
+ issuerId: 'issuer-did',
+ name: 'schema-name',
+ version: '1.0',
+ attrNames: [],
+ },
+ options: {},
+ }
+
+ it('should call ledgerService.registerSchema and return result on success', async () => {
+ const expected: RegisterSchemaReturn = {
+ schemaMetadata: {},
+ registrationMetadata: {},
+ schemaState: {
+ state: 'finished',
+ schema: options.schema,
+ schemaId: expect.any(String),
+ },
+ }
+ mockFunction(mockLedgerService.registerSchema).mockResolvedValue(expected)
+
+ const result = await registry.registerSchema(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith('Registering schema on Hedera ledger')
+ expect(mockAgentContext.dependencyManager.resolve).toHaveBeenCalledWith(
+ expect.any(Function) || HederaLedgerService
+ )
+ expect(mockLedgerService.registerSchema).toHaveBeenCalledWith(mockAgentContext, options)
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return failed state', async () => {
+ const error = new Error('fail')
+ mockFunction(mockLedgerService.registerSchema).mockRejectedValue(error)
+
+ const result = await registry.registerSchema(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.debug).toHaveBeenCalledWith(
+ `Error registering schema for did '${options.schema.issuerId}'`,
+ expect.objectContaining({ error, did: options.schema.issuerId, schema: options })
+ )
+ expect(result.schemaState.state).toBe('failed')
+ if (result.schemaState.state === 'failed') expect(result.schemaState.reason).toContain('fail')
+ })
+ })
+
+ describe('getSchema', () => {
+ const mockSchemaId = 'mock-schema-id'
+
+ it('should call ledgerService.getSchema and return result on success', async () => {
+ const expected: GetSchemaReturn = {
+ schemaId: mockSchemaId,
+ resolutionMetadata: {},
+ schemaMetadata: {},
+ }
+ mockFunction(mockLedgerService.getSchema).mockResolvedValue(expected)
+
+ const result = await registry.getSchema(mockAgentContext, mockSchemaId)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ `Resolving schema '${mockSchemaId}' from Hedera ledger`
+ )
+ expect(mockLedgerService.getSchema).toHaveBeenCalledWith(mockAgentContext, mockSchemaId)
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return notFound error state', async () => {
+ const error = new Error('not found')
+ mockFunction(mockLedgerService.getSchema).mockRejectedValue(error)
+
+ const result = await registry.getSchema(mockAgentContext, mockSchemaId)
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error retrieving schema '${mockSchemaId}'`,
+ expect.objectContaining({ error, schemaId: mockSchemaId })
+ )
+ expect(result.resolutionMetadata.error).toBe('notFound')
+ expect(result.resolutionMetadata.message).toContain('not found')
+ })
+ })
+
+ describe('registerCredentialDefinition', () => {
+ const options: RegisterCredentialDefinitionOptions = {
+ options: {},
+ credentialDefinition: {
+ issuerId: 'did:hedera:issuer',
+ schemaId: '',
+ type: 'CL',
+ tag: '',
+ value: {
+ primary: {},
+ revocation: undefined,
+ },
+ },
+ }
+
+ it('should call ledgerService.registerCredentialDefinition and return result on success', async () => {
+ const expected: RegisterCredentialDefinitionReturn = {
+ credentialDefinitionMetadata: {},
+ registrationMetadata: {},
+ credentialDefinitionState: {
+ state: 'finished',
+ credentialDefinition: {
+ issuerId: '',
+ schemaId: '',
+ type: 'CL',
+ tag: '',
+ value: {
+ primary: {},
+ revocation: undefined,
+ },
+ },
+ credentialDefinitionId: 'did:hedera:issuerId',
+ },
+ }
+ mockFunction(mockLedgerService.registerCredentialDefinition).mockResolvedValue(expected)
+
+ const result = await registry.registerCredentialDefinition(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ 'Registering credential definition on Hedera ledger'
+ )
+ expect(mockLedgerService.registerCredentialDefinition).toHaveBeenCalledWith(mockAgentContext, options)
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return failed state', async () => {
+ const error = new Error('fail')
+ mockFunction(mockLedgerService.registerCredentialDefinition).mockRejectedValue(error)
+
+ const result = await registry.registerCredentialDefinition(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error registering credential definition for did '${options.credentialDefinition.issuerId}'`,
+ expect.objectContaining({ error, did: options.credentialDefinition.issuerId, schema: options })
+ )
+ expect(result.credentialDefinitionState.state).toBe('failed')
+ if (result.credentialDefinitionState.state === 'failed')
+ expect(result.credentialDefinitionState.reason).toContain('fail')
+ })
+ })
+
+ describe('getCredentialDefinition', () => {
+ const mockCredentialDefinitionId = 'mock-cred-def-id'
+
+ it('should call ledgerService.getCredentialDefinition and return result on success', async () => {
+ const expected: GetCredentialDefinitionReturn = {
+ credentialDefinitionId: mockCredentialDefinitionId,
+ resolutionMetadata: {},
+ credentialDefinitionMetadata: {},
+ }
+ mockFunction(mockLedgerService.getCredentialDefinition).mockResolvedValue(expected)
+
+ const result = await registry.getCredentialDefinition(mockAgentContext, mockCredentialDefinitionId)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ `Resolving credential definition '${mockCredentialDefinitionId}' from Hedera ledger`
+ )
+ expect(mockLedgerService.getCredentialDefinition).toHaveBeenCalledWith(
+ mockAgentContext,
+ mockCredentialDefinitionId
+ )
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return notFound error state', async () => {
+ const error = new Error('not found')
+ mockFunction(mockLedgerService.getCredentialDefinition).mockRejectedValue(error)
+
+ const result = await registry.getCredentialDefinition(mockAgentContext, mockCredentialDefinitionId)
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error retrieving credential definition '${mockCredentialDefinitionId}'`,
+ expect.objectContaining({ error, credentialDefinitionId: mockCredentialDefinitionId })
+ )
+ expect(result.resolutionMetadata.error).toBe('notFound')
+ expect(result.resolutionMetadata.message).toContain('not found')
+ })
+ })
+
+ describe('registerRevocationRegistryDefinition', () => {
+ const options: RegisterRevocationRegistryDefinitionOptions = {
+ options: {},
+ revocationRegistryDefinition: {
+ credDefId: 'credDef1',
+ issuerId: 'did:hedera:issuer',
+ revocDefType: 'CL_ACCUM',
+ tag: '',
+ value: {
+ publicKeys: {
+ accumKey: {
+ z: '',
+ },
+ },
+ maxCredNum: 0,
+ tailsLocation: '',
+ tailsHash: '',
+ },
+ },
+ }
+
+ it('should call ledgerService.registerRevocationRegistryDefinition and return result on success', async () => {
+ const expected: RegisterRevocationRegistryDefinitionReturn = {
+ revocationRegistryDefinitionMetadata: {},
+ registrationMetadata: {},
+ revocationRegistryDefinitionState: {
+ state: 'finished',
+ revocationRegistryDefinitionId: 'test',
+ revocationRegistryDefinition: {
+ issuerId: '',
+ revocDefType: 'CL_ACCUM',
+ credDefId: '',
+ tag: '',
+ value: {
+ publicKeys: {
+ accumKey: {
+ z: '',
+ },
+ },
+ maxCredNum: 0,
+ tailsLocation: '',
+ tailsHash: '',
+ },
+ },
+ },
+ }
+ mockFunction(mockLedgerService.registerRevocationRegistryDefinition).mockResolvedValue(expected)
+
+ const result = await registry.registerRevocationRegistryDefinition(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ `Registering revocation registry definition for '${options.revocationRegistryDefinition.credDefId}' on Hedera ledger`
+ )
+ expect(mockLedgerService.registerRevocationRegistryDefinition).toHaveBeenCalledWith(mockAgentContext, options)
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return failed state', async () => {
+ const error = new Error('fail')
+ mockFunction(mockLedgerService.registerRevocationRegistryDefinition).mockRejectedValue(error)
+
+ const result = await registry.registerRevocationRegistryDefinition(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error registering revocation registry definition for did '${options.revocationRegistryDefinition.issuerId}'`,
+ expect.objectContaining({ error, did: options.revocationRegistryDefinition.issuerId, options })
+ )
+ expect(result.revocationRegistryDefinitionState.state).toBe('failed')
+ if (result.revocationRegistryDefinitionState.state === 'failed')
+ expect(result.revocationRegistryDefinitionState.reason).toContain('fail')
+ })
+ })
+
+ describe('getRevocationRegistryDefinition', () => {
+ const mockRevocationRegistryDefinitionId = 'mock-rev-reg-def-id'
+
+ it('should call ledgerService.getRevocationRegistryDefinition and return result on success', async () => {
+ const expected: GetRevocationRegistryDefinitionReturn = {
+ revocationRegistryDefinitionId: mockRevocationRegistryDefinitionId,
+ resolutionMetadata: {},
+ revocationRegistryDefinitionMetadata: {},
+ }
+ mockFunction(mockLedgerService.getRevocationRegistryDefinition).mockResolvedValue(expected)
+
+ const result = await registry.getRevocationRegistryDefinition(
+ mockAgentContext,
+ mockRevocationRegistryDefinitionId
+ )
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ `Resolving revocation registry definition for '${mockRevocationRegistryDefinitionId}' from Hedera ledger`
+ )
+ expect(mockLedgerService.getRevocationRegistryDefinition).toHaveBeenCalledWith(
+ mockAgentContext,
+ mockRevocationRegistryDefinitionId
+ )
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return notFound error state', async () => {
+ const error = new Error('not found')
+ mockFunction(mockLedgerService.getRevocationRegistryDefinition).mockRejectedValue(error)
+
+ const result = await registry.getRevocationRegistryDefinition(
+ mockAgentContext,
+ mockRevocationRegistryDefinitionId
+ )
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error retrieving revocation registry definition '${mockRevocationRegistryDefinitionId}'`,
+ expect.objectContaining({ error, revocationRegistryDefinitionId: mockRevocationRegistryDefinitionId })
+ )
+ expect(result.resolutionMetadata.error).toBe('notFound')
+ expect(result.resolutionMetadata.message).toContain('not found')
+ })
+ })
+
+ describe('registerRevocationStatusList', () => {
+ const options: RegisterRevocationStatusListOptions = {
+ options: {},
+ revocationStatusList: {
+ revRegDefId: 'regDef1',
+ issuerId: 'did:hedera:issuer',
+ revocationList: [],
+ currentAccumulator: '',
+ },
+ }
+
+ it('should call ledgerService.registerRevocationStatusList and return result on success', async () => {
+ const expected: RegisterRevocationStatusListReturn = {
+ revocationStatusListMetadata: {},
+ registrationMetadata: {},
+ revocationStatusListState: {
+ state: 'finished',
+ revocationStatusList: {
+ revRegDefId: '',
+ issuerId: '',
+ revocationList: [],
+ timestamp: 0,
+ currentAccumulator: '',
+ },
+ },
+ }
+ mockFunction(mockLedgerService.registerRevocationStatusList).mockResolvedValue(expected)
+
+ const result = await registry.registerRevocationStatusList(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ `Registering revocation status list for '${options.revocationStatusList.revRegDefId}' on Hedera ledger`
+ )
+ expect(mockLedgerService.registerRevocationStatusList).toHaveBeenCalledWith(mockAgentContext, options)
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return failed state', async () => {
+ const error = new Error('fail')
+ mockFunction(mockLedgerService.registerRevocationStatusList).mockRejectedValue(error)
+
+ const result = await registry.registerRevocationStatusList(mockAgentContext, options)
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error registering revocation status list for did '${options.revocationStatusList.issuerId}'`,
+ expect.objectContaining({ error, did: options.revocationStatusList.issuerId, options })
+ )
+ expect(result.revocationStatusListState.state).toBe('failed')
+ if (result.revocationStatusListState.state === 'failed')
+ expect(result.revocationStatusListState.reason).toContain('fail')
+ })
+ })
+
+ describe('getRevocationStatusList', () => {
+ const mockRevocationRegistryId = 'mock-rev-reg-def-id'
+ const timestamp = 1234567890
+
+ it('should call ledgerService.getRevocationStatusList and return result on success', async () => {
+ const expected: GetRevocationStatusListReturn = {
+ resolutionMetadata: {},
+ revocationStatusListMetadata: {},
+ }
+ mockFunction(mockLedgerService.getRevocationStatusList).mockResolvedValue(expected)
+
+ const result = await registry.getRevocationStatusList(mockAgentContext, mockRevocationRegistryId, timestamp)
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith(
+ `Resolving revocation status for for '${mockRevocationRegistryId}' from Hedera ledger`
+ )
+ expect(mockLedgerService.getRevocationStatusList).toHaveBeenCalledWith(
+ mockAgentContext,
+ mockRevocationRegistryId,
+ timestamp * 1000
+ )
+ expect(result).toEqual(expected)
+ })
+
+ it('should catch error and return notFound error state', async () => {
+ const error = new Error('not found')
+ mockFunction(mockLedgerService.getRevocationStatusList).mockRejectedValue(error)
+
+ const result = await registry.getRevocationStatusList(mockAgentContext, mockRevocationRegistryId, timestamp)
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith(
+ `Error retrieving revocation registry status list '${mockRevocationRegistryId}'`,
+ expect.objectContaining({ error, revocationRegistryId: mockRevocationRegistryId })
+ )
+ expect(result.resolutionMetadata.error).toBe('notFound')
+ expect(result.resolutionMetadata.message).toContain('not found')
+ })
+ })
+})
diff --git a/packages/hedera/tests/unit/hedera-did-registrar.test.ts b/packages/hedera/tests/unit/hedera-did-registrar.test.ts
new file mode 100644
index 0000000000..02d6cd3b58
--- /dev/null
+++ b/packages/hedera/tests/unit/hedera-did-registrar.test.ts
@@ -0,0 +1,266 @@
+import { AgentContext, DidDocumentKey, DidRecord, DidRepository } from '@credo-ts/core'
+
+import { DidDocumentRole } from '@credo-ts/core'
+import { HederaDidRegistrar } from '@credo-ts/hedera'
+import { mockFunction } from '../../../core/tests/helpers'
+import { HederaDidUpdateOptions, HederaLedgerService } from '../../src/ledger/HederaLedgerService'
+import { did, didDocument, didResolutionMetadata } from './fixtures/did-document'
+
+const mockDidRepository = {
+ save: jest.fn(),
+ findCreatedDid: jest.fn(),
+ update: jest.fn(),
+} as unknown as DidRepository
+
+const mockLedgerService = {
+ createDid: jest.fn(),
+ resolveDid: jest.fn(),
+ updateDid: jest.fn(),
+ deactivateDid: jest.fn(),
+} as unknown as HederaLedgerService
+
+const mockAgentContext = {
+ dependencyManager: {
+ resolve: jest.fn().mockImplementation((cls) => {
+ if (cls === DidRepository) return mockDidRepository
+ if (cls === HederaLedgerService) return mockLedgerService
+ }),
+ },
+ config: {
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ },
+ },
+} as unknown as AgentContext
+
+describe('HederaDidRegistrar', () => {
+ const registrar: HederaDidRegistrar = new HederaDidRegistrar()
+
+ describe('create', () => {
+ it('should create DID, save it, and return finished state on success', async () => {
+ const rootKey = { kmsKeyId: 'key1', didDocumentRelativeKeyId: 'rootKeyId' }
+
+ mockFunction(mockLedgerService.createDid).mockResolvedValue({
+ did,
+ didDocument,
+ rootKey,
+ })
+
+ const result = await registrar.create(mockAgentContext, {
+ method: 'hedera',
+ options: {},
+ })
+
+ expect(mockDidRepository.save).toHaveBeenCalled()
+ const savedRecord = mockFunction(mockDidRepository.save).mock.calls[0][1]
+ expect(savedRecord.did).toBe(did)
+ expect(savedRecord.role).toBe(DidDocumentRole.Created)
+ expect(savedRecord.didDocument).toBeInstanceOf(Object)
+ expect(savedRecord.didDocument?.service).toBeDefined()
+ // biome-ignore lint/style/noNonNullAssertion:
+ expect(savedRecord.didDocument?.service![0]).toBeInstanceOf(Object)
+
+ expect(result.didState.state).toBe('finished')
+ expect(result.didState.did).toBe(did)
+ expect(result.didState.didDocument).toBeInstanceOf(Object)
+ })
+
+ it('should handle error and return failed state', async () => {
+ mockFunction(mockLedgerService.createDid).mockRejectedValue(new Error('Create failed'))
+
+ const result = await registrar.create(mockAgentContext, {
+ method: 'hedera',
+ options: {},
+ })
+
+ expect(mockAgentContext.config.logger.debug).toHaveBeenCalledWith('Error creating DID', expect.any(Object))
+
+ expect(result.didState.state).toBe('failed')
+ if (result.didState.state === 'failed')
+ expect(result.didState.reason).toBe('Unable to register Did: Create failed')
+ })
+ })
+
+ describe('update', () => {
+ it('should update DID and save record successfully', async () => {
+ const updatedDidDocument = {
+ ...didDocument,
+ service: [
+ ...didDocument.service,
+ { id: 'added-service', type: 'MockService', serviceEndpoint: 'https://example.com/added-service/' },
+ ],
+ }
+
+ const foundDidRecord = {
+ didDocument,
+ keys: [{ didDocumentRelativeKeyId: 'key1' }],
+ } as unknown as DidRecord
+
+ mockFunction(mockLedgerService.resolveDid).mockResolvedValue({
+ didDocument,
+ didDocumentMetadata: { deactivated: false },
+ didResolutionMetadata,
+ })
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValue(foundDidRecord)
+ mockFunction(mockLedgerService.updateDid).mockResolvedValue({ did, didDocument: updatedDidDocument })
+
+ const options: HederaDidUpdateOptions = {
+ did,
+ didDocumentOperation: 'setDidDocument',
+ secret: {
+ keys: [
+ {
+ didDocumentRelativeKeyId: 'key2',
+ kmsKeyId: 'some-key',
+ },
+ ],
+ },
+ didDocument: {},
+ }
+
+ const result = await registrar.update(mockAgentContext, options)
+
+ expect(mockLedgerService.resolveDid).toHaveBeenCalledWith(mockAgentContext, did)
+ expect(mockDidRepository.findCreatedDid).toHaveBeenCalledWith(mockAgentContext, did)
+
+ expect(mockLedgerService.updateDid).toHaveBeenCalledWith(
+ mockAgentContext,
+ expect.objectContaining({
+ secret: { keys: expect.any(Array) },
+ })
+ )
+
+ expect(mockDidRepository.update).toHaveBeenCalledWith(mockAgentContext, foundDidRecord)
+
+ expect(result.didState.state).toBe('finished')
+ expect(result.didState.did).toBe(did)
+ expect(result.didState.didDocument).toBeInstanceOf(Object)
+ })
+
+ it('should return failed state if DID not found or deactivated', async () => {
+ mockFunction(mockLedgerService.resolveDid).mockResolvedValue({
+ didDocument,
+ didResolutionMetadata,
+ didDocumentMetadata: { deactivated: true },
+ })
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValue(null)
+
+ const result = await registrar.update(mockAgentContext, {
+ did,
+ didDocument: {},
+ })
+
+ expect(result.didState.state).toBe('failed')
+ if (result.didState.state === 'failed') expect(result.didState.reason).toBe('Did not found')
+ })
+
+ it('should handle error and return failed state', async () => {
+ mockFunction(mockLedgerService.resolveDid).mockRejectedValue(new Error('Update failed'))
+
+ const result = await registrar.update(mockAgentContext, {
+ did,
+ didDocumentOperation: 'setDidDocument',
+ didDocument: {},
+ })
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith('Error updating DID', expect.any(Error))
+ expect(result.didState.state).toBe('failed')
+ if (result.didState.state === 'failed') expect(result.didState.reason).toBe('Unable update DID: Update failed')
+ })
+ })
+
+ describe('deactivate', () => {
+ it('should deactivate DID and save updated record successfully', async () => {
+ const deactivatedDidDocument = { ...didDocument, deactivated: true }
+
+ const foundDidRecord = {
+ didDocument,
+ keys: [{ didDocumentRelativeKeyId: 'key1' }],
+ } as unknown as DidRecord
+
+ mockFunction(mockLedgerService.resolveDid).mockResolvedValue({
+ didDocument,
+ didResolutionMetadata,
+ didDocumentMetadata: {},
+ })
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValue(foundDidRecord)
+ mockFunction(mockLedgerService.deactivateDid).mockResolvedValue({
+ did,
+ didDocument: deactivatedDidDocument,
+ })
+ mockFunction(mockDidRepository.update).mockResolvedValue(undefined)
+
+ const result = await registrar.deactivate(mockAgentContext, {
+ did,
+ })
+
+ expect(mockLedgerService.resolveDid).toHaveBeenCalledWith(mockAgentContext, did)
+ expect(mockDidRepository.findCreatedDid).toHaveBeenCalledWith(mockAgentContext, did)
+ expect(mockLedgerService.deactivateDid).toHaveBeenCalledWith(
+ mockAgentContext,
+ expect.objectContaining({
+ secret: { keys: foundDidRecord.keys },
+ })
+ )
+ expect(mockDidRepository.update).toHaveBeenCalledWith(mockAgentContext, foundDidRecord)
+
+ expect(result.didState.state).toBe('finished')
+ expect(result.didState.did).toBe(did)
+ expect(result.didState.didDocument).toBeInstanceOf(Object)
+ })
+
+ it('should return failed state if DID is deactivated', async () => {
+ mockFunction(mockLedgerService.resolveDid).mockResolvedValueOnce({
+ didDocument,
+ didResolutionMetadata,
+ didDocumentMetadata: { deactivated: true },
+ })
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValue(null)
+
+ const result = await registrar.deactivate(mockAgentContext, {
+ did,
+ })
+
+ expect(result.didState.state).toBe('failed')
+ // @ts-ignore
+ expect(result.didState.reason).toBe('Did not found')
+ })
+
+ it('should handle error and return failed state', async () => {
+ mockFunction(mockLedgerService.resolveDid).mockRejectedValue(new Error('Deactivate failed'))
+
+ const result = await registrar.deactivate(mockAgentContext, { did })
+
+ expect(mockAgentContext.config.logger.error).toHaveBeenCalledWith('Error deactivating DID', expect.any(Error))
+ expect(result.didState.state).toBe('failed')
+ if (result.didState.state === 'failed')
+ expect(result.didState.reason).toBe('Unable deactivating DID: Deactivate failed')
+ })
+ })
+
+ describe('concatKeys (private method)', () => {
+ it('should concatenate keys without duplicates based on relativeKeyId', () => {
+ const keys1 = [{ didDocumentRelativeKeyId: 'key1' }, { didDocumentRelativeKeyId: 'key2' }] as DidDocumentKey[]
+ const keys2 = [{ didDocumentRelativeKeyId: 'key2' }, { didDocumentRelativeKeyId: 'key3' }] as DidDocumentKey[]
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const result = (registrar as any).concatKeys(keys1, keys2)
+
+ expect(result).toHaveLength(3)
+ expect(result).toEqual(
+ expect.arrayContaining([
+ { didDocumentRelativeKeyId: 'key1' },
+ { didDocumentRelativeKeyId: 'key2' },
+ { didDocumentRelativeKeyId: 'key3' },
+ ])
+ )
+ })
+
+ it('should handle undefined arguments and return empty array', () => {
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const result = (registrar as any).concatKeys(undefined, undefined)
+ expect(result).toEqual([])
+ })
+ })
+})
diff --git a/packages/hedera/tests/unit/hedera-did-resolver.test.ts b/packages/hedera/tests/unit/hedera-did-resolver.test.ts
new file mode 100644
index 0000000000..f39904bcce
--- /dev/null
+++ b/packages/hedera/tests/unit/hedera-did-resolver.test.ts
@@ -0,0 +1,70 @@
+import { AgentContext, DidDocument, JsonTransformer } from '@credo-ts/core'
+import { HederaDidResolver } from '@credo-ts/hedera'
+import { mockFunction } from '../../../core/tests/helpers'
+import { HederaLedgerService } from '../../src/ledger/HederaLedgerService'
+import { did, didDocument, didResolutionMetadata, parsedDid } from './fixtures/did-document'
+
+const mockLedgerService = {
+ resolveDid: jest.fn(),
+} as unknown as HederaLedgerService
+
+const mockAgentContext = {
+ config: {
+ logger: {
+ trace: jest.fn(),
+ debug: jest.fn(),
+ },
+ },
+ dependencyManager: {
+ resolve: jest.fn().mockImplementation((cls) => {
+ if (cls === HederaLedgerService) return mockLedgerService
+ }),
+ },
+} as unknown as AgentContext
+
+const resolver = new HederaDidResolver()
+
+describe('HederaDidResolver', () => {
+ it('should successfully resolve DID', async () => {
+ const resolutionResult = {
+ didDocument,
+ didDocumentMetadata: {},
+ didResolutionMetadata,
+ }
+
+ mockFunction(mockLedgerService.resolveDid).mockResolvedValue(resolutionResult)
+
+ jest.spyOn(JsonTransformer, 'fromJSON').mockReturnValue(didDocument)
+
+ const result = await resolver.resolve(mockAgentContext, did, parsedDid, {})
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith('Try to resolve a did document from ledger')
+ expect(mockAgentContext.dependencyManager.resolve).toHaveBeenCalledWith(HederaLedgerService)
+ expect(mockLedgerService.resolveDid).toHaveBeenCalledWith(mockAgentContext, did)
+ expect(JsonTransformer.fromJSON).toHaveBeenCalledWith(resolutionResult.didDocument, DidDocument)
+ expect(result).toEqual(resolutionResult)
+ })
+
+ it('should handle error and return notFound', async () => {
+ const error = new Error('Some error')
+
+ mockFunction(mockLedgerService.resolveDid).mockRejectedValue(error)
+
+ const result = await resolver.resolve(mockAgentContext, did, parsedDid, {})
+
+ expect(mockAgentContext.config.logger.trace).toHaveBeenCalledWith('Try to resolve a did document from ledger')
+ expect(mockAgentContext.config.logger.debug).toHaveBeenCalledWith('Error resolving the did', {
+ error,
+ did,
+ })
+
+ expect(result).toEqual({
+ didDocument: null,
+ didDocumentMetadata: {},
+ didResolutionMetadata: {
+ error: 'notFound',
+ message: `Unable to resolve did '${did}': ${error}`,
+ },
+ })
+ })
+})
diff --git a/packages/hedera/tests/unit/hedera-ledger-service.test.ts b/packages/hedera/tests/unit/hedera-ledger-service.test.ts
new file mode 100644
index 0000000000..6120d6355b
--- /dev/null
+++ b/packages/hedera/tests/unit/hedera-ledger-service.test.ts
@@ -0,0 +1,566 @@
+import {
+ RegisterCredentialDefinitionOptions,
+ RegisterRevocationRegistryDefinitionOptions,
+ RegisterRevocationStatusListOptions,
+ RegisterSchemaOptions,
+} from '@credo-ts/anoncreds'
+import { DidDocument, DidRecord, DidRepository } from '@credo-ts/core'
+import { AgentContext } from '@credo-ts/core'
+import { DidDocumentKey, Kms } from '@credo-ts/core'
+import { KmsJwkPublicOkp } from '@credo-ts/core/src/modules/kms'
+import { Client, PrivateKey } from '@hashgraph/sdk'
+import { HederaLedgerService } from '../../src/ledger/HederaLedgerService'
+
+jest.mock('@hiero-did-sdk/registrar', () => ({
+ DIDUpdateBuilder: jest.fn().mockReturnValue({
+ addService: jest.fn().mockReturnThis(),
+ removeService: jest.fn().mockReturnThis(),
+ addVerificationMethod: jest.fn().mockReturnThis(),
+ removeVerificationMethod: jest.fn().mockReturnThis(),
+ addAssertionMethod: jest.fn().mockReturnThis(),
+ removeAssertionMethod: jest.fn().mockReturnThis(),
+ addAuthenticationMethod: jest.fn().mockReturnThis(),
+ removeAuthenticationMethod: jest.fn().mockReturnThis(),
+ addCapabilityDelegationMethod: jest.fn().mockReturnThis(),
+ removeCapabilityDelegationMethod: jest.fn().mockReturnThis(),
+ addCapabilityInvocationMethod: jest.fn().mockReturnThis(),
+ removeCapabilityInvocationMethod: jest.fn().mockReturnThis(),
+ addKeyAgreementMethod: jest.fn().mockReturnThis(),
+ removeKeyAgreementMethod: jest.fn().mockReturnThis(),
+ build: jest.fn(),
+ }),
+ generateCreateDIDRequest: jest.fn(),
+ submitCreateDIDRequest: jest.fn(),
+ generateUpdateDIDRequest: jest.fn(),
+ submitUpdateDIDRequest: jest.fn(),
+ generateDeactivateDIDRequest: jest.fn(),
+ submitDeactivateDIDRequest: jest.fn(),
+}))
+
+import {
+ CreateDIDRequest,
+ DIDUpdateBuilder,
+ DeactivateDIDRequest,
+ UpdateDIDRequest,
+ generateCreateDIDRequest,
+ generateDeactivateDIDRequest,
+ generateUpdateDIDRequest,
+ submitCreateDIDRequest,
+ submitDeactivateDIDRequest,
+ submitUpdateDIDRequest,
+} from '@hiero-did-sdk/registrar'
+
+jest.mock('@hiero-did-sdk/resolver', () => ({
+ resolveDID: jest.fn(),
+ TopicReaderHederaHcs: jest.fn(),
+}))
+
+import { resolveDID } from '@hiero-did-sdk/resolver'
+
+jest.mock('../../src/ledger/utils')
+
+import { AskarKeyManagementService } from '@credo-ts/askar'
+import { DID_ROOT_KEY_ID } from '@hiero-did-sdk/core'
+import { KeyEntryObject } from '@openwallet-foundation/askar-nodejs'
+import { mockFunction } from '../../../core/tests/helpers'
+import { HederaAnonCredsRegistry } from '../../src/anoncreds/HederaAnonCredsRegistry'
+import { createOrGetKey } from '../../src/ledger/utils'
+import { did, didDocument } from './fixtures/did-document'
+
+const mockKeyId = 'mock-key-id'
+
+const mockPublicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' } = { crv: 'Ed25519', kty: 'OKP', x: 'abc' }
+
+const mockKeyManagementService = {
+ getKeyAsserted: jest
+ .fn()
+ .mockReturnValue({ key: { secretBytes: PrivateKey.generateED25519().toBytes() } } as unknown as KeyEntryObject),
+} as unknown as AskarKeyManagementService
+
+const mockKms = {
+ sign: jest.fn().mockResolvedValue({ signature: new Uint8Array([1, 2, 3]) }),
+ getKms: jest.fn().mockReturnValue(mockKeyManagementService),
+} as unknown as Kms.KeyManagementApi
+
+const mockDidRepository = {
+ findCreatedDid: jest.fn().mockResolvedValue({
+ keys: [
+ {
+ didDocumentRelativeKeyId: DID_ROOT_KEY_ID,
+ kmsKeyId: 'kmsKeyId',
+ },
+ ],
+ }),
+} as unknown as DidRepository
+
+const mockAgentContext = {
+ dependencyManager: {
+ resolve: jest.fn((cls) => {
+ if (cls === Kms.KeyManagementApi) {
+ return mockKms
+ }
+ if (cls === DidRepository) {
+ return mockDidRepository
+ }
+ throw new Error(`No instance found for ${cls}`)
+ }),
+ },
+} as unknown as AgentContext
+
+const mockHederaAnonCredsRegistry = {
+ getSchema: jest.fn().mockResolvedValue('schema'),
+ registerSchema: jest.fn().mockResolvedValue('registerSchema'),
+ getCredentialDefinition: jest.fn().mockResolvedValue('credDef'),
+ registerCredentialDefinition: jest.fn().mockResolvedValue('registerCredDef'),
+ getRevocationRegistryDefinition: jest.fn().mockResolvedValue('revRegDef'),
+ registerRevocationRegistryDefinition: jest.fn().mockResolvedValue('registerRevRegDef'),
+ getRevocationStatusList: jest.fn().mockResolvedValue('revStatusList'),
+ registerRevocationStatusList: jest.fn().mockResolvedValue('registerRevStatus'),
+} as unknown as HederaAnonCredsRegistry
+
+describe('HederaLedgerService', () => {
+ const service = new HederaLedgerService({
+ options: {
+ networks: [
+ {
+ network: 'testnet',
+ operatorId: 'mock-operator-id',
+ operatorKey: 'mock-operator-key',
+ },
+ ],
+ cache: {
+ get: jest.fn().mockResolvedValue(null),
+ set: jest.fn().mockResolvedValue(undefined),
+ remove: jest.fn().mockResolvedValue(undefined),
+ clear: jest.fn(),
+ cleanupExpired: jest.fn(),
+ },
+ },
+ })
+ const builder: DIDUpdateBuilder = new DIDUpdateBuilder()
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ jest.spyOn((service as any).clientService, 'withClient').mockImplementation(async (_props, operation) => {
+ const mockClient = {} as Client
+ // @ts-ignore
+ return operation(mockClient)
+ })
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ jest.spyOn(service as any, 'getHederaAnonCredsRegistry').mockReturnValue(mockHederaAnonCredsRegistry)
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ jest.spyOn(service as any, 'getPublisher').mockResolvedValue({})
+
+ describe('resolveDid', () =>
+ it('should call resolveDID with proper args and returns result', async () => {
+ // @ts-ignore - there is a conflict with 'resolveDID' "overloaded" signatures
+ mockFunction(resolveDID).mockResolvedValueOnce(didDocument)
+
+ const result = await service.resolveDid(mockAgentContext, did)
+
+ expect(resolveDID).toHaveBeenCalledWith(
+ did,
+ 'application/ld+json;profile="https://w3id.org/did-resolution"',
+ expect.any(Object)
+ )
+ expect(result).toBe(didDocument)
+ }))
+
+ describe('createDid', () => {
+ it('should create DID without didDocument', async () => {
+ const createDidRequest = {
+ state: {},
+ signingRequest: { serializedPayload: new Uint8Array() },
+ } as unknown as CreateDIDRequest
+
+ mockFunction(createOrGetKey).mockResolvedValueOnce({ keyId: mockKeyId, publicJwk: mockPublicJwk })
+ mockFunction(generateCreateDIDRequest).mockResolvedValueOnce(createDidRequest)
+ mockFunction(submitCreateDIDRequest).mockResolvedValueOnce({ did, didDocument })
+
+ const result = await service.createDid(mockAgentContext, {
+ method: 'hedera',
+ options: { network: 'testnet' },
+ secret: { rootKeyId: mockKeyId, keys: [] },
+ })
+
+ expect(createOrGetKey).toHaveBeenCalledWith(mockKms, mockKeyId)
+ expect(generateCreateDIDRequest).toHaveBeenCalled()
+ expect(submitCreateDIDRequest).toHaveBeenCalled()
+ expect(result.did).toBe(did)
+ expect(result.rootKey).toBeDefined()
+ })
+
+ it('should create DID with didDocument and calls updateDid', async () => {
+ const createDidRequest = {
+ state: {},
+ signingRequest: { serializedPayload: new Uint8Array() },
+ } as unknown as CreateDIDRequest
+
+ mockFunction(createOrGetKey).mockResolvedValueOnce({ keyId: mockKeyId, publicJwk: mockPublicJwk })
+ mockFunction(generateCreateDIDRequest).mockResolvedValueOnce(createDidRequest)
+ mockFunction(submitCreateDIDRequest).mockResolvedValueOnce({ did, didDocument })
+
+ const updateDidSpy = jest.spyOn(service, 'updateDid').mockResolvedValueOnce({ did, didDocument })
+
+ const result = await service.createDid(mockAgentContext, {
+ method: 'hedera',
+ options: { network: 'testnet' },
+ secret: { rootKeyId: mockKeyId, keys: [] },
+ didDocument: DidDocument.fromJSON(didDocument),
+ })
+
+ expect(updateDidSpy).toHaveBeenCalled()
+ expect(result.rootKey).toBeDefined()
+ })
+ })
+
+ describe('updateDid', () => {
+ it('should throw error if didDocumentOperation is missing', async () => {
+ await expect(service.updateDid(mockAgentContext, { did, didDocument })).rejects.toThrow(
+ 'DidDocumentOperation is required'
+ )
+ })
+
+ it('should throw error if rootKey missing', async () => {
+ const keys: DidDocumentKey[] = []
+ await expect(
+ service.updateDid(mockAgentContext, {
+ did,
+ didDocumentOperation: 'setDidDocument',
+ secret: { keys },
+ didDocument: {},
+ })
+ ).rejects.toThrow('The root key not found in the KMS')
+ })
+
+ it('should call correct builder methods for each field and action', () => {
+ const spies = {
+ addService: jest.spyOn(builder, 'addService'),
+ removeService: jest.spyOn(builder, 'removeService'),
+ addVerificationMethod: jest.spyOn(builder, 'addVerificationMethod'),
+ removeVerificationMethod: jest.spyOn(builder, 'removeVerificationMethod'),
+ addAssertionMethod: jest.spyOn(builder, 'addAssertionMethod'),
+ removeAssertionMethod: jest.spyOn(builder, 'removeAssertionMethod'),
+ addAuthenticationMethod: jest.spyOn(builder, 'addAuthenticationMethod'),
+ removeAuthenticationMethod: jest.spyOn(builder, 'removeAuthenticationMethod'),
+ addCapabilityDelegationMethod: jest.spyOn(builder, 'addCapabilityDelegationMethod'),
+ removeCapabilityDelegationMethod: jest.spyOn(builder, 'removeCapabilityDelegationMethod'),
+ addCapabilityInvocationMethod: jest.spyOn(builder, 'addCapabilityInvocationMethod'),
+ removeCapabilityInvocationMethod: jest.spyOn(builder, 'removeCapabilityInvocationMethod'),
+ addKeyAgreementMethod: jest.spyOn(builder, 'addKeyAgreementMethod'),
+ removeKeyAgreementMethod: jest.spyOn(builder, 'removeKeyAgreementMethod'),
+ }
+
+ const testCases: [string, 'add' | 'remove', string, jest.SpyInstance][] = [
+ ['service', 'add', 'service-item', spies.addService],
+ ['service', 'remove', 'service-id', spies.removeService],
+
+ ['verificationMethod', 'add', 'verificationMethod-item', spies.addVerificationMethod],
+ ['verificationMethod', 'remove', 'verificationMethod-id', spies.removeVerificationMethod],
+
+ ['assertionMethod', 'add', 'assertionMethod-item', spies.addAssertionMethod],
+ ['assertionMethod', 'remove', 'assertionMethod-id', spies.removeAssertionMethod],
+
+ ['authentication', 'add', 'authentication-item', spies.addAuthenticationMethod],
+ ['authentication', 'remove', 'authentication-id', spies.removeAuthenticationMethod],
+
+ ['capabilityDelegation', 'add', 'capabilityDelegation-item', spies.addCapabilityDelegationMethod],
+ ['capabilityDelegation', 'remove', 'capabilityDelegation-id', spies.removeCapabilityDelegationMethod],
+
+ ['capabilityInvocation', 'add', 'capabilityInvocation-item', spies.addCapabilityInvocationMethod],
+ ['capabilityInvocation', 'remove', 'capabilityInvocation-id', spies.removeCapabilityInvocationMethod],
+
+ ['keyAgreement', 'add', 'keyAgreement-item', spies.addKeyAgreementMethod],
+ ['keyAgreement', 'remove', 'keyAgreement-id', spies.removeKeyAgreementMethod],
+ ]
+
+ for (const [property, action, param, spy] of testCases) {
+ jest.clearAllMocks()
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const builderMethod = (service as any).getUpdateMethod(builder, property, action)
+
+ const result = builderMethod(param)
+
+ expect(result).toBe(builder)
+ expect(spy).toHaveBeenCalledTimes(1)
+ expect(spy).toHaveBeenCalledWith(param)
+ for (const otherSpy of Object.values(spies)) {
+ if (otherSpy !== spy) expect(otherSpy).not.toHaveBeenCalled()
+ }
+ }
+ })
+
+ it('should return builder unchanged for unknown property', () => {
+ const unknownProperty = 'unknown-property'
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const builderMethod = (service as any).getUpdateMethod(builder, unknownProperty, 'add')
+ const result = builderMethod({})
+
+ expect(result).toBe(builder)
+ })
+
+ it('should perform update flow successfully', async () => {
+ const keys: DidDocumentKey[] = [
+ { kmsKeyId: mockKeyId, didDocumentRelativeKeyId: DID_ROOT_KEY_ID },
+ { kmsKeyId: 'some-key', didDocumentRelativeKeyId: '#abc' },
+ ]
+
+ const updatedDidDocument = {
+ ...didDocument,
+ verificationMethod: [
+ ...didDocument.verificationMethod,
+ {
+ id: '#abc',
+ type: 'Ed25519VerificationKey2020' as const,
+ controller: 'test',
+ publicKeyMultibase: 'mock-public-key-multibase',
+ },
+ ],
+ }
+
+ const updateDidRequest = {
+ state: {},
+ signingRequest: { serializedPayload: new Uint8Array() },
+ } as unknown as UpdateDIDRequest
+
+ // @ts-ignore - there is a conflict with 'resolveDID' "overloaded" signatures
+ mockFunction(resolveDID).mockResolvedValueOnce({ didDocument })
+
+ jest
+ // biome-ignore lint/suspicious/noExplicitAny:
+ .spyOn(service as any, 'prepareDidUpdates')
+ .mockReturnValueOnce({ build: jest.fn().mockReturnValueOnce(updatedDidDocument) })
+
+ mockFunction(generateUpdateDIDRequest).mockResolvedValueOnce(updateDidRequest)
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ jest.spyOn(service as any, 'signRequests').mockResolvedValueOnce(Promise.resolve())
+ mockFunction(submitUpdateDIDRequest).mockResolvedValueOnce({ did, didDocument: updatedDidDocument })
+
+ await expect(
+ service.updateDid(mockAgentContext, {
+ did,
+ didDocumentOperation: 'setDidDocument',
+ didDocument: updatedDidDocument,
+ secret: { keys },
+ })
+ ).resolves.toHaveProperty('did', did)
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ expect((service as any).prepareDidUpdates).toHaveBeenCalled()
+ expect(generateUpdateDIDRequest).toHaveBeenCalled()
+ expect(submitUpdateDIDRequest).toHaveBeenCalled()
+ })
+ })
+
+ describe('deactivateDid', () => {
+ it('should throw error if rootKey is missing', async () => {
+ await expect(service.deactivateDid(mockAgentContext, { did, secret: { keys: [] } })).rejects.toThrow(
+ 'The root key not found in the KMS'
+ )
+ })
+
+ it('should throw an error if root key is not found in deactivateDid', async () => {
+ mockFunction(mockAgentContext.dependencyManager.resolve).mockReturnValueOnce({ sign: jest.fn() })
+
+ await expect(
+ service.deactivateDid(mockAgentContext, {
+ did,
+ secret: {
+ keys: [],
+ },
+ })
+ ).rejects.toThrow('The root key not found in the KMS')
+ })
+
+ it('should deactivate DID successfully', async () => {
+ const deactivateDidRequest = {
+ state: {},
+ signingRequest: { serializedPayload: new Uint8Array() },
+ } as unknown as DeactivateDIDRequest
+
+ mockFunction(generateDeactivateDIDRequest).mockResolvedValueOnce(deactivateDidRequest)
+ mockFunction(submitDeactivateDIDRequest).mockResolvedValueOnce({
+ did,
+ didDocument,
+ })
+
+ const result = await service.deactivateDid(mockAgentContext, {
+ did,
+ secret: { keys: [{ kmsKeyId: mockKeyId, didDocumentRelativeKeyId: DID_ROOT_KEY_ID }] },
+ })
+
+ expect(result).toHaveProperty('did', did)
+ expect(mockKms.sign).toHaveBeenCalledWith({
+ keyId: mockKeyId,
+ data: deactivateDidRequest.signingRequest.serializedPayload,
+ algorithm: 'EdDSA',
+ })
+ })
+ })
+
+ describe('anoncreds SDK methods', () => {
+ it('getSchema', async () => {
+ const result = await service.getSchema(mockAgentContext, 'schemaId')
+ expect(mockHederaAnonCredsRegistry.getSchema).toHaveBeenCalledWith('schemaId')
+ expect(result).toBe('schema')
+ })
+
+ it('registerSchema', async () => {
+ const options: RegisterSchemaOptions = {
+ schema: {
+ issuerId: '',
+ name: '',
+ version: '',
+ attrNames: [],
+ },
+ options: {},
+ }
+ const result = await service.registerSchema(mockAgentContext, options)
+ expect(mockHederaAnonCredsRegistry.registerSchema).toHaveBeenCalledWith({
+ ...options,
+ issuerKeyDer: expect.anything(),
+ })
+ expect(result).toBe('registerSchema')
+ })
+
+ it('getCredentialDefinition', async () => {
+ const result = await service.getCredentialDefinition(mockAgentContext, 'credDefId')
+ expect(mockHederaAnonCredsRegistry.getCredentialDefinition).toHaveBeenCalledWith('credDefId')
+ expect(result).toBe('credDef')
+ })
+
+ it('registerCredentialDefinition', async () => {
+ const options: RegisterCredentialDefinitionOptions = {
+ options: {
+ supportRevocation: true,
+ },
+ credentialDefinition: {
+ issuerId: '',
+ schemaId: '',
+ type: 'CL',
+ tag: '',
+ value: {
+ primary: {},
+ revocation: undefined,
+ },
+ },
+ }
+ await service.registerCredentialDefinition(mockAgentContext, options)
+ expect(mockHederaAnonCredsRegistry.registerCredentialDefinition).toHaveBeenCalledWith({
+ ...options,
+ issuerKeyDer: expect.anything(),
+ options: {
+ supportRevocation: true,
+ },
+ })
+ })
+
+ it('getRevocationRegistryDefinition', async () => {
+ const result = await service.getRevocationRegistryDefinition(mockAgentContext, 'revRegDefId')
+ expect(mockHederaAnonCredsRegistry.getRevocationRegistryDefinition).toHaveBeenCalledWith('revRegDefId')
+ expect(result).toBe('revRegDef')
+ })
+
+ it('registerRevocationRegistryDefinition', async () => {
+ const options: RegisterRevocationRegistryDefinitionOptions = {
+ revocationRegistryDefinition: {
+ issuerId: '',
+ revocDefType: 'CL_ACCUM',
+ credDefId: '',
+ tag: '',
+ value: {
+ publicKeys: {
+ accumKey: {
+ z: '',
+ },
+ },
+ maxCredNum: 0,
+ tailsLocation: '',
+ tailsHash: '',
+ },
+ },
+ options: {},
+ }
+ const result = await service.registerRevocationRegistryDefinition(mockAgentContext, options)
+ expect(mockHederaAnonCredsRegistry.registerRevocationRegistryDefinition).toHaveBeenCalledWith({
+ ...options,
+ issuerKeyDer: expect.anything(),
+ })
+ expect(result).toBe('registerRevRegDef')
+ })
+
+ it('getRevocationStatusList', async () => {
+ const result = await service.getRevocationStatusList(mockAgentContext, 'revRegId', 12345)
+ expect(mockHederaAnonCredsRegistry.getRevocationStatusList).toHaveBeenCalledWith('revRegId', 12345)
+ expect(result).toBe('revStatusList')
+ })
+
+ it('registerRevocationStatusList', async () => {
+ const options: RegisterRevocationStatusListOptions = {
+ options: {},
+ revocationStatusList: {
+ revRegDefId: '',
+ issuerId: '',
+ revocationList: [],
+ currentAccumulator: '',
+ },
+ }
+ const result = await service.registerRevocationStatusList(mockAgentContext, options)
+ expect(mockHederaAnonCredsRegistry.registerRevocationStatusList).toHaveBeenCalledWith({
+ ...options,
+ issuerKeyDer: expect.anything(),
+ })
+ expect(result).toBe('registerRevStatus')
+ })
+ })
+
+ describe('getIssuerPrivateKey', () => {
+ it('should return PrivateKey from secretBytes when rootKey exists', async () => {
+ const secretBytes = PrivateKey.generate().toBytes()
+ const keyInfo = { key: { secretBytes } }
+
+ const didRecord = {
+ keys: [{ didDocumentRelativeKeyId: DID_ROOT_KEY_ID, kmsKeyId: 'kms-key-id' }],
+ } as unknown as DidRecord
+
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValueOnce(didRecord)
+ // @ts-ignore
+ mockFunction(mockKeyManagementService.getKeyAsserted).mockResolvedValue(keyInfo)
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const result = await (service as any).getIssuerPrivateKey(mockAgentContext, 'issuer-id')
+
+ expect(mockDidRepository.findCreatedDid).toHaveBeenCalledWith(mockAgentContext, 'issuer-id')
+ // @ts-ignore
+ expect(mockKms.getKms).toHaveBeenCalledWith(mockAgentContext, 'askar')
+ // @ts-ignore
+ expect(mockKeyManagementService.getKeyAsserted).toHaveBeenCalledWith(mockAgentContext, 'kms-key-id')
+ expect(result).toEqual(PrivateKey.fromBytesED25519(secretBytes))
+ })
+
+ it('should throw error if no rootKey found', async () => {
+ const didRecord = {
+ keys: [],
+ } as unknown as DidRecord
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValue(didRecord)
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ await expect((service as any).getIssuerPrivateKey(mockAgentContext, 'issuer-id')).rejects.toThrow(
+ 'The root key not found in the KMS'
+ )
+ })
+
+ it('should throw error if didRecord is null or undefined', async () => {
+ mockFunction(mockDidRepository.findCreatedDid).mockResolvedValue(null)
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ await expect((service as any).getIssuerPrivateKey(mockAgentContext, 'issuer-id')).rejects.toThrow(
+ 'The root key not found in the KMS'
+ )
+ })
+ })
+})
diff --git a/packages/hedera/tests/unit/kms-publisher.test.ts b/packages/hedera/tests/unit/kms-publisher.test.ts
new file mode 100644
index 0000000000..42aa1adf23
--- /dev/null
+++ b/packages/hedera/tests/unit/kms-publisher.test.ts
@@ -0,0 +1,124 @@
+import { AgentContext, Kms, TypedArrayEncoder } from '@credo-ts/core'
+import { KmsJwkPublicOkp } from '@credo-ts/core/src/modules/kms'
+import { KeysUtility } from '@hiero-did-sdk/core'
+import { KmsPublisher } from '../../src/ledger/publisher/KmsPublisher'
+
+jest.mock('@hiero-did-sdk/core', () => ({
+ KeysUtility: {
+ fromBytes: jest.fn(),
+ },
+ DIDError: class DIDError extends Error {},
+}))
+
+jest.mock('@credo-ts/core', () => ({
+ TypedArrayEncoder: {
+ fromBase64: jest.fn(),
+ },
+ Kms: {
+ KeyManagementApi: jest.fn().mockImplementation(() => ({})),
+ },
+}))
+
+jest.mock('../../src/ledger/utils', () => ({
+ createOrGetKey: jest.fn(),
+}))
+import { createOrGetKey } from '../../src/ledger/utils'
+
+jest.mock('@hiero-did-sdk/publisher-internal', () => {
+ return {
+ Publisher: jest.fn(),
+ }
+})
+
+describe('KmsPublisher', () => {
+ const mockClient = {
+ freezeWith: jest.fn(),
+ signWith: jest.fn(),
+ execute: jest.fn(),
+ operator: {
+ accountId: '0.0.1234',
+ publicKey: {},
+ },
+ }
+
+ const mockFrozenTransaction = {
+ signWith: jest.fn(),
+ }
+
+ const mockResponse = {
+ getReceipt: jest.fn(),
+ }
+
+ const signMock = jest.fn().mockResolvedValue({ signature: 'signature-bytes' })
+
+ const kmsMock = {
+ sign: signMock,
+ }
+
+ const agentContext = {
+ dependencyManager: {
+ resolve: jest.fn().mockImplementation((key) => {
+ if (key === Kms.KeyManagementApi) {
+ return kmsMock
+ }
+ throw new Error(`Unexpected dependency: ${key}`)
+ }),
+ },
+ }
+
+ const keyId = 'test-key-id'
+ const base64X = 'base64-x'
+ const publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' } = { x: base64X, crv: 'Ed25519', kty: 'OKP' }
+ const key: { keyId: string; publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' } } = { keyId, publicJwk }
+
+ const mockPublicKey = {
+ toPublicKey: jest.fn(),
+ }
+
+ const fakePublicKey = {}
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+ ;(TypedArrayEncoder.fromBase64 as jest.Mock).mockReturnValue(new Uint8Array([1, 2, 3]))
+ ;(KeysUtility.fromBytes as jest.Mock).mockReturnValue(mockPublicKey)
+ mockPublicKey.toPublicKey.mockReturnValue(fakePublicKey)
+
+ mockClient.freezeWith.mockReturnValue(mockFrozenTransaction)
+
+ mockFrozenTransaction.signWith.mockImplementation(async (_publicKey, signCallback) => {
+ const signature = await signCallback(new Uint8Array([4, 5, 6]))
+ expect(signature).toBe('signature-bytes')
+ return
+ })
+
+ mockClient.execute.mockResolvedValue(mockResponse)
+
+ mockResponse.getReceipt.mockResolvedValue('receipt-object')
+ })
+
+ it('should correctly create an instance via constructor', () => {
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const publisher = new KmsPublisher(agentContext as any, mockClient as any, key)
+ expect(agentContext.dependencyManager.resolve).toHaveBeenCalledWith(expect.anything())
+ expect(publisher.publicKey()).toBe(fakePublicKey)
+ })
+
+ it('should correctly update key in setKeyId', async () => {
+ ;(createOrGetKey as jest.Mock).mockResolvedValue({
+ publicJwk: { x: base64X, crv: 'Ed25519' },
+ })
+
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const publisher = new KmsPublisher(agentContext as unknown as AgentContext, mockClient as any, key)
+ await publisher.setKeyId('new-key-id')
+
+ expect(createOrGetKey).toHaveBeenCalledWith(kmsMock, 'new-key-id')
+ expect(KeysUtility.fromBytes).toHaveBeenCalledTimes(2)
+ })
+
+ it('should return correct publicKey', () => {
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const publisher = new KmsPublisher(agentContext as unknown as AgentContext, mockClient as any, key)
+ expect(publisher.publicKey()).toBe(fakePublicKey)
+ })
+})
diff --git a/packages/hedera/tests/unit/utils.test.ts b/packages/hedera/tests/unit/utils.test.ts
new file mode 100644
index 0000000000..1b2901bf8a
--- /dev/null
+++ b/packages/hedera/tests/unit/utils.test.ts
@@ -0,0 +1,85 @@
+import { Kms } from '@credo-ts/core'
+import type { KeyManagementApi, KmsJwkPublicOkp, KmsJwkPublicRsa } from '@credo-ts/core/src/modules/kms'
+import { createOrGetKey, getMultibasePublicKey } from '../../src/ledger/utils'
+
+describe('getMultibasePublicKey', () => {
+ it('should return a base58 key string prefixed with "z"', () => {
+ const base64X = 'dGVzdGtleQ==' // base64 for 'testkey'
+ const publicJwk = {
+ crv: 'Ed25519',
+ x: base64X,
+ }
+ const multibaseKey = getMultibasePublicKey(publicJwk as KmsJwkPublicOkp & { crv: 'Ed25519' })
+
+ expect(multibaseKey.startsWith('z')).toBe(true)
+ expect(typeof multibaseKey).toBe('string')
+ })
+})
+
+describe('createOrGetKey', () => {
+ let kmsMock: jest.Mocked
+
+ beforeEach(() => {
+ kmsMock = {
+ createKey: jest.fn(),
+ getPublicKey: jest.fn(),
+ } as unknown as jest.Mocked
+ })
+
+ it('should create a key if keyId is not provided', async () => {
+ const fakeKeyId = 'key123'
+ const fakeJwk: KmsJwkPublicOkp & { kid: string } = { kty: 'OKP', crv: 'Ed25519', x: 'xxx', kid: 'key123' }
+ kmsMock.createKey.mockResolvedValue({
+ keyId: fakeKeyId,
+ publicJwk: fakeJwk,
+ })
+
+ const result = await createOrGetKey(kmsMock, undefined)
+
+ expect(kmsMock.createKey).toHaveBeenCalledWith({ type: { crv: 'Ed25519', kty: 'OKP' } })
+ expect(result).toEqual({
+ keyId: fakeKeyId,
+ publicJwk: fakeJwk,
+ })
+ })
+
+ it('should retrieve an existing key if keyId is provided', async () => {
+ const keyId = 'key456'
+ const publicJwk: KmsJwkPublicOkp & { kid: string } = { kty: 'OKP', crv: 'Ed25519', x: 'xxx', kid: 'key123' }
+ kmsMock.getPublicKey.mockResolvedValue(publicJwk)
+
+ const result = await createOrGetKey(kmsMock, keyId)
+
+ expect(kmsMock.getPublicKey).toHaveBeenCalledWith({ keyId })
+ expect(result).toEqual({
+ keyId,
+ publicJwk: {
+ ...publicJwk,
+ crv: publicJwk.crv,
+ },
+ })
+ })
+
+ it('should throw an error if key with given keyId is not found', async () => {
+ // @ts-ignore
+ kmsMock.getPublicKey.mockResolvedValue(null)
+
+ // Expect the function to throw an error for a missing key
+ await expect(createOrGetKey(kmsMock, 'notfound')).rejects.toThrowError("Key with key id 'notfound' not found")
+ })
+
+ it('should throw an error if key has unsupported kty or crv', async () => {
+ const keyId = 'badkey'
+ const badJwk: KmsJwkPublicRsa & { kid: string } = { e: '', kid: 'key-1', n: '', kty: 'RSA' }
+
+ kmsMock.getPublicKey.mockResolvedValue(badJwk)
+
+ const spyDesc = jest.spyOn(Kms, 'getJwkHumanDescription').mockReturnValue('unsupported key type')
+
+ await expect(createOrGetKey(kmsMock, keyId)).rejects.toThrow(
+ `Key with key id '${keyId}' uses unsupported unsupported key type for did:hedera`
+ )
+
+ spyDesc.mockRestore()
+ })
+})
diff --git a/packages/hedera/tsconfig.build.json b/packages/hedera/tsconfig.build.json
new file mode 100644
index 0000000000..e7ee40ad18
--- /dev/null
+++ b/packages/hedera/tsconfig.build.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.build.json",
+ "compilerOptions": {
+ "outDir": "./build",
+ "baseUrl": ".",
+ "skipDefaultLibCheck": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["../core"]
+}
diff --git a/packages/hedera/tsconfig.json b/packages/hedera/tsconfig.json
new file mode 100644
index 0000000000..dcd84a3af2
--- /dev/null
+++ b/packages/hedera/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "types": ["jest"],
+ "moduleResolution": "node"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c73a0244ca..748523b3d3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -195,12 +195,18 @@ importers:
'@credo-ts/didcomm':
specifier: workspace:*
version: link:../packages/didcomm
+ '@credo-ts/hedera':
+ specifier: workspace:*
+ version: link:../packages/hedera
'@credo-ts/indy-vdr':
specifier: workspace:*
version: link:../packages/indy-vdr
'@credo-ts/node':
specifier: workspace:*
version: link:../packages/node
+ '@hiero-did-sdk/client':
+ specifier: 0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
'@types/figlet':
specifier: ^1.5.4
version: 1.5.8
@@ -663,6 +669,52 @@ importers:
specifier: 'catalog:'
version: 5.8.3
+ packages/hedera:
+ dependencies:
+ '@credo-ts/anoncreds':
+ specifier: workspace:*
+ version: link:../anoncreds
+ '@credo-ts/core':
+ specifier: workspace:*
+ version: link:../core
+ '@hashgraph/sdk':
+ specifier: ^2.72.0
+ version: 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/anoncreds':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/client':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/hcs':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/publisher-internal':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/registrar':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/resolver':
+ specifier: ^0.1.3
+ version: 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ devDependencies:
+ '@credo-ts/node':
+ specifier: workspace:*
+ version: link:../node
+ '@hyperledger/anoncreds-nodejs':
+ specifier: ^0.3.1
+ version: 0.3.1
+ rimraf:
+ specifier: ^4.4.0
+ version: 4.4.1
+ zstd-napi:
+ specifier: ^0.0.10
+ version: 0.0.10
+
packages/indy-sdk-to-askar-migration:
dependencies:
'@credo-ts/anoncreds':
@@ -1940,6 +1992,36 @@ packages:
'@bufbuild/protobuf@2.2.5':
resolution: {integrity: sha512-/g5EzJifw5GF8aren8wZ/G5oMuPoGeS6MQD3ca8ddcvdXR5UELUfdTZITCGNhNXynY/AYl3Z4plmxdj/tRl/hQ==}
+ '@cbor-extract/cbor-extract-darwin-arm64@2.2.0':
+ resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@cbor-extract/cbor-extract-darwin-x64@2.2.0':
+ resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@cbor-extract/cbor-extract-linux-arm64@2.2.0':
+ resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@cbor-extract/cbor-extract-linux-arm@2.2.0':
+ resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==}
+ cpu: [arm]
+ os: [linux]
+
+ '@cbor-extract/cbor-extract-linux-x64@2.2.0':
+ resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@cbor-extract/cbor-extract-win32-x64@2.2.0':
+ resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==}
+ cpu: [x64]
+ os: [win32]
+
'@changesets/apply-release-plan@7.0.12':
resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==}
@@ -2308,6 +2390,60 @@ packages:
cpu: [x64]
os: [win32]
+ '@ethersproject/abi@5.8.0':
+ resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==}
+
+ '@ethersproject/abstract-provider@5.8.0':
+ resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==}
+
+ '@ethersproject/abstract-signer@5.8.0':
+ resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==}
+
+ '@ethersproject/address@5.8.0':
+ resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==}
+
+ '@ethersproject/base64@5.8.0':
+ resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==}
+
+ '@ethersproject/bignumber@5.8.0':
+ resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==}
+
+ '@ethersproject/bytes@5.8.0':
+ resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==}
+
+ '@ethersproject/constants@5.8.0':
+ resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==}
+
+ '@ethersproject/hash@5.8.0':
+ resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==}
+
+ '@ethersproject/keccak256@5.8.0':
+ resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==}
+
+ '@ethersproject/logger@5.8.0':
+ resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==}
+
+ '@ethersproject/networks@5.8.0':
+ resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==}
+
+ '@ethersproject/properties@5.8.0':
+ resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==}
+
+ '@ethersproject/rlp@5.8.0':
+ resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==}
+
+ '@ethersproject/signing-key@5.8.0':
+ resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==}
+
+ '@ethersproject/strings@5.8.0':
+ resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==}
+
+ '@ethersproject/transactions@5.8.0':
+ resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==}
+
+ '@ethersproject/web@5.8.0':
+ resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==}
+
'@expo/bunyan@4.0.0':
resolution: {integrity: sha512-Ydf4LidRB/EBI+YrB+cVLqIseiRfjUI/AeHBgjGMtq3GroraDu81OV7zqophRgupngoL3iS3JUMDMnxO7g39qA==}
engines: {'0': node >=0.10.0}
@@ -2381,6 +2517,15 @@ packages:
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ '@grpc/grpc-js@1.13.4':
+ resolution: {integrity: sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg==}
+ engines: {node: '>=12.10.0'}
+
+ '@grpc/proto-loader@0.7.15':
+ resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==}
+ engines: {node: '>=6'}
+ hasBin: true
+
'@hapi/bourne@3.0.0':
resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
@@ -2390,6 +2535,81 @@ packages:
'@hapi/topo@5.1.0':
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+ '@hashgraph/cryptography@1.9.0':
+ resolution: {integrity: sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ expo-crypto: '*'
+ peerDependenciesMeta:
+ expo-crypto:
+ optional: true
+
+ '@hashgraph/proto@2.22.0':
+ resolution: {integrity: sha512-+h2qqk+KwpV+rr1AN4ip1Gel3X4v0DvFO9WH7o0ZR3gQX9pfzurptKGs30DlBnH21xPqDH61v90bZvVknE27NA==}
+ engines: {node: '>=10.0.0'}
+
+ '@hashgraph/sdk@2.72.0':
+ resolution: {integrity: sha512-w35M77OAkJutENG4CldUGzfT+qubDjEYCQR5Ran75uHB+SLeCodR87AXWJ3ocr5vPaZ7lsflBXEYZLhgCi1G2g==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ bn.js: ^5.2.1
+
+ '@hiero-did-sdk/anoncreds@0.1.3':
+ resolution: {integrity: sha512-SUeUdHFbZTHF5fTGZTcMqrAFfQTQBdFhFvUCf95Yv1MGYMaLEZfPaCs/x95/TjJFN1j9F0nZlvEkJnW56OoGow==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/cache@0.1.3':
+ resolution: {integrity: sha512-ucmuFhZNZwI3BRzxUU+x7T50n4O7t6Y9dRTxNM7cQOYajwyGTNDuR/2Mp87DqvlGXKEj8Yj5JYE/1hX+fdZViQ==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/client@0.1.3':
+ resolution: {integrity: sha512-DE/xiQCz83zlxO1pmouy+wSvxbMBsKPgfCRTW0Kr7FuVqnBP6ihCbNfdPU9Sj9jgVyGQIey+UPNRiY5lzYYvrA==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/core@0.1.3':
+ resolution: {integrity: sha512-v0O2ssemyBVZuduwjojdHL66YCo322Z+xGIt7cd2UCNu8beztGF5eRJxY+W+mCX/H3m8lcxqL2hAcF04KmhEjQ==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/crypto@0.1.3':
+ resolution: {integrity: sha512-xQnJXHPSFVT56kz2EHqBRVPUqrqNPDmRRYHaeqctvm+62cjKhYv+ja/w7CWamoMlobLe1bzU1KZqVQDWqBDUbQ==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/hcs@0.1.3':
+ resolution: {integrity: sha512-Gm43RLGDUpGfc/olCMQEMgZXP11ZZt8WMsb/7VaN5fNhxf6qE2y2k7V9thcJSqrSvJ2nvZeWDzGnCcb4VIj+pg==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/lifecycle@0.1.3':
+ resolution: {integrity: sha512-A2Mlsxtx8XZAUxpcNBnHvNENdlC0vNaSDU8eFXpxpA9B7LP/Bx/WaH0RYOW1nZBiXMaApBGLbZoJPTTbWRE5Mg==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/messages@0.1.3':
+ resolution: {integrity: sha512-5WNmNbxNDRTTsfjObE09Su7ERBAVjQNcKFgPC0oBvDhyEE3cknYcBkc9P+G8Uoee/+zxebfZR9KTISqbvdQ9lw==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/publisher-internal@0.1.3':
+ resolution: {integrity: sha512-qGsV3no4jUo/R0VzcDar3hZ+IiaHJVnhdM6fmrUPNikbnVhTTNmJ5g2ci0Ed6NkXhPCuaJtcCK4SgGdEB6jOrQ==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/registrar@0.1.3':
+ resolution: {integrity: sha512-EDuuNRzkgLbWXacqaF59q7Do3U1p1w11g33FaJNWJ0gCd0S6imrxwUfDE/6THQjhSOVtfkqzo8Ge2Vm/pLQUQg==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/resolver@0.1.3':
+ resolution: {integrity: sha512-TfSCcC0gGU/jgiJK5qr6cwW1Mpmj9vYwIo24YygUxXP47+wPQ4suk/K5FlAsPOq8oga47RwLWVFX+ys66Y2r1w==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/signer-internal@0.1.3':
+ resolution: {integrity: sha512-W5yMxz5VSnJA6B5M02YggbhcSDgQnTK50lBv5koTF534gR0vRSuX49i02EqxUrBB3NTahZ7vWNhr+YrP6t6Akw==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/verifier-internal@0.1.3':
+ resolution: {integrity: sha512-ybGwSU+9rA9pIOeGkCCiFIcbgG/WvW85igBj2wWQPCwH9G9c6qW/alHX5Az/9C7O//f2/CzVaHeVVFQ1CTcLBg==}
+ engines: {node: '>=20'}
+
+ '@hiero-did-sdk/zstd@0.1.3':
+ resolution: {integrity: sha512-s+kqRhNbtMhGA7X6CtiTgGpLGqVAflxdPAJ5PqblgSGosa6m23SIe9rTC5mRkOziJ4NeoYvx2/NuosT2faSJKw==}
+ engines: {node: '>=20'}
+
'@hyperledger/anoncreds-nodejs@0.3.1':
resolution: {integrity: sha512-/oWmWgcOPqjAtd2+dKASPYL84Qd7sAFyCBfEKM7PAgVbObaZUZc0kqA7hkEz/qyiqUvcP/JwKTc1v4zVZi6BTg==}
engines: {node: '>= 18'}
@@ -2549,6 +2769,9 @@ packages:
peerDependencies:
'@js-joda/core': '>=1.11.0'
+ '@js-sdsl/ordered-map@4.4.2':
+ resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==}
+
'@koa/bodyparser@5.1.1':
resolution: {integrity: sha512-ZBF49xqNVxnmJ+8iXegq+fXPQm9RSX8giNl/aXS5rW1VpNct92wnFbGR/47vfoRJVLARGQ4HVL4WaQ0u8IJVoA==}
engines: {node: '>= 16'}
@@ -2846,8 +3069,8 @@ packages:
resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==}
engines: {node: '>=14.15'}
- '@scure/base@1.2.1':
- resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==}
+ '@scure/base@1.2.6':
+ resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==}
'@sd-jwt/core@0.10.0':
resolution: {integrity: sha512-EuFsIHP76fwNi97dGcz2jdEenHL/AkDGcqrEA00k82Uw0HP/hvbAfB+yyPxYrd3dVaxe5PWSKvDkgDK6kKk+6Q==}
@@ -3405,6 +3628,10 @@ packages:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
+ atomic-sleep@1.0.0:
+ resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
+ engines: {node: '>=8.0.0'}
+
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@@ -3692,6 +3919,13 @@ packages:
canonicalize@2.0.0:
resolution: {integrity: sha512-ulDEYPv7asdKvqahuAY35c1selLdzDwHqugK92hfkzvlDCwXRRelDkR+Er33md/PtnpqHemgkuDPanZ4fiYZ8w==}
+ cbor-extract@2.2.0:
+ resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==}
+ hasBin: true
+
+ cbor-x@1.6.0:
+ resolution: {integrity: sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==}
+
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@@ -3710,6 +3944,9 @@ packages:
charenc@0.0.2:
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
+ chownr@1.1.4:
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+
chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
@@ -3819,6 +4056,9 @@ packages:
colorette@1.4.0:
resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
+ colorette@2.0.20:
+ resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
@@ -3962,6 +4202,9 @@ packages:
crypt@0.0.2:
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
+ crypto-js@4.2.0:
+ resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
+
crypto-ld@6.0.0:
resolution: {integrity: sha512-XWL1LslqggNoaCI/m3I7HcvaSt9b2tYzdrXO+jHLUj9G1BvRfvV7ZTFDVY5nifYuIGAPdAGu7unPxLRustw3VA==}
engines: {node: '>=8.3.0'}
@@ -4001,6 +4244,9 @@ packages:
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
engines: {node: '>= 0.4'}
+ dateformat@4.6.3:
+ resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
+
dayjs@1.11.11:
resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
@@ -4381,6 +4627,10 @@ packages:
resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
engines: {node: '>= 0.8.0'}
+ expand-template@2.0.3:
+ resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
+ engines: {node: '>=6'}
+
expect@29.7.0:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -4451,6 +4701,9 @@ packages:
fast-base64-decode@1.0.0:
resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==}
+ fast-copy@3.0.2:
+ resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -4464,6 +4717,10 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ fast-redact@3.5.0:
+ resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==}
+ engines: {node: '>=6'}
+
fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
@@ -4595,6 +4852,10 @@ packages:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
+ forge-light@1.1.4:
+ resolution: {integrity: sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g==}
+ engines: {node: '>= 6.13.0'}
+
form-data-encoder@2.1.4:
resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
engines: {node: '>= 14.17'}
@@ -4630,6 +4891,9 @@ packages:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'}
+ fs-constants@1.0.0:
+ resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+
fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'}
@@ -4730,6 +4994,9 @@ packages:
resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==}
engines: {node: '>=6'}
+ github-from-package@0.0.0:
+ resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
+
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -4840,6 +5107,9 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ help-me@5.0.0:
+ resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
+
hermes-estree@0.19.1:
resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==}
@@ -5412,9 +5682,16 @@ packages:
jose@5.10.0:
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
+ joycon@3.1.1:
+ resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
+ engines: {node: '>=10'}
+
js-base64@3.7.7:
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
+ js-sha3@0.8.0:
+ resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -5649,6 +5926,9 @@ packages:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
+ lodash.camelcase@4.3.0:
+ resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
+
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
@@ -5848,7 +6128,6 @@ packages:
metro-react-native-babel-preset@0.73.10:
resolution: {integrity: sha512-1/dnH4EHwFb2RKEKx34vVDpUS3urt2WEeR8FYim+ogqALg4sTpG7yeQPxWpbgKATezt4rNfqAANpIyH19MS4BQ==}
- deprecated: Use @react-native/babel-preset instead
peerDependencies:
'@babel/core': '*'
@@ -6017,6 +6296,9 @@ packages:
resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==}
engines: {node: '>= 18'}
+ mkdirp-classic@0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+
mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
@@ -6079,6 +6361,9 @@ packages:
engines: {node: ^18 || >=20}
hasBin: true
+ napi-build-utils@2.0.0:
+ resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
+
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@@ -6110,12 +6395,19 @@ packages:
resolution: {integrity: sha512-R49fALR9caB6vxuSWUIaK2eBYeTloZQUFBZ4rHO+TbhMGQHtwnhdqKLYki+o+8qMgLvoBYWrp/2KzGPhxL4S6w==}
engines: {node: '>=18.20.0 <20 || >=20.12.1'}
+ node-abi@3.75.0:
+ resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
+ engines: {node: '>=10'}
+
node-addon-api@3.2.1:
resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
node-addon-api@5.1.0:
resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
node-dir@0.1.17:
resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==}
engines: {node: '>= 0.10.5'}
@@ -6146,6 +6438,10 @@ packages:
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
engines: {node: '>= 6.13.0'}
+ node-gyp-build-optional-packages@5.1.1:
+ resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==}
+ hasBin: true
+
node-gyp-build@4.8.1:
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
hasBin: true
@@ -6228,6 +6524,10 @@ packages:
resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==}
engines: {node: ^10.13.0 || >=12.0.0}
+ on-exit-leak-free@2.1.2:
+ resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
+ engines: {node: '>=14.0.0'}
+
on-finished@2.3.0:
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
engines: {node: '>= 0.8'}
@@ -6436,6 +6736,20 @@ packages:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
engines: {node: '>=6'}
+ pino-abstract-transport@2.0.0:
+ resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==}
+
+ pino-pretty@13.1.1:
+ resolution: {integrity: sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA==}
+ hasBin: true
+
+ pino-std-serializers@7.0.0:
+ resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==}
+
+ pino@9.9.0:
+ resolution: {integrity: sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ==}
+ hasBin: true
+
pirates@4.0.6:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
@@ -6464,6 +6778,11 @@ packages:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
+ prebuild-install@7.1.3:
+ resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
+ engines: {node: '>=10'}
+ hasBin: true
+
prelude-ls@1.1.2:
resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
engines: {node: '>= 0.8.0'}
@@ -6492,6 +6811,9 @@ packages:
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+ process-warning@5.0.0:
+ resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
+
progress@2.0.3:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
@@ -6517,6 +6839,10 @@ packages:
resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==}
hasBin: true
+ protobufjs@7.2.5:
+ resolution: {integrity: sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==}
+ engines: {node: '>=12.0.0'}
+
protobufjs@7.4.0:
resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==}
engines: {node: '>=12.0.0'}
@@ -6538,9 +6864,6 @@ packages:
pure-rand@6.1.0:
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
- pvtsutils@1.3.5:
- resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==}
-
pvtsutils@1.3.6:
resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==}
@@ -6573,6 +6896,9 @@ packages:
queue@6.0.2:
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
+ quick-format-unescaped@4.0.4:
+ resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
+
quick-lru@5.1.1:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
@@ -6676,6 +7002,10 @@ packages:
readonly-date@1.0.0:
resolution: {integrity: sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==}
+ real-require@0.2.0:
+ resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
+ engines: {node: '>= 12.13.0'}
+
recast@0.21.5:
resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==}
engines: {node: '>= 4'}
@@ -6797,6 +7127,9 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ rfc4648@1.5.4:
+ resolution: {integrity: sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==}
+
rimraf@2.2.8:
resolution: {integrity: sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==}
deprecated: Rimraf versions prior to v4 are no longer supported
@@ -6867,6 +7200,10 @@ packages:
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
engines: {node: '>= 0.4'}
+ safe-stable-stringify@2.5.0:
+ resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
+ engines: {node: '>=10'}
+
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
@@ -6880,6 +7217,9 @@ packages:
resolution: {integrity: sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==}
engines: {node: '>=18.0.0'}
+ secure-json-parse@4.0.0:
+ resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==}
+
selfsigned@2.4.1:
resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==}
engines: {node: '>=10'}
@@ -6989,6 +7329,12 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
+ simple-concat@1.0.1:
+ resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+
+ simple-get@4.0.1:
+ resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
+
simple-plist@1.3.1:
resolution: {integrity: sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==}
@@ -7007,6 +7353,9 @@ packages:
resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
engines: {node: '>=8.0.0'}
+ sonic-boom@4.2.0:
+ resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==}
+
source-map-js@1.2.0:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
@@ -7029,6 +7378,9 @@ packages:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
+ spark-md5@3.0.2:
+ resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==}
+
spawndamnit@3.0.1:
resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==}
@@ -7036,6 +7388,10 @@ packages:
resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
engines: {node: '>=6'}
+ split2@4.2.0:
+ resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
+ engines: {node: '>= 10.x'}
+
split@1.0.1:
resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==}
@@ -7155,6 +7511,10 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
+ strip-json-comments@5.0.3:
+ resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==}
+ engines: {node: '>=14.16'}
+
strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
@@ -7189,6 +7549,7 @@ packages:
superagent@10.2.1:
resolution: {integrity: sha512-O+PCv11lgTNJUzy49teNAWLjBZfc+A1enOwTpLlH6/rsvKcTwcdTT8m9azGkVqM7HBl5jpyZ7KTPhHweokBcdg==}
engines: {node: '>=14.18.0'}
+ deprecated: Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net
supertest@7.1.1:
resolution: {integrity: sha512-aI59HBTlG9e2wTjxGJV+DygfNLgnWbGdZxiA/sgrnNNikIW8lbDvCtF6RnhZoJ82nU7qv7ZLjrvWqCEm52fAmw==}
@@ -7219,6 +7580,13 @@ packages:
resolution: {integrity: sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==}
engines: {node: '>=0.10'}
+ tar-fs@2.1.3:
+ resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==}
+
+ tar-stream@2.2.0:
+ resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+ engines: {node: '>=6'}
+
tar@6.2.1:
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
engines: {node: '>=10'}
@@ -7278,6 +7646,9 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ thread-stream@3.1.0:
+ resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
+
throat@5.0.0:
resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==}
@@ -7392,6 +7763,12 @@ packages:
resolution: {integrity: sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==}
engines: {node: '>= 6.0.0'}
+ tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+
+ tweetnacl@1.0.3:
+ resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
+
type-check@0.3.2:
resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}
engines: {node: '>= 0.8.0'}
@@ -7833,6 +8210,10 @@ packages:
zod@3.25.67:
resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==}
+ zstd-napi@0.0.10:
+ resolution: {integrity: sha512-pwnG+auSiIrD2BNSIpPEUtcRSK33cfYmKo3sJPTohFiPqPci9F4SIRPR7gGeI45Maj4nFoyyxzT2YDxVXIIgzQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || ^15.12.0 || >=16}
+
snapshots:
'@2060.io/ffi-napi@4.0.9':
@@ -8991,6 +9372,24 @@ snapshots:
'@bufbuild/protobuf@2.2.5': {}
+ '@cbor-extract/cbor-extract-darwin-arm64@2.2.0':
+ optional: true
+
+ '@cbor-extract/cbor-extract-darwin-x64@2.2.0':
+ optional: true
+
+ '@cbor-extract/cbor-extract-linux-arm64@2.2.0':
+ optional: true
+
+ '@cbor-extract/cbor-extract-linux-arm@2.2.0':
+ optional: true
+
+ '@cbor-extract/cbor-extract-linux-x64@2.2.0':
+ optional: true
+
+ '@cbor-extract/cbor-extract-win32-x64@2.2.0':
+ optional: true
+
'@changesets/apply-release-plan@7.0.12':
dependencies:
'@changesets/config': 3.1.1
@@ -9621,6 +10020,129 @@ snapshots:
'@esbuild/win32-x64@0.25.5':
optional: true
+ '@ethersproject/abi@5.8.0':
+ dependencies:
+ '@ethersproject/address': 5.8.0
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/constants': 5.8.0
+ '@ethersproject/hash': 5.8.0
+ '@ethersproject/keccak256': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/properties': 5.8.0
+ '@ethersproject/strings': 5.8.0
+
+ '@ethersproject/abstract-provider@5.8.0':
+ dependencies:
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/networks': 5.8.0
+ '@ethersproject/properties': 5.8.0
+ '@ethersproject/transactions': 5.8.0
+ '@ethersproject/web': 5.8.0
+
+ '@ethersproject/abstract-signer@5.8.0':
+ dependencies:
+ '@ethersproject/abstract-provider': 5.8.0
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/properties': 5.8.0
+
+ '@ethersproject/address@5.8.0':
+ dependencies:
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/keccak256': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/rlp': 5.8.0
+
+ '@ethersproject/base64@5.8.0':
+ dependencies:
+ '@ethersproject/bytes': 5.8.0
+
+ '@ethersproject/bignumber@5.8.0':
+ dependencies:
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ bn.js: 5.2.1
+
+ '@ethersproject/bytes@5.8.0':
+ dependencies:
+ '@ethersproject/logger': 5.8.0
+
+ '@ethersproject/constants@5.8.0':
+ dependencies:
+ '@ethersproject/bignumber': 5.8.0
+
+ '@ethersproject/hash@5.8.0':
+ dependencies:
+ '@ethersproject/abstract-signer': 5.8.0
+ '@ethersproject/address': 5.8.0
+ '@ethersproject/base64': 5.8.0
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/keccak256': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/properties': 5.8.0
+ '@ethersproject/strings': 5.8.0
+
+ '@ethersproject/keccak256@5.8.0':
+ dependencies:
+ '@ethersproject/bytes': 5.8.0
+ js-sha3: 0.8.0
+
+ '@ethersproject/logger@5.8.0': {}
+
+ '@ethersproject/networks@5.8.0':
+ dependencies:
+ '@ethersproject/logger': 5.8.0
+
+ '@ethersproject/properties@5.8.0':
+ dependencies:
+ '@ethersproject/logger': 5.8.0
+
+ '@ethersproject/rlp@5.8.0':
+ dependencies:
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/logger': 5.8.0
+
+ '@ethersproject/signing-key@5.8.0':
+ dependencies:
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/properties': 5.8.0
+ bn.js: 5.2.1
+ elliptic: 6.6.1
+ hash.js: 1.1.7
+
+ '@ethersproject/strings@5.8.0':
+ dependencies:
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/constants': 5.8.0
+ '@ethersproject/logger': 5.8.0
+
+ '@ethersproject/transactions@5.8.0':
+ dependencies:
+ '@ethersproject/address': 5.8.0
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/constants': 5.8.0
+ '@ethersproject/keccak256': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/properties': 5.8.0
+ '@ethersproject/rlp': 5.8.0
+ '@ethersproject/signing-key': 5.8.0
+
+ '@ethersproject/web@5.8.0':
+ dependencies:
+ '@ethersproject/base64': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/logger': 5.8.0
+ '@ethersproject/properties': 5.8.0
+ '@ethersproject/strings': 5.8.0
+
'@expo/bunyan@4.0.0':
dependencies:
uuid: 8.3.2
@@ -9906,6 +10428,18 @@ snapshots:
dependencies:
graphql: 15.8.0
+ '@grpc/grpc-js@1.13.4':
+ dependencies:
+ '@grpc/proto-loader': 0.7.15
+ '@js-sdsl/ordered-map': 4.4.2
+
+ '@grpc/proto-loader@0.7.15':
+ dependencies:
+ lodash.camelcase: 4.3.0
+ long: 5.3.1
+ protobufjs: 7.4.0
+ yargs: 17.7.2
+
'@hapi/bourne@3.0.0': {}
'@hapi/hoek@9.3.0':
@@ -9916,6 +10450,190 @@ snapshots:
'@hapi/hoek': 9.3.0
optional: true
+ '@hashgraph/cryptography@1.9.0(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@noble/curves': 1.9.2
+ asn1js: 3.0.6
+ bignumber.js: 9.1.2
+ bn.js: 5.2.1
+ buffer: 6.0.3
+ crypto-js: 4.2.0
+ forge-light: 1.1.4
+ js-base64: 3.7.7
+ react-native-get-random-values: 1.11.0(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ spark-md5: 3.0.2
+ tweetnacl: 1.0.3
+ utf8: 3.0.0
+ transitivePeerDependencies:
+ - react-native
+
+ '@hashgraph/proto@2.22.0':
+ dependencies:
+ long: 5.3.1
+ protobufjs: 7.2.5
+
+ '@hashgraph/sdk@2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@ethersproject/abi': 5.8.0
+ '@ethersproject/bignumber': 5.8.0
+ '@ethersproject/bytes': 5.8.0
+ '@ethersproject/rlp': 5.8.0
+ '@grpc/grpc-js': 1.13.4
+ '@hashgraph/cryptography': 1.9.0(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hashgraph/proto': 2.22.0
+ bignumber.js: 9.1.2
+ bn.js: 5.2.1
+ crypto-js: 4.2.0
+ js-base64: 3.7.7
+ long: 5.3.1
+ pino: 9.9.0
+ pino-pretty: 13.1.1
+ protobufjs: 7.2.5
+ rfc4648: 1.5.4
+ utf8: 3.0.0
+ transitivePeerDependencies:
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/anoncreds@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/hcs': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/zstd': 0.1.3
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/cache@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/client@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/core@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@scure/base': 1.2.6
+ buffer: 6.0.3
+ cbor-x: 1.6.0
+ varint: 6.0.0
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/crypto@0.1.3':
+ dependencies:
+ buffer: 6.0.3
+
+ '@hiero-did-sdk/hcs@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/cache': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/client': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/crypto': 0.1.3
+ '@hiero-did-sdk/zstd': 0.1.3
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/lifecycle@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/messages@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/lifecycle': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/resolver': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/publisher-internal@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/registrar@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/lifecycle': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/messages': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/publisher-internal': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/resolver': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/signer-internal': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/verifier-internal': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/resolver@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/client': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/hcs': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/verifier-internal': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/signer-internal@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/verifier-internal@0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))':
+ dependencies:
+ '@hashgraph/sdk': 2.72.0(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ '@hiero-did-sdk/core': 0.1.3(bn.js@5.2.1)(react-native@0.79.4(@babel/core@7.27.7)(@react-native-community/cli@10.2.7(@babel/core@7.27.7))(react@18.3.1))
+ buffer: 6.0.3
+ transitivePeerDependencies:
+ - bn.js
+ - expo-crypto
+ - react-native
+
+ '@hiero-did-sdk/zstd@0.1.3': {}
+
'@hyperledger/anoncreds-nodejs@0.3.1':
dependencies:
'@2060.io/ffi-napi': 4.0.9
@@ -10200,6 +10918,8 @@ snapshots:
dependencies:
'@js-joda/core': 5.6.3
+ '@js-sdsl/ordered-map@4.4.2': {}
+
'@koa/bodyparser@5.1.1(koa@2.16.0)':
dependencies:
co-body: 6.2.0
@@ -10741,7 +11461,7 @@ snapshots:
metro: 0.82.4
metro-config: 0.82.4
metro-core: 0.82.4
- semver: 7.6.2
+ semver: 7.7.2
optionalDependencies:
'@react-native-community/cli': 10.2.7(@babel/core@7.27.7)
transitivePeerDependencies:
@@ -10818,7 +11538,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@scure/base@1.2.1': {}
+ '@scure/base@1.2.6': {}
'@sd-jwt/core@0.10.0':
dependencies:
@@ -11418,7 +12138,7 @@ snapshots:
asn1js@3.0.5:
dependencies:
- pvtsutils: 1.3.5
+ pvtsutils: 1.3.6
pvutils: 1.1.3
tslib: 2.8.1
@@ -11449,6 +12169,8 @@ snapshots:
at-least-node@1.0.0: {}
+ atomic-sleep@1.0.0: {}
+
available-typed-arrays@1.0.7:
dependencies:
possible-typed-array-names: 1.0.0
@@ -11864,6 +12586,22 @@ snapshots:
canonicalize@2.0.0: {}
+ cbor-extract@2.2.0:
+ dependencies:
+ node-gyp-build-optional-packages: 5.1.1
+ optionalDependencies:
+ '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0
+ '@cbor-extract/cbor-extract-darwin-x64': 2.2.0
+ '@cbor-extract/cbor-extract-linux-arm': 2.2.0
+ '@cbor-extract/cbor-extract-linux-arm64': 2.2.0
+ '@cbor-extract/cbor-extract-linux-x64': 2.2.0
+ '@cbor-extract/cbor-extract-win32-x64': 2.2.0
+ optional: true
+
+ cbor-x@1.6.0:
+ optionalDependencies:
+ cbor-extract: 2.2.0
+
chalk@2.4.2:
dependencies:
ansi-styles: 3.2.1
@@ -11881,6 +12619,8 @@ snapshots:
charenc@0.0.2: {}
+ chownr@1.1.4: {}
+
chownr@2.0.0: {}
chownr@3.0.0: {}
@@ -11989,6 +12729,8 @@ snapshots:
colorette@1.4.0:
optional: true
+ colorette@2.0.20: {}
+
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
@@ -12156,6 +12898,8 @@ snapshots:
crypt@0.0.2: {}
+ crypto-js@4.2.0: {}
+
crypto-ld@6.0.0: {}
crypto-random-string@1.0.0: {}
@@ -12191,6 +12935,8 @@ snapshots:
es-errors: 1.3.0
is-data-view: 1.0.2
+ dateformat@4.6.3: {}
+
dayjs@1.11.11:
optional: true
@@ -12307,7 +13053,7 @@ snapshots:
'@noble/ciphers': 1.2.1
'@noble/curves': 1.9.2
'@noble/hashes': 1.8.0
- '@scure/base': 1.2.1
+ '@scure/base': 1.2.6
canonicalize: 2.0.0
did-resolver: 4.1.0
multibase: 4.0.6
@@ -12605,6 +13351,8 @@ snapshots:
exit@0.1.2: {}
+ expand-template@2.0.3: {}
+
expect@29.7.0:
dependencies:
'@jest/expect-utils': 29.7.0
@@ -12749,6 +13497,8 @@ snapshots:
fast-base64-decode@1.0.0: {}
+ fast-copy@3.0.2: {}
+
fast-deep-equal@3.1.3: {}
fast-glob@3.3.2:
@@ -12763,6 +13513,8 @@ snapshots:
fast-levenshtein@2.0.6: {}
+ fast-redact@3.5.0: {}
+
fast-safe-stringify@2.1.1: {}
fast-text-encoding@1.0.6: {}
@@ -12917,6 +13669,8 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
+ forge-light@1.1.4: {}
+
form-data-encoder@2.1.4: {}
form-data@3.0.1:
@@ -12951,6 +13705,8 @@ snapshots:
fresh@0.5.2: {}
+ fs-constants@1.0.0: {}
+
fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11
@@ -13073,6 +13829,8 @@ snapshots:
getenv@1.0.0: {}
+ github-from-package@0.0.0: {}
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -13209,6 +13967,8 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ help-me@5.0.0: {}
+
hermes-estree@0.19.1: {}
hermes-estree@0.25.1: {}
@@ -14013,8 +14773,12 @@ snapshots:
jose@5.10.0: {}
+ joycon@3.1.1: {}
+
js-base64@3.7.7: {}
+ js-sha3@0.8.0: {}
+
js-tokens@4.0.0: {}
js-yaml@3.14.1:
@@ -14268,6 +15032,8 @@ snapshots:
dependencies:
p-locate: 5.0.0
+ lodash.camelcase@4.3.0: {}
+
lodash.debounce@4.0.8: {}
lodash.defaults@4.2.0: {}
@@ -14917,6 +15683,8 @@ snapshots:
minipass: 7.1.2
rimraf: 5.0.10
+ mkdirp-classic@0.5.3: {}
+
mkdirp@0.5.6:
dependencies:
minimist: 1.2.8
@@ -14970,6 +15738,8 @@ snapshots:
nanoid@5.0.9: {}
+ napi-build-utils@2.0.0: {}
+
natural-compare@1.4.0: {}
ncp@2.0.0:
@@ -14994,10 +15764,16 @@ snapshots:
json-stringify-safe: 5.0.1
propagate: 2.0.1
+ node-abi@3.75.0:
+ dependencies:
+ semver: 7.7.2
+
node-addon-api@3.2.1: {}
node-addon-api@5.1.0: {}
+ node-addon-api@7.1.1: {}
+
node-dir@0.1.17:
dependencies:
minimatch: 3.1.2
@@ -15023,6 +15799,11 @@ snapshots:
node-forge@1.3.1: {}
+ node-gyp-build-optional-packages@5.1.1:
+ dependencies:
+ detect-libc: 2.0.3
+ optional: true
+
node-gyp-build@4.8.1: {}
node-int64@0.4.0: {}
@@ -15110,6 +15891,8 @@ snapshots:
oidc-token-hash@5.0.3: {}
+ on-exit-leak-free@2.1.2: {}
+
on-finished@2.3.0:
dependencies:
ee-first: 1.1.1
@@ -15307,6 +16090,42 @@ snapshots:
pify@4.0.1: {}
+ pino-abstract-transport@2.0.0:
+ dependencies:
+ split2: 4.2.0
+
+ pino-pretty@13.1.1:
+ dependencies:
+ colorette: 2.0.20
+ dateformat: 4.6.3
+ fast-copy: 3.0.2
+ fast-safe-stringify: 2.1.1
+ help-me: 5.0.0
+ joycon: 3.1.1
+ minimist: 1.2.8
+ on-exit-leak-free: 2.1.2
+ pino-abstract-transport: 2.0.0
+ pump: 3.0.0
+ secure-json-parse: 4.0.0
+ sonic-boom: 4.2.0
+ strip-json-comments: 5.0.3
+
+ pino-std-serializers@7.0.0: {}
+
+ pino@9.9.0:
+ dependencies:
+ atomic-sleep: 1.0.0
+ fast-redact: 3.5.0
+ on-exit-leak-free: 2.1.2
+ pino-abstract-transport: 2.0.0
+ pino-std-serializers: 7.0.0
+ process-warning: 5.0.0
+ quick-format-unescaped: 4.0.4
+ real-require: 0.2.0
+ safe-stable-stringify: 2.5.0
+ sonic-boom: 4.2.0
+ thread-stream: 3.1.0
+
pirates@4.0.6: {}
pkg-dir@3.0.0:
@@ -15333,6 +16152,21 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.0
+ prebuild-install@7.1.3:
+ dependencies:
+ detect-libc: 2.0.3
+ expand-template: 2.0.3
+ github-from-package: 0.0.0
+ minimist: 1.2.8
+ mkdirp-classic: 0.5.3
+ napi-build-utils: 2.0.0
+ node-abi: 3.75.0
+ pump: 3.0.0
+ rc: 1.2.8
+ simple-get: 4.0.1
+ tar-fs: 2.1.3
+ tunnel-agent: 0.6.0
+
prelude-ls@1.1.2: {}
prettier@2.8.8: {}
@@ -15363,6 +16197,8 @@ snapshots:
process-nextick-args@2.0.1:
optional: true
+ process-warning@5.0.0: {}
+
progress@2.0.3: {}
promise@7.3.1:
@@ -15402,6 +16238,21 @@ snapshots:
'@types/node': 20.19.2
long: 4.0.0
+ protobufjs@7.2.5:
+ dependencies:
+ '@protobufjs/aspromise': 1.1.2
+ '@protobufjs/base64': 1.1.2
+ '@protobufjs/codegen': 2.0.4
+ '@protobufjs/eventemitter': 1.1.0
+ '@protobufjs/fetch': 1.1.0
+ '@protobufjs/float': 1.0.2
+ '@protobufjs/inquire': 1.1.0
+ '@protobufjs/path': 1.1.2
+ '@protobufjs/pool': 1.1.0
+ '@protobufjs/utf8': 1.1.0
+ '@types/node': 20.19.2
+ long: 5.3.1
+
protobufjs@7.4.0:
dependencies:
'@protobufjs/aspromise': 1.1.2
@@ -15415,7 +16266,7 @@ snapshots:
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/node': 20.19.2
- long: 5.2.3
+ long: 5.3.1
proxy-addr@2.0.7:
dependencies:
@@ -15433,10 +16284,6 @@ snapshots:
pure-rand@6.1.0: {}
- pvtsutils@1.3.5:
- dependencies:
- tslib: 2.8.1
-
pvtsutils@1.3.6:
dependencies:
tslib: 2.8.1
@@ -15468,6 +16315,8 @@ snapshots:
dependencies:
inherits: 2.0.4
+ quick-format-unescaped@4.0.4: {}
+
quick-lru@5.1.1: {}
quick-lru@7.0.0: {}
@@ -15619,6 +16468,8 @@ snapshots:
readonly-date@1.0.0: {}
+ real-require@0.2.0: {}
+
recast@0.21.5:
dependencies:
ast-types: 0.15.2
@@ -15753,6 +16604,8 @@ snapshots:
reusify@1.0.4: {}
+ rfc4648@1.5.4: {}
+
rimraf@2.2.8:
optional: true
@@ -15823,6 +16676,8 @@ snapshots:
es-errors: 1.3.0
is-regex: 1.2.1
+ safe-stable-stringify@2.5.0: {}
+
safer-buffer@2.1.2: {}
sax@1.4.1: {}
@@ -15835,6 +16690,8 @@ snapshots:
node-addon-api: 5.1.0
node-gyp-build: 4.8.1
+ secure-json-parse@4.0.0: {}
+
selfsigned@2.4.1:
dependencies:
'@types/node-forge': 1.3.11
@@ -15977,6 +16834,14 @@ snapshots:
signal-exit@4.1.0: {}
+ simple-concat@1.0.1: {}
+
+ simple-get@4.0.1:
+ dependencies:
+ decompress-response: 6.0.0
+ once: 1.4.0
+ simple-concat: 1.0.1
+
simple-plist@1.3.1:
dependencies:
bplist-creator: 0.1.0
@@ -15996,6 +16861,10 @@ snapshots:
slugify@1.6.6: {}
+ sonic-boom@4.2.0:
+ dependencies:
+ atomic-sleep: 1.0.0
+
source-map-js@1.2.0: {}
source-map-support@0.5.13:
@@ -16015,6 +16884,8 @@ snapshots:
source-map@0.7.4:
optional: true
+ spark-md5@3.0.2: {}
+
spawndamnit@3.0.1:
dependencies:
cross-spawn: 7.0.6
@@ -16022,6 +16893,8 @@ snapshots:
split-on-first@1.1.0: {}
+ split2@4.2.0: {}
+
split@1.0.1:
dependencies:
through: 2.3.8
@@ -16135,6 +17008,8 @@ snapshots:
strip-json-comments@3.1.1: {}
+ strip-json-comments@5.0.3: {}
+
strnum@1.0.5:
optional: true
@@ -16209,6 +17084,21 @@ snapshots:
symbol-observable@2.0.3: {}
+ tar-fs@2.1.3:
+ dependencies:
+ chownr: 1.1.4
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 2.2.0
+
+ tar-stream@2.2.0:
+ dependencies:
+ bl: 4.1.0
+ end-of-stream: 1.4.4
+ fs-constants: 1.0.0
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+
tar@6.2.1:
dependencies:
chownr: 2.0.0
@@ -16285,6 +17175,10 @@ snapshots:
dependencies:
any-promise: 1.3.0
+ thread-stream@3.1.0:
+ dependencies:
+ real-require: 0.2.0
+
throat@5.0.0: {}
through2@2.0.5:
@@ -16390,6 +17284,12 @@ snapshots:
dependencies:
tslib: 1.14.1
+ tunnel-agent@0.6.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ tweetnacl@1.0.3: {}
+
type-check@0.3.2:
dependencies:
prelude-ls: 1.1.2
@@ -16803,3 +17703,9 @@ snapshots:
zod: 3.25.67
zod@3.25.67: {}
+
+ zstd-napi@0.0.10:
+ dependencies:
+ '@types/node': 20.19.2
+ node-addon-api: 7.1.1
+ prebuild-install: 7.1.3
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 8da71a7c33..944c8e8d31 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -44,3 +44,5 @@ onlyBuiltDependencies:
- "@hyperledger/anoncreds-nodejs"
- "@hyperledger/indy-vdr-nodejs"
- "@openwallet-foundation/askar-nodejs"
+ - "zstd-napi"
+ - "cbor-extract"
|