Summary
packages/a2x/tsup.config.ts builds the root index entry and the subpath entries (client, x402, …) as two separate tsup configs. Each bundle therefore carries its own copy of shared classes: dist/index.js defines e.g. X402PaymentFailedError inline, while dist/x402/index.js imports it from a chunk shared only among the second config's entries.
As a result, an error thrown by A2XClient (imported from @a2x/sdk) is never instanceof the class a consumer imports from @a2x/sdk/x402:
import { A2XClient } from '@a2x/sdk';
import { X402PaymentFailedError } from '@a2x/sdk/x402';
try {
await client.sendMessage(...);
} catch (err) {
err instanceof X402PaymentFailedError; // always false
}
This bit the in-repo CLI: printX402Error matched only via instanceof, so every payment failure fell through to the generic connection-error path (exit 1, no x402 message). #226 works around it CLI-side by also matching on err.name, but the hazard remains for every external consumer and for all classes exported from more than one entry (X402Error subclasses, and any A2AError subclasses if they are reachable from multiple entries).
Possible fixes
- Merge the two tsup configs into one so ESM entries share chunks (fixes ESM; CJS needs
splitting enabled or the same class copied — CJS consumers requiring both entries would still be broken without cjs splitting).
- And/or make
instanceof non-load-bearing: give SDK error classes a stable discriminator (name is already set; document name-based narrowing, or export isX402PaymentFailedError()-style guards that match cross-realm).
Related
Summary
packages/a2x/tsup.config.tsbuilds the rootindexentry and the subpath entries (client,x402, …) as two separate tsup configs. Each bundle therefore carries its own copy of shared classes:dist/index.jsdefines e.g.X402PaymentFailedErrorinline, whiledist/x402/index.jsimports it from a chunk shared only among the second config's entries.As a result, an error thrown by
A2XClient(imported from@a2x/sdk) is neverinstanceofthe class a consumer imports from@a2x/sdk/x402:This bit the in-repo CLI:
printX402Errormatched only viainstanceof, so every payment failure fell through to the generic connection-error path (exit 1, no x402 message). #226 works around it CLI-side by also matching onerr.name, but the hazard remains for every external consumer and for all classes exported from more than one entry (X402Errorsubclasses, and anyA2AErrorsubclasses if they are reachable from multiple entries).Possible fixes
splittingenabled or the same class copied — CJS consumers requiring both entries would still be broken without cjs splitting).instanceofnon-load-bearing: give SDK error classes a stable discriminator (nameis already set; document name-based narrowing, or exportisX402PaymentFailedError()-style guards that match cross-realm).Related