did-btcr2-js

ADR 019: Browser Compatibility Constraint; @noble/* and @scure/* for Crypto

Status: Accepted

Date: 2026-03-30

Commits: 77a551b, 19818d0

Context

did:btcr2 targets two distinct runtimes:

An early implementation used node:crypto directly (HMAC, digests), along with node:buffer and node:fs touches scattered through the code. Every such dependency produced a broken browser build: either silent failures when APIs were missing, or bundler explosions from Node-only require calls.

Rather than continue playing whack-a-mole, the project adopted a hard constraint: no Node.js-only APIs anywhere in library source code. lib/ scripts (test-vector generators, interactive examples) are allowed Node-only APIs because they’re never meant to run in a browser; everything under packages/*/src/ must work in both runtimes.

Options considered

  1. Keep node:crypto + ship a separate browser polyfill. Two codebases in effect, divergence risk.
  2. Use Web Crypto (globalThis.crypto.subtle) directly. Async-only API, limited primitives, clumsy for the didcore hashing patterns we rely on.
  3. Adopt the @noble/* + @scure/* stack: @noble/hashes, @noble/curves, @noble/secp256k1, @scure/base, @scure/btc-signer, @scure/bip32, @scure/bip39.

Decision

Option 3. Library code depends only on cross-runtime packages. Specifically:

Node-only modules (node:http, node:fs, node:crypto, node:path) are disallowed in src/. They are allowed in lib/ scripts and test helpers under tests/helpers/ with clear intent.

Enforcement: code review. CI could add a grep-based check; not currently wired.

Consequences

Positive

Negative

Explicitly accepted trade-offs

References