From c92159c32a4f45aae73eb16199185af95a4b55e3 Mon Sep 17 00:00:00 2001 From: Liran Cohen Date: Thu, 26 Sep 2024 14:06:51 -0400 Subject: [PATCH] Refactor `IdentityApi` to be scoped to the agent as a tenant. (#911) - simplify `IdentityApi` to be agent-focused and storing both the DID and IdentityMetadata under the agent's tenant. - Remove the need for `manage` in IdentityApi. - DIDs that are created/imported are automatically pre-populated in the resolution cache. - Update vulnerable packages The DidApi remains unchanged and a default `did.create()` will store the DID document as the tenant of the newly created DID. --- .changeset/fifty-beers-bake.md | 5 + .changeset/itchy-mayflies-camp.md | 8 + package.json | 3 +- packages/agent/src/did-api.ts | 15 ++ packages/agent/src/identity-api.ts | 87 ++++------ packages/agent/src/test-harness.ts | 7 - packages/agent/tests/dwn-api.spec.ts | 20 --- packages/agent/tests/identity-api.spec.ts | 98 ++++++----- packages/agent/tests/permissions-api.spec.ts | 2 - packages/agent/tests/store-identity.spec.ts | 26 ++- packages/api/src/web5.ts | 7 +- packages/api/tests/dwn-api.spec.ts | 6 +- packages/api/tests/permission-grant.spec.ts | 2 - packages/api/tests/permission-request.spec.ts | 2 - packages/api/tests/protocol.spec.ts | 1 - packages/api/tests/record.spec.ts | 3 - packages/identity-agent/README.md | 73 ++++----- .../tests/identity-agent.spec.ts | 12 +- .../tests/managing-identities.spec.ts | 72 +-------- .../proxy-agent/tests/proxy-agent.spec.ts | 12 +- packages/user-agent/tests/user-agent.spec.ts | 12 +- pnpm-lock.yaml | 153 +++++++++--------- 22 files changed, 255 insertions(+), 371 deletions(-) create mode 100644 .changeset/fifty-beers-bake.md create mode 100644 .changeset/itchy-mayflies-camp.md diff --git a/.changeset/fifty-beers-bake.md b/.changeset/fifty-beers-bake.md new file mode 100644 index 000000000..0137223db --- /dev/null +++ b/.changeset/fifty-beers-bake.md @@ -0,0 +1,5 @@ +--- +"@web5/api": patch +--- + +Update usage of new IdentityApi behavior internally. diff --git a/.changeset/itchy-mayflies-camp.md b/.changeset/itchy-mayflies-camp.md new file mode 100644 index 000000000..e2f247a39 --- /dev/null +++ b/.changeset/itchy-mayflies-camp.md @@ -0,0 +1,8 @@ +--- +"@web5/identity-agent": minor +"@web5/proxy-agent": minor +"@web5/user-agent": minor +"@web5/agent": minor +--- + +Simplify IdentityApi to be agent-focused and storing both the DID and IdentityMetadata under the agent's tenant. diff --git a/package.json b/package.json index 8198bb4a2..903e77a75 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,8 @@ "body-parser@<1.20.3": ">=1.20.3", "send@<0.19.0": ">=0.19.0", "serve-static@<1.16.0": ">=1.16.0", - "express@<4.20.0": ">=4.20.0" + "express@<4.20.0": ">=4.20.0", + "rollup@>=4.0.0 <4.22.4": ">=4.22.4" } } } diff --git a/packages/agent/src/did-api.ts b/packages/agent/src/did-api.ts index 4a17d57af..91abb5807 100644 --- a/packages/agent/src/did-api.ts +++ b/packages/agent/src/did-api.ts @@ -103,6 +103,12 @@ export function isDidRequest( return didRequest.messageType === messageType; } +/** + * This API is used to manage and interact with DIDs within the Web5 Agent framework. + * + * If a DWN Data Store is used, the DID information is stored under DID's own tenant by default. + * If a tenant property is passed, that tenant will be used to store the DID information. + */ export class AgentDidApi extends UniversalResolver { /** * Holds the instance of a `Web5PlatformAgent` that represents the current execution context for @@ -170,6 +176,9 @@ export class AgentDidApi // Create the DID and store the generated keys in the Agent's key manager. const bearerDid = await didMethod.create({ keyManager: this.agent.keyManager, options }); + // pre-populate the resolution cache with the document and metadata + await this.cache.set(bearerDid.uri, { didDocument: bearerDid.document, didResolutionMetadata: { }, didDocumentMetadata: bearerDid.metadata }); + // Persist the DID to the store, by default, unless the `store` option is set to false. if (store ?? true) { // Data stored in the Agent's DID store must be in PortableDid format. @@ -260,6 +269,9 @@ export class AgentDidApi const { uri, document, metadata } = bearerDid; const portableDidWithoutKeys: PortableDid = { uri, document, metadata }; + // pre-populate the resolution cache with the document and metadata + await this.cache.set(uri, { didDocument: document, didResolutionMetadata: { }, didDocumentMetadata: metadata }); + // Store the DID in the agent's DID store. // Unless an existing `tenant` is specified, a record that includes the DID's URI, document, // and metadata will be stored under a new tenant controlled by the imported DID. @@ -285,6 +297,9 @@ export class AgentDidApi throw new Error('AgentDidApi: Could not delete, DID not found'); } + // delete from the cache + await this.cache.delete(didUri); + // Delete the data before deleting the associated keys. await this._store.delete({ id: didUri, agent: this.agent, tenant }); diff --git a/packages/agent/src/identity-api.ts b/packages/agent/src/identity-api.ts index b857a67e6..113f35e9c 100644 --- a/packages/agent/src/identity-api.ts +++ b/packages/agent/src/identity-api.ts @@ -23,7 +23,6 @@ export interface IdentityCreateParams< metadata: RequireOnly; didMethod?: TMethod; didOptions?: DidMethodCreateOptions[TMethod]; - tenant?: string; store?: boolean; } @@ -35,6 +34,16 @@ export function isPortableIdentity(obj: unknown): obj is PortableIdentity { && isPortableDid(obj.did); } +/** + * This API is used to manage and interact with Identities within the Web5 Agent framework. + * An Identity is a DID that is associated with metadata that describes the Identity. + * Metadata includes A name(label), and whether or not the Identity is connected (delegated to act on the behalf of another DID). + * + * A KeyManager is used to manage the cryptographic keys associated with the Identities. + * + * The `DidApi` is used internally to create, store, and manage DIDs. + * When a DWN Data Store is used, the Identity and DID information are stored under the Agent DID's tenant. + */ export class AgentIdentityApi { /** * Holds the instance of a `Web5PlatformAgent` that represents the current execution context for @@ -71,22 +80,29 @@ export class AgentIdentityApi ): Promise { - // Unless an existing `tenant` is specified, a record that includes the DID's URI, document, - // and metadata will be stored under a new tenant controlled by the newly created DID. + const bearerDid = await this.agent.did.create({ method : didMethod, options : didOptions, + tenant : this.tenant, store, - tenant }); // Create the BearerIdentity object. const identity = new BearerIdentity({ did : bearerDid, - metadata : { ...metadata, uri: bearerDid.uri, tenant: tenant ?? bearerDid.uri } + metadata : { ...metadata, uri: bearerDid.uri, tenant: this.tenant } }); // Persist the Identity to the store, by default, unless the `store` option is set to false. @@ -104,12 +120,10 @@ export class AgentIdentityApi { - // Attempt to retrieve the Identity from the Agent's Identity store. - const bearerIdentity = await this.get({ didUri, tenant }); + const bearerIdentity = await this.get({ didUri }); if (!bearerIdentity) { throw new Error(`AgentIdentityApi: Failed to export due to Identity not found: ${didUri}`); @@ -122,12 +136,10 @@ export class AgentIdentityApi { - // Attempt to retrieve the Identity from the Agent's Identity store. - const storedIdentity = await this._store.get({ id: didUri, agent: this.agent, tenant, useCache: true }); + const storedIdentity = await this._store.get({ id: didUri, agent: this.agent, useCache: true }); // If the Identity is not found in the store, return undefined. if (!storedIdentity) return undefined; @@ -150,6 +162,10 @@ export class AgentIdentityApi { + + // set the tenant of the portable identity to the agent's tenant + portableIdentity.metadata.tenant = this.tenant; + // Import the PortableDid to the Agent's DID store. const storedDid = await this.agent.did.import({ portableDid : portableIdentity.portableDid, @@ -183,56 +199,21 @@ export class AgentIdentityApi { - return this.get({ didUri: metadata.uri, tenant: metadata.tenant }); - }) - ); + const identities = await Promise.all(storedIdentities.map(metadata => this.get({ didUri: metadata.uri }))); return identities.filter(identity => typeof identity !== 'undefined') as BearerIdentity[]; } - public async manage({ portableIdentity }: { - portableIdentity: PortableIdentity; - }): Promise { - // Retrieve the DID using the `tenant` stored in the given Identity's metadata. - const storedDid = await this.agent.did.get({ - didUri : portableIdentity.metadata.uri, - tenant : portableIdentity.metadata.tenant - }); - - // Verify the DID is present in the DID store. - if (!storedDid) { - throw new Error(`AgentIdentityApi: Failed to manage Identity: ${portableIdentity.metadata.uri}`); - } - - // Create the BearerIdentity object. - const identity = new BearerIdentity({ did: storedDid, metadata: portableIdentity.metadata }); - - // Store the Identity metadata in the Agent's Identity store. - await this._store.set({ - id : identity.did.uri, - data : identity.metadata, - agent : this.agent, - preventDuplicates : true, - useCache : true - }); - - return identity; - } - - public async delete({ didUri, tenant }:{ + public async delete({ didUri }:{ didUri: string; - tenant?: string; }): Promise { - // Attempt to retrieve the Identity from the Agent's Identity store. - const storedIdentity = await this._store.get({ id: didUri, agent: this.agent, tenant, useCache: true }); + const storedIdentity = await this._store.get({ id: didUri, agent: this.agent, useCache: true }); if (!storedIdentity) { throw new Error(`AgentIdentityApi: Failed to purge due to Identity not found: ${didUri}`); } // Delete the Identity from the Agent's Identity store. - await this._store.delete({ id: didUri, agent: this.agent, tenant }); + await this._store.delete({ id: didUri, agent: this.agent }); } /** diff --git a/packages/agent/src/test-harness.ts b/packages/agent/src/test-harness.ts index 4628233aa..fa6043831 100644 --- a/packages/agent/src/test-harness.ts +++ b/packages/agent/src/test-harness.ts @@ -170,13 +170,6 @@ export class PlatformAgentTestHarness { return bearerIdentity; } - public async preloadResolverCache({ didUri, resolutionResult }: { - didUri: string; - resolutionResult: DidResolutionResult; - }): Promise { - await this.didResolverCache.set(didUri, resolutionResult); - } - public static async setup({ agentClass, agentStores, testDataLocation }: { agentClass: new (params: any) => Web5PlatformAgent agentStores?: 'dwn' | 'memory'; diff --git a/packages/agent/tests/dwn-api.spec.ts b/packages/agent/tests/dwn-api.spec.ts index 7983204ce..85c5abc2b 100644 --- a/packages/agent/tests/dwn-api.spec.ts +++ b/packages/agent/tests/dwn-api.spec.ts @@ -1082,15 +1082,6 @@ describe('AgentDwnApi', () => { } }; - await testHarness.preloadResolverCache({ - didUri : testPortableIdentity.portableDid.uri, - resolutionResult : { - didDocument : testPortableIdentity.portableDid.document, - didDocumentMetadata : testPortableIdentity.portableDid.metadata, - didResolutionMetadata : {} - } - }); - alice = await testHarness.agent.identity.import({ portableIdentity: testPortableIdentity }); @@ -1840,17 +1831,6 @@ describe('AgentDwnApi', () => { store : false }); - // Since the DID DHT document wasn't published, add the DID DHT document to the resolver - // cache so that DID resolution will succeed during the dereferencing operation. - await testHarness.preloadResolverCache({ - didUri : identity.did.uri, - resolutionResult : { - didDocument : identity.did.document, - didDocumentMetadata : identity.did.metadata, - didResolutionMetadata : {} - } - }); - try { await testHarness.agent.dwn.sendRequest({ author : identity.did.uri, diff --git a/packages/agent/tests/identity-api.spec.ts b/packages/agent/tests/identity-api.spec.ts index 3a5f79214..b143a17db 100644 --- a/packages/agent/tests/identity-api.spec.ts +++ b/packages/agent/tests/identity-api.spec.ts @@ -4,6 +4,7 @@ import { expect } from 'chai'; import { TestAgent } from './utils/test-agent.js'; import { AgentIdentityApi } from '../src/identity-api.js'; import { PlatformAgentTestHarness } from '../src/test-harness.js'; +import { PortableIdentity } from '../src/index.js'; describe('AgentIdentityApi', () => { @@ -35,6 +36,23 @@ describe('AgentIdentityApi', () => { }); }); + describe('get tenant', () => { + it('should throw if no agent is set', async () => { + const identityApi = new AgentIdentityApi(); + expect(() => + identityApi.tenant + ).to.throw(Error, 'The agent must be set to perform tenant specific actions.'); + }); + + it('should return the did of the agent as the tenant', async () => { + const mockAgent: any = { + agentDid: { uri: 'did:method:abc123' } + }; + const identityApi = new AgentIdentityApi({ agent: mockAgent }); + expect(identityApi.tenant).to.equal('did:method:abc123'); + }); + }); + // Run tests for each supported data store type. const agentStoreTypes = ['dwn'] as const; // const agentStoreTypes = ['dwn', 'memory'] as const; @@ -63,6 +81,42 @@ describe('AgentIdentityApi', () => { await testHarness.closeStorage(); }); + describe('export', () => { + it('should fail to export a DID that is not found', async () => { + const identityApi = new AgentIdentityApi({ agent: testHarness.agent }); + try { + await identityApi.export({ didUri: 'did:method:xyz123' }); + expect.fail('Expected an error to be thrown'); + } catch (error: any) { + expect(error.message).to.include('AgentIdentityApi: Failed to export due to Identity not found'); + } + }); + + it('should export a DID', async () => { + // Create a new Identity. + const identity = await testHarness.agent.identity.create({ + didMethod : 'jwk', + metadata : { name: 'Test Identity' }, + store : true + }); + + // Export the Identity. + const exportedIdentity = await testHarness.agent.identity.export({ didUri: identity.did.uri }); + + // create a synthetic PortableIdentity based on the returned BearerIdentity without calling the export function. + const portableIdentity:PortableIdentity = { + portableDid : { uri: identity.did.uri, document: identity.did.document, metadata: identity.did.metadata }, + metadata : { ...identity.metadata }, + }; + + // the exported DID comes with private key material + // those are not exposed in the returned BearIdentity object, so we add them to the rest of the identity we are comparing + portableIdentity.portableDid.privateKeys = exportedIdentity.portableDid.privateKeys; + + expect(exportedIdentity).to.deep.equal(portableIdentity); + }); + }); + describe('create()', () => { it('creates and returns an Identity', async () => { @@ -83,53 +137,20 @@ describe('AgentIdentityApi', () => { }); }); - describe('manage()' , () => { - it('imports only the Identity Metadata to Agent tenant', async () => { - // Create a new Identity, which by default is stored under the tenant of the created DID. - const identity = await testHarness.agent.identity.create({ - didMethod : 'jwk', - metadata : { name: 'Test Identity' }, - }); - - // Verify that the Identity is stored under the new Identity's tenant. - let storedIdentity = await testHarness.agent.identity.get({ didUri: identity.did.uri, tenant: identity.did.uri }); - expect(storedIdentity).to.exist; - - // Add a managed Identity to the Agent's tenant. - const managedIdentity = await testHarness.agent.identity.manage({ - portableIdentity: await identity.export() - }); - expect(managedIdentity).to.deep.equal(identity); - - // Verify that the Identity Metadata is stored under the Agent's tenant. - storedIdentity = await testHarness.agent.identity.get({ didUri: identity.did.uri }); - expect(storedIdentity).to.exist; - - // Verify the DID ONLY exists under the tenant of the previously created DID. - let storedDidAgent = await testHarness.agent.did.get({ didUri: identity.did.uri }); - expect(storedDidAgent).to.not.exist; - let storedDidNewIdentity = await testHarness.agent.did.get({ didUri: identity.did.uri, tenant: identity.did.uri }); - expect(storedDidNewIdentity).to.exist; - }); - }); - describe('list()', () => { it('returns an array of all identities', async () => { // Create three new identities all under the Agent's tenant. const alice = await testHarness.agent.identity.create({ didMethod : 'jwk', metadata : { name: 'Alice' }, - tenant : testHarness.agent.agentDid.uri }); const bob = await testHarness.agent.identity.create({ didMethod : 'jwk', metadata : { name: 'Bob' }, - tenant : testHarness.agent.agentDid.uri }); const carol = await testHarness.agent.identity.create({ didMethod : 'jwk', metadata : { name: 'Carol' }, - tenant : testHarness.agent.agentDid.uri }); // List identities and verify the result. @@ -159,19 +180,19 @@ describe('AgentIdentityApi', () => { }); // Verify that the Identity exists. - let storedIdentity = await testHarness.agent.identity.get({ didUri: identity.did.uri, tenant: identity.did.uri }); + let storedIdentity = await testHarness.agent.identity.get({ didUri: identity.did.uri }); expect(storedIdentity).to.exist; expect(storedIdentity?.did.uri).to.equal(identity.did.uri); // Delete the Identity. - await testHarness.agent.identity.delete({ didUri: identity.did.uri, tenant: identity.did.uri }); + await testHarness.agent.identity.delete({ didUri: identity.did.uri }); // Verify that the Identity no longer exists. - storedIdentity = await testHarness.agent.identity.get({ didUri: identity.did.uri, tenant: identity.did.uri }); + storedIdentity = await testHarness.agent.identity.get({ didUri: identity.did.uri }); expect(storedIdentity).to.not.exist; // Verify that the DID still exists - const storedDid = await testHarness.agent.did.get({ didUri: identity.did.uri, tenant: identity.did.uri }); + const storedDid = await testHarness.agent.did.get({ didUri: identity.did.uri }); expect(storedDid).to.not.be.undefined; expect(storedDid!.uri).to.equal(identity.did.uri); }); @@ -212,7 +233,6 @@ describe('AgentIdentityApi', () => { await testHarness.agent.identity.create({ didMethod : 'jwk', metadata : { name: 'Alice' }, - tenant : testHarness.agent.agentDid.uri }); // attempt to get a connected identity when none exist @@ -223,14 +243,12 @@ describe('AgentIdentityApi', () => { const connectedDid1 = await testHarness.agent.identity.create({ didMethod : 'jwk', metadata : { name: 'Bob', connectedDid: 'did:method:abc123' }, - tenant : testHarness.agent.agentDid.uri }); // Create another connected Identity. const connectedDid2 = await testHarness.agent.identity.create({ didMethod : 'jwk', metadata : { name: 'Carol', connectedDid: 'did:method:def456' }, - tenant : testHarness.agent.agentDid.uri }); // get the first connected identity diff --git a/packages/agent/tests/permissions-api.spec.ts b/packages/agent/tests/permissions-api.spec.ts index df4b9e49f..d1d3e4ed0 100644 --- a/packages/agent/tests/permissions-api.spec.ts +++ b/packages/agent/tests/permissions-api.spec.ts @@ -35,11 +35,9 @@ describe('AgentPermissionsApi', () => { // Create an "alice" Identity to author the DWN messages. const alice = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Alice' } }); - await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; const bob = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Bob' } }); - await testHarness.agent.identity.manage({ portableIdentity: await bob.export() }); bobDid = bob.did; }); diff --git a/packages/agent/tests/store-identity.spec.ts b/packages/agent/tests/store-identity.spec.ts index ddc3b15ff..dd93c89f1 100644 --- a/packages/agent/tests/store-identity.spec.ts +++ b/packages/agent/tests/store-identity.spec.ts @@ -64,17 +64,15 @@ describe('IdentityStore', () => { // Test deleting the Identity and validate the result. const deleteResult = await identityStore.delete({ - id : identity.did.uri, - tenant : identity.did.uri, - agent : testHarness.agent + id : identity.did.uri, + agent : testHarness.agent }); expect(deleteResult).to.be.true; // Verify the Identity is no longer in the store. const storedIdentity = await identityStore.get({ - id : identity.did.uri, - tenant : identity.did.uri, - agent : testHarness.agent + id : identity.did.uri, + agent : testHarness.agent }); expect(storedIdentity).to.be.undefined; }); @@ -116,7 +114,7 @@ describe('IdentityStore', () => { }); // Test getting the Identity. - const storedIdentity = await identityStore.get({ id: identity.did.uri, tenant: identity.did.uri, agent: testHarness.agent }); + const storedIdentity = await identityStore.get({ id: identity.did.uri, agent: testHarness.agent }); // Verify the Identity is in the store. expect(storedIdentity).to.exist; @@ -155,9 +153,9 @@ describe('IdentityStore', () => { describe('list()', () => { it('should return an array of all Identities in the store', async () => { // Generate three new Identities that are stored under the Agent's context. - const bearerIdentity1 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 1' }, tenant: testHarness.agent.agentDid.uri }); - const bearerIdentity2 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 2' }, tenant: testHarness.agent.agentDid.uri }); - const bearerIdentity3 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 3' }, tenant: testHarness.agent.agentDid.uri }); + const bearerIdentity1 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 1' } }); + const bearerIdentity2 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 2' } }); + const bearerIdentity3 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 3' } }); // List Identities and verify the result. const storedDids = await identityStore.list({ agent: testHarness.agent }); @@ -183,12 +181,12 @@ describe('IdentityStore', () => { await testHarness.agent.keyManager.importKey({ key: authorDid.privateKeys![0] }); // Generate three new Identities that are stored under the custom author context. - const bearerIdentity1 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 1' }, tenant: authorDid.uri }); - const bearerIdentity2 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 2' }, tenant: authorDid.uri }); - const bearerIdentity3 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 3' }, tenant: authorDid.uri }); + const bearerIdentity1 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 1' } }); + const bearerIdentity2 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 2' } }); + const bearerIdentity3 = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Test Identity 3' } }); // List Identities and verify the result. - const storedDids = await identityStore.list({ tenant: authorDid.uri, agent: testHarness.agent }); + const storedDids = await identityStore.list({ agent: testHarness.agent }); expect(storedDids).to.have.length(3); const importedDids = [bearerIdentity1.did.uri, bearerIdentity2.did.uri, bearerIdentity3.did.uri]; for (const storedIdentity of storedDids) { diff --git a/packages/api/src/web5.ts b/packages/api/src/web5.ts index bf07f732d..6636026f5 100644 --- a/packages/api/src/web5.ts +++ b/packages/api/src/web5.ts @@ -324,11 +324,10 @@ export class Web5 { metadata : { connectedDid, name : 'Default', - tenant : delegatePortableDid.uri, uri : delegatePortableDid.uri, + tenant : agent.agentDid.uri, } }}); - await userAgent.identity.manage({ portableIdentity: await identity.export() }); // Attempts to process the connected grants to be used by the delegateDID // If the process fails, we want to clean up the identity @@ -380,10 +379,6 @@ export class Web5 { } }); - // The User Agent will manage the Identity, which ensures it will be available on future - // sessions. - await userAgent.identity.manage({ portableIdentity: await identity.export() }); - } else { // If multiple identities are found, use the first one. // TODO: Implement selecting a connectedDid from multiple identities diff --git a/packages/api/tests/dwn-api.spec.ts b/packages/api/tests/dwn-api.spec.ts index ca3081664..7f332c000 100644 --- a/packages/api/tests/dwn-api.spec.ts +++ b/packages/api/tests/dwn-api.spec.ts @@ -38,12 +38,10 @@ describe('DwnApi', () => { // Create an "alice" Identity to author the DWN messages. const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; // Create a "bob" Identity to author the DWN messages. const bob = await testHarness.createIdentity({ name: 'Bob', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await bob.export() }); bobDid = bob.did; // Instantiate DwnApi for both test identities. @@ -699,7 +697,7 @@ describe('DwnApi', () => { } // create a grant for the protocol - const delegatedBearerDid = await delegateHarness.agent.did.get({ didUri: delegateDid.uri, tenant: delegateDid.uri }); + const delegatedBearerDid = await delegateHarness.agent.did.get({ didUri: delegateDid.uri }); const grants = await Oidc.createPermissionGrants(aliceDid.uri, delegatedBearerDid, testHarness.agent, [{ interface : DwnInterfaceName.Protocols, method : DwnMethodName.Configure, @@ -754,7 +752,7 @@ describe('DwnApi', () => { expect(nonPublicProtocols).to.have.lengthOf(0); // grant the delegate DID access to query the non-public protocol - const delegatedBearerDid = await delegateHarness.agent.did.get({ didUri: delegateDid.uri, tenant: delegateDid.uri }); + const delegatedBearerDid = await delegateHarness.agent.did.get({ didUri: delegateDid.uri }); const grants = await Oidc.createPermissionGrants(aliceDid.uri, delegatedBearerDid, testHarness.agent, [{ interface : DwnInterfaceName.Protocols, method : DwnMethodName.Query, diff --git a/packages/api/tests/permission-grant.spec.ts b/packages/api/tests/permission-grant.spec.ts index cb070723b..58e10bb24 100644 --- a/packages/api/tests/permission-grant.spec.ts +++ b/packages/api/tests/permission-grant.spec.ts @@ -37,12 +37,10 @@ describe('PermissionGrant', () => { // Create an "alice" Identity to author the DWN messages. const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; // Create a "bob" Identity to author the DWN messages. const bob = await testHarness.createIdentity({ name: 'Bob', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await bob.export() }); bobDid = bob.did; aliceDwn = new DwnApi({ agent: testHarness.agent, connectedDid: aliceDid.uri }); diff --git a/packages/api/tests/permission-request.spec.ts b/packages/api/tests/permission-request.spec.ts index 8cadb4c7e..726cac285 100644 --- a/packages/api/tests/permission-request.spec.ts +++ b/packages/api/tests/permission-request.spec.ts @@ -33,12 +33,10 @@ describe('PermissionRequest', () => { // Create an "alice" Identity to author the DWN messages. const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; // Create a "bob" Identity to author the DWN messages. const bob = await testHarness.createIdentity({ name: 'Bob', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await bob.export() }); bobDid = bob.did; aliceDwn = new DwnApi({ agent: testHarness.agent, connectedDid: aliceDid.uri }); diff --git a/packages/api/tests/protocol.spec.ts b/packages/api/tests/protocol.spec.ts index 541a77fc2..28825834a 100644 --- a/packages/api/tests/protocol.spec.ts +++ b/packages/api/tests/protocol.spec.ts @@ -34,7 +34,6 @@ describe('Protocol', () => { // Create an "alice" Identity to author the DWN messages. const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; // Instantiate DwnApi for both test identities. diff --git a/packages/api/tests/record.spec.ts b/packages/api/tests/record.spec.ts index 68f4388ee..7d147d633 100644 --- a/packages/api/tests/record.spec.ts +++ b/packages/api/tests/record.spec.ts @@ -55,12 +55,10 @@ describe('Record', () => { // Create an "alice" Identity to author the DWN messages. const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; // Create a "bob" Identity to author the DWN messages. const bob = await testHarness.createIdentity({ name: 'Bob', testDwnUrls }); - await testHarness.agent.identity.manage({ portableIdentity: await bob.export() }); bobDid = bob.did; // Instantiate DwnApi for both test identities. @@ -1641,7 +1639,6 @@ describe('Record', () => { // Create a carol Identity to author the DWN messages. const carol = await testHarnessCarol.createIdentity({ name: 'Carol', testDwnUrls }); - await testHarnessCarol.agent.identity.manage({ portableIdentity: await carol.export() }); carolDid = carol.did; // Instantiate a new `DwnApi` using Bob's test agent. diff --git a/packages/identity-agent/README.md b/packages/identity-agent/README.md index 8fb2a118a..b50a40002 100644 --- a/packages/identity-agent/README.md +++ b/packages/identity-agent/README.md @@ -39,7 +39,7 @@ manage one or more decentralized identities. ## Getting Started This JavaScript library was designed for modern development runtimes, including Node.js, web -browsers, and React Native. The package is distributed as `@web5/identity-agent` via +browsers, and React Native. The package is distributed as `@web5/identity-agent` via [npmjs.com][identity-agent-npm-link], [jsdelivr.com][identity-agent-jsdelivr-link], [unpkg.com][identity-agent-unpkg-link], and [github.com][identity-agent-repo-link]. @@ -192,7 +192,7 @@ Agent, and store data in the data store controlled by the newly created identity. ```ts -import { getTechPreviewDwnEndpoints, Web5 } from '@web5/api'; +import { getTechPreviewDwnEndpoints, Web5 } from "@web5/api"; // Retrieve publicly addressable DWNs that other network participants can use to exchange messages // and data with the new Identity. @@ -200,42 +200,39 @@ const serviceEndpointNodes = await getTechPreviewDwnEndpoints(); // Generate a new Identity for the end-user. const careerIdentity = await agent.identity.create({ - didMethod : 'dht', - metadata : { name: 'Alice' }, - didOptions : { + didMethod: "dht", + metadata: { name: "Alice" }, + didOptions: { services: [ { - id : 'dwn', - type : 'DecentralizedWebNode', - serviceEndpoint : serviceEndpointNodes, - enc : '#enc', - sig : '#sig', - } + id: "dwn", + type: "DecentralizedWebNode", + serviceEndpoint: serviceEndpointNodes, + enc: "#enc", + sig: "#sig", + }, ], verificationMethods: [ { - algorithm : 'Ed25519', - id : 'sig', - purposes : ['assertionMethod', 'authentication'] + algorithm: "Ed25519", + id: "sig", + purposes: ["assertionMethod", "authentication"], }, { - algorithm : 'secp256k1', - id : 'enc', - purposes : ['keyAgreement'] - } - ] - } + algorithm: "secp256k1", + id: "enc", + purposes: ["keyAgreement"], + }, + ], + }, }); - -// Enable management by this Identity Manager. -await agent.identity.manage({ portableIdentity: await identity.export() }); ``` ### Writing Data to an Identity's Data Store The [Web5 API](https://github.com/TBD54566975/web5-js/tree/main/packages/api) makes it simple to store data in an identity's DWN data store by handling all of the message and data preparation and -processing steps. Using the `careerIdentity` created earlier, a simple message payload can be +processing steps. Using the `careerIdentity` created earlier, a simple message payload can be written as follows: ```ts @@ -244,13 +241,13 @@ const web5Career = new Web5({ agent, connectedDid: careerIdentity.did.uri }); // Write a simple text record. const { record, status } = await web5Career.dwn.records.write({ - data : 'Message', - message : { - dataFormat : 'text/plain' - } + data: "Message", + message: { + dataFormat: "text/plain", + }, }); -console.log(status.code) // Output: 202 +console.log(status.code); // Output: 202 const recordData = await record?.data.text(); console.log(recordData); // Output: Message @@ -271,26 +268,26 @@ interface can be substituted for the default identity vault and DID resolver cac For example, to use the in-memory `KeyValueStore` implementation from `@web5/common`: ```ts -import { MemoryStore } from '@web5/common'; -import { DidDht, DidJwk } from '@web5/dids'; -import { Web5IdentityAgent } from '@web5/identity-agent'; -import { AgentDidApi, DidResolverCacheLevel, DwnDidStore } from '@web5/agent'; +import { MemoryStore } from "@web5/common"; +import { DidDht, DidJwk } from "@web5/dids"; +import { Web5IdentityAgent } from "@web5/identity-agent"; +import { AgentDidApi, DidResolverCacheLevel, DwnDidStore } from "@web5/agent"; // Instantiate Identity Vault with an in-memory store. const agentVault = new HdIdentityVault({ keyDerivationWorkFactor: 210_000, - store: new MemoryStore() + store: new MemoryStore(), }); // Instantiate DID API with an in-memory resolver cache. const didApi = new AgentDidApi({ - didMethods : [DidDht, DidJwk], - resolverCache : new DidResolverCacheMemory(), - store : new DwnDidStore() + didMethods: [DidDht, DidJwk], + resolverCache: new DidResolverCacheMemory(), + store: new DwnDidStore(), }); // Create a Web5 Identity Agent instance. -const agent = await Web5IdentityAgent.create({ agentVault, didApi}); +const agent = await Web5IdentityAgent.create({ agentVault, didApi }); ``` ## Project Resources diff --git a/packages/identity-agent/tests/identity-agent.spec.ts b/packages/identity-agent/tests/identity-agent.spec.ts index 43a3b2abd..56f7b0bd1 100644 --- a/packages/identity-agent/tests/identity-agent.spec.ts +++ b/packages/identity-agent/tests/identity-agent.spec.ts @@ -331,15 +331,6 @@ describe('Web5IdentityAgent', () => { } }; - await testHarness.preloadResolverCache({ - didUri : testPortableIdentity.portableDid.uri, - resolutionResult : { - didDocument : testPortableIdentity.portableDid.document, - didDocumentMetadata : testPortableIdentity.portableDid.metadata, - didResolutionMetadata : {} - } - }); - alice = await testHarness.agent.identity.import({ portableIdentity: testPortableIdentity }); @@ -415,8 +406,7 @@ describe('Web5IdentityAgent', () => { // Try to get the identity and verify it exists. const storedIdentity = await testHarness.agent.identity.get({ - didUri : socialIdentity.did.uri, - tenant : socialIdentity.did.uri + didUri: socialIdentity.did.uri, }); expect(storedIdentity).to.exist; diff --git a/packages/identity-agent/tests/managing-identities.spec.ts b/packages/identity-agent/tests/managing-identities.spec.ts index 616fbe5ad..e4a0dd8ff 100644 --- a/packages/identity-agent/tests/managing-identities.spec.ts +++ b/packages/identity-agent/tests/managing-identities.spec.ts @@ -59,79 +59,13 @@ describe('Managing Identities', () => { }); // Verify the Identities were stored in each new Identity's tenant. - const storedCareerIdentity = await testHarness.agent.identity.get({ didUri: careerIdentity.did.uri, tenant: careerIdentity.did.uri }); - const storedFamilyIdentity = await testHarness.agent.identity.get({ didUri: familyIdentity.did.uri, tenant: familyIdentity.did.uri }); - const storedSocialIdentity = await testHarness.agent.identity.get({ didUri: socialIdentity.did.uri, tenant: socialIdentity.did.uri }); + const storedCareerIdentity = await testHarness.agent.identity.get({ didUri: careerIdentity.did.uri }); + const storedFamilyIdentity = await testHarness.agent.identity.get({ didUri: familyIdentity.did.uri }); + const storedSocialIdentity = await testHarness.agent.identity.get({ didUri: socialIdentity.did.uri }); expect(storedCareerIdentity!.did).to.have.property('uri', careerIdentity.did.uri); expect(storedFamilyIdentity!.did).to.have.property('uri', familyIdentity.did.uri); expect(storedSocialIdentity!.did).to.have.property('uri', socialIdentity.did.uri); }).timeout(30000); - - // Tests that should only run for DWN-backed stores that provide multi-tenancy. - if (agentStoreType === 'dwn') { - it('supports tenant isolation between Identity Agent and Identities under management', async () => { - // First launch and initialization. - await testHarness.agent.initialize({ password: 'test' }); - - // Start the Agent, which will decrypt and load the Agent's DID from the vault. - await testHarness.agent.start({ password: 'test' }); - - // Create three identities, each of which is stored in a new tenant. - const careerIdentity = await testHarness.agent.identity.create({ - metadata : { name: 'Social' }, - didMethod : 'jwk' - }); - - const familyIdentity = await testHarness.agent.identity.create({ - metadata : { name: 'Social' }, - didMethod : 'jwk' - }); - - const socialIdentity = await testHarness.agent.identity.create({ - metadata : { name: 'Social' }, - didMethod : 'jwk' - }); - - // Manage the newly created identities with the Identity Agent. - await testHarness.agent.identity.manage({ portableIdentity: await careerIdentity.export() }); - await testHarness.agent.identity.manage({ portableIdentity: await familyIdentity.export() }); - await testHarness.agent.identity.manage({ portableIdentity: await socialIdentity.export() }); - - // Verify the Identities were ALSO stored in the Identity Agent's tenant. - const storedIdentities = await testHarness.agent.identity.list(); - expect(storedIdentities).to.have.length(3); - - // Verify the DIDs were only stored in the new Identity's tenant. - let storedCareerDid = await testHarness.agent.did.get({ didUri: careerIdentity.did.uri, tenant: careerIdentity.did.uri }); - expect(storedCareerDid).to.exist; - storedCareerDid = await testHarness.agent.did.get({ didUri: careerIdentity.did.uri }); - expect(storedCareerDid).to.not.exist; - let storedFamilyDid = await testHarness.agent.did.get({ didUri: familyIdentity.did.uri, tenant: familyIdentity.did.uri }); - expect(storedFamilyDid).to.exist; - storedFamilyDid = await testHarness.agent.did.get({ didUri: familyIdentity.did.uri }); - expect(storedFamilyDid).to.not.exist; - let storedSocialDid = await testHarness.agent.did.get({ didUri: socialIdentity.did.uri, tenant: socialIdentity.did.uri }); - expect(storedSocialDid).to.exist; - storedSocialDid = await testHarness.agent.did.get({ didUri: socialIdentity.did.uri }); - expect(storedSocialDid).to.not.exist; - - // Verify keys were stored in Identity Agent's DWN. - const careerVm = await testHarness.agent.did.getSigningMethod({ didUri: careerIdentity.did.uri }); - const careerKeyUri = await testHarness.agent.keyManager.getKeyUri({ key: careerVm!.publicKeyJwk! }); - const careerPublicKey = await testHarness.agent.keyManager.getPublicKey({ keyUri: careerKeyUri }); - expect(careerPublicKey).to.exist; - - const familyVm = await testHarness.agent.did.getSigningMethod({ didUri: familyIdentity.did.uri }); - const familyKeyUri = await testHarness.agent.keyManager.getKeyUri({ key: familyVm!.publicKeyJwk! }); - const familyPublicKey = await testHarness.agent.keyManager.getPublicKey({ keyUri: familyKeyUri }); - expect(familyPublicKey).to.exist; - - const socialVm = await testHarness.agent.did.getSigningMethod({ didUri: socialIdentity.did.uri }); - const socialKeyUri = await testHarness.agent.keyManager.getKeyUri({ key: socialVm!.publicKeyJwk! }); - const socialPublicKey = await testHarness.agent.keyManager.getPublicKey({ keyUri: socialKeyUri }); - expect(socialPublicKey).to.exist; - }); - } }); }); }); diff --git a/packages/proxy-agent/tests/proxy-agent.spec.ts b/packages/proxy-agent/tests/proxy-agent.spec.ts index 8408ebc82..351e88b33 100644 --- a/packages/proxy-agent/tests/proxy-agent.spec.ts +++ b/packages/proxy-agent/tests/proxy-agent.spec.ts @@ -331,15 +331,6 @@ describe('Web5ProxyAgent', () => { } }; - await testHarness.preloadResolverCache({ - didUri : testPortableIdentity.portableDid.uri, - resolutionResult : { - didDocument : testPortableIdentity.portableDid.document, - didDocumentMetadata : testPortableIdentity.portableDid.metadata, - didResolutionMetadata : {} - } - }); - alice = await testHarness.agent.identity.import({ portableIdentity: testPortableIdentity }); @@ -415,8 +406,7 @@ describe('Web5ProxyAgent', () => { // Try to get the identity and verify it exists. const storedIdentity = await testHarness.agent.identity.get({ - didUri : socialIdentity.did.uri, - tenant : socialIdentity.did.uri + didUri: socialIdentity.did.uri, }); expect(storedIdentity).to.exist; diff --git a/packages/user-agent/tests/user-agent.spec.ts b/packages/user-agent/tests/user-agent.spec.ts index 05a8f8c11..6ee45434b 100644 --- a/packages/user-agent/tests/user-agent.spec.ts +++ b/packages/user-agent/tests/user-agent.spec.ts @@ -331,15 +331,6 @@ describe('Web5UserAgent', () => { } }; - await testHarness.preloadResolverCache({ - didUri : testPortableIdentity.portableDid.uri, - resolutionResult : { - didDocument : testPortableIdentity.portableDid.document, - didDocumentMetadata : testPortableIdentity.portableDid.metadata, - didResolutionMetadata : {} - } - }); - alice = await testHarness.agent.identity.import({ portableIdentity: testPortableIdentity }); @@ -415,8 +406,7 @@ describe('Web5UserAgent', () => { // Try to get the identity and verify it exists. const storedIdentity = await testHarness.agent.identity.get({ - didUri : socialIdentity.did.uri, - tenant : socialIdentity.did.uri + didUri: socialIdentity.did.uri, }); expect(storedIdentity).to.exist; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05e5de743..3252bf6e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,7 @@ overrides: send@<0.19.0: '>=0.19.0' serve-static@<1.16.0: '>=1.16.0' express@<4.20.0: '>=4.20.0' + rollup@>=4.0.0 <4.22.4: '>=4.22.4' importers: @@ -1867,7 +1868,7 @@ packages: resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 + rollup: '>=4.22.4' peerDependenciesMeta: rollup: optional: true @@ -1876,88 +1877,88 @@ packages: resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + rollup: '>=4.22.4' peerDependenciesMeta: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.20.0': - resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} + '@rollup/rollup-android-arm-eabi@4.22.4': + resolution: {integrity: sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.20.0': - resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==} + '@rollup/rollup-android-arm64@4.22.4': + resolution: {integrity: sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.20.0': - resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==} + '@rollup/rollup-darwin-arm64@4.22.4': + resolution: {integrity: sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.20.0': - resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==} + '@rollup/rollup-darwin-x64@4.22.4': + resolution: {integrity: sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.20.0': - resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==} + '@rollup/rollup-linux-arm-gnueabihf@4.22.4': + resolution: {integrity: sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.20.0': - resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==} + '@rollup/rollup-linux-arm-musleabihf@4.22.4': + resolution: {integrity: sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.20.0': - resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==} + '@rollup/rollup-linux-arm64-gnu@4.22.4': + resolution: {integrity: sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.20.0': - resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==} + '@rollup/rollup-linux-arm64-musl@4.22.4': + resolution: {integrity: sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': - resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.22.4': + resolution: {integrity: sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.20.0': - resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==} + '@rollup/rollup-linux-riscv64-gnu@4.22.4': + resolution: {integrity: sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.20.0': - resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==} + '@rollup/rollup-linux-s390x-gnu@4.22.4': + resolution: {integrity: sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.20.0': - resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==} + '@rollup/rollup-linux-x64-gnu@4.22.4': + resolution: {integrity: sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.20.0': - resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==} + '@rollup/rollup-linux-x64-musl@4.22.4': + resolution: {integrity: sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.20.0': - resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==} + '@rollup/rollup-win32-arm64-msvc@4.22.4': + resolution: {integrity: sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.20.0': - resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==} + '@rollup/rollup-win32-ia32-msvc@4.22.4': + resolution: {integrity: sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.20.0': - resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==} + '@rollup/rollup-win32-x64-msvc@4.22.4': + resolution: {integrity: sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==} cpu: [x64] os: [win32] @@ -5249,8 +5250,8 @@ packages: ripemd160@2.0.2: resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - rollup@4.20.0: - resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==} + rollup@4.22.4: + resolution: {integrity: sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7014,71 +7015,71 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-node-resolve@15.2.3(rollup@4.20.0)': + '@rollup/plugin-node-resolve@15.2.3(rollup@4.22.4)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.20.0) + '@rollup/pluginutils': 5.1.0(rollup@4.22.4) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.8 optionalDependencies: - rollup: 4.20.0 + rollup: 4.22.4 - '@rollup/pluginutils@5.1.0(rollup@4.20.0)': + '@rollup/pluginutils@5.1.0(rollup@4.22.4)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: - rollup: 4.20.0 + rollup: 4.22.4 - '@rollup/rollup-android-arm-eabi@4.20.0': + '@rollup/rollup-android-arm-eabi@4.22.4': optional: true - '@rollup/rollup-android-arm64@4.20.0': + '@rollup/rollup-android-arm64@4.22.4': optional: true - '@rollup/rollup-darwin-arm64@4.20.0': + '@rollup/rollup-darwin-arm64@4.22.4': optional: true - '@rollup/rollup-darwin-x64@4.20.0': + '@rollup/rollup-darwin-x64@4.22.4': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.20.0': + '@rollup/rollup-linux-arm-gnueabihf@4.22.4': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.20.0': + '@rollup/rollup-linux-arm-musleabihf@4.22.4': optional: true - '@rollup/rollup-linux-arm64-gnu@4.20.0': + '@rollup/rollup-linux-arm64-gnu@4.22.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.20.0': + '@rollup/rollup-linux-arm64-musl@4.22.4': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.22.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.20.0': + '@rollup/rollup-linux-riscv64-gnu@4.22.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.20.0': + '@rollup/rollup-linux-s390x-gnu@4.22.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.20.0': + '@rollup/rollup-linux-x64-gnu@4.22.4': optional: true - '@rollup/rollup-linux-x64-musl@4.20.0': + '@rollup/rollup-linux-x64-musl@4.22.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.20.0': + '@rollup/rollup-win32-arm64-msvc@4.22.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.20.0': + '@rollup/rollup-win32-ia32-msvc@4.22.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.20.0': + '@rollup/rollup-win32-x64-msvc@4.22.4': optional: true '@scure/base@1.1.7': {} @@ -8200,11 +8201,11 @@ snapshots: '@web/dev-server-rollup@0.6.4': dependencies: - '@rollup/plugin-node-resolve': 15.2.3(rollup@4.20.0) + '@rollup/plugin-node-resolve': 15.2.3(rollup@4.22.4) '@web/dev-server-core': 0.7.2 nanocolors: 0.2.13 parse5: 6.0.1 - rollup: 4.20.0 + rollup: 4.22.4 whatwg-url: 14.0.0 transitivePeerDependencies: - bufferutil @@ -11640,26 +11641,26 @@ snapshots: hash-base: 3.1.0 inherits: 2.0.4 - rollup@4.20.0: + rollup@4.22.4: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.20.0 - '@rollup/rollup-android-arm64': 4.20.0 - '@rollup/rollup-darwin-arm64': 4.20.0 - '@rollup/rollup-darwin-x64': 4.20.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.20.0 - '@rollup/rollup-linux-arm-musleabihf': 4.20.0 - '@rollup/rollup-linux-arm64-gnu': 4.20.0 - '@rollup/rollup-linux-arm64-musl': 4.20.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0 - '@rollup/rollup-linux-riscv64-gnu': 4.20.0 - '@rollup/rollup-linux-s390x-gnu': 4.20.0 - '@rollup/rollup-linux-x64-gnu': 4.20.0 - '@rollup/rollup-linux-x64-musl': 4.20.0 - '@rollup/rollup-win32-arm64-msvc': 4.20.0 - '@rollup/rollup-win32-ia32-msvc': 4.20.0 - '@rollup/rollup-win32-x64-msvc': 4.20.0 + '@rollup/rollup-android-arm-eabi': 4.22.4 + '@rollup/rollup-android-arm64': 4.22.4 + '@rollup/rollup-darwin-arm64': 4.22.4 + '@rollup/rollup-darwin-x64': 4.22.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.22.4 + '@rollup/rollup-linux-arm-musleabihf': 4.22.4 + '@rollup/rollup-linux-arm64-gnu': 4.22.4 + '@rollup/rollup-linux-arm64-musl': 4.22.4 + '@rollup/rollup-linux-powerpc64le-gnu': 4.22.4 + '@rollup/rollup-linux-riscv64-gnu': 4.22.4 + '@rollup/rollup-linux-s390x-gnu': 4.22.4 + '@rollup/rollup-linux-x64-gnu': 4.22.4 + '@rollup/rollup-linux-x64-musl': 4.22.4 + '@rollup/rollup-win32-arm64-msvc': 4.22.4 + '@rollup/rollup-win32-ia32-msvc': 4.22.4 + '@rollup/rollup-win32-x64-msvc': 4.22.4 fsevents: 2.3.3 run-parallel-limit@1.1.0: