Status: Accepted
Date: 2025-09-18
At inception (see ADR 001) the project was organized as a pnpm workspace, but not all of today’s layer-one packages existed yet. Bitcoin client code: REST (Esplora) and RPC (Bitcoin Core): originally lived inside packages/method/lib/bitcoin/* as a subdirectory of the method package. Several practical problems accumulated:
@did-btcr2/method imports reached down into the embedded Bitcoin code, which imported node:http, node:https, and JSON-RPC transport code that does not exist in browsers. Browser builds either failed at bundle time or silently broke at runtime when the client actually tried to open a socket.bitcoin.node.ts and bitcoin.browser.ts, with separate index.node.ts / index.browser.ts entry points. Bundlers were expected to pick the right one based on a "browser" field in package.json. This works until it doesn’t: some bundlers honor the field, some don’t, and the method package couldn’t rely on either branch existing for its consumers.method can also drive a Bitcoin Core RPC connection. The monorepo’s intent (ADR 001) was that layer-one concerns be installable independently. Bitcoin-as-subdirectory blocked that.There were two distinct decisions to make, and they landed two days apart: which is why this ADR covers both commits:
faff3be (2025-09-16): should Bitcoin client code live inside method or as its own package?0d957d6 (2025-09-18): given a separate package, should the package ship two builds (node + browser) or one universal build?For the extraction:
method. Simplest; blocks browser consumers of method and muddles the consumer surface.@did-btcr2/bitcoin with its own versioning. Clean layer boundary, independent testing, independent publishing; adds one more package to maintain.For the build shape (after extraction):
bitcoin.node.ts + bitcoin.browser.ts), rely on "browser" field. Bundler-dependent resolution, fragile across consumers. Duplication between the two files drifts.globalThis.fetch, platform crypto), with any Node-specific helpers confined to lib/ scripts that aren’t part of the library’s public surface. Single source of truth.Extraction: Option 2. Bitcoin code moves out of packages/method/lib/bitcoin/ into a new @did-btcr2/bitcoin package on 2025-09-16 (commit faff3be). The package scope is the full Bitcoin-client surface: REST (Esplora) client, RPC (Bitcoin Core) client, JSON-RPC transport, network constants, shared error types, and the Bitcoin utilities. method declares @did-btcr2/bitcoin as a workspace dependency.
Build shape: Option 2. Two days later (commit 0d957d6), the dual-build pattern is collapsed:
packages/bitcoin/src/bitcoin.node.ts: deleted.packages/bitcoin/src/bitcoin.browser.ts to renamed to bitcoin.ts as the single entry point.packages/bitcoin/src/index.node.ts and packages/bitcoin/src/index.browser.ts: deleted.index.ts replaces both.At the same time, the large monolithic rest-client.ts (420 lines) and rpc-client.ts (888 lines) are broken up into modular sub-clients (client/rest/{address,block,transaction,index}.ts and client/rpc/{index,interface,json-rpc}.ts). The decomposition is needed anyway: the monoliths were hard to test and hard to reuse: but it also makes the “single module, no Node-only APIs” rule practical to enforce in code review.
The method package’s browser build no longer reaches into Node-only Bitcoin code because that code no longer exists; what remains in @did-btcr2/bitcoin is runtime-universal.
Positive
method becomes publishable as a browser-safe package. Consumers that only need to resolve a DID in a browser no longer drag Node-only Bitcoin internals into their bundle.rest-client.ts and rpc-client.ts into sub-clients sets up the shape that later becomes the sans-I/O protocol layer (see ADR 009).Negative
workspace:^ semver ranges (the broader policy is described in ADR 001).bitcoin.browser.ts to bitcoin.ts deletes legitimate-looking history in a git log --follow; contributors reading historical blame across the September 2025 window have to know that faff3be/0d957d6 is a boundary point.@did-btcr2/method@<0.15 who also interacted with embedded Bitcoin code directly had to migrate their imports. No @did-btcr2/bitcoin re-export was added inside method.Explicitly accepted trade-offs
fetch does the wire-level work. Any Node-specific conveniences (e.g., reading bitcoin.conf for RPC credentials) belong in consumer code or lib/ scripts, not the library.bitcoin-rest / bitcoin-rpc. Both are Bitcoin-client concerns and version together; splitting them would be a distinction without a consumer benefit.packages/bitcoin/: the package that resulted.faff3be (2025-09-16): initial extraction.0d957d6 (2025-09-18): dual-build consolidation and client decomposition.