Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: didcomm module #2127

Merged
merged 25 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ededb58
refactor: move to separate didcomm package
genaris Nov 11, 2024
89f8d62
Merge branch 'main' into refactor/didcomm-module
genaris Dec 19, 2024
524a07c
refactor: remove didcomm packages from BaseAgent
genaris Dec 19, 2024
73fafcf
fix: move luxon dependency to didcomm
genaris Dec 19, 2024
851cf8a
fix: fixed cheqd SDK to 2.5.1 because otherwise it won't build (targe…
genaris Dec 19, 2024
17b2674
test: fix some core tests
genaris Dec 19, 2024
618b975
test: more fixed tests
genaris Dec 20, 2024
0e46629
test: fixes
genaris Dec 24, 2024
17386a4
fix: update pnpm lock
genaris Jan 22, 2025
bb6917a
test: fix most tests
genaris Jan 23, 2025
add1645
Merge branch 'main' into refactor/didcomm-module
genaris Jan 23, 2025
d1143ad
fix: several types, format and lint errors
genaris Jan 24, 2025
5b40e63
fix: upgrade asn1/sd-swt libraries to pass x509/oidc tests
genaris Jan 24, 2025
c902a37
fix: demo and extension module
genaris Jan 24, 2025
6d21374
test: storage tests
genaris Jan 25, 2025
02e8d90
fix: types
genaris Jan 25, 2025
bc1ba33
fix: sphereon lib as didcomm dev dep
genaris Jan 25, 2025
17e4fe2
feat: add some basic documentation and expose convenience function
genaris Jan 27, 2025
d50f20e
Merge branch 'main' into refactor/didcomm-module
genaris Jan 27, 2025
76813b0
docs(changeset): DIDComm has been extracted out of the Core. This mea…
genaris Jan 27, 2025
30a937d
fix: changeset comment
genaris Jan 27, 2025
e64dfb6
style: fix prettier
genaris Jan 27, 2025
728aa33
fix: address PR feedback
genaris Jan 28, 2025
a93c6ba
Merge branch 'main' into refactor/didcomm-module
genaris Jan 28, 2025
ba42e98
fix: no updateConfig currently used
genaris Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
67 changes: 67 additions & 0 deletions .changeset/purple-donkeys-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
'@credo-ts/question-answer': minor
'@credo-ts/bbs-signatures': minor
'@credo-ts/action-menu': minor
'@credo-ts/anoncreds': minor
'@credo-ts/indy-vdr': minor
'@credo-ts/didcomm': minor
'@credo-ts/tenants': minor
'@credo-ts/askar': minor
'@credo-ts/cheqd': minor
'@credo-ts/core': minor
'@credo-ts/drpc': minor
'@credo-ts/node': minor
---

DIDComm has been extracted out of the Core. This means that now all DIDComm related modules (e.g. proofs, credentials) must be explicitly added when creating an `Agent` instance. Therefore, their API will be accesable under `agent.modules.[moduleAPI]` instead of `agent.[moduleAPI]`. Some `Agent` DIDComm-related properties and methods where also moved to the API of a new DIDComm module (e.g. `agent.registerInboundTransport` turned into `agent.modules.didcomm.registerInboundTransport`).
Copy link
Contributor

@TimoGlastra TimoGlastra Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not for this PR, but I think before 0.6 we should look at making:

  • agent.didcomm possible (nesting is getting quite large)
  • nest didcomm modules under agent.didcomm, also because agent.credentials / agent.modules.credentials is misleading, since it's didcomm specific. I think registerin
  • Adopting the conenctions / oob modules into the didcomm module by default, and you can configure it in the didcomm module config again. I think this simplifies setup.
  • Registering custom didcomm protocols on the didcomm module rather than the agent? This may solve some of the initialization and feature registry issues. We can create a DidcommModule interface that has special feature registry etc.
  • Rename modules to have DIDcomm prefix (DidCommConnectionsModule, DidCommMessageHandlerRegistry). This will help with identifiying for what feature a class is
  • Add inbound / outbound transports to the config? I always found it a bit weird you can't just add this to the didcomm config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good ideas there! Initially I made a "DidCommModule" but I decided to leave it for a further PR to not overcomplicate it. But for sure it is something that makes sense, especially to have a tidy Agent API.

