@app_/custodian-client

HTTP client for the Custodian service — a local daemon that manages your private key, identity sessions, Proof of Work generation, and encrypted operations. All requests use a 10-second timeout.

Creating a client

import { createCustodianClient } from '@app_/custodian-client';

const custodian = createCustodianClient({
  // Optional — defaults to https://127.0.0.1:6473
  getCustodianUrl: () => 'https://my-custodian.local:6473',
});

Identity management

Bootstrap a new identity (generate or import keypair), get authenticated sessions with delegated keys, and manage logout.

// Generate a new identity
const { ok, publicKey } = await custodian.bootstrapIdentity({
  mode: 'generate',
});

// Or import an existing keypair
const result = await custodian.bootstrapIdentity({
  mode: 'import',
  signingKeys: { publicKey: '...', privateKey: '...' },
});

// Get a session with delegated keys and proofs
const session = await custodian.getIdentitySession(
  'https://my-app.example',  // origin
  ['read', 'write'],         // scopes
);
// Returns: { publicKey, publicEncryptionKey?, delegatedPrivateKey, proofs[], preferences }

// Logout
await custodian.logout();

Proof of Work

Generate PoW proofs that attest computational effort. The PoW tier corresponds to difficulty levels defined in @app_/consts: hero (2), titan (6), atlas (9). Supports streaming progress updates.

// Ensure a Proof of Work exists (generates if missing)
const { ok, progress } = await custodian.ensureKeyPow(6); // tier = difficulty

// Force regenerate
await custodian.regenerateKeyPow(9);

// Check current progress
const progress = await custodian.getKeyPowProgress();
// Returns: { id, tier, status, progress, workProof?, error, startedAt, updatedAt }

// Stream progress updates
const result = await custodian.waitForKeyPowProgressStream((progress) => {
  console.log(progress.progress + '% complete');
});
// Returns: { workProof?: ProofOfWork }

// Cancel in-progress PoW
await custodian.cancelKeyPow();

Key management

Export or back up your private key. Backups are encrypted with a passphrase using PBKDF2 key derivation and AES-256-GCM.

// Get URL for private key export (opens in browser)
const url = custodian.getPrivateKeyExportUrl();

// Get encrypted backup (PBKDF2 + AES-256-GCM)
const { encrypted } = await custodian.getEncryptedPrivateKeyBackup('my-passphrase');

Decryption

Decrypt HPKE-encrypted items using the Custodian's private key. Used for end-to-end encrypted envelopes.

// Decrypt HPKE-encrypted items
const items = [
  { kemCiphertext: '...', encryptedData: '...' },
  { kemCiphertext: '...', encryptedData: '...' },
];
const decrypted = await custodian.decrypt<MyType>(items);

Preferences

await custodian.setPreferences({
  theme: 'dark',
  language: 'en',
  guides: [{ url: 'https://guide.example', publicKeyHash: 'abc...' }],
  shelters: [{ url: 'https://shelter.example', publicKeyHash: 'def...' }],
});

API methods

Method Returns Description
bootstrapIdentity(body)BootstrapIdentityResponseGenerate or import identity
getIdentitySession(origin, scopes)IdentitySessionResponse | nullGet authenticated session
logout()OkResponseEnd current session
ensureKeyPow(tier?)KeyPowRegenerateResponseEnsure PoW exists
regenerateKeyPow(tier?)KeyPowRegenerateResponseForce regenerate PoW
getKeyPowProgress()KeyPowProgress | undefinedCheck PoW progress
cancelKeyPow()OkResponseCancel PoW generation
waitForKeyPowProgressStream(cb?){workProof?}Stream PoW progress
decrypt<T>(items)T[]Decrypt HPKE items
getPrivateKeyExportUrl()stringURL for key export
getEncryptedPrivateKeyBackup(pass){encrypted}Encrypted key backup
setPreferences(config)OkResponseUpdate user preferences