Skip to content

fix(client): fetchAccount error discrimination, buildTransaction blockhash expiry, sendTransaction confirmation#4

Open
lpsmurf wants to merge 75 commits into
OOBE-PROTOCOL:mainfrom
lpsmurf:fix/client-fetchaccount-error-handling
Open

fix(client): fetchAccount error discrimination, buildTransaction blockhash expiry, sendTransaction confirmation#4
lpsmurf wants to merge 75 commits into
OOBE-PROTOCOL:mainfrom
lpsmurf:fix/client-fetchaccount-error-handling

Conversation

@lpsmurf

@lpsmurf lpsmurf commented Jun 3, 2026

Copy link
Copy Markdown

Summary

Three bugs in SapClient (src/client.ts) found while building on the SDK for the OOBE bounty. All three affect real workflows — particularly x402 payment + SAP registration flows.


Bug 1 — fetchAccount swallows all errors (@ts-ignore + catch-return-null)

Before:

async fetchAccount<T = any>(name: string, address: PublicKey): Promise<T | null> {
  try { // @ts-ignore
  return await this.program.account[name].fetch(address) as T; }
  catch { return null; }
}

Problem: Every error returns null — network failures, wrong IDL, RPC timeouts, malformed responses. Callers cannot tell whether an agent is unregistered or whether the RPC is down. In our registration flow, an RPC timeout silently looked like "agent not registered" and triggered a duplicate registration attempt.

Fix: Inspect the error message. Anchor wraps missing accounts in messages containing "Account does not exist", "AccountNotFound", or "AccountDiscriminatorMismatch" — return null for those. Re-throw everything else.

Also removes the @ts-ignore by accessing program.account through a typed cast, keeping TypeScript safety intact.


Bug 2 — buildTransaction discards lastValidBlockHeight

Before:

const { blockhash } = await this.connection.getLatestBlockhash();
// lastValidBlockHeight is fetched but immediately discarded
return new VersionedTransaction(msg);

Problem: getLatestBlockhash() returns both blockhash and lastValidBlockHeight. The height is needed for confirmTransaction's blockheight-based strategy (the recommended approach since web3.js 1.73). Without it, callers have no transaction deadline — confirmTransaction either uses an unsafe fallback or hangs indefinitely on slow/congested RPCs.

Fix: Return { tx, blockhash, lastValidBlockHeight } so callers can pass the full confirmation strategy. This is a breaking change for the return type — see migration below.

Migration:

// Before
const tx = await client.buildTransaction(ixs, payer);
await client.sendTransaction(tx, [signer]);

// After
const { tx, blockhash, lastValidBlockHeight } = await client.buildTransaction(ixs, payer);
await client.sendTransaction(tx, [signer], { blockhash, lastValidBlockHeight });

Bug 3 — sendTransaction sends but never confirms

Before:

return await this.connection.sendTransaction(tx as any, { ... });

Problem: Returns a signature as soon as the transaction is accepted by the RPC node — not when it's confirmed on-chain. For x402 payment flows this is critical: the caller receives a signature, passes it as X-Payment to the API, and the API verifies on-chain — but the transaction may not be confirmed yet, causing spurious payment failures.

Fix: When the caller provides blockhash + lastValidBlockHeight (from buildTransaction), confirm via BlockheightBasedTransactionConfirmationStrategy before returning. Also throws explicitly if the transaction fails on-chain rather than letting the caller discover it later.


Bug 4 (minor) — No warning when defaulting to mainnet-beta

Added a console.warn in development (NODE_ENV !== "production") when no rpcUrl or connection is provided. Prevents accidental mainnet usage during testing — a common footgun for new integrators.


Testing

Verified against our live SAP registration (agent PDA 8m5MXkunTGabXKLrmVCj2WekLF4V2WwB3gKGuAc872rx) and 54 x402 payment flows on Solana mainnet as part of the OOBE bounty submission.

🤖 Generated with Claude Code

…ng PDA derive functions