Same thing about the transport config, which is something not so evident for developers.


**Example of DIDComm Agent**

Previously:

```ts
const config = {
label: name,
endpoints: ['https://myendpoint'],
walletConfig: {
id: name,
key: name,
},
} satisfies InitConfig

const agent = new Agent({
config,
dependencies: agentDependencies,
modules: {
connections: new ConnectionsModule({
autoAcceptConnections: true,
})
})
this.agent.registerInboundTransport(new HttpInboundTransport({ port }))
this.agent.registerOutboundTransport(new HttpOutboundTransport())

```

Now:

```ts
const config = {
label: name,
walletConfig: {
id: name,
key: name,
},
} satisfies InitConfig

const agent = new Agent({
config,
dependencies: agentDependencies,
modules: {
...getDefaultDidcommModules({ endpoints: ['https://myendpoint'] }),
connections: new ConnectionsModule({
autoAcceptConnections: true,
})
})
agent.modules.didcomm.registerInboundTransport(new HttpInboundTransport({ port }))
agent.modules.didcomm.registerOutboundTransport(new HttpOutboundTransport())
```
27 changes: 11 additions & 16 deletions demo-openid/src/BaseAgent.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import type { InitConfig, KeyDidCreateOptions, ModulesMap, VerificationMethod } from '@credo-ts/core'
import type { Express } from 'express'
import type { Server } from 'http'

import {
Agent,
ConsoleLogger,
DidKey,
HttpOutboundTransport,
KeyType,
LogLevel,
TypedArrayEncoder,
} from '@credo-ts/core'
import { HttpInboundTransport, agentDependencies } from '@credo-ts/node'
import { Agent, ConsoleLogger, DidKey, KeyType, LogLevel, TypedArrayEncoder } from '@credo-ts/core'
import { agentDependencies } from '@credo-ts/node'
import express from 'express'

import { greenText } from './OutputClass'
Expand All @@ -21,6 +14,7 @@ export class BaseAgent<AgentModules extends ModulesMap> {
public name: string
public config: InitConfig
public agent: Agent<AgentModules>
public server?: Server
public did!: string
public didKey!: DidKey
public kid!: string
Expand All @@ -41,17 +35,13 @@ export class BaseAgent<AgentModules extends ModulesMap> {
this.config = config

this.agent = new Agent({ config, dependencies: agentDependencies, modules })

const httpInboundTransport = new HttpInboundTransport({ app: this.app, port: this.port })
const httpOutboundTransport = new HttpOutboundTransport()

this.agent.registerInboundTransport(httpInboundTransport)
this.agent.registerOutboundTransport(httpOutboundTransport)
}

public async initializeAgent(secretPrivateKey: string) {
await this.agent.initialize()

this.server = this.app.listen(this.port)

const didCreateResult = await this.agent.dids.create<KeyDidCreateOptions>({
method: 'key',
options: { keyType: KeyType.Ed25519 },
Expand All @@ -68,4 +58,9 @@ export class BaseAgent<AgentModules extends ModulesMap> {

console.log(greenText(`\nAgent ${this.name} created!\n`))
}

public async shutdown() {
this.server?.close()
await this.agent.shutdown()
}
}
4 changes: 2 additions & 2 deletions demo-openid/src/Holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,11 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>

public async exit() {
console.log(Output.Exit)
await this.agent.shutdown()
await this.shutdown()
process.exit(0)
}

public async restart() {
await this.agent.shutdown()
await this.shutdown()
}
}
4 changes: 2 additions & 2 deletions demo-openid/src/Issuer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,12 @@ export class Issuer extends BaseAgent<{

public async exit() {
console.log(Output.Exit)
await this.agent.shutdown()
await this.shutdown()
process.exit(0)
}

public async restart() {
await this.agent.shutdown()
await this.shutdown()
}
}

Expand Down
4 changes: 2 additions & 2 deletions demo-openid/src/Verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ export class Verifier extends BaseAgent<{ askar: AskarModule; openId4VcVerifier:

public async exit() {
console.log(Output.Exit)
await this.agent.shutdown()
await this.shutdown()
process.exit(0)
}

public async restart() {
await this.agent.shutdown()
await this.shutdown()
}
}
1 change: 1 addition & 0 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@credo-ts/anoncreds": "workspace:*",
"@credo-ts/askar": "workspace:*",
"@credo-ts/core": "workspace:*",
"@credo-ts/didcomm": "workspace:*",
"@credo-ts/indy-vdr": "workspace:*",
"@credo-ts/cheqd": "workspace:*",
"@credo-ts/node": "workspace:*",
Expand Down
16 changes: 8 additions & 8 deletions demo/src/Alice.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ConnectionRecord, CredentialExchangeRecord, ProofExchangeRecord } from '@credo-ts/core'
import type { ConnectionRecord, CredentialExchangeRecord, ProofExchangeRecord } from '@credo-ts/didcomm'

import { BaseAgent } from './BaseAgent'
import { greenText, Output, redText } from './OutputClass'
Expand All @@ -22,19 +22,19 @@ export class Alice extends BaseAgent {
if (!this.connectionRecordFaberId) {
throw Error(redText(Output.MissingConnectionRecord))
}
return await this.agent.connections.getById(this.connectionRecordFaberId)
return await this.agent.modules.connections.getById(this.connectionRecordFaberId)
}

private async receiveConnectionRequest(invitationUrl: string) {
const { connectionRecord } = await this.agent.oob.receiveInvitationFromUrl(invitationUrl)
const { connectionRecord } = await this.agent.modules.oob.receiveInvitationFromUrl(invitationUrl)
if (!connectionRecord) {
throw new Error(redText(Output.NoConnectionRecordFromOutOfBand))
}
return connectionRecord
}

private async waitForConnection(connectionRecord: ConnectionRecord) {
connectionRecord = await this.agent.connections.returnWhenIsConnected(connectionRecord.id)
connectionRecord = await this.agent.modules.connections.returnWhenIsConnected(connectionRecord.id)
this.connected = true
console.log(greenText(Output.ConnectionEstablished))
return connectionRecord.id
Expand All @@ -46,17 +46,17 @@ export class Alice extends BaseAgent {
}

public async acceptCredentialOffer(credentialRecord: CredentialExchangeRecord) {
await this.agent.credentials.acceptOffer({
await this.agent.modules.credentials.acceptOffer({
credentialRecordId: credentialRecord.id,
})
}

public async acceptProofRequest(proofRecord: ProofExchangeRecord) {
const requestedCredentials = await this.agent.proofs.selectCredentialsForRequest({
const requestedCredentials = await this.agent.modules.proofs.selectCredentialsForRequest({
proofRecordId: proofRecord.id,
})

await this.agent.proofs.acceptRequest({
await this.agent.modules.proofs.acceptRequest({
proofRecordId: proofRecord.id,
proofFormats: requestedCredentials.proofFormats,
})
Expand All @@ -65,7 +65,7 @@ export class Alice extends BaseAgent {

public async sendMessage(message: string) {
const connectionRecord = await this.getConnectionRecord()
await this.agent.basicMessages.sendMessage(connectionRecord.id, message)
await this.agent.modules.basicMessages.sendMessage(connectionRecord.id, message)
}

public async exit() {
Expand Down
6 changes: 3 additions & 3 deletions demo/src/AliceInquirer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CredentialExchangeRecord, ProofExchangeRecord } from '@credo-ts/core'
import type { CredentialExchangeRecord, ProofExchangeRecord } from '@credo-ts/didcomm'

import { clear } from 'console'
import { textSync } from 'figlet'
Expand Down Expand Up @@ -72,7 +72,7 @@ export class AliceInquirer extends BaseInquirer {
public async acceptCredentialOffer(credentialRecord: CredentialExchangeRecord) {
const confirm = await prompt([this.inquireConfirmation(Title.CredentialOfferTitle)])
if (confirm.options === ConfirmOptions.No) {
await this.alice.agent.credentials.declineOffer(credentialRecord.id)
await this.alice.agent.modules.credentials.declineOffer(credentialRecord.id)
} else if (confirm.options === ConfirmOptions.Yes) {
await this.alice.acceptCredentialOffer(credentialRecord)
}
Expand All @@ -81,7 +81,7 @@ export class AliceInquirer extends BaseInquirer {
public async acceptProofRequest(proofRecord: ProofExchangeRecord) {
const confirm = await prompt([this.inquireConfirmation(Title.ProofRequestTitle)])
if (confirm.options === ConfirmOptions.No) {
await this.alice.agent.proofs.declineRequest({ proofRecordId: proofRecord.id })
await this.alice.agent.modules.proofs.declineRequest({ proofRecordId: proofRecord.id })
} else if (confirm.options === ConfirmOptions.Yes) {
await this.alice.acceptProofRequest(proofRecord)
}
Expand Down
17 changes: 9 additions & 8 deletions demo/src/BaseAgent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { InitConfig } from '@credo-ts/core'
import type { DidCommModuleConfigOptions } from '@credo-ts/didcomm'
import type { IndyVdrPoolConfig } from '@credo-ts/indy-vdr'

import {
Expand All @@ -18,18 +19,18 @@ import {
CheqdModule,
CheqdModuleConfig,
} from '@credo-ts/cheqd'
import { DidsModule, Agent } from '@credo-ts/core'
import {
ConnectionsModule,
DidsModule,
V2ProofProtocol,
V2CredentialProtocol,
ProofsModule,
AutoAcceptProof,
AutoAcceptCredential,
CredentialsModule,
Agent,
HttpOutboundTransport,
} from '@credo-ts/core'
getDefaultDidcommModules,
} from '@credo-ts/didcomm'
import { IndyVdrIndyDidResolver, IndyVdrAnonCredsRegistry, IndyVdrModule } from '@credo-ts/indy-vdr'
import { agentDependencies, HttpInboundTransport } from '@credo-ts/node'
import { anoncreds } from '@hyperledger/anoncreds-nodejs'
Expand Down Expand Up @@ -68,18 +69,17 @@ export class BaseAgent {
id: name,
key: name,
},
endpoints: [`http://localhost:${this.port}`],
} satisfies InitConfig

this.config = config

this.agent = new Agent({
config,
dependencies: agentDependencies,
modules: getAskarAnonCredsIndyModules(),
modules: getAskarAnonCredsIndyModules({ endpoints: [`http://localhost:${this.port}`] }),
})
this.agent.registerInboundTransport(new HttpInboundTransport({ port }))
this.agent.registerOutboundTransport(new HttpOutboundTransport())
this.agent.modules.didcomm.registerInboundTransport(new HttpInboundTransport({ port }))
this.agent.modules.didcomm.registerOutboundTransport(new HttpOutboundTransport())
}

public async initializeAgent() {
Expand All @@ -89,11 +89,12 @@ export class BaseAgent {
}
}

function getAskarAnonCredsIndyModules() {
function getAskarAnonCredsIndyModules(didcommConfig: DidCommModuleConfigOptions) {
const legacyIndyCredentialFormatService = new LegacyIndyCredentialFormatService()
const legacyIndyProofFormatService = new LegacyIndyProofFormatService()

return {
...getDefaultDidcommModules(didcommConfig),
connections: new ConnectionsModule({
autoAcceptConnections: true,
}),
Expand Down
19 changes: 10 additions & 9 deletions demo/src/Faber.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { RegisterCredentialDefinitionReturnStateFinished } from '@credo-ts/anoncreds'
import type { ConnectionRecord, ConnectionStateChangedEvent } from '@credo-ts/core'
import type { ConnectionRecord, ConnectionStateChangedEvent } from '@credo-ts/didcomm'
import type { IndyVdrRegisterSchemaOptions, IndyVdrRegisterCredentialDefinitionOptions } from '@credo-ts/indy-vdr'
import type BottomBar from 'inquirer/lib/ui/bottom-bar'

import { ConnectionEventTypes, KeyType, TypedArrayEncoder, utils } from '@credo-ts/core'
import { KeyType, TypedArrayEncoder, utils } from '@credo-ts/core'
import { ConnectionEventTypes } from '@credo-ts/didcomm'
import { ui } from 'inquirer'

import { BaseAgent, indyNetworkConfig } from './BaseAgent'
Expand Down Expand Up @@ -58,7 +59,7 @@ export class Faber extends BaseAgent {
throw Error(redText(Output.MissingConnectionRecord))
}

const [connection] = await this.agent.connections.findAllByOutOfBandId(this.outOfBandId)
const [connection] = await this.agent.modules.connections.findAllByOutOfBandId(this.outOfBandId)

if (!connection) {
throw Error(redText(Output.MissingConnectionRecord))
Expand All @@ -68,7 +69,7 @@ export class Faber extends BaseAgent {
}

private async printConnectionInvite() {
const outOfBand = await this.agent.oob.createInvitation()
const outOfBand = await this.agent.modules.oob.createInvitation()
this.outOfBandId = outOfBand.id

console.log(
Expand Down Expand Up @@ -99,7 +100,7 @@ export class Faber extends BaseAgent {
})

// Also retrieve the connection record by invitation if the event has already fired
void this.agent.connections.findAllByOutOfBandId(outOfBandId).then(([connectionRecord]) => {
void this.agent.modules.connections.findAllByOutOfBandId(outOfBandId).then(([connectionRecord]) => {
if (connectionRecord) {
clearTimeout(timeoutId)
resolve(connectionRecord)
Expand All @@ -110,7 +111,7 @@ export class Faber extends BaseAgent {
const connectionRecord = await getConnectionRecord(this.outOfBandId)

try {
await this.agent.connections.returnWhenIsConnected(connectionRecord.id)
await this.agent.modules.connections.returnWhenIsConnected(connectionRecord.id)
} catch (e) {
console.log(redText(`\nTimeout of 20 seconds reached.. Returning to home screen.\n`))
return
Expand Down Expand Up @@ -200,7 +201,7 @@ export class Faber extends BaseAgent {

this.ui.updateBottomBar('\nSending credential offer...\n')

await this.agent.credentials.offerCredential({
await this.agent.modules.credentials.offerCredential({
connectionId: connectionRecord.id,
protocolVersion: 'v2',
credentialFormats: {
Expand Down Expand Up @@ -254,7 +255,7 @@ export class Faber extends BaseAgent {
const proofAttribute = await this.newProofAttribute()
await this.printProofFlow(greenText('\nRequesting proof...\n', false))

await this.agent.proofs.requestProof({
await this.agent.modules.proofs.requestProof({
protocolVersion: 'v2',
connectionId: connectionRecord.id,
proofFormats: {
Expand All @@ -272,7 +273,7 @@ export class Faber extends BaseAgent {

public async sendMessage(message: string) {
const connectionRecord = await this.getConnectionRecord()
await this.agent.basicMessages.sendMessage(connectionRecord.id, message)
await this.agent.modules.basicMessages.sendMessage(connectionRecord.id, message)
}

public async exit() {
Expand Down
Loading
Loading