owned this note
owned this note
Published
Linked with GitHub
# Modular AFJ
Although Aries Framework JavaScript is structured as a monorepo, %99 of the code stil lives in one big `@aries-framework/core` package. This documents describes the design of a more modular AFJ, so people with different use case can use the framework.
## Motivation
With more and more usage of AFJ in different environments, with different restrictions and different business requirements it's becoming more of an issue to work with the fat `@aries-framework/core` package. The Node.JS and React Native specific code have been ectracted from the core a while ago but with the addition of multipile storage implementations, multiple wallets and multiple credential formats it's becoming harder to work with the single core package. A more modular AFJ would allow different restrictions in terms of use case, environment, credential formats, etc.. to be managed by different packages, while still providing an powerfull core module.
## Pluggable Components
Although it's already possible to write custom modules for AFJ (see [Extension Module example](https://github.com/hyperledger/aries-framework-javascript/tree/main/samples/extension-module)), for a lot of parts of the framework it's not possible yet to configure it to different needs.
This sections lists all components that should be configurable and pluggable.
- Did methods (both resolver and registrar)
- Should be able to plug in dif did resolver (we already use it internally for e.g. did:web)
- Credential formats
- Modules
- Protocols
- Storage
- Wallet
## Plugin System
Extracting components from the core into separate modules would require better support for plugins. The idea is to add support for plugins to the agent initialization config. Plugins can be any class that implements the `Plugin` interface.
```typescript
import { Agent } from '@aries-framework/core'
import { CredentialModule } from '@aries-framework/module-credentials'
const myAgent = Agent.create({
modules: {
credentials: new CredentialsModule({
autoAcceptCredentials: true,
credentialProtocols: [V1CredentialProtocol],
credentialFormats: [IndyCredentialFormat]
}),
dids: new DidsModule({
resolvers: [SovDidResolver, WebDidResolver, KeyDidResolver, PeerDidResolver],
registrars: [SovDidRegistrar, WebDidRegistrar, KeyDidRegistrar, PeerDidRegistrar]
}),
}
})
await myAgent.initialize()
// fully typed
const record = myAgent.credentials.offerCredentials({ /* the config */ })
```
```typescript=
interface CredentialsModuleConfig {
autoAcceptCredentials: boolean,
CredentialProtocols: CredentialProtocol[],
CredentialFormats: CredentialFormat[]
}
class CredentialsModule<CredentialFormats, CredentialProtocols> implements Module {
public config: CredentialsModuleConfig
// define modules this class needs (so we can infer whether all required modules are registered)
public needsModules = [ConnectionsModule]
// Api defines the public api on the agent instance (optional)
public api = CredentialsApi<CredentialFormats, CredentialProtocols>
public constructor(config: CredentialsModuleConfig) {
this.config = config
}
public register(dependencyManager: DependencyManager) {
dependencyManager.registerSingleton(CredentialsRepository)
// Register this class, so we can inject it and use the config later on
dependencyManager.registerSingleton(CredentialModule, this)
// Dynamically register credential protocols based on user config
for (const CredentialProtocol of this.config.credentialProtocols) {
// Token is to be defined. probably CredentialService.token (stratic property on the abstract class)
dependencyManager.registerSingleton("CredentialProtocol", CredentialProtocol)
}
// Dynamically register credential formats based on user config
for (const CredentialFormat of this.config.credentialFormats) {
// Token is to be defined. probably Credentialformat.token (stratic property on the abstract class)
dependencyManager.registerSingleton("CredentialFormat", CredentialFormat)
}
}
}
```
## Packages
Not looking to split in so much packages, but this is basically a separation of different components. Whether some of them are internal to core is tbd later, but to get the mental model right. Sepearting into multiple packages will also help with boundaries between different packages.
### Core
* `@aries-framework/core`
* Can run in any environment -- no environment specific dependencies
* Defines StorageService, Wallet, FileSystem interfaces
* defines DidResolver, DidRegistrar
### Node.JS
* `@aries-framework/node`
* Provides common Node.JS dependencies
### React Native
* `@aries-framework/react-native`
* Provides common React Native dependencies
* `@aries-framework/file-system-rnfs`
* Implements FileSystem
* We can later add a `@aries-framework/file-system-expo`
### Credentials
* `@aries-framework/module-credentials`
* `@aries-framework/protocol-issue-credential-v2`
### Proofs
* `@aries-framework/module-proofs`
* `@aries-framework/protocol-present-proof-v2`
### Indy
* `@aries-framework/credential-anoncreds`
* Interfaces for AnonCredsHolderService, AnonCredsVerifierService, AnonCredsIssuerService, AnonCredsRevocationService, AnonCredsResourceService
* Implementation of ProofFormatService (AnonCredsProofFormatService) -- or should this still be IndyProofFormatService? In that case it shouldn't be in the AnonCreds package
* Implementation of CredentialFormatService (AnonCredsCredentialFormatService) -- or should this still be IndyCredentialFormatService? In that case it shouldn't be in the AnonCreds package
* Implementation of ProofService (V1ProofService)
* Implementation of CredentialService (V1CredentialService)
* Implementation of the `SovDidResolver`, `SovDidRegistrar`, `IndyDidResolver` and `IndyDidRegistrar`
* `@aries-framework/indy-sdk`
* Implementation of AnonCredsHolderService, AnonCredsVerifierService, AnonCredsIssuerService, AnonCredsRevocationService, AnonCredsResourceService
* Implementation of StorageService, Wallet
* Depends on the `Indy` interface defined in `@types/indy-sdk` which can be fulfilled using either `indy-sdk` or `indy-sdk-react-native`
* `@aries-framework/indy-vdr` -- we could combine this with indy-credx, just have to make sure the binaries are not required to import, and only to use the specific classes. You must be able to to use indy-vdr for dids without indy-credx
* Implementation of AnonCredsResourceService
* Depends on the interfaces from `indy-vdr-shared` which can be fulfilled using either `indy-vdr-react-native` or `indy-vdr-nodejs`
* `@aries-framework/indy-credx`
* Implementation of AnonCredsHolderService, AnonCredsVerifierService, AnonCredsIssuerService, AnonCredsRevocationService
* Depends on the interfaces from `indy-credx-shared` which can be fulfilled using either `indy-credx-react-native` or `indy-credx-nodejs`
### W3C Credentials
* `@aries-framework/credential-w3c`
* Adds support for the `W3cCredentialService`, `W3cCredentialRecord`
* Adds support for the `JsonLdCredentialFormatService`
* Adds support for the `PresentationExchangeProofFormatService`
* Adds support for the `Ed25519Signature2018` signature suite (no heavy native dependencies)
* Defines `SignatureSuiteRegistry` so signature suites can be dynamically registered
* `@aries-framework/bbs-signatures`
* Depends on `@mattrglobal/bbs-signatures` (`@animo-id/react-native-bbs-signatures` in React Native environment)
* Adds support for the `BbsBlsSignature2020` and `BbsBlsSignatureProof2020` signature suites
* Will be dynamically registered in the `SignatureSuiteRegistry`
* Adds support for the `Bls12381g2SigningProvider`
* Will be dynamically register in the `SigningProviderRegistry`
### Askar
* `@aries-framework/askar`
* Adds `AskarStorageService` and `AskarWallet`
* Depends on `aries-askar-shared` which can be fulfilled using either `aries-askar-react-native` or `aries-askar-nodejs`
### 0.3.0
As 0.3.0 will still depend on the indy-sdk, there's no need to extract all dependencies out of core yet. The most important part is to extract the bbs dependencies and make them optional. With the addition of the `SignatureSuiteRegistry` and the `SigningProviderRegistry` we can move all bbs dependencies to the `@aries-framework/bbs-signatures` package.
Over time we can make sure the other parts are extracted from the core.
```typescript
import { BbsSignaturesModule } from '@aries-framework/bbs-signatures'
const agent = new Agent({
modules: {
// This will add support for creating bbs keys, and signing/verifying/deriving BbsBlsSignature(Proof)2020 jsonld credentials
// As there is no public api, the `bbs` key won't be added to the `agent` instance.
bbs: BbsSignaturesModule
},
})
```