Skip to content

fix: remove implicit bitcoinjs require from DescriptorsFactory#67

Closed
Kukks wants to merge 1 commit intobitcoinerlab:mainfrom
Kukks:fix/remove-implicit-bitcoinjs-require
Closed

fix: remove implicit bitcoinjs require from DescriptorsFactory#67
Kukks wants to merge 1 commit intobitcoinerlab:mainfrom
Kukks:fix/remove-implicit-bitcoinjs-require

Conversation

@Kukks
Copy link
Copy Markdown
Contributor

@Kukks Kukks commented Mar 29, 2026

Summary

  • Removes the lazy require('./adapters/bitcoinjs') fallback from DescriptorsFactory that caused bundler failures when bitcoinjs-lib is not installed
  • DescriptorsFactory now requires an explicit BitcoinLib backend adapter (createBitcoinjsLib(ecc) or createScureLib()) instead of accepting a raw TinySecp256k1Interface
  • The convenience packages (@bitcoinerlab/descriptors, @bitcoinerlab/descriptors-scure) already use explicit adapters and are unaffected

Problem

The require('./adapters/bitcoinjs') in DescriptorsFactory creates a static dependency chain:

descriptors.ts → require('./adapters/bitcoinjs') → import 'bitcoinjs-lib'

Bundlers like esbuild (Cloudflare Wrangler), Webpack, and Metro resolve this chain statically — even inside try/catch blocks — causing build failures when bitcoinjs-lib is not installed. This affects consumers who only use the scure backend.

Converting require() to import() does not help because with "module": "commonjs" in tsconfig, TypeScript compiles import() to Promise.resolve().then(() => require(...)), which bundlers still follow (as documented in ledger.ts lines 70-81).

Solution

Remove the implicit fallback entirely. Consumers must now explicitly choose their backend:

// Before (broken with bundlers when bitcoinjs-lib is not installed):
DescriptorsFactory(ecc);

// After:
import { createBitcoinjsLib } from '@bitcoinerlab/descriptors-core/bitcoinjs';
DescriptorsFactory(createBitcoinjsLib(ecc));

// Or:
import { createScureLib } from '@bitcoinerlab/descriptors-core/scure';
DescriptorsFactory(createScureLib());

This is a minor breaking change for consumers who used the implicit DescriptorsFactory(ecc) shorthand directly on descriptors-core. The convenience wrapper packages are unaffected since they already pass pre-built adapters.

Note on remaining require() calls

The other require() calls in the codebase (psbt.ts, keyInterfaces.ts, signers.ts, ledger.ts) resolve to internal adapter files that are always present in the package, so they don't cause bundler failures. The ledger.ts require('@ledgerhq/ledger-bitcoin') is only reached when consumers explicitly use Ledger functionality.

Ref: #66

Remove the lazy `require('./adapters/bitcoinjs')` fallback that fired
when DescriptorsFactory received a raw TinySecp256k1Interface instead
of a pre-built BitcoinLib adapter.

The require chain (descriptors.ts → adapters/bitcoinjs.ts → bitcoinjs-lib)
caused bundlers like esbuild (Cloudflare Wrangler), Webpack, and Metro to
statically resolve bitcoinjs-lib even when consumers only use the scure
backend. This broke builds where bitcoinjs-lib is not installed.

DescriptorsFactory now requires an explicit backend adapter:
  - DescriptorsFactory(createBitcoinjsLib(ecc))
  - DescriptorsFactory(createScureLib())

The convenience packages (@bitcoinerlab/descriptors, descriptors-scure)
already pass pre-built adapters, so they are unaffected.

Ref: bitcoinerlab#66
@landabaso
Copy link
Copy Markdown
Member

Thanks for the PR. I have an alternative non-breaking fix that will be merged today, @Kukks. I'd like to verify it doesn't affect downstream dependents before proceeding further.

@landabaso
Copy link
Copy Markdown
Member

landabaso commented Mar 30, 2026

Thanks again! Closed in favour of #68 .

Published as @bitcoinerlab/descriptors@3.1.7.

@landabaso landabaso closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants