@web5/agent
Version:
262 lines • 12.4 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { BearerIdentity } from './bearer-identity.js';
import { isPortableDid } from './prototyping/dids/utils.js';
import { InMemoryIdentityStore } from './store-identity.js';
import { getDwnServiceEndpointUrls } from './utils.js';
export function isPortableIdentity(obj) {
// Validate that the given value is an object that has the necessary properties of PortableIdentity.
return !(!obj || typeof obj !== 'object' || obj === null)
&& 'did' in obj
&& 'metadata' in obj
&& 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 {
constructor({ agent, store } = {}) {
this._agent = agent;
// If `store` is not given, use an in-memory store by default.
this._store = store !== null && store !== void 0 ? store : new InMemoryIdentityStore();
}
/**
* Retrieves the `Web5PlatformAgent` execution context.
*
* @returns The `Web5PlatformAgent` instance that represents the current execution context.
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('AgentIdentityApi: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
}
get tenant() {
if (!this._agent) {
throw new Error('AgentIdentityApi: The agent must be set to perform tenant specific actions.');
}
return this._agent.agentDid.uri;
}
create({ metadata, didMethod = 'dht', didOptions, store }) {
return __awaiter(this, void 0, void 0, function* () {
const bearerDid = yield this.agent.did.create({
method: didMethod,
options: didOptions,
tenant: this.tenant,
store,
});
// Create the BearerIdentity object.
const identity = new BearerIdentity({
did: bearerDid,
metadata: Object.assign(Object.assign({}, metadata), { uri: bearerDid.uri, tenant: this.tenant })
});
// Persist the Identity to the store, by default, unless the `store` option is set to false.
if (store !== null && store !== void 0 ? store : true) {
yield this._store.set({
id: identity.did.uri,
data: identity.metadata,
agent: this.agent,
tenant: identity.metadata.tenant,
preventDuplicates: false,
useCache: true
});
}
return identity;
});
}
export({ didUri }) {
return __awaiter(this, void 0, void 0, function* () {
const bearerIdentity = yield this.get({ didUri });
if (!bearerIdentity) {
throw new Error(`AgentIdentityApi: Failed to export due to Identity not found: ${didUri}`);
}
// If the Identity was found, return the Identity in a portable format, and if supported by the
// Agent's key manager, the private key material.
const portableIdentity = yield bearerIdentity.export();
return portableIdentity;
});
}
get({ didUri }) {
return __awaiter(this, void 0, void 0, function* () {
const storedIdentity = yield 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;
// Retrieve the DID from the Agent's DID store using the tenant value from the stored
// Identity's metadata.
const storedDid = yield this.agent.did.get({ didUri, tenant: storedIdentity.tenant });
// If the Identity is present but the DID is not found, throw an error.
if (!storedDid) {
throw new Error(`AgentIdentityApi: Identity is present in the store but DID is missing: ${didUri}`);
}
// Create the BearerIdentity object.
const identity = new BearerIdentity({ did: storedDid, metadata: storedIdentity });
return identity;
});
}
import({ portableIdentity }) {
return __awaiter(this, void 0, void 0, function* () {
// 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 = yield this.agent.did.import({
portableDid: portableIdentity.portableDid,
tenant: portableIdentity.metadata.tenant
});
// Verify the DID is present in the Agent's DID store.
if (!storedDid) {
throw new Error(`AgentIdentityApi: Failed to import 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.
yield this._store.set({
id: identity.did.uri,
data: identity.metadata,
agent: this.agent,
tenant: identity.metadata.tenant,
preventDuplicates: true,
useCache: true
});
return identity;
});
}
list({ tenant } = {}) {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the list of Identities from the Agent's Identity store.
const storedIdentities = yield this._store.list({ agent: this.agent, tenant });
const identities = yield Promise.all(storedIdentities.map(metadata => this.get({ didUri: metadata.uri })));
return identities.filter(identity => typeof identity !== 'undefined');
});
}
delete({ didUri }) {
return __awaiter(this, void 0, void 0, function* () {
const storedIdentity = yield 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.
yield this._store.delete({ id: didUri, agent: this.agent });
});
}
/**
* Returns the DWN endpoints for the given DID.
*
* @param didUri - The DID URI to get the DWN endpoints for.
* @returns An array of DWN endpoints.
* @throws An error if the DID is not found, or no DWN service exists.
*/
getDwnEndpoints({ didUri }) {
return getDwnServiceEndpointUrls(didUri, this.agent.did);
}
/**
* Sets the DWN endpoints for the given DID.
*
* @param didUri - The DID URI to set the DWN endpoints for.
* @param endpoints - The array of DWN endpoints to set.
* @throws An error if the DID is not found, or if an update cannot be performed.
*/
setDwnEndpoints({ didUri, endpoints }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const bearerDid = yield this.agent.did.get({ didUri });
if (!bearerDid) {
throw new Error(`AgentIdentityApi: Failed to set DWN endpoints due to DID not found: ${didUri}`);
}
const portableDid = yield bearerDid.export();
const dwnService = (_a = portableDid.document.service) === null || _a === void 0 ? void 0 : _a.find(service => service.id.endsWith('dwn'));
if (dwnService) {
// Update the existing DWN Service with the provided endpoints
dwnService.serviceEndpoint = endpoints;
}
else {
// create a DWN Service to add to the DID document
const newDwnService = {
id: 'dwn',
type: 'DecentralizedWebNode',
serviceEndpoint: endpoints,
enc: '#enc',
sig: '#sig'
};
// if no other services exist, create a new array with the DWN service
if (!portableDid.document.service) {
portableDid.document.service = [newDwnService];
}
else {
// otherwise, push the new DWN service to the existing services
portableDid.document.service.push(newDwnService);
}
}
yield this.agent.did.update({ portableDid, tenant: this.agent.agentDid.uri });
});
}
/**
* Updates the Identity's metadata name field.
*
* @param didUri - The DID URI of the Identity to update.
* @param name - The new name to set for the Identity.
*
* @throws An error if the Identity is not found, name is not provided, or no changes are detected.
*/
setMetadataName({ didUri, name }) {
return __awaiter(this, void 0, void 0, function* () {
if (!name) {
throw new Error('AgentIdentityApi: Failed to set metadata name due to missing name value.');
}
const identity = yield this.get({ didUri });
if (!identity) {
throw new Error(`AgentIdentityApi: Failed to set metadata name due to Identity not found: ${didUri}`);
}
if (identity.metadata.name === name) {
throw new Error('AgentIdentityApi: No changes detected.');
}
// Update the name in the Identity's metadata and store it
yield this._store.set({
id: identity.did.uri,
data: Object.assign(Object.assign({}, identity.metadata), { name }),
agent: this.agent,
tenant: identity.metadata.tenant,
updateExisting: true,
useCache: true
});
});
}
/**
* Returns the connected Identity, if one is available.
*
* Accepts optional `connectedDid` parameter to filter the a specific connected identity,
* if none is provided the first connected identity is returned.
*/
connectedIdentity({ connectedDid } = {}) {
return __awaiter(this, void 0, void 0, function* () {
const identities = yield this.list();
if (identities.length < 1) {
return undefined;
}
// If a specific connected DID is provided, return the first identity that matches it.
// Otherwise, return the first connected identity.
return connectedDid ?
identities.find(identity => identity.metadata.connectedDid === connectedDid) :
identities.find(identity => identity.metadata.connectedDid !== undefined);
});
}
}
//# sourceMappingURL=identity-api.js.map