Skip to content

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

Description

@imaksp

What happens

@metamask/connect-multichain@1.2.0. Connecting via MWP (the QR flow, no extension installed) throws PrivateKey is not a constructor in a production browser bundle. Seen on Angular 22 / esbuild; reproduces in a Vite production build too, but not in Vite dev.

Cause

packages/connect-multichain/src/multichain/transports/mwp/KeyManager.ts#L20:

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

eciesjs@0.4.17 is CJS-only — no module field, and its exports map has no import condition. Bundlers therefore shape the dynamic import as { default: <module.exports> }, leaving all four bindings undefined. Node and Vite's dev prebundle synthesize the named exports, which is likely why this wasn't caught.

Introduced by #244, which moved eciesjs behind import().

Workaround we ship (patched dist)

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

Happy to open that as a PR if you want it — the source version needs a small cast, and you may prefer a static import or an ESM-capable crypto dependency instead.

Same bug, two lines away

#createDappClient() in src/multichain/index.ts destructures mwpCore.SessionStore from await import('@metamask/mobile-wallet-protocol-core'), which is also CJS-resolved, giving undefined is not an object (evaluating 'mwpCore.SessionStore.create'). That one's root cause is a missing exports field upstream, fixed in MetaMask/mobile-wallet-protocol#85 — but it needs a release before it reaches consumers.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions