did-btcr2-js

@did-btcr2/api

High-level SDK facade for the did:btcr2 DID method. Wraps @did-btcr2/method and the surrounding crypto / bitcoin / key-management packages behind a single ergonomic entry point.

Part of the did-btcr2-js monorepo.

Summary

The lower-level packages (@did-btcr2/method, @did-btcr2/cryptosuite, @did-btcr2/key-manager, @did-btcr2/bitcoin) are designed to be composable and sans-I/O. This package is the thin layer above them: it owns Bitcoin endpoint configuration, CAS retrieval, key management, and the dispatch loop for the sans-I/O state machines.

If you’re integrating did:btcr2 into an app, start here. If you’re customizing the protocol, drop down to @did-btcr2/method directly.

The api wires the configured BitcoinApi into the sans-I/O Resolver and Updater state machines, fulfilling NeedBeaconSignals, NeedFunding, NeedBroadcast, and CAS-related needs (NeedGenesisDocument, NeedCASAnnouncement, NeedSignedUpdate) automatically. NeedSMTProof is not auto-fulfilled by the facade: SMT proofs must be provided upfront via options.sidecar.smtProofs. Multi-party aggregation is out of scope here; drive the Updater directly and hand NeedBroadcast to the aggregation runner from @did-btcr2/method.

Install

npm install @did-btcr2/api

Or with pnpm:

pnpm add @did-btcr2/api

Runtime note: ESM-only package (requires import, not require). Ships a browser bundle at dist/browser.mjs for bundler-based environments. Requires Node >= 22.

Key Exports

Concern Entry point
Main facade DidBtcr2Api, createApi(config?)
Sub-facades BitcoinApi, CasApi, CryptoApi, DidApi, KeyManagerApi, DidMethodApi
Fluent update UpdateBuilder (from api.btcr2.buildUpdate(...))
Config types ApiConfig, BitcoinApiConfig, CasConfig, Logger
Resolution result ResolutionResult (tryResolveDid return type)
Re-exports from method/common DidDocument, DidDocumentBuilder, Identifier, IdentifierTypes

Quick Start

Generate a DID and resolve it

import { createApi } from '@did-btcr2/api';

const api = createApi({ btc: { network: 'mutinynet' } });

// Generate keypair, derive DID, import the secret into the in-process KMS.
const { did, keyId } = api.generateDid({ network: 'mutinynet' });

// Resolve. Bitcoin signals are fetched automatically via the configured BitcoinApi.
const resolution = await api.resolveDid(did);
console.log(resolution.didDocument?.id);

Update via the fluent builder

import { LocalSigner } from '@did-btcr2/keypair';

const signed = await api.btcr2
  .buildUpdate(currentDoc)
  .patch({ op: 'add', path: '/service/-', value: newService })
  .version(2)
  .verificationMethodId('#initialKey')
  .beacon('#beacon-0')
  .signer(new LocalSigner(secretKey))
  .execute();

Resolve without throwing

const result = await api.tryResolveDid(did);
if (result.ok) {
  console.log(result.document);
} else {
  console.warn(`resolve failed: ${result.error} - ${result.errorMessage}`);
}

Sign with a KMS-backed signer (HSM / cloud / external keystore)

import { KeyManagerSigner } from '@did-btcr2/key-manager';

const signer = new KeyManagerSigner(api.kms.kms, keyId);

await api.updateDid({
  did,
  patches              : [{ op: 'add', path: '/service/-', value: newService }],
  verificationMethodId : '#initialKey',
  beaconId             : '#beacon-0',
  signer,
});

Architecture Principles

Build & Test

# From packages/api/
pnpm build              # Compile ESM + browser bundle + type declarations
pnpm build:tests        # Compile tests to tests/compiled/
pnpm test               # Run the test suite with coverage
pnpm lint               # ESLint (zero warnings tolerated)

The lib/ directory contains end-to-end scripts that exercise the full update path against regtest, mutinynet, signet, testnet3, and testnet4. Run with bun packages/api/lib/e2e-*.ts or tsx. On non-regtest networks the scripts persist generated secret keys to lib/.e2e-keys/ (gitignored) so funds at beacon addresses can be recovered.

Documentation

License

MPL-2.0