diff --git a/packages/w3up-client/README.md b/packages/w3up-client/README.md index 92f5e14e4..3d1ce549b 100644 --- a/packages/w3up-client/README.md +++ b/packages/w3up-client/README.md @@ -387,6 +387,7 @@ sequenceDiagram - [`uploadCAR`](#uploadcar) - [`agent`](#agent) - [`authorize`](#authorize) + - [`accounts`](#accounts) - [`currentSpace`](#currentspace) - [`setCurrentSpace`](#setcurrentspace) - [`spaces`](#spaces) @@ -513,6 +514,14 @@ function authorize (email: string, options?: { signal?: AbortSignal }): Promise< Authorize the current agent to use capabilities granted to the passed email account. +### `accounts` + +```ts +function accounts (): Record +``` + +List all accounts the agent has stored access to. + ### `currentSpace` ```ts @@ -730,7 +739,6 @@ export interface Capability< nb?: Caveats } - export type Ability = `${string}/${string}` | "*" export type Resource = `${string}:${string}` diff --git a/packages/w3up-client/src/client.js b/packages/w3up-client/src/client.js index 03511b64e..448378ad6 100644 --- a/packages/w3up-client/src/client.js +++ b/packages/w3up-client/src/client.js @@ -8,6 +8,7 @@ import { Upload as UploadCapabilities, } from '@web3-storage/capabilities' import { Base } from './base.js' +import * as Account from './account.js' import { Space } from './space.js' import { Delegation as AgentDelegation } from './delegation.js' import { StoreClient } from './capability/store.js' @@ -59,6 +60,14 @@ export class Client extends Base { } /* c8 ignore stop */ + /** + * List all accounts that agent has stored access to. Returns a dictionary + * of accounts keyed by their `did:mailto` identifier. + */ + accounts() { + return Account.list(this) + } + /** * Uploads a file to the service and returns the root data CID for the * generated DAG. diff --git a/packages/w3up-client/test/client-accounts.test.js b/packages/w3up-client/test/client-accounts.test.js new file mode 100644 index 000000000..c627f6805 --- /dev/null +++ b/packages/w3up-client/test/client-accounts.test.js @@ -0,0 +1,37 @@ +import * as Test from './test.js' +import * as Account from '../src/account.js' + +/** + * @type {Test.Suite} + */ +export const testClientAccounts = { + 'list accounts': async (assert, { client, mail, grantAccess }) => { + const email = 'alice@web.mail' + + assert.deepEqual(client.accounts(), {}, 'no accounts yet') + + const login = Account.login(client, email) + const message = await mail.take() + assert.deepEqual(message.to, email) + await grantAccess(message) + const session = await login + assert.equal(session.error, undefined) + assert.equal(session.ok?.did(), Account.fromEmail(email)) + assert.equal(session.ok?.toEmail(), email) + assert.equal(session.ok?.proofs.length, 2) + + assert.deepEqual(client.accounts(), {}, 'no accounts have been saved') + await session.ok?.save() + const accounts = client.accounts() + + assert.deepEqual(Object.values(accounts).length, 1) + assert.ok(accounts[Account.fromEmail(email)]) + + const account = accounts[Account.fromEmail(email)] + assert.equal(account.toEmail(), email) + assert.equal(account.did(), Account.fromEmail(email)) + assert.equal(account.proofs.length, 2) + }, +} + +Test.test({ 'Client accounts': testClientAccounts })