Skip to content

fix: unwrap the CommonJS default export when loading eciesjs - #343

Open
imaksp wants to merge 1 commit into
MetaMask:mainfrom
imaksp:fix/eciesjs-cjs-interop
Open

fix: unwrap the CommonJS default export when loading eciesjs#343
imaksp wants to merge 1 commit into
MetaMask:mainfrom
imaksp:fix/eciesjs-cjs-interop

Conversation

@imaksp

@imaksp imaksp commented Jul 28, 2026

Copy link
Copy Markdown

Explanation

createKeyManager() destructures a dynamic import of eciesjs:

const { decrypt, encrypt, PrivateKey, PublicKey } = await import('eciesjs');

eciesjs@0.4.17 publishes CommonJS only — no module field, and no import condition in its exports map. Bundlers therefore shape that import as { default: <module.exports> } instead of a namespace carrying the named exports, so all four bindings come back undefined and connecting over MWP throws PrivateKey is not a constructor. Node and dev servers synthesize the named exports, which is why this survives CI and Vite dev but breaks a production browser build (hit on Angular 22 / esbuild).

This unwraps default when it is present, leaving the lazy import() from #244 intact.

The new KeyManager.test.ts round-trips generate → validate → encrypt → decrypt against real eciesjs in both module shapes; the { default } case fails on main and passes here.

I audited the other dynamic imports in connect-multichain: the only remaining third-party CommonJS one is @metamask/mobile-wallet-protocol-core in #createDappClient(), which fails the same way (undefined is not an object (evaluating 'mwpCore.SessionStore.create')). That one is a packaging bug at the source — the package ships an ESM build but declares no module/exports — so I've fixed it there rather than working around it here: MetaMask/mobile-wallet-protocol#85. ws is only imported on the non-browser branch, where Node's named-export detection applies.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes — n/a, no breaking changes

🤖 Generated with Claude Code

@imaksp
imaksp requested a review from a team as a code owner July 28, 2026 08:12
imaksp pushed a commit to imaksp/connect-monorepo that referenced this pull request Jul 28, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`eciesjs` publishes CommonJS only, so bundlers shape
`await import('eciesjs')` as `{ default: <module.exports> }` rather than a
namespace carrying the named exports. Destructuring it directly left
`decrypt`, `encrypt`, `PrivateKey` and `PublicKey` undefined, so connecting
over MWP from a bundled browser app threw
`PrivateKey is not a constructor`.

Unwrap `default` when it is present, and cover both module shapes with a
round-trip test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@imaksp
imaksp force-pushed the fix/eciesjs-cjs-interop branch from b1395b2 to d477ef6 Compare July 28, 2026 08:17
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.

[connect-multichain] createKeyManager() throws "PrivateKey is not a constructor" in browser bundles — eciesjs is CJS-only

1 participant