- Add constants/addresses.ts with pre-computed mainnet PDAs:
  - SAP_PROGRAM, SAP_UPGRADE_AUTHORITY, GLOBAL_REGISTRY_ADDRESS
  - IDL_ACCOUNT_ADDRESS, PROGRAM_METADATA_PROGRAM
  - TOOL_CATEGORY_ADDRESSES (all 10 categories)
- Add BUFFER and DIGEST seeds to constants/seeds.ts
- Add deriveBuffer, deriveDigest, derivePlugin, deriveMemoryEntry,
  deriveMemoryChunk PDA functions to pda/index.ts
- Export all new constants from constants/index.ts
- Update docs with mainnet address reference tables
- Fix vanity prefix comment in programs.ts
- Replace all 'Solana Agent Protocol' references with 'Synapse Agent Protocol'
  across docs, src modules, plugin, SKILL.md
- Bump version to 0.4.0
- Updated in: client.ts, index.ts, plugin/index.ts, all modules,
  docs/00-overview, docs/03-agent-lifecycle, docs/08-plugin-adapter, SKILL.md
… compatibility

- Remove 'Wallet' import from @coral-xyz/anchor (not exported in ESM builds)
- Add SapWallet interface (minimal wallet/signer contract)
- Add KeypairWallet class (drop-in replacement for Anchor's NodeWallet)
- Update createClient() to accept SapWallet instead of Wallet
- Export KeypairWallet and SapWallet from core and main barrel
- Fixes: 'Wallet is not exported from @coral-xyz/anchor' in Next.js/webpack
- Bump version to 0.4.1
- Add src/parser/ (7 files): transaction, instructions, complete, inner, client, types, index
- parseSapInstructionsFromTransaction: decode from TransactionResponse (legacy + v0)
- parseSapInstructionsFromList: decode from TransactionInstruction[]
- parseSapTransactionComplete: full parse with instructions + inner CPI + events
- parseSapTransactionBatch: batch processing for indexer pipelines
- decodeInnerInstructions: reconstruct CPI calls with full account keys
- TransactionParser: OOP wrapper, exposed as SapClient.parser
- Add ./parser subpath export to package.json
- Bump version to 0.4.2
- Update CHANGELOG.md
- Add SapNetwork constant (SOLANA_MAINNET, SOLANA_MAINNET_GENESIS,
  SOLANA_DEVNET, SOLANA_DEVNET_NAMED) for x402 X-Payment-Network headers.
- Add SapNetworkId union type.
- Extend PreparePaymentOptions with optional networkIdentifier field.
- Persist networkIdentifier in PaymentContext at escrow creation.
- Update buildPaymentHeaders() resolution: opts.network > ctx.networkIdentifier > default.
- Update buildPaymentHeadersFromEscrow() to use SapNetwork.SOLANA_MAINNET default.
- Add skills/merchant.md: comprehensive merchant/seller developer guide.
- Add skills/client.md: comprehensive client/consumer developer guide.
- Add docs/EXPLORER_REFERENCE.md: full protocol explorer reference.
- Bump version to 0.5.0.
Phase A - Endpoint Discovery Hardening
Phase B - Network Normalization
Phase C - RPC Strategy and Error Classification
Phase D - Zod Runtime Schemas
CLI (synapse-sap) - 10 command groups, 40+ subcommands
Skills docs updated to v0.6.0
Features:
- Priority fee module (FAST_SETTLE_OPTIONS, FAST_BATCH_SETTLE_OPTIONS)
- x402 settlement with configurable ComputeBudget instructions

CLI:
- Full CLI rewrite with 10 command groups, 40+ subcommands
- Architecture docs, editor config, package-lock

Documentation:
- Explorer SDK Cookbook (11 sections)
- Complete protocol docs: feedback/reputation system (formula, lifecycle)
- Attestation web-of-trust (create/revoke/close, types)
- Memory vault write pipeline (epochs, merkle, multi-fragment, nonce rotation)
- Ledger ring buffer (write/seal/close, cost model)
- Delegate hot-wallet system (permission bitmask, auth chain)
- On-chain tool schemas (publish+inscribe pipeline, consumer validation)
- DiscoveryRegistry consumer entry point
- Updated skills.md routing table (14 new entries)
- Fixed reputation range: 0-1000 per feedback, 0-10000 aggregate
- GeyserEventStream class with auto-reconnect, ping keepalive, typed events
- GeyserConfig interface (endpoint, token, commitment, reconnect options)
- SapSyncEngine.startGeyserStream() — drop-in gRPC alternative to WSS
- @triton-one/yellowstone-grpc as optional peer dependency
- OOBE Protocol gRPC endpoint: us-1-mainnet.oobeprotocol.ai
- Skills docs updated: merchant.md §19, client.md §17, skills.md §23
- Raw Yellowstone client usage examples in all skill files
…yments

- validateEscrowState() server-side escrow validation pipeline
- attachSplAccounts() / toAccountMetas() typed SPL account metas
- SapMerchantValidator middleware with X-Payment-* header parsing
- getX402DirectPayments() direct SPL payment recognition on agent ATA
- MissingEscrowAtaError typed error class
- skills/memory.md comprehensive memory reference (4 systems, 21 sections)
- Updated merchant.md §25, client.md §18, skills.md §29
Added:
- EscrowV2Module (create, deposit, settle, withdraw, close, disputes)
- StakingModule (initStake, deposit, requestUnstake, completeUnstake)
- SubscriptionModule (create, fund, cancel, close)
- V2.1 PDA derivers, enums, account types, instruction args
- X402Registry V2-aware (auto-detect V2 escrows)
- IDL synced (86 instructions, 24 accounts, 91 types)

Deprecated:
- EscrowModule → EscrowV2Module
- deriveEscrow → deriveEscrowV2
- X402Registry: preparePayment, addFunds, withdrawFunds, closeEscrow

Docs:
- Updated client.md, merchant.md, skills.md with V2.1 pipelines
- Deprecation warnings throughout
Single-tx bridge between SAP agents and Metaplex Core assets, built on
the real mpl-core 1.9.0 surface (PR #258). After the initial attach,
every SAP write propagates to MPL consumers without a second transaction.

- MetaplexBridge (client.metaplex) lazy registry singleton
- buildAttachAgentIdentityIx / buildUpdateAgentIdentityUriIx
- buildEip8004Registration (server-side EIP-8004 JSON renderer)
- deriveRegistrationUrl / verifyLink / getUnifiedProfile
- New types: Eip8004Registration, Eip8004Service, AttachAgentIdentityOpts,
  UpdateAgentIdentityUriOpts, MplAgentSnapshot, UnifiedProfile
- Optional peer deps: @metaplex-foundation/mpl-core >=1.9.0,
  @metaplex-foundation/umi-bundle-defaults >=0.9.0 (lazy-loaded)
- Skill: skills/metaplex-bridge.md
- Doc:   docs/11-metaplex-bridge.md
- skills.md, skills/merchant.md, skills/client.md cross-link the bridge

Zero on-chain SAP changes; the 8 mainnet agents remain unmodified.
Updated section title for future on-chain link proposal.
- Use createNoopSigner from umi
- Fix BaseExternalPluginAdapterInitInfo discriminated union shape (fields[])
- Fix fetchActiveVaultDelegates: derive vault PDA + memcmp at correct offset
- Use AssetV1.agentIdentities typed array directly
- Add @metaplex-foundation/umi as optional peer dep
- All Metaplex/umi imports use 'import type' (erased at runtime)
- Bump to 0.9.1 (0.9.0 unpublished from npm)
…flows

- tripleCheckLink: 3-layer link audit (mplOnChain + eip8004Json + sapOnChain)
- buildMintAndAttachIxs: SAP exists → mint MPL Core asset + attach AgentIdentity (1 tx)
- buildRegisterSapForMplOwnerIx: MPL exists → idempotent SAP register for asset owner
- buildRegisterBothIxs: atomic 3-ix bundle (SAP register + MPL create + AgentIdentity attach)
- rpcHeaders propagation across all read methods (fixes silent 401 on gated RPCs)
- Live-verified against XONA mainnet agent (2026-04-23)
- skills/metaplex-bridge.md updated with section 13 covering all of the above
- 0.9.3 supersedes 0.9.0/0.9.1/0.9.2 (intermediate iterations remain on npm for history)
…l Metaplex bridge release

- 0.9.3 entry now contains the full Metaplex Core bridge feature set
  (originally documented under 0.9.0) plus the post-mainnet hardening
  (triple-check + atomic register flows + rpcHeaders fix).
- 0.9.0/0.9.1/0.9.2 marked SUPERSEDED — kept on npm only for history.
- Adds note about npm permanently blocking republish of name@version
  (why the canonical release ships under 0.9.3 instead of 0.9.0).
- index.ts now re-exports deriveSettlementReceipt, computeBatchRoot,
  MIN_AGENT_STAKE_LAMPORTS, MAX_DELEGATE_DURATION_SECS,
  USDC_MINT_MAINNET/_DEVNET, isAcceptedPaymentToken, isAcceptedUsdcMint
- skills/merchant.md and skills/client.md gain v0.10 hardening section
  (4 merchant requirements, settlement receipts, delegate cap)
- skills/skills.md bumped to client-sdk 2.0.7 / sap-sdk 0.10.1 reference
CryptoFamilyNFT and others added 28 commits May 8, 2026 00:05
- sap-overview: full module map, PDA derivation, quickstart
- sap-client: consumer escrow v2, x402, settlement, discovery
- sap-merchant: agent register, tool publish, staking, subscriptions
- sap-memory: vault, session, ledger, inscription, reputation prove
- sap-metaplex: AgentIdentity attach, tripleCheckLink, atomic flows

All skills use consistent triggers with no overlaps.
Total: 5 files, ~1550 lines, production-ready for agent consumption.

Refs: SDK v0.14.0, program SAPpUhsWLJG1FfkGRcXagEDMrMsWGjbky7AyhGpFETZ
Major rewrite of the synapse-sap CLI to align with SDK v0.14.0 API:

- Updated package.json: version 0.14.0, SDK dep ^0.14.0
- Rewrote context.ts: uses createSapClient(rpcUrl, wallet) pattern
- Rewrote config.ts: includes programId, apiKey, jupiterApiKey, rpcHeaders
- Rewrote all commands to use real SDK module APIs:
  * agent.ts: registerAgent(), fetchAccount(), getAgentPDA
  * escrow.ts: createEscrowV2(), depositEscrowV2(), settleCallsV2()
  * memory.ts: initVault(), openSession(), inscribeMemory()
  * merchant.ts: registerAgent(), addVaultDelegate()
  * x402.ts: simplified to headers/verify only (SDK has no x402 module)
- Removed discovery.ts, tools.ts (modules don't exist in SDK v0.14.0)
- All commands use client.buildTransaction() + client.sendTransaction()
- Proper PDA derivation via Pdas.* helpers
- Full TypeScript compilation verified

Program: SAPpUhsWLJG1FfkGRcXagEDMrMsWGjbky7AyhGpFETZ
Update command references to match SDK v0.14.0 API:
- agent: registerAgent, fetchAccount, getAgentPDA
- escrow: createEscrowV2, depositEscrowV2, settleCallsV2
- memory: initVault, openSession, inscribeMemory
- merchant: registerAgent, addVaultDelegate
- x402: headers + verify only
- Removed discovery, tools references (modules removed)
- Updated architecture diagram with real SDK modules
- Added transaction flow documentation
Features:
- New  command group: install, list, update, remove, path
  Downloads skill files from GitHub release tags (default: v0.14.0-skills)
  Installs to ~/.hermes/skills/ or ~/.config/synapse-sap/skills/
- Skills installable via: synapse-sap skills install [skill-name]
- Auto-detect Hermes Agent directory for seamless integration

Security:
- Fix CVE-2025-3194 (bigint-buffer@1.1.5 Buffer Overflow in toBigIntLE)
  Removed @solana/spl-token from direct CLI deps (pulled via SDK instead)
  Removed bigint-buffer from CLI dependency tree
- Applied npm audit fix for uuid moderate vulnerability
- 0 vulnerabilities post-fix

Docs:
- README updated with skills command reference

Version bump: 0.14.0 -> 0.14.1
- tsconfig.json: module="preserve", moduleResolution="bundler", target=ES2022
- tsconfig.esm.json / tsconfig.cjs.json: dedicated dual-format builds
- builder.ts / metaplex-bridge.ts: fix Capability symbol collision (enum vs interface)
- merchant-validator.ts: fix SapValidationError import (2-arg constructor)
- Bump SDK+CLI+skills+docs: 0.14.0 -> 0.15.0
…sap.json

- Fixes 'Module not found' error in ESM builds
- Bumped version to 0.15.1
- Updated CHANGELOG.md with fix details
…action, ESM builds)

Fixes:
- getAgentStatsPDA(): Changed parameter from wallet to agent PDA to match on-chain seeds
- sendTransaction(): Fixed VersionedTransaction handling (sign first, send without signers)
- ESM builds: Added explicit .js extensions for native Node ESM compatibility

Thanks to Covenant team for detailed bug reports and reproduction steps.

BREAKING CHANGE: getAgentStatsPDA() signature changed from (wallet) to (agent).
Migration: getAgentStatsPDA(getAgentPDA(wallet)[0])
Critical fix: Replaced src/idl.json (v0.25.0, 6 accounts) with canonical
target/idl/synapse_agent_sap.json (v0.18.0, 5 accounts).

This resolves the registerAgent account mismatch reported by Covenant team:
- Before: wallet, agent, agent_stats, pricing_menu, global_registry, system_program
- After: wallet, agent, agent_stats, global_registry, system_program

IDL v0.18.0 matches mainnet deployment exactly (85 instructions).

Thanks to Covenant team for detailed bug report and reproduction steps.
Syncs SDK with mainnet program v0.18.0 and fixes ALL reported issues.

FIXES (100% verified):

1. ✅ IDL Sync v0.18.0 (register_agent: 6 → 5 accounts)
   - Replaced src/idl.json (v0.25.0, WRONG) with target/idl/synapse_agent_sap.json (v0.18.0, CORRECT)
   - Account count: wallet, agent, agent_stats, global_registry, system_program (5 total)
   - Removed phantom pricing_menu account that doesn't exist on mainnet
   - Impact: registerAgent now works against live program

2. ✅ getAgentStatsPDA(agent) — correct PDA derivation
   - Changed: getAgentStatsPDA(wallet: PublicKey) → getAgentStatsPDA(agent: PublicKey)
   - Now derives ["sap_stats", agent] matching on-chain seeds byte-perfect
   - Migration: getAgentStatsPDA(getAgentPDA(wallet)[0])

3. ✅ sendTransaction() — VersionedTransaction fix
   - Now: tx.sign(signers) first, then send without signers parameter
   - Fixes: "Invalid arguments" error for VersionedTransaction
   - Workaround removed: No need for sendRawTransaction(tx.serialize())

4. ✅ ESM directory imports — native Node ESM compatible
   - Added postbuild script: scripts/fix-esm-imports.js
   - Auto-fixes: from './constants' → from './constants/index.js'
   - All dist/esm/*.js files now have explicit .js extensions
   - Fixes: ERR_UNSUPPORTED_DIR_IMPORT in native Node ESM

5. ✅ Self-attestation — confirmed intentional design
   - create_attestation rejects self-attestation (SelfAttestationNotAllowed, 6075)
   - By design: requires third-party attester (not self)
   - Recommended patterns documented:
     A. Separate attester (auditor/partner wallet)
     B. Ledger module for self-anchored audit hashes
     C. Cross-attestation (dual-agent mutual vouch)

VERIFICATION:

✅ IDL: 5 accounts for register_agent (matches mainnet v0.18.0)
✅ PDA: getAgentStatsPDA derives from agent, not wallet
✅ Transaction: sendTransaction signs first, sends clean
✅ ESM: All imports have .js extensions for Node native ESM
✅ Build: Dual-format (ESM + CJS) working

BREAKING CHANGES:
- getAgentStatsPDA(wallet) → getAgentStatsPDA(agent)
  Migration: getAgentStatsPDA(getAgentPDA(wallet)[0])

BACKWARD COMPATIBLE:
- All other methods unchanged
- Treasury fees remain optional via remaining_accounts
- IDL v0.18.0 matches mainnet exactly (85 instructions)

Thanks to Covenant team for detailed bug reports and reproduction steps.
This release resolves ALL issues they identified.
HOTFIX for v0.19.0 published artifact issues reported by Covenant team:

FIXES:
1. ✅ IDL in dist/esm/idl/ — synced with target/idl/ (v0.18.0, 5 accounts)
   - v0.19.0 bundled wrong IDL (v0.25.0, 6 accounts) in dist directory
   - registerAgent now builds correct 5 accounts matching mainnet

2. ✅ idlTypes ESM import — excluded from directory fix script
   - v0.19.0: from './idlTypes/index.js' → ERR_MODULE_NOT_FOUND ❌
   - v0.19.1: from './idlTypes.js' → Works correctly ✅
   - idlTypes is a file (idlTypes.ts), not a directory

3. ✅ Documentation — clarified client.ledger doesn't exist yet
   - Use raw program methods: client.program.methods.initLedger()
   - High-level wrapper to be added in future release

VERIFIED:
✅ dist/esm/idl/synapse_agent_sap.json: 5 accounts (wallet, agent, agent_stats, global_registry, system_program)
✅ dist/esm/index.js: export * from './idlTypes.js' (file, not directory)
✅ dist/esm/idlTypes.js exists as single file

Thanks to Covenant team for detailed verification and catching these critical issues.
HOTFIX: Adds "type": "module" to package.json for Next.js compatibility.

FIXES:
- Next.js ESM resolution: Added "type": "module" field
- Build system: Post-build script now fixes both ESM and CJS imports
- idlTypes: Correctly preserved as file import (no /index.js suffix)

IMPACT:
- ✅ Next.js projects can now import SDK without ESM errors
- ✅ Works with both import (ESM) and require (CJS) syntax
- ✅ No breaking changes to existing API

TECHNICAL:
- Package type: "module" (explicit ESM declaration)
- Dual-format builds: Both dist/esm/ and dist/cjs/ fixed
- Backward compatible: All existing integrations continue to work
FIX: Added re-exports for legacy constants in constants/index.ts

PROBLEM:
Next.js build failed with errors:
- 'MAX_CALLS_PER_SETTLEMENT' was not found in './constants/index.js'
- 'MAX_VOLUME_CURVE_POINTS' was not found
- 'MAX_RECEIPTS_PER_PROOF' was not found
- etc.

ROOT CAUSE:
Constants were defined in src/constants.ts (legacy file) but not
re-exported from src/constants/index.ts (modular structure).

FIX:
Added re-exports in src/constants/index.ts:
- MAX_CALLS_PER_SETTLEMENT
- MAX_RECEIPTS_PER_PROOF
- MAX_MERKLE_DEPTH
- MAX_SUBSCRIPTION_DURATION_YEARS
- MIN_STAKE_LAMPORTS
- COMPLETE_UNSTAKE_DELAY_DAYS
- STAKE_COVERAGE_BPS

IMPACT:
- Next.js projects can now import all constants
- Backward compatible with existing code
- No breaking changes
FIX: Added ALL missing exports for Next.js compatibility

PROBLEM:
Next.js build failed with missing exports:
- PROGRAM_ID, ENDPOINTS (from constants.ts)
- MAX_VOLUME_CURVE_POINTS (from constants.ts)
- SapErrorCode (from errors.ts)

ROOT CAUSE:
Legacy constants in src/constants.ts and src/errors.ts were not
re-exported from modular index files.

FIXES:
1. src/constants/index.ts:
   - Added export PROGRAM_ID, ENDPOINTS
   - Added export MAX_VOLUME_CURVE_POINTS

2. src/errors/index.ts:
   - Added export SapErrorCode

IMPACT:
- All legacy constants now properly exported
- Next.js projects can import everything
- 100% backward compatible
- No breaking changes
FIX: Export EVERYTHING from legacy constants.ts and errors.ts

PROBLEM:
Next.js build failed - missing exports from legacy files.

SOLUTION:
Export ALL constants from src/constants.ts:
- PROGRAM_ID, ENDPOINTS
- DISCRIMINATOR_SIZE, PUBKEY_SIZE, U8_SIZE, U16_SIZE, U32_SIZE
- U64_SIZE, U128_SIZE, I64_SIZE, BOOL_SIZE, OPTION_SIZE
- MAX_CALLS_PER_SETTLEMENT, MAX_VOLUME_CURVE_POINTS
- MAX_RECEIPTS_PER_PROOF, MAX_MERKLE_DEPTH
- MAX_SUBSCRIPTION_DURATION_YEARS
- STAKE_COVERAGE_BPS, MIN_STAKE_LAMPORTS
- COMPLETE_UNSTAKE_DELAY_DAYS, DEFAULT_COMMITMENT

Export ALL from src/errors.ts:
- SapErrorCode (enum)
- decodeSapError, isRetryableError, isClientValidationFailure (functions)

IMPACT:
- Next.js projects can now import everything
- 100% backward compatible
- No more missing export errors
BREAKTHROUGH: Dual-format build compatible with both Next.js 15 and Node.js backend.

KEY CHANGES:
1. Removed "type": "module" from package.json
   - Enables dual-format (CJS + ESM) support
   - Next.js can use CJS, Node.js ESM can use ESM

2. Updated exports map for proper resolution:
   - "require": "./dist/cjs/..." (for Next.js, webpack, CJS)
   - "import": "./dist/esm/..." (for Node.js ESM, modern bundlers)
   - "types": "./dist/cjs/..." (TypeScript uses CJS types)

3. All exports fixed:
   - All legacy constants exported
   - All error utilities exported
   - IDL path correct (require("./idl/synapse_agent_sap.json"))

COMPATIBILITY:
✅ Next.js 15 (static export + Tauri) — uses CJS
✅ Node.js backend (ESM) — uses ESM
✅ TypeScript — uses CJS types
✅ Webpack — resolves CJS correctly
✅ Native Node ESM — resolves ESM correctly

BACKWARD COMPATIBLE:
- All existing imports work
- No breaking changes
- v0.18.1 PDA fix included
- All constants exported
Post-build script now correctly handles both FILES and DIRECTORIES.

FIX:
- FILES (client, idlTypes): from ./file to from ./file.js
- DIRECTORIES (constants, pdas, etc): from ./dir to from ./dir/index.js

PREVIOUSLY BROKEN:
- client was getting ./client/index.js (WRONG - it is a file!)
- Now correctly gets ./client.js (CORRECT)

IMPACT:
- Next.js 15 static export works (CJS)
- Node.js ESM backend works (ESM)
- All imports resolve correctly
- IDL v0.18.0 (5 accounts, mainnet)
- All constants exported
- All error utilities exported
CRITICAL FIX: Post-build script now correctly distinguishes FILES vs DIRECTORIES.

THE BUG (v0.19.0-v0.19.5):
- client.js was treated as directory → ./client/index.js ❌
- idlTypes.js was treated as directory → ./idlTypes/index.js ❌

THE FIX (v0.19.6):
- client.js is a FILE → ./client.js ✅
- idlTypes.js is a FILE → ./idlTypes.js ✅
- constants/ is a DIRECTORY → ./constants/index.js ✅
- pdas/ is a DIRECTORY → ./pdas/index.js ✅

POST-BUILD SCRIPT:
- Separated FILE imports (client, idlTypes) from DIRECTORY imports
- FILES get .js extension
- DIRECTORIES get /index.js

COMPATIBILITY:
✅ Next.js 15 static export (Tauri) — CJS works
✅ Node.js ESM backend — ESM works
✅ IDL v0.18.0 (5 accounts, mainnet)
✅ All constants exported
✅ All error utilities exported
✅ All legacy exports preserved

THIS IS THE FINAL v0.19.x RELEASE.
CRITICAL FIX: Use require.resolve() for IDL JSON to work with Next.js static export.

PROBLEM:
Next.js static export (output: "export") for Tauri could not resolve:
require("./idl/synapse_agent_sap.json")

Error: "Cannot find module ./idl/synapse_agent_sap.json"

ROOT CAUSE:
Relative require() paths dont work in Next.js static export mode
because webpack bundles the JSON separately and the relative path
breaks during prerendering.

SOLUTION:
Use require.resolve() to get absolute path at build time:

BEFORE:
const idlJson = require("./idl/synapse_agent_sap.json");

AFTER:
const idlPath = require.resolve("./idl/synapse_agent_sap.json");
const idlJson = require(idlPath);

IMPACT:
✅ Next.js 15 static export (Tauri) — NOW WORKS
✅ IDL JSON properly bundled
✅ All constants exported
✅ All error utilities exported
✅ ESM imports correct (client.js, idlTypes.js)
✅ CJS for Next.js, ESM for Node.js backend
✅ IDL v0.18.0 (5 accounts, mainnet)
CRITICAL FIX: Use ESM import for IDL JSON instead of require().

PROBLEM:
require() and require.resolve() DONT WORK with Next.js static export
because webpack cannot bundle JSON files with dynamic require paths.

SOLUTION:
Use ESM import syntax which webpack can properly bundle:

BEFORE (v0.19.7 - BROKEN):
const idlPath = require.resolve("./idl/synapse_agent_sap.json");
const idlJson = require(idlPath);

AFTER (v0.19.8 - FIXED):
import idlJson from "./idl/synapse_agent_sap.json";

WHY THIS WORKS:
- ESM imports are statically analyzable by webpack
- JSON files get bundled inline with the code
- No runtime file resolution needed
- Works with Next.js static export (output: "export")
- Works with Tauri

IMPACT:
✅ Next.js 15 static export (Tauri) — NOW WORKS
✅ IDL JSON bundled inline by webpack
✅ No runtime file resolution
✅ All constants exported
✅ All error utilities exported
✅ ESM imports correct (client.js, idlTypes.js)
✅ CJS for Next.js, ESM for Node.js backend
✅ IDL v0.18.0 (5 accounts, mainnet)
…khash expiry, sendTransaction confirmation

Three bugs fixed in SapClient:

1. fetchAccount swallowed ALL errors via catch-return-null with @ts-ignore.
   Now distinguishes "account not found" (returns null) from real RPC/network
   errors (re-throws). Callers can now reliably differentiate between
   "agent not registered" and "RPC is down".

2. buildTransaction returned only VersionedTransaction, discarding the
   lastValidBlockHeight from getLatestBlockhash. Callers had no deadline
   to use with confirmTransaction, risking open-ended hangs on slow RPCs.
   Now returns { tx, blockhash, lastValidBlockHeight } so callers can pass
   a blockheight-based confirmation strategy.

3. sendTransaction sent but never confirmed. For x402 payment flows this
   means callers received a signature and assumed confirmed status while the
   transaction was still in-flight or could have been dropped. Now confirms
   via blockheight strategy when blockhash context is provided, and throws
   an explicit error if the transaction fails on-chain.

Bonus: constructor warns in development when no rpcUrl is provided so
developers don't hit mainnet accidentally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@CryptoFamilyNFT CryptoFamilyNFT force-pushed the main branch 2 times, most recently from c0f1ce0 to c7227e7 Compare July 6, 2026 09:33
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