did-btcr2-js

ADR 069: Fetch-Based CAS Executors Replace the In-Process IPFS Dependency

Status: Accepted

Date: 2026-07-06

Branch / PR: refactor/cas-drop-helia

References: ADR 023, ADR 058, ADR 064

Context

The SDK’s content-addressed storage layer (CasApi, ADR 023) selects a CasExecutor backend from its configuration. Until now the api package offered two executors: a read-only HTTP executor speaking the IPFS Trustless Gateway protocol, and IpfsCasExecutor, which wrapped a caller-supplied Helia (in-process IPFS node) instance and was typed against the Helia interface. That typing made helia a production dependency of the api package, even though:

The cost of that one declaration was carried by every consumer and by CI:

Decision

Drop the helia dependency entirely and restructure the executor set around plain fetch and structural typing:

  1. BlockstoreCasExecutor replaces IpfsCasExecutor. It is typed against two local structural interfaces, BlockstoreLike (get/put of raw blocks by CID) and BlockstoreProviderLike (anything exposing a blockstore property). A Helia instance satisfies BlockstoreProviderLike unchanged, so in-process IPFS nodes still plug in with the same one-argument construction, without this package declaring any IPFS implementation as a dependency.
  2. IpfsRpcCasExecutor is added as the fetch-based read-write backend. It speaks the IPFS HTTP RPC API (the interface a Kubo node exposes): block/put with the raw codec, SHA-256 multihash, and pinning for publishes; block/get for retrieval. publish derives the expected CID locally from the content hash and rejects if the node reports a different CID, so a misconfigured node cannot silently store content under a different address.
  3. CasConfig selects among four backends with the priority executor > blockstore > rpcUrl > gateway. The helia field is replaced by blockstore; rpcUrl is new; the read-only gateway default is unchanged.
  4. The helia production dependency is removed from the api package, and the two Helia-based dev scripts are replaced by one that exercises the RPC executor against a real node. Helia leaves the workspace lockfile entirely.
  5. The dependency-audit gate is tightened from critical to high and scoped to production dependencies (skip-dev), with its allowlist emptied, as the gate’s own configuration comment had planned once the Helia surface was gone. Dev-tooling chains (eslint, mocha, rollup, esbuild, browser-polyfill shims) still carry transitive advisories pinned by their parents; those never ship, and a plain pnpm audit still surfaces them.

Consequences

Rejected alternatives