@dexterai/x402 6.0.0-rc.2 → 6.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +749 -0
- package/README.md +34 -3
- package/REFERENCE.md +67 -3
- package/dist/tab/seller/index.cjs +25 -4
- package/dist/tab/seller/index.d.cts +190 -80
- package/dist/tab/seller/index.d.ts +190 -80
- package/dist/tab/seller/index.js +25 -4
- package/package.json +4 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [6.0.0-rc.4] - 2026-08-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Rebound the exact Vault peer and development dependency to
|
|
15
|
+
`@dexterai/vault@0.43.3-rc.1`. This is a package-metadata-only successor to
|
|
16
|
+
rc.3 so the canonical archive-mode Vault release resolves as one dependency
|
|
17
|
+
graph; x402 runtime source and declarations are unchanged.
|
|
18
|
+
|
|
19
|
+
## [6.0.0-rc.3] - 2026-08-17
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Seller-owned delivery accounting is now restart- and takeover-safe. Every
|
|
24
|
+
channel lease carries an unguessable owner token plus a monotonically
|
|
25
|
+
increasing fence, and every ledger write, delete, renewal, and release is
|
|
26
|
+
conditional on that exact lease generation. The SSE meter writes each
|
|
27
|
+
charge to the fenced durable ledger before the corresponding service may be
|
|
28
|
+
sent; a crash can conservatively over-account an unsent unit, but cannot
|
|
29
|
+
erase delivered service and re-grant the same signed budget after restart.
|
|
30
|
+
- `RedisChannelLedger` declares explicit restart/multi-instance capabilities,
|
|
31
|
+
performs authoritative reads on the Redis primary, renews live leases, and
|
|
32
|
+
fails closed on store or lease loss. Its `restartSafe` capability requires
|
|
33
|
+
both the exact AOF-always/no-data-loss/noeviction/dedicated-instance
|
|
34
|
+
durability attestation and
|
|
35
|
+
`writerCutover: 'all-legacy-writers-stopped'`.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Seller admission revalidates the current durable voucher registration,
|
|
40
|
+
cumulative amount, and reservation proof after acquiring the channel lease.
|
|
41
|
+
Delayed requests therefore cannot overwrite a newer process's accepted
|
|
42
|
+
state. A response that disconnects during proof work cannot later acquire or
|
|
43
|
+
indefinitely renew a lease.
|
|
44
|
+
- Channel IDs are canonical lowercase 64-character hex at seller admission.
|
|
45
|
+
Every bundled ledger adapter also rejects noncanonical IDs before acquiring
|
|
46
|
+
a lock or touching storage, so direct adapter calls cannot recreate aliases.
|
|
47
|
+
- `ledgerSafetyMode` must be explicit unless `NODE_ENV` is exactly `test` or
|
|
48
|
+
`development`. `production-single-instance` requires durable restart-safe
|
|
49
|
+
state plus the explicit channel-alias cutover; `production-multi-instance`
|
|
50
|
+
additionally requires cross-process atomic fencing. There is no production
|
|
51
|
+
fallback to memory or inferred single-process topology.
|
|
52
|
+
|
|
53
|
+
### Breaking
|
|
54
|
+
|
|
55
|
+
- Custom `ChannelLedger` adapters must expose `capabilities`, use the new
|
|
56
|
+
`ChannelLease { ownerToken, fence, heldUntilUnixMs }`, accept that lease on
|
|
57
|
+
every `set`, `update`, and `delete`, and implement conditional
|
|
58
|
+
`tryAcquireLease`, `renewLease`, and `releaseLease`. Adapters must reject
|
|
59
|
+
stale owner/fence mutations instead of silently applying them, reject every
|
|
60
|
+
non-lowercase/non-64-hex channel ID before locking or storage access, and
|
|
61
|
+
declare `canonicalChannelIds` only after historical aliases are migrated or
|
|
62
|
+
the durable store is proven empty.
|
|
63
|
+
- `SseMeter.charge()` is asynchronous write-ahead accounting and must be
|
|
64
|
+
awaited before `send()`. Concurrent charges are serialized against the
|
|
65
|
+
signed cap; `send()` fails while a charge commit is pending.
|
|
66
|
+
|
|
67
|
+
### Seller-ledger upgrade and Redis keyspace migration
|
|
68
|
+
|
|
69
|
+
- **Canonical channel-ID cutover is mandatory for every durable adapter.** The
|
|
70
|
+
voucher signature covers the decoded 32 channel bytes, so historical SDKs
|
|
71
|
+
could persist the same signed channel under multiple case spellings. Before
|
|
72
|
+
setting `channelIdCutover: 'legacy-case-aliases-migrated-or-empty'`, stop all
|
|
73
|
+
seller writers and enumerate every ledger, lease, and fence key/file. Group
|
|
74
|
+
records by lowercase channel ID; wait for and remove every alias lease;
|
|
75
|
+
require exact session/public-key/registration compatibility (otherwise
|
|
76
|
+
quarantine the entire group for manual review); retain the highest valid
|
|
77
|
+
signed voucher by cumulative then sequence; **sum** delivered cumulative
|
|
78
|
+
across distinct aliases; take the maximum crystallized and gate-refused
|
|
79
|
+
watermarks; and publish the lowercase fence at least one greater than the
|
|
80
|
+
maximum alias fence. Overcounting a copied duplicate is safer than re-granting
|
|
81
|
+
delivered service. Verify the canonical record before deleting every alias
|
|
82
|
+
ledger/lease/fence. A brand-new proven-empty store may acknowledge the same
|
|
83
|
+
cutover without migration. Production middleware refuses File, Redis, or a
|
|
84
|
+
custom adapter until `canonicalChannelIds` attests this invariant.
|
|
85
|
+
|
|
86
|
+
- The default Redis layout remains `legacy-v0` (`<prefix>ledger:<channelId>`,
|
|
87
|
+
`<prefix>lease:<channelId>`, `<prefix>fence:<channelId>`) so upgrading does
|
|
88
|
+
not hide existing ledger state or split leases during rollout. Before
|
|
89
|
+
asserting `writerCutover`, stop every pre-fencing seller process. A raw UUID
|
|
90
|
+
lease written by an older process is respected until it expires; the new
|
|
91
|
+
writer never renews or releases that foreign lease.
|
|
92
|
+
- `cluster-v1` is opt-in and never supports a rolling mixed-layout deploy. Stop
|
|
93
|
+
all seller writers; wait for every legacy lease to expire; copy every legacy
|
|
94
|
+
canonical lowercase ledger record and fence counter to the corresponding hash-tagged
|
|
95
|
+
`<prefix>{<channelId>}:ledger|fence` keys (preserving or increasing each
|
|
96
|
+
fence); verify the copies; then remove all legacy ledger, lease, and fence
|
|
97
|
+
keys. Only after that stop-the-world procedure may the service start with
|
|
98
|
+
`keyLayout: 'cluster-v1'`,
|
|
99
|
+
`keyspaceCutover: 'legacy-state-migrated-or-empty'`, the writer cutover, and
|
|
100
|
+
the channel-ID cutover acknowledgements. Runtime admission rejects any
|
|
101
|
+
legacy ledger, lease, or fence remnant rather than treating the new keyspace
|
|
102
|
+
as empty.
|
|
103
|
+
|
|
104
|
+
## [6.0.0-rc.2] - 2026-08-16
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
|
|
108
|
+
- Native Tab V2 buyer and seller admission now completes at Solana `confirmed` after independently fetching the exact successful reservation transaction, verifying its Dexter-authority-signed voucher-binding Memo, and reading coherent Vault/SessionAccount state anchored to that transaction slot. Paid requests no longer wait for finalization; processed-only evidence still fails closed.
|
|
109
|
+
- V2 seller channel binding can no longer be poisoned by a scope-rejected first request, a concurrent competing registration, lease refusal, or a downstream durable-ledger failure.
|
|
110
|
+
|
|
111
|
+
### Unchanged safety boundaries
|
|
112
|
+
|
|
113
|
+
- Rollback, failed-transaction retirement, blockhash-expiry adjudication, close, and revoke retain their finalized/background boundaries. A later finalization preserves the already-issued confirmed receipt byte-for-byte.
|
|
114
|
+
|
|
115
|
+
## [6.0.0-rc.1] - 2026-08-16
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
|
|
119
|
+
- Native Tab V2 sellers now require the complete reservation receipt in the existing `X-Tab-Voucher` envelope and independently prove the exact finalized `settle_voucher` transaction plus its Dexter-authority-signed voucher-binding Memo before delivery. Missing, malformed, confirmed-only, replayed, consumed, wrong-version, stale-registration, and same-amount substituted proofs fail closed.
|
|
120
|
+
- V2 seller admission re-reads the exact finalized SessionAccount PDA for every voucher and requires `currentOutstanding` to equal only the uncovered voucher increment above the authoritative settled/crystallized frontier.
|
|
121
|
+
- V2 terminal settlement sends the exact final reservation increment as `attemptedAmount`, rather than reconstructing it from the tab's lifetime cumulative amount.
|
|
122
|
+
- The CommonJS `@dexterai/x402/server` entrypoint now bundles the ESM-only sponsored-access runtime constant, so a clean `require()` consumer no longer fails during module loading.
|
|
123
|
+
|
|
124
|
+
### Changed
|
|
125
|
+
|
|
126
|
+
- The complete verified `FinalVoucherV2ReservationReceipt` now survives every buyer route (`openTab`, `tabFromGrant`, `stream`, and `payAndFetch`) inside the existing voucher envelope. Provider-local lifecycle metadata remains non-authoritative; finalized transaction, Memo, and coherent post-state evidence authorize seller delivery.
|
|
127
|
+
- `@dexterai/vault` is pinned exactly to `0.43.2` for both peer and development use, including its corrected optional-account sentinel encoding.
|
|
128
|
+
|
|
129
|
+
## [6.0.0-rc.0] - 2026-08-16
|
|
130
|
+
|
|
131
|
+
### Added
|
|
132
|
+
|
|
133
|
+
- Context-bound FINAL V2 vouchers bind the Vault program, Vault, SessionAccount, seller, session generation, channel, cumulative amount, and sequence into the signed voucher.
|
|
134
|
+
- FINAL V2 release now requires a complete versioned reservation receipt, finality for the exact Solana reservation transaction, and an independent finalized post-state verification. A merely confirmed transaction and the former `{ armed: true }` acknowledgement are rejected.
|
|
135
|
+
- Live-session replacement uses one guard-bound V7 passkey ceremony and one atomic replacement transaction.
|
|
136
|
+
- Tab voucher signing and close share one fail-fast local operation gate, preventing two concurrent calls from reserving the same sequence/cumulative frontier.
|
|
137
|
+
|
|
138
|
+
### Changed
|
|
139
|
+
|
|
140
|
+
- `@dexterai/vault` is pinned to the published `0.43.1` release. Close/revoke now signs the 252-byte V3 message over one coherent, authoritative Vault + SessionAccount snapshot, including all live meters and `pendingVoucherCount`.
|
|
141
|
+
- `VaultAdapter.sessionVoucherVersion` and `Tab.voucherVersion` are required. Buyer-side V1 open and reconstruction now fail with `HistoricalV1MigrationRequiredError`; seller-side verification remains available only for already-issued V1 vouchers. Missing, invalid, or unsupported generations fail closed.
|
|
142
|
+
- The Node P-256 signer no longer guesses a revoke authorization nonce. Revoke requires an authoritative `resolveAuthorizationContext`; unknown operations sign nothing unless the caller explicitly opts into the deprecated legacy operation hash.
|
|
143
|
+
|
|
144
|
+
### Breaking
|
|
145
|
+
|
|
146
|
+
- V2 reservation callbacks now return the full `FinalVoucherV2ReservationReceipt`; boolean acknowledgements are invalid.
|
|
147
|
+
- V2 adapters must implement `verifyFinalVoucherV2Reservation`.
|
|
148
|
+
- Node.js 22 or newer is required. Node 18 and Node 20 are end-of-life, and the current Solana dependency graph relies on modern ESM loading unavailable on Node 18.
|
|
149
|
+
- This release is a major-version candidate because its reservation, revocation, and adapter contracts are intentionally incompatible with the abandoned 5.4.3 candidate.
|
|
150
|
+
|
|
151
|
+
### Compatibility notice
|
|
152
|
+
|
|
153
|
+
- Public `@dexterai/x402@5.4.2` contains the historical V1 Native Tab rail. Its broad Vault peer range admits `0.43.1`, but its close wire predates Vault 0.43.x exact-state revocation. Existing 5.4.2 consumers should not upgrade Vault to 0.43.x until they move to this v6 line.
|
|
154
|
+
|
|
155
|
+
### Added (buyer, K-T4e)
|
|
156
|
+
- **`openTab` / `authorizeSession` are now live-session-aware.** The session PDA is keyed by (vault, counterparty), so re-opening a tab against a seller you already hold a LIVE session with resolves to the same PDA. A live target either throws the typed `LiveSessionExistsError` (default — carrying spent, crystallized, outstanding, and frontier evidence) or, with `onLiveSession: 'replace'`, uses one guard-nonce-bound V7 passkey ceremony and one atomic `[secp(replace), replace_session_key_v1]` transaction. The buyer is never left sessionless mid-flow. The v0 + address-lookup-table transport manages priority fees, expiry rebroadcast, and ALT deactivation.
|
|
157
|
+
- **BEHAVIOR CHANGE:** pre-5.3.1, `openTab` against a live same-seller session silently overwrote it on-chain — stranding any of the old session's signed-but-unsettled vouchers. That silent path is gone: you get the typed error (settle the old tab first, or acknowledge with `onLiveSession: 'replace'`).
|
|
158
|
+
- `@dexterai/vault` peer/dev dependency raised `>=0.20.0` → `>=0.34.0` (the atomic compose primitive lives there).
|
|
159
|
+
|
|
160
|
+
### Changed (seller, K-T3)
|
|
161
|
+
- **`lockCadence` demotes to advisory.** The crystallization cadence is becoming facilitator-owned: a server-side engine that fires locks at the operator's on-chain intent knob for every seller, whatever the client-side threshold says. This setting defers to that engine as it rolls out — until it is live on your facilitator, `lockCadence` is still your mid-stream protection, so don't loosen it on the strength of this note. It remains the seller's own lock-more-aggressively dial either way.
|
|
162
|
+
- **`below_lock_cadence` gate refusals are handled first-class.** A cadence-gated facilitator may refuse sub-threshold seller-initiated `/tab/lock` posts with `below_lock_cadence`. The SDK classifies this as benign (console.warn, never console.error — a facilitator only gates spans its own cadence engine owns) and records a **gate-refused watermark** (`ChannelLedgerEntry.gateRefusedCumulativeAtomic`, persisted) so the identical refused span is never re-attempted on subsequent deliveries or response closes — previously each would have retry-stormed the gate. A new signed voucher (higher cumulative) always re-attempts; a landed lock clears the watermark.
|
|
163
|
+
|
|
164
|
+
## [4.0.0] - 2026-06-17
|
|
165
|
+
|
|
166
|
+
### Removed (BREAKING)
|
|
167
|
+
|
|
168
|
+
The v1-era public exports are gone, completing the 3.9.0 deprecation. The payment engine is unchanged — `payAndFetch` (client) and `x402Middleware` (server) have been the canonical paths since 3.x and cover everything the removed helpers did.
|
|
169
|
+
|
|
170
|
+
- **client:** `createX402Client`, `wrapFetch` (and the `X402Client`, `X402ClientConfig`, `WrapFetchOptions` types). → `payAndFetch(url, init, wallets)`.
|
|
171
|
+
- **server:** `x402AccessPass`, `x402BrowserSupport`, `escapeHtml`. → `x402Middleware`.
|
|
172
|
+
- **server:** `createDynamicPricing`, `formatPricing`. → compute the price per request in your handler and pass it to `x402Middleware`.
|
|
173
|
+
- **server:** the entire token/model pricing surface — `createTokenPricing`, `countTokens`, `getAvailableModels`, `isValidModel`, `formatTokenPricing`, `MODEL_PRICING`, `MODEL_REGISTRY`, `MODEL_PRICING_MAP`, `getModel`, `findModel`, `isValidModelId`, `getAvailableModelIds`, `getModelsByTier`, `getModelsByFamily`, `getActiveModels`, `getTextModels`, `getCheapestModel`, `estimateCost`, `formatModelPricing` (and their types). This wrapped a hardcoded January-2026 OpenAI snapshot that goes stale fast; price requests with your model provider's live API and pass the amount to `x402Middleware`.
|
|
174
|
+
- **server:** `stripePayTo`. → a `PayToProvider` map on `x402Middleware`. (`getStripeProviderNetwork` stays internal.)
|
|
175
|
+
- **react:** `useAccessPass`. → `useX402Payment`.
|
|
176
|
+
|
|
177
|
+
### Notes
|
|
178
|
+
|
|
179
|
+
- **EVM one-shot pay-per-call is unchanged.** `payAndFetch` remains the live EVM path until Tabs reaches EVM. The `createX402Client` / `wrapFetch` implementations are retained internally — they still power `payAndFetch`, the v2 strategy, and `useX402Payment`; only their public *exports* were removed.
|
|
180
|
+
- To stay on the old surface, pin `@dexterai/x402@^3`.
|
|
181
|
+
|
|
182
|
+
## [3.9.0] - 2026-05-21
|
|
183
|
+
|
|
184
|
+
### Documentation
|
|
185
|
+
- **README restructured to lead with the canonical paths.** The Quick Start now opens with `payAndFetch` (the version-agnostic 2026+ client) instead of the deprecated `wrapFetch`. New "Discovery (bazaar extension)" section documents the 3.8.0 `bazaarExtension` / `declareDiscoveryExtension` API, which had shipped but was undocumented. Sponsored Access reframed around the MCP-agent reality it already serves. The v1-era pricing helpers (Dynamic Pricing, Token Pricing, Access Pass, Stripe) collapsed from ~300 lines of feature sections into a single "Legacy capabilities" table with migration targets. Stale marketplace counts removed. README is ~40% shorter.
|
|
186
|
+
|
|
187
|
+
### Fixed
|
|
188
|
+
- **`PayResult` no longer reports a phantom network on unpaid responses.** When `payAndFetch` hits an endpoint that returns 200 (or any non-402) directly, the result is now `{ ok: true, paid: false, response }` instead of `{ ok: true, response, amountPaid: '0', network: { caip2: '', bare: '', family: 'evm' } }`. The old placeholder poisoned any downstream analytics that grouped by network — every free-endpoint hit registered as an empty-CAIP-2 EVM payment. The `ok: true` variant is now discriminated by `paid: true | false`; callers should narrow on `paid` before reading `network` / `amountPaid` / `txSignature`. Strategy implementations (v1, v2) also set `paid: true` on their success path. (Source: `payment/dispatcher.ts:104` had a `// not-applicable placeholder` self-flag that finally got the type-level fix it was waiting for.)
|
|
189
|
+
- **`payAndFetch` no longer reports `timeout` on a payment that may have settled.** Previously a single 15s deadline governed the whole paid call — both the on-chain settlement and the wait for the merchant's response. A merchant slower than 15s (research / scout / agent endpoints routinely are) had its payment settled, then the abort fired and `payAndFetch` returned `{ ok: false, reason: 'timeout' }` — which reads as "safe to retry" and caused a silent double-charge. The timeout is now two-phase: a short pre-payment deadline (`timeoutMs`, default 15000) covers the unpaid probe and build/sign; a long post-payment deadline (new `responseTimeoutMs`, default 120000) covers the wait for the merchant's response. A pre-payment abort still yields `reason: 'timeout'` (no money moved, safe to retry). A post-payment abort yields the new `reason: 'payment_unconfirmed'` — the payment authorization was sent and may have settled on-chain, so a consumer must NOT blind-retry; the `detail` field spells this out. The `ok: true; paid: true` variant's `response` is now `Response | undefined`. Both v1 and v2 strategies are fixed. (Reported via a bake-off audit — see `FINDINGS-pay-timeout-double-charge-2026-05-21.md`.)
|
|
190
|
+
- **`payAndFetch` confirms settlement on-chain after a post-payment timeout.** When the merchant never responds, the SDK now asks the chain directly whether the payment settled, rather than always reporting `payment_unconfirmed`. EVM EIP-3009 payments (the default `exact` scheme) are confirmed via the token contract's `authorizationState(authorizer, nonce)` view — the nonce is the exact value the SDK generated, so this is a definitive yes/no. EVM Permit2 payments check `Permit2.nonceBitmap`. Solana payments scan recent signatures on the merchant's destination token account for a matching transfer, bounded by the transaction's blockhash validity. When the chain confirms settlement, the result is upgraded to `{ ok: true, paid: true, response: undefined, txSignature }` — a confirmed-but-unanswered payment, so the caller knows it paid and does not retry. When confirmation cannot be performed (RPC failure, or a scheme with no on-chain check such as EVM `exact-approval`), the result stays `payment_unconfirmed` with an explanatory `detail`. New `ChainAdapter.confirmSettlement` method and `SettlementProbe` type.
|
|
191
|
+
|
|
192
|
+
### Deprecated
|
|
193
|
+
|
|
194
|
+
Internal hygiene pass ahead of 4.0 and 5.0. No runtime behavior changes — every symbol below still works exactly as before. JSDoc `@deprecated` markers now surface editor warnings so consumers can migrate ahead of the removal releases.
|
|
195
|
+
|
|
196
|
+
**Slated for removal in 4.0:**
|
|
197
|
+
|
|
198
|
+
- `x402AccessPass`, `X402AccessPassConfig`, `X402AccessPassRequest` (`@dexterai/x402/server`) — use per-request `x402Middleware` with `payAndFetch` clients.
|
|
199
|
+
- `useAccessPass`, `UseAccessPassConfig`, `UseAccessPassReturn` (`@dexterai/x402/react`) — use `useX402Payment` for per-request payments.
|
|
200
|
+
- `createDynamicPricing`, `formatPricing`, `DynamicPricingConfig`, `DynamicPricing`, `PriceQuote` (`@dexterai/x402/server`) — compute the price per request in your handler and pass it to `x402Middleware`.
|
|
201
|
+
- `createTokenPricing`, `countTokens`, `getAvailableModels`, `isValidModel`, `formatTokenPricing`, `MODEL_PRICING`, `TokenPricingConfig`, `TokenPricing`, `TokenPriceQuote`, `ModelPricing` (`@dexterai/x402/server`) — price requests with your model provider's live API and pass the amount to `x402Middleware`.
|
|
202
|
+
- `MODEL_REGISTRY`, `MODEL_PRICING_MAP`, `getModel`, `findModel`, `isValidModelId`, `getAvailableModelIds`, `getModelsByTier`, `getModelsByFamily`, `getActiveModels`, `getTextModels`, `getCheapestModel`, `estimateCost`, `formatModelPricing`, and the related types (`@dexterai/x402/server`) — January 2026 hardcoded snapshot; goes stale fast.
|
|
203
|
+
- `x402BrowserSupport`, `X402BrowserSupportConfig` (`@dexterai/x402/server`) — no replacement; build a custom paywall page if needed. (`escapeHtml` stays.)
|
|
204
|
+
- `stripePayTo`, `StripePayToConfig`, `getStripeProviderNetwork` (`@dexterai/x402/server`) — integrate Stripe at the application layer if still needed. The Stripe-network check in `x402Middleware` is removed alongside this in 4.0.
|
|
205
|
+
|
|
206
|
+
**Slated for removal in 5.0** (longer migration window because of real consumers):
|
|
207
|
+
|
|
208
|
+
- `createX402Client`, `X402Client`, `X402ClientConfig` (`@dexterai/x402/client`) — use `payAndFetch` instead. Migration: `client.fetch(url)` → `(await payAndFetch(url, undefined, wallets)).response`.
|
|
209
|
+
- `wrapFetch`, `WrapFetchOptions` (`@dexterai/x402/client`) — use `payAndFetch` with a wallet from `createKeypairWallet` / `createEvmKeypairWallet`.
|
|
210
|
+
|
|
211
|
+
`getPaymentReceipt` and `PaymentReceipt` (`@dexterai/x402/client`) are NOT deprecated.
|
|
212
|
+
|
|
213
|
+
## [3.8.1] - 2026-05-20
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
- **Bazaar `routeTemplate` now includes the mount path.** When `x402Middleware` is mounted on a sub-router via `app.use('/v1/agent', router)`, the bazaar extension previously emitted `routeTemplate: "/campaigns/:id"` instead of the full external-visible `"/v1/agent/campaigns/:id"`. The middleware now prepends `req.baseUrl` to `req.route.path`, so the emitted template matches the URL clients actually call. Without mounting, `req.baseUrl` is empty and behavior is unchanged.
|
|
217
|
+
|
|
218
|
+
## [3.8.0] - 2026-05-20
|
|
219
|
+
|
|
220
|
+
Adds a resource-server extension system and the **bazaar discovery extension**, making `x402Middleware`-built 402 responses discoverable via the official x402 bazaar standard (`extensions.bazaar`). Fully backward compatible — calls without the new config fields emit a 402 byte-identical to today.
|
|
221
|
+
|
|
222
|
+
### Added
|
|
223
|
+
- **`ResourceServerExtension` contract** (`@dexterai/x402/server`) — generic interface ported from the upstream `@x402/core` extension model. An extension namespaces its output under its own `key` inside `PaymentRequired.extensions`. Future extensions (offer-receipt, payment-identifier, etc.) plug in the same way.
|
|
224
|
+
- **Extension registry with failure isolation.** A throwing extension is caught, logged, and skipped — the 402 still goes out, just without that key. Never propagates, never 500s the payment path.
|
|
225
|
+
- **`bazaarExtension()` factory** — the first concrete extension. When configured, the 402 response carries the spec-compliant `extensions.bazaar` block: `{ info, schema, routeTemplate? }`, with `info.input` discriminated by HTTP method (GET/HEAD/DELETE → `queryParams`; POST/PUT/PATCH → `bodyType` + `body`) and `schema` as a JSON Schema (Draft 2020-12) validating `info`. Path-parameterized routes carry `info.input.pathParams` and a top-level `routeTemplate`.
|
|
226
|
+
- **`declareDiscoveryExtension(config)` helper** — wrap a route's discovery config as `{ bazaar: <config> }` for `x402Middleware`'s `declarations` map. Method may be omitted; the extension stamps the actual request method at 402 time.
|
|
227
|
+
- **`X402MiddlewareConfig.extensions`** + **`X402MiddlewareConfig.declarations`** — new optional fields. Pair them to opt routes into the registry. Example:
|
|
228
|
+
```ts
|
|
229
|
+
x402Middleware({
|
|
230
|
+
payTo, network, amount, facilitatorUrl,
|
|
231
|
+
extensions: [bazaarExtension()],
|
|
232
|
+
declarations: {
|
|
233
|
+
...declareDiscoveryExtension({
|
|
234
|
+
method: 'POST',
|
|
235
|
+
bodyType: 'json',
|
|
236
|
+
inputSchema: { properties: { amount: { type: 'string' } }, required: ['amount'] },
|
|
237
|
+
output: { example: { campaign: {} } },
|
|
238
|
+
}),
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
- **`routeTemplate` validator** — enforces the bazaar spec's rules (non-empty, starts with `/`, allowed chars, no `..`/`://` even after percent-decoding). Invalid templates are dropped (`routeTemplate` is omitted), the 402 still ships.
|
|
243
|
+
- **End-to-end test** (`bazaar-middleware.test.ts`) — drives the full middleware with a mocked facilitator and asserts the 402 body carries `extensions.bazaar` when configured, and is `extensions`-free when not.
|
|
244
|
+
- **Public exports** from `@dexterai/x402/server`: `bazaarExtension`, `declareDiscoveryExtension`, and the types `ResourceServerExtension`, `PaymentRequiredContext`, `DiscoveryConfig`, `QueryDiscoveryConfig`, `BodyDiscoveryConfig`, `DiscoveryExtension`, `DeclareDiscoveryConfig`.
|
|
245
|
+
|
|
246
|
+
### Notes
|
|
247
|
+
- **Backward compatible.** A `x402Middleware` call with no `extensions`/`declarations` emits a 402 byte-identical to 3.7.8.
|
|
248
|
+
- **HTTP only in v1.** MCP-tool discovery (`input.type: "mcp"`) is intentionally out of scope — a clean discriminated-union add-on later.
|
|
249
|
+
- **Spec-conformant.** The emitted `extensions.bazaar` was cross-checked against `/tmp/x402-spec/specs/extensions/bazaar.md` (the official x402 bazaar spec) and the upstream test oracle — field-for-field match on `info.input`, `info.output`, `schema.$schema`, `schema.properties.input.required`, `schema.required`, and `routeTemplate`.
|
|
250
|
+
- **272 tests passing.**
|
|
251
|
+
|
|
252
|
+
## [3.7.4] - 2026-05-18
|
|
253
|
+
|
|
254
|
+
### Fixed
|
|
255
|
+
- **v1 `exact`-scheme EVM payments no longer crash on Node 18.** `buildV1PaymentHeader` generated its EIP-3009 replay nonce via `globalThis.crypto.getRandomValues`, which is undefined on Node 18 (`crypto` is only a global in browsers and Node 19+). The SDK supports Node 18 (`engines: >=18`). The nonce generator now resolves `globalThis.crypto` with a `node:crypto` `webcrypto` fallback, the same fix applied to the batch-settlement salt generator in 3.7.3.
|
|
256
|
+
|
|
257
|
+
## [3.7.3] - 2026-05-18
|
|
258
|
+
|
|
259
|
+
### Fixed
|
|
260
|
+
- **`openBatchChannel` no longer crashes on Node 18.** 3.7.2's channel-salt generator called `crypto.getRandomValues` on the global `crypto`, which is only defined in browsers and Node 19+. The SDK supports Node 18 (`engines: >=18`), so on Node 18 `openBatchChannel` threw `ReferenceError: crypto is not defined`. The salt generator now resolves `globalThis.crypto` with a `node:crypto` `webcrypto` fallback, matching the pattern used elsewhere in the SDK.
|
|
261
|
+
|
|
262
|
+
## [3.7.2] - 2026-05-18
|
|
263
|
+
|
|
264
|
+
Fixes a batch-settlement channel-identity bug: every channel between the same
|
|
265
|
+
buyer, seller, and token collided on a single deterministic id, so a buyer
|
|
266
|
+
could never open a second channel with a seller they had already used —
|
|
267
|
+
`openBatchChannel` would silently reopen the first, exhausted channel.
|
|
268
|
+
|
|
269
|
+
### Fixed
|
|
270
|
+
- **Batch-settlement channels now have unique identities.** `openBatchChannel` generates a fresh random channel-config salt for each channel, so the deterministic `channelId` differs per channel. A buyer can hold multiple independent channels with the same seller over time. Previously the SDK never passed a salt to the upstream scheme, so every channel fell back to the zero `DEFAULT_SALT` and collided.
|
|
271
|
+
|
|
272
|
+
### Added
|
|
273
|
+
- **`channel.salt`** — the 32-byte channel-config salt a channel was opened with, exposed on the `BatchSettlementChannel` handle. Persist it to later resume that exact channel.
|
|
274
|
+
- **`OpenBatchChannelOptions.salt`** (optional) — pass an explicit salt to deterministically reopen a specific channel; omit it for a fresh random one.
|
|
275
|
+
|
|
276
|
+
### Breaking
|
|
277
|
+
- **`resumeBatchChannel` now requires `salt`.** Resuming a channel needs the exact salt it was opened with — a `channelId` cannot be reversed to a salt. Persist `channel.salt` at open time and pass it to `resumeBatchChannel`. (Resuming previously relied on the zero `DEFAULT_SALT`, which is the collision bug above; it could not correctly resume a distinct channel.)
|
|
278
|
+
|
|
279
|
+
## [3.4.0] - 2026-05-17
|
|
280
|
+
|
|
281
|
+
Batch settlement is now functional end-to-end. 3.3.0 shipped a batch-settlement
|
|
282
|
+
buyer but no seller runtime, so a seller had no way to collect the vouchers a
|
|
283
|
+
buyer signed. This release adds the seller runtime and corrects the buyer's
|
|
284
|
+
`channel.close()`.
|
|
285
|
+
|
|
286
|
+
### Added
|
|
287
|
+
- **Batch-settlement seller runtime** — `createBatchSettlementSeller(config)`, exported from `@dexterai/x402/batch-settlement/seller`. Returns a callable object that **is** an Express request handler (mount it directly) and also exposes `.closeChannel(channelId)`, `.closeAll()`, and `.stop()`. It accepts batch-settlement payments — incoming vouchers are verified and persisted to channel storage — and collects them (claim → settle → refund), automatically via a background loop (on by default) and on explicit demand via `closeChannel` / `closeAll`. Config: `{ payTo, network, price, facilitatorUrl?, route?, channelStore?, autoSettle?, verbose? }`.
|
|
288
|
+
- **`x402Middleware({ scheme: 'batch-settlement', ... })` now returns the callable seller object** — a seller that mounts the batch-settlement scheme via `x402Middleware` still gets a `.stop()` / `.closeAll()` / `.closeChannel()` handle.
|
|
289
|
+
- **Buyer escape hatch** — `channel.forceWithdraw()` followed (after the channel's withdraw delay) by `channel.finalizeWithdraw()` reclaims unspent escrow directly via the contract's timed withdrawal if the seller never settles. This is a last-resort safety net; normal operation does not need it. Unlike every other batch-settlement step, the escape hatch costs the buyer gas — the buyer's wallet must be transaction-capable (it must expose a `sendTransaction` method). A signature-only wallet cannot use it.
|
|
290
|
+
|
|
291
|
+
### Breaking
|
|
292
|
+
- **`channel.close()` no longer returns a `CloseReceipt`.** It now returns `{ closed: true }` and is an intent signal that the buyer is finished with the channel — it is not a settlement and does not move funds. The buyer's unspent escrow returns via the seller's refund on the normal settlement path. (3.3.0's `close()` threw and never worked; this corrects it.)
|
|
293
|
+
|
|
294
|
+
### Fixed
|
|
295
|
+
- **Batch settlement is now functional end-to-end** — a seller can collect the payments a buyer makes, which 3.3.0 could not (it shipped a buyer with no seller runtime).
|
|
296
|
+
|
|
297
|
+
## [3.2.0] - 2026-05-03
|
|
298
|
+
|
|
299
|
+
Multi-chain coverage parity. The facilitator has supported Polygon, Optimism, Avalanche, BSC, and SKALE Base for a while; the client adapters and helper functions now declare every one of those chains explicitly instead of relying on `eip155:` substring fallbacks. This closes the gap that caused downstream consumers (e.g. the Dexter resource verifier) to display "Insufficient balance on Base" for resources that actually accepted payment on a different EVM chain.
|
|
300
|
+
|
|
301
|
+
### Added
|
|
302
|
+
- `EvmAdapter.networks` now declares Polygon, Optimism, Avalanche, SKALE Base, and SKALE Base Sepolia in addition to Base mainnet, Base Sepolia, Ethereum, Arbitrum, and BSC. Behaviour for unknown `eip155:N` strings is unchanged (still accepted via prefix match) — the difference is that supported chains are now first-class enumerated entries.
|
|
303
|
+
- `getChainName()` extended with mappings for BSC, Polygon, Optimism, Avalanche, SKALE Base, and SKALE Base Sepolia. Legacy short-form aliases (`'polygon'`, `'avalanche'`, `'bsc'`, `'skale-base'`, etc.) are accepted alongside the canonical CAIP-2 form.
|
|
304
|
+
- `getExplorerUrl()` extended with explorer URL templates for the same set of chains (Polygonscan, Optimistic Etherscan, Snowtrace, BscScan, SKALE Base + SKALE Base Sepolia explorers).
|
|
305
|
+
- `getChainDisplayName(network, family)` exported from `@dexterai/x402/utils` — same mapping as `getChainName()` but falls back to the adapter family name (`'Solana'` / `'EVM'`) instead of the raw CAIP-2 string. Use this in user-facing error messages and UI badges.
|
|
306
|
+
- New test suite `evm-chain-coverage.test.ts` (71 cases) locks in the adapter declaration / canHandle / RPC / USDC / chain ID matrix per chain so future contributors can't add a constant without wiring the adapter.
|
|
307
|
+
|
|
308
|
+
### Fixed
|
|
309
|
+
- The pre-payment `insufficient_balance` X402Error in `createX402Client` now resolves the chain name from the canonical registry, so the message reads "Insufficient balance on Polygon" instead of the previous hardcoded "Insufficient balance on Base" for non-Base EVM chains.
|
|
310
|
+
- Access-pass purchase flow's `insufficient_balance` error now includes the chain name. Previously it omitted the chain entirely, which made the diagnosis ambiguous when the same wallet was authorized on multiple chains.
|
|
311
|
+
|
|
312
|
+
### Changed
|
|
313
|
+
- Consolidated network identifiers, token addresses, RPC URLs, chain IDs, Permit2 addresses, and protocol defaults into a single `src/constants.ts` module. Types, adapters, server middleware, access pass, and Stripe PayTo now import from it instead of carrying their own duplicates. Public export surface is unchanged. ([`4d3e881`])
|
|
314
|
+
- `getChainName('eip155:42161')` now returns `'Arbitrum'` (was `'Arbitrum One'`). The shorter form reads better in error messages and matches every other chain's display convention. The CAIP-2 identifier is unchanged.
|
|
315
|
+
|
|
316
|
+
### Removed
|
|
317
|
+
- `X402ErrorCode` member `no_solana_accept` — zero callers anywhere in the ecosystem. ([`58c7eea`])
|
|
318
|
+
- `KeypairWallet.keypair` — the deprecated field that shadowed `KEYPAIR_SYMBOL`. `isKeypairWallet()` now checks the symbol directly. No external callers were found. ([`58c7eea`])
|
|
319
|
+
- Implicit `(response as any)._x402 = receipt` mutation after payment settlement. The typed `getPaymentReceipt(response)` + `PaymentReceipt` WeakMap path has been the public API since 1.8.0; the legacy mutation no longer had any readers. ([`58c7eea`])
|
|
320
|
+
|
|
321
|
+
## [3.1.1] - 2026-04-18
|
|
322
|
+
|
|
323
|
+
### Changed
|
|
324
|
+
- `capabilitySearch` implementation moved to `@dexterai/x402-core` — this SDK now re-exports from the shared core package so discovery logic stays consistent across Dexter surfaces (SDK, OpenDexter, MCP servers, widgets). Public API unchanged.
|
|
325
|
+
- Build now minifies output and targets ES2022.
|
|
326
|
+
- Bumped `@dexterai/x402-ads-types` from `^0.1.0` to `^0.2.0`.
|
|
327
|
+
|
|
328
|
+
### Added
|
|
329
|
+
- `@dexterai/x402-core` as a runtime dependency.
|
|
330
|
+
|
|
331
|
+
### Removed
|
|
332
|
+
- Stale `tweet-thread-v2.md` draft marketing content from the repo root.
|
|
333
|
+
|
|
334
|
+
## [3.0.0] - 2026-04-15
|
|
335
|
+
|
|
336
|
+
### Breaking
|
|
337
|
+
- **`searchAPIs()` is gone. Replaced by `capabilitySearch()`.** The legacy substring ranker at `/api/facilitator/marketplace/resources` was retired — discovery now goes through the semantic capability search pipeline at `/api/x402gle/capability` (vector search + similarity floor + tiering + cross-encoder LLM rerank).
|
|
338
|
+
- **`DiscoveredAPI` type removed. Replaced by `CapabilityAPI`.** The new shape carries `tier: 'strong' | 'related'`, a raw `similarity` score (0–1), a `why` string explaining the ranking factors, and a final combined `score`. It also nests gaming-flag signals (`gamingFlags`, `gamingSuspicious`) and drops `sellerReputation`, `totalVolume` (formatted), `lastActive`, and `authRequired`.
|
|
339
|
+
- **Hard-filter params are gone.** `category`, `network`, `maxPrice`, `verifiedOnly`, and `sort` were removed from the search options. They were the source of silent false-empties (e.g. `{ query: 'ETH price', network: 'ethereum' }` returned zero results because every ETH-price resource accepts payment on Base). The ranker handles these semantically; payment rail is a checkout-time concern the caller handles separately. The new options are: `query` (required), `limit`, `unverified`, `testnets`, `rerank`, and `endpoint`.
|
|
340
|
+
- **Response is tiered.** `capabilitySearch()` returns `{ strongResults, relatedResults, strongCount, relatedCount, topSimilarity, noMatchReason, rerank, intent, durationMs }` instead of a flat array. `strongResults` are high-confidence matches that cleared the strong similarity threshold; `relatedResults` are adjacent candidates that cleared the floor but not the strong threshold.
|
|
341
|
+
|
|
342
|
+
### Added
|
|
343
|
+
- **`capabilitySearch(options: CapabilitySearchOptions): Promise<CapabilitySearchResult>`** — semantic search with synonym expansion at the intent parse layer, similarity floor filtering, strong/related tiering, and cross-encoder LLM rerank on the top strong results.
|
|
344
|
+
- **`NoMatchReason` type** — `'below_similarity_threshold' | 'below_strong_threshold' | null`. Callers can distinguish "corpus has zero candidates" from "candidates exist but none are high-confidence".
|
|
345
|
+
- **Intent telemetry on every response** — `result.intent` exposes the parsed `capabilityText` and the synonym-expanded `expandedCapabilityText` that was actually embedded for the vector search. Useful for debugging why a query ranked a particular way.
|
|
346
|
+
- **Rerank telemetry on every response** — `result.rerank.applied` tells you whether the LLM cross-encoder actually reordered the top strong results, and `result.rerank.reason` explains any skip.
|
|
347
|
+
|
|
348
|
+
### Migration
|
|
349
|
+
Replace the search call:
|
|
350
|
+
```ts
|
|
351
|
+
// Before (2.x)
|
|
352
|
+
const results = await searchAPIs({ query: 'ETH price', category: 'data', maxPrice: 0.10 });
|
|
353
|
+
for (const api of results) { console.log(api.name, api.price); }
|
|
354
|
+
|
|
355
|
+
// After (3.0)
|
|
356
|
+
const result = await capabilitySearch({ query: 'ETH price' });
|
|
357
|
+
for (const api of result.strongResults) { console.log(api.name, api.price, api.why); }
|
|
358
|
+
if (result.strongCount === 0 && result.relatedCount > 0) {
|
|
359
|
+
// Fall back to related matches when nothing cleared the strong threshold
|
|
360
|
+
for (const api of result.relatedResults) { console.log('related:', api.name); }
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Filter semantically via the query text, not parameters:
|
|
365
|
+
- `searchAPIs({ category: 'defi' })` → `capabilitySearch({ query: 'DeFi tools' })`
|
|
366
|
+
- `searchAPIs({ network: 'solana' })` → `capabilitySearch({ query: 'on Solana' })` (or filter client-side via `pricing.network`)
|
|
367
|
+
- `searchAPIs({ maxPrice: 0.10 })` → filter the result array: `result.strongResults.filter(r => r.priceUsdc != null && r.priceUsdc <= 0.10)`
|
|
368
|
+
|
|
369
|
+
## [2.0.0] - 2026-03-15
|
|
370
|
+
|
|
371
|
+
### Breaking
|
|
372
|
+
- **`PaymentAccept.amount` is now required** — v2 spec field. `maxAmountRequired` is deprecated (optional alias for v1 compat).
|
|
373
|
+
- **`PaymentAccept.extra` is now optional** — per v2 spec.
|
|
374
|
+
- **`TokenPricing` methods are async** — `calculate()`, `validateQuote()`, `countTokens()` return Promises. `tiktoken` is now an optional peer dependency (lazy-loaded on first call).
|
|
375
|
+
|
|
376
|
+
### Added
|
|
377
|
+
- **Budget Accounts** — `createBudgetAccount()` wraps fetch with spending controls: total budget, per-request cap, hourly rate limit, and domain allowlist. Tracks cumulative spend with a full payment ledger. Give your agent $50 and let it spend autonomously.
|
|
378
|
+
- **API Discovery** — `searchAPIs()` searches the Dexter marketplace for x402 paid APIs by query, category, network, price range, and quality score. Returns typed `DiscoveredAPI[]` that can be called directly with `wrapFetch`.
|
|
379
|
+
- **Retry with exponential backoff** — `maxRetries` and `retryDelayMs` in client config. Retries on network errors and 502/503/504. Safe for payments — EIP-3009 nonces prevent double-spend.
|
|
380
|
+
- **First-class Sponsored Access (Ads for Agents)** — `getSponsoredRecommendations()`, `getSponsoredAccessInfo()`, `fireImpressionBeacon()` client helpers. React hook `sponsoredRecommendations`. Server `onMatch` callback. `@dexterai/x402-ads-types` promoted to direct dependency.
|
|
381
|
+
- **Pre-payment inspection** — `onPaymentRequired` callback on client and `wrapFetch`. Return `false` to reject a payment before signing.
|
|
382
|
+
- **Settlement webhooks** — `onSettlement` and `onVerifyFailed` callbacks in middleware config.
|
|
383
|
+
- **CSP headers** on browser paywall page.
|
|
384
|
+
- **`KEYPAIR_SYMBOL`** for safe access to the Solana Keypair (Symbol-keyed, hidden from serialization).
|
|
385
|
+
- **`escapeHtml()`** exported from server for safe HTML rendering of payment data.
|
|
386
|
+
- **`isSolanaNetwork()` / `isEvmNetwork()`** utility functions.
|
|
387
|
+
- **New error codes** — `wallet_disconnected`, `user_rejected_signature`, `rpc_timeout`, `facilitator_timeout`.
|
|
388
|
+
- **Typed `WalletSet`** — `solana` and `evm` fields are now typed as `SolanaWallet` and `EvmWallet` instead of `unknown`.
|
|
389
|
+
- **52 unit tests** covering dynamic pricing, XSS escaping, USDC detection, type compliance, amount conversion, sponsored access.
|
|
390
|
+
- **CI/CD** — GitHub Actions: typecheck + build + test on Node 18/20/22. Publish workflow gated on tests, auto-creates GitHub releases.
|
|
391
|
+
- **`extensions` field** on `PaymentRequired` and `PaymentSignature` per v2 spec.
|
|
392
|
+
- **Auto GitHub releases** from tag pushes with changelog extraction.
|
|
393
|
+
|
|
394
|
+
### Fixed
|
|
395
|
+
- **EVM nonce security** — `Math.random()` replaced with `crypto.getRandomValues()`.
|
|
396
|
+
- **Dynamic pricing security** — FNV-1a replaced with HMAC-SHA256 with timestamp-bounded quotes (5-min TTL).
|
|
397
|
+
- **Balance checks** throw on RPC errors instead of silently returning 0.
|
|
398
|
+
- **Resource URL validation** — blocks `javascript:`, `data:`, `file:` schemes.
|
|
399
|
+
- **Internal errors** no longer leaked to clients.
|
|
400
|
+
- **Stripe guard** uses WeakMap instead of fragile `as any` property.
|
|
401
|
+
- **Source maps removed** from production build (62% smaller package).
|
|
402
|
+
- **Client JWT cache** capped to 24h regardless of decoded `exp`.
|
|
403
|
+
|
|
404
|
+
## [1.9.4] - 2026-03-15
|
|
405
|
+
|
|
406
|
+
### Fixed
|
|
407
|
+
- **Balance checks no longer silently swallow RPC errors** — Solana adapter now only returns 0 for `TokenAccountNotFoundError` (new wallets). EVM adapter throws on HTTP errors and RPC errors. The client gracefully skips the pre-check on RPC failure and lets the chain reject if balance is actually insufficient.
|
|
408
|
+
- **Resource URLs validated for scheme** — client rejects `javascript:`, `data:`, and `file:` URLs from payment requirement headers. Only `http:` and `https:` are accepted.
|
|
409
|
+
- **Internal error details no longer leaked to clients** — middleware 500 responses now return generic `"Payment processing error"` without the underlying error message.
|
|
410
|
+
- **CSP headers on browser paywall** — the generated HTML paywall page now sets `Content-Security-Policy` and `X-Content-Type-Options: nosniff` headers.
|
|
411
|
+
- **Stripe PayTo documentation** — JSDoc now explicitly documents the Base-only limitation with a multi-chain workaround example.
|
|
412
|
+
- **sessionStorage risk documented** — `useAccessPass` JSDoc warns about XSS exposure of stored JWTs.
|
|
413
|
+
|
|
414
|
+
### Added
|
|
415
|
+
- **`onSettlement` callback** in middleware config — called after every successful payment settlement for logging, analytics, or webhooks.
|
|
416
|
+
- **`onVerifyFailed` callback** in middleware config — called when payment verification fails for monitoring suspicious activity.
|
|
417
|
+
- **`onPaymentRequired` callback** in client config — pre-payment inspection hook. Return `false` to reject a payment before signing. Critical for agent budget controls.
|
|
418
|
+
- **`KEYPAIR_SYMBOL`** — Symbol-keyed access to the underlying Solana Keypair, preventing accidental private key exposure via `console.log` or `JSON.stringify`. The `keypair` property is deprecated but kept for backwards compat.
|
|
419
|
+
- **New error codes** — `wallet_disconnected`, `user_rejected_signature`, `rpc_timeout`, `facilitator_timeout`.
|
|
420
|
+
- **`isSolanaNetwork()` and `isEvmNetwork()`** — exported utility functions for network detection, replacing duplicated `startsWith` checks.
|
|
421
|
+
|
|
422
|
+
## [1.9.3] - 2026-03-15
|
|
423
|
+
|
|
424
|
+
### Added
|
|
425
|
+
- **52 unit tests** (up from 6) covering dynamic pricing HMAC validation, amount conversion edge cases, network detection, XSS escaping, USDC detection across all chains, v2 type compliance, sponsored access helpers, and X402Error behavior.
|
|
426
|
+
- **`escapeHtml()` exported** from `@dexterai/x402/server` — the XSS escape function is now public and tested for consumers who render payment data in HTML.
|
|
427
|
+
|
|
428
|
+
## [1.9.2] - 2026-03-15
|
|
429
|
+
|
|
430
|
+
### Breaking
|
|
431
|
+
- **`TokenPricing.calculate()`, `validateQuote()`, and `countTokens()` are now async** — returns `Promise<TokenPriceQuote>`, `Promise<boolean>`, and `Promise<number>` respectively. This is required because tiktoken is now lazy-loaded. Add `await` to all calls.
|
|
432
|
+
- **`TokenPricingConfig.tokenizer` now accepts async functions** — type changed from `(text: string) => number` to `(text: string) => number | Promise<number>`. Existing sync tokenizers still work.
|
|
433
|
+
|
|
434
|
+
### Fixed
|
|
435
|
+
- **tiktoken is no longer a hard dependency** — moved from `dependencies` to optional `peerDependencies`. The 5MB+ WASM binary is only loaded when `createTokenPricing()` or `countTokens()` is actually called. Consumers who don't use token pricing save the install cost entirely. Throws a helpful error if tiktoken is needed but not installed.
|
|
436
|
+
- **Stripe PayTo guard used fragile private property** — replaced `(provider as any)._stripeNetwork` with a `WeakMap` registry that survives wrapping, proxying, and `bind()`. Exported `getStripeProviderNetwork()` for external use.
|
|
437
|
+
|
|
438
|
+
### Added
|
|
439
|
+
- **EVM wallet Quick Start in README** — `wrapFetch` with `evmPrivateKey` is now documented alongside the Solana example in the Quick Start section.
|
|
440
|
+
|
|
441
|
+
## [1.9.1] - 2026-03-15
|
|
442
|
+
|
|
443
|
+
### Added
|
|
444
|
+
- **First-class Sponsored Access (Ads for Agents)** — typed helpers for consuming sponsored recommendations from x402 payment receipts:
|
|
445
|
+
- `getSponsoredRecommendations(response)` — extract typed `SponsoredRecommendation[]` from a payment response
|
|
446
|
+
- `getSponsoredAccessInfo(response)` — extract the full `SponsoredAccessSettlementInfo` extension data
|
|
447
|
+
- `fireImpressionBeacon(response)` — fire-and-forget delivery confirmation to the ad network
|
|
448
|
+
- **React hook support** — `useX402Payment` now returns `sponsoredRecommendations` (auto-populated after payment, auto-fires impression beacon)
|
|
449
|
+
- **Server `onMatch` callback** — `sponsoredAccess: { onMatch: (recs, settlement) => ... }` for server-side logging/analytics when recommendations are delivered
|
|
450
|
+
- **Typed middleware injection** — `sponsoredAccess.inject` callback now receives typed `SponsoredRecommendation[]` instead of `unknown[]`
|
|
451
|
+
- **Re-exported types** — `SponsoredRecommendation`, `SponsoredAccessSettlementInfo`, `SponsoredAccessPaymentRequiredInfo`, `SponsoredAccessClientConsent`, and `SPONSORED_ACCESS_EXTENSION_KEY` are now exported from `@dexterai/x402/client`, `@dexterai/x402/server`, and `@dexterai/x402/react`
|
|
452
|
+
|
|
453
|
+
### Changed
|
|
454
|
+
- **`@dexterai/x402-ads-types` is now a direct dependency** — moved from optional peer dependency to ensure types are always available. Package is 72KB (mostly type declarations, 12 lines of JS).
|
|
455
|
+
|
|
456
|
+
## [1.9.0] - 2026-03-15
|
|
457
|
+
|
|
458
|
+
### Breaking
|
|
459
|
+
- **`PaymentAccept.amount` is now required, `maxAmountRequired` is deprecated** — Aligns with the x402 v2 specification. `amount` is the v2 spec field; `maxAmountRequired` remains as an optional alias for backwards compatibility with v1 data. TypeScript consumers referencing `accept.maxAmountRequired` directly will get deprecation warnings. Server output includes both fields during the transition period.
|
|
460
|
+
- **`PaymentAccept.extra` is now optional** — Per v2 spec, `extra` is not required on all payment options. Existing code that accesses `accept.extra.feePayer` should use optional chaining: `accept.extra?.feePayer`.
|
|
461
|
+
|
|
462
|
+
### Fixed
|
|
463
|
+
- **EVM nonce used `Math.random()`** — Replaced with `crypto.getRandomValues()` for cryptographically secure nonce generation in EIP-3009 authorizations. Falls back to Node.js `crypto.webcrypto` for older environments.
|
|
464
|
+
- **Dynamic pricing used non-cryptographic hash** — Replaced FNV-1a with HMAC-SHA256 for quote validation. Quotes now include a timestamp and are rejected after 5 minutes, preventing both hash collision attacks and stale quote reuse.
|
|
465
|
+
- **Client-side access pass cache didn't cap expiry** — JWT `exp` decoded from unverified tokens is now capped to 24 hours max cache TTL, preventing forged far-future timestamps from caching indefinitely. Server-side verification is unaffected (always enforces HMAC signature).
|
|
466
|
+
|
|
467
|
+
### Added
|
|
468
|
+
- **`extensions` field on `PaymentRequired` and `PaymentSignature`** — Per v2 spec, both types now support optional `extensions: Record<string, unknown>` for protocol extensions like sponsored-access and bazaar.
|
|
469
|
+
|
|
470
|
+
## [1.8.2] - 2026-03-11
|
|
471
|
+
|
|
472
|
+
### Fixed
|
|
473
|
+
- **`getFeePayer()` throws on EVM networks** — `FacilitatorClient.getFeePayer()` required a `feePayer` field that only exists for SVM networks. Now returns `undefined` for EVM instead of throwing. Only throws if the network isn't supported at all.
|
|
474
|
+
|
|
475
|
+
## [1.8.1] - 2026-03-11
|
|
476
|
+
|
|
477
|
+
### Fixed
|
|
478
|
+
- **Server SDK crashes on EVM networks** — `createX402Server()` threw "Facilitator does not provide feePayer" when used with any EVM network (Base, Polygon, SKALE, etc.) because `getNetworkExtra()` unconditionally required a `feePayer` field from the facilitator's `/supported` response. That field only exists for Solana. The check is now SVM-only; EVM networks pass through `decimals` and EIP-712 fields without it.
|
|
479
|
+
|
|
480
|
+
## [1.8.0] - 2026-03-10
|
|
481
|
+
|
|
482
|
+
### Breaking
|
|
483
|
+
- **`createKeypairWallet` is now async** — Returns `Promise<KeypairWallet>` instead of `KeypairWallet`. You must `await` the result: `const wallet = await createKeypairWallet(key)`. This change was required for ESM compatibility (`require('bs58')` → `await import('bs58')`). `wrapFetch` handles this automatically — only direct callers are affected.
|
|
484
|
+
|
|
485
|
+
### Fixed
|
|
486
|
+
- **Verify/settle amount bug** — Server was passing `amountAtomic: '0'` to the facilitator when verifying or settling payments with dynamic payTo (e.g., Stripe). Added an in-memory requirements cache that preserves the correct amount between the initial 402 response and the retry with payment. Falls back to extracting the amount from the payment header if the cache misses.
|
|
487
|
+
- **ESM compatibility** — Replaced `require()` calls in `adapters/index.ts` and `keypair-wallet.ts` with ESM-compatible static imports and `await import()`. The package is `"type": "module"` and now works correctly in strict ESM environments.
|
|
488
|
+
- **XSS in browser paywall** — HTML-escape all interpolated values (description, price, requestUrl) in the browser paywall page to prevent injection from malicious payment requirement fields.
|
|
489
|
+
- **USDC decimal inference** — Client now recognizes USDC on all supported chains (Polygon, Arbitrum, Optimism, Avalanche, SKALE) for decimal inference, not just Solana and Base. Uses a shared `isKnownUSDC()` helper instead of hardcoded lists.
|
|
490
|
+
- **Wrong facilitator URL in JSDoc** — Fixed `@default` annotations in middleware, wrap-fetch, and access-pass that said `x402-facilitator.dexter.cash` (wrong) instead of `x402.dexter.cash` (correct).
|
|
491
|
+
- **Stripe type safety** — Stripe client, PaymentIntent response, and crypto options are now typed via `import('stripe')` instead of `any`.
|
|
492
|
+
|
|
493
|
+
### Added
|
|
494
|
+
- **Multi-network middleware** — `x402Middleware` now accepts `network: string | string[]` and `payTo: Record<string, string | PayToProvider>` with glob matching (`eip155:*`, `solana:*`, `*`). Endpoints can accept payments on all chains simultaneously. The client picks whichever chain it has a wallet for.
|
|
495
|
+
- **Full chain parity with facilitator** — EVM adapter now supports all 10 networks from the Dexter facilitator: Base, Polygon, Arbitrum, Optimism, Avalanche, SKALE Base (mainnet + testnet), and Base Sepolia. Ethereum mainnet is deprecated (not in facilitator).
|
|
496
|
+
- **Resilient facilitator client** — `FacilitatorClient` now retries on 5xx and network errors with exponential backoff (3 attempts, 500ms/1s/2s). All requests have a 10s timeout. Both limits are configurable via `FacilitatorClientConfig`.
|
|
497
|
+
- **`getPaymentReceipt(response)`** — Typed helper (backed by `WeakMap`) replaces the `(response as any)._x402` pattern. Exported from `@dexterai/x402/client`.
|
|
498
|
+
- **`@dexterai/x402-ads-types`** — Added as an optional peer dependency for typed sponsored-access extensions. No inlining; single source of truth.
|
|
499
|
+
- **New chain constants** — Exported `POLYGON`, `OPTIMISM`, `AVALANCHE`, `SKALE_BASE`, `SKALE_BASE_SEPOLIA`, `USDC_ADDRESSES` from `@dexterai/x402/adapters`.
|
|
500
|
+
|
|
501
|
+
## [1.7.2] - 2026-02-28
|
|
502
|
+
|
|
503
|
+
### Added
|
|
504
|
+
- **Sponsored access support** — Server middleware accepts `sponsoredAccess: true` config. Reads `extensions["sponsored-access"]` from the facilitator's settlement response and injects `_x402_sponsored` into the JSON response body.
|
|
505
|
+
- `SettleResponse.extensions` field for protocol extensions
|
|
506
|
+
|
|
507
|
+
## [1.7.1] - 2026-02-25
|
|
508
|
+
|
|
509
|
+
### Fixed
|
|
510
|
+
- Added `@types/aws-lambda` to fix DTS build errors
|
|
511
|
+
- Updated npm metadata and package description
|
|
512
|
+
|
|
513
|
+
## [1.7.0] - 2026-02-20
|
|
514
|
+
|
|
515
|
+
### Added
|
|
516
|
+
- OpenDexter marketplace auto-discovery section in README
|
|
517
|
+
- Updated header with marketplace links
|
|
518
|
+
|
|
519
|
+
## [1.6.6] - 2026-02-12
|
|
520
|
+
|
|
521
|
+
### Fixed
|
|
522
|
+
- Unicode-safe base64 encoding for server-side `btoa`/`atob`
|
|
523
|
+
|
|
524
|
+
## [1.6.5] - 2026-02-10
|
|
525
|
+
|
|
526
|
+
### Fixed
|
|
527
|
+
- **`wrapFetch` + `createEvmKeypairWallet` ESM compatibility** — v1.6.4 used `require('viem/accounts')` which fails in ESM consumers because viem 2.x is ESM-only. Replaced with `await import('viem/accounts')` (dynamic import). `createEvmKeypairWallet` is now async; `wrapFetch` starts the import eagerly and awaits it before the first fetch call, keeping its own signature synchronous.
|
|
528
|
+
|
|
529
|
+
## [1.6.4] - 2026-02-10
|
|
530
|
+
|
|
531
|
+
### Fixed
|
|
532
|
+
- **`wrapFetch` EVM support** — `evmPrivateKey` option now works. Previously, passing an EVM private key to `wrapFetch` would log a warning and silently discard the key, causing all Base/EVM payments to fail with `no_matching_payment_option`. The key is now used to create a proper EVM wallet via viem's `privateKeyToAccount` (chain-agnostic EIP-712 signing).
|
|
533
|
+
|
|
534
|
+
### Added
|
|
535
|
+
- **`createEvmKeypairWallet()`** — New helper (parallel to `createKeypairWallet` for Solana) that creates an `EvmWallet` from a hex private key. Exported from `@dexterai/x402/client`. Useful for Node.js scripts that need EVM payments without a browser wallet.
|
|
536
|
+
|
|
537
|
+
## [1.5.0] - 2026-02-09
|
|
538
|
+
|
|
539
|
+
### Added
|
|
540
|
+
- **Access Pass** — New payment pattern: pay once, get a time-limited JWT for unlimited API requests. Works with both SVM and EVM.
|
|
541
|
+
- **Server**: `x402AccessPass` middleware (`@dexterai/x402/server`) — drop-in Express middleware with tier-based and custom duration pricing. Issues JWTs after x402 payment settlement. Validates passes on subsequent requests without touching the facilitator.
|
|
542
|
+
- **Client**: `accessPass` option on `wrapFetch` and `createX402Client` (`@dexterai/x402/client`) — auto-detects servers that offer access passes, purchases one, caches the JWT, and includes it on all subsequent requests. Auto-renews expired passes.
|
|
543
|
+
- **React**: `useAccessPass` hook (`@dexterai/x402/react`) — dedicated hook for managing the access pass lifecycle: tier discovery, pass purchase, token caching, countdown timer, and auto-fetch with pass.
|
|
544
|
+
- New types: `AccessPassTier`, `AccessPassInfo`, `AccessPassClaims`, `AccessPassClientConfig`
|
|
545
|
+
- New error codes: `access_pass_expired`, `access_pass_invalid`, `access_pass_tier_not_found`, `access_pass_exceeds_max_spend`
|
|
546
|
+
- New HTTP headers: `X-ACCESS-PASS-TIERS` (server -> client on 402), `ACCESS-PASS` (server -> client on pass purchase)
|
|
547
|
+
- `test/access-pass.ts` — 8-assertion test suite covering the full access pass lifecycle
|
|
548
|
+
|
|
549
|
+
## [1.4.1] - 2026-02-09
|
|
550
|
+
|
|
551
|
+
### Fixed
|
|
552
|
+
- **PAYMENT-RESPONSE header** — Server middleware now sets `PAYMENT-RESPONSE` header (base64-encoded settlement data) on 200 OK responses after successful payment, per the x402 v2 HTTP transport spec. Previously, settlement data was only attached to `req.x402` but not surfaced as a response header.
|
|
553
|
+
- **`amount` field in 402 response** — The `accepts` array in payment requirements now includes both `amount` (v2 spec field) and `maxAmountRequired` (legacy field). Non-Dexter v2 clients that look for `amount` instead of `maxAmountRequired` will now find it.
|
|
554
|
+
- **`x402Version` in facilitator requests** — The `FacilitatorClient` now sends `x402Version: 2` at the top level of `/verify` and `/settle` request bodies, matching the Coinbase reference implementation format.
|
|
555
|
+
|
|
556
|
+
### Added
|
|
557
|
+
- `test/v2-spec-compliance.ts` — Automated test suite validating all three v2 spec compliance fixes against a mock facilitator (6 assertions).
|
|
558
|
+
|
|
559
|
+
## [1.4.0] - 2026-01-11
|
|
560
|
+
|
|
561
|
+
### Added
|
|
562
|
+
- **Model Registry** - Comprehensive single source of truth for all OpenAI models (`model-registry.ts`)
|
|
563
|
+
- 25 models across 5 tiers: fast, standard, reasoning, premium, specialized
|
|
564
|
+
- Complete pricing data from OpenAI (January 2026)
|
|
565
|
+
- GPT-5 family: gpt-5-nano, gpt-5-mini, gpt-5, gpt-5.1, gpt-5.2, gpt-5-pro, gpt-5.2-pro
|
|
566
|
+
- Reasoning models: o1, o1-mini, o1-pro, o3, o3-mini, o3-pro, o4-mini
|
|
567
|
+
- Specialized: deep-research, computer-use-preview, realtime models
|
|
568
|
+
- **Registry API**:
|
|
569
|
+
- `MODEL_REGISTRY` - Full model definitions with pricing, capabilities, and API parameters
|
|
570
|
+
- `getModel(id)` - Get model by ID (throws if not found)
|
|
571
|
+
- `findModel(id)` - Get model by ID (returns undefined if not found)
|
|
572
|
+
- `getModelsByTier(tier)` - Get all models in a tier
|
|
573
|
+
- `getModelsByFamily(family)` - Get models by family (gpt-5, o3, etc.)
|
|
574
|
+
- `getTextModels()` - Get all text-capable models for chat completions
|
|
575
|
+
- `getActiveModels()` - Get all non-deprecated models
|
|
576
|
+
- `getCheapestModel(minTier?)` - Find cheapest model meeting requirements
|
|
577
|
+
- `estimateCost(modelId, inputTokens, outputTokens)` - Calculate request cost
|
|
578
|
+
- **Model Parameters** - Each model specifies API compatibility:
|
|
579
|
+
- `usesMaxCompletionTokens` - GPT-5/reasoning models require this instead of `max_tokens`
|
|
580
|
+
- `supportsTemperature` - GPT-5 models only support default (1)
|
|
581
|
+
- `supportsReasoningEffort` - For o-series models
|
|
582
|
+
- `supportsTools`, `supportsStructuredOutput`, `supportsStreaming`
|
|
583
|
+
|
|
584
|
+
### Changed
|
|
585
|
+
- `token-pricing.ts` now uses `MODEL_REGISTRY` as its data source (no more duplicate pricing)
|
|
586
|
+
- `getAvailableModels()` returns models sorted by tier then price
|
|
587
|
+
|
|
588
|
+
### Developer Tools
|
|
589
|
+
- **Model Evaluation Harness** (`test/model-eval/`) - CLI for testing models
|
|
590
|
+
- Test prompts across multiple models simultaneously
|
|
591
|
+
- Compare response quality, timing, and costs
|
|
592
|
+
- Context injection from files (`--context`)
|
|
593
|
+
- Full output logging with metrics
|
|
594
|
+
|
|
595
|
+
## [1.3.1] - 2025-01-10
|
|
596
|
+
|
|
597
|
+
### Fixed
|
|
598
|
+
- Minor type exports cleanup
|
|
599
|
+
|
|
600
|
+
## [1.3.0] - 2025-01-09
|
|
601
|
+
|
|
602
|
+
### Changed
|
|
603
|
+
- Internal refactoring for model pricing
|
|
604
|
+
|
|
605
|
+
## [1.2.4] - 2024-12-30
|
|
606
|
+
|
|
607
|
+
### Fixed
|
|
608
|
+
- **x402 v1 compatibility** - SDK now echoes the `x402Version` from the server's 402 response instead of hardcoding v2. This enables compatibility with v1-only facilitators.
|
|
609
|
+
- Added `x402Version` field to `PaymentAccept` type
|
|
610
|
+
|
|
611
|
+
## [1.2.1] - 2024-12-28
|
|
612
|
+
|
|
613
|
+
### Added
|
|
614
|
+
- **Custom model support** for `createTokenPricing()`:
|
|
615
|
+
- `inputRate` - Custom USD per 1M input tokens (for Anthropic, Gemini, Mistral, etc.)
|
|
616
|
+
- `outputRate` - Custom USD per 1M output tokens
|
|
617
|
+
- `maxTokens` - Custom max output tokens
|
|
618
|
+
- `tokenizer` - Custom tokenizer function for non-OpenAI models
|
|
619
|
+
- `'custom'` tier for user-defined pricing
|
|
620
|
+
|
|
621
|
+
### Changed
|
|
622
|
+
- `createDynamicPricing()` documentation clarified: works for ANY pricing scenario, not just LLM
|
|
623
|
+
- README now shows examples for Anthropic Claude, Google Gemini, and local models
|
|
624
|
+
|
|
625
|
+
## [1.2.0] - 2024-12-28
|
|
626
|
+
|
|
627
|
+
### Added
|
|
628
|
+
- **Token Pricing** - `createTokenPricing()` for accurate LLM pricing using tiktoken
|
|
629
|
+
- Uses real OpenAI model rates (gpt-4o-mini, gpt-4o, o1, o3, etc.)
|
|
630
|
+
- `MODEL_PRICING` - Complete pricing table for 20+ models across fast/standard/reasoning/premium tiers
|
|
631
|
+
- `countTokens()` - Accurate token counting using OpenAI's tiktoken
|
|
632
|
+
- `getAvailableModels()` - List all models sorted by tier and price
|
|
633
|
+
- `isValidModel()` - Check if a model is supported
|
|
634
|
+
- `formatTokenPricing()` - Display helper (e.g., "$0.15 per 1M tokens")
|
|
635
|
+
|
|
636
|
+
### Changed
|
|
637
|
+
- Dynamic pricing now has two variants:
|
|
638
|
+
- `createDynamicPricing()` - Character-based (generic, no deps)
|
|
639
|
+
- `createTokenPricing()` - Token-based (LLM-accurate, uses tiktoken)
|
|
640
|
+
|
|
641
|
+
## [1.1.0] - 2024-12-27
|
|
642
|
+
|
|
643
|
+
### Added
|
|
644
|
+
- **Dynamic Pricing** - `createDynamicPricing()` for LLM/AI endpoints where cost scales with input
|
|
645
|
+
- Quote hash validation prevents prompt manipulation (includes pricing config in hash)
|
|
646
|
+
- `formatPricing()` helper for display strings
|
|
647
|
+
- Client SDK now forwards `X-Quote-Hash` header on retry
|
|
648
|
+
|
|
649
|
+
## [1.0.4] - 2024-12-27
|
|
650
|
+
|
|
651
|
+
### Changed
|
|
652
|
+
- **README overhaul** - Professional documentation with live demo links, emoji formatting, and clear API reference
|
|
653
|
+
- Prominent link to [dexter.cash/sdk](https://dexter.cash/sdk) for live verification
|
|
654
|
+
|
|
655
|
+
## [1.0.3] - 2024-12-27
|
|
656
|
+
|
|
657
|
+
### Added
|
|
658
|
+
- **Utils export** - `toAtomicUnits()` and `fromAtomicUnits()` now available via `@dexterai/x402/utils`
|
|
659
|
+
- `getChainFamily()`, `getChainName()`, `getExplorerUrl()` helpers
|
|
660
|
+
|
|
661
|
+
### Changed
|
|
662
|
+
- README now includes notice that server SDK is not yet battle-tested
|
|
663
|
+
|
|
664
|
+
## [1.0.2] - 2024-12-27
|
|
665
|
+
|
|
666
|
+
### Added
|
|
667
|
+
- **Pre-flight balance check** - SDK now checks USDC balance before signing transactions
|
|
668
|
+
- `insufficient_balance` error code with clear message: "Insufficient USDC balance on [Network]. Have $X, need $Y"
|
|
669
|
+
|
|
670
|
+
### Fixed
|
|
671
|
+
- Prevents confusing "Payment was rejected by the server: {}" error when user has insufficient funds
|
|
672
|
+
- Users now see a clear, actionable error message before wallet popup appears
|
|
673
|
+
|
|
674
|
+
## [1.0.1] - 2024-12-26
|
|
675
|
+
|
|
676
|
+
### Fixed
|
|
677
|
+
- EVM adapter payload structure now correctly separates `authorization` and `signature` fields to match upstream `@x402/evm` format
|
|
678
|
+
- Removed unnecessary `feePayer` validation for EVM networks (users pay their own gas)
|
|
679
|
+
|
|
680
|
+
## [1.0.0] - 2024-12-26
|
|
681
|
+
|
|
682
|
+
### Added
|
|
683
|
+
- **Chain-agnostic architecture** - Support for multiple blockchains through adapter pattern
|
|
684
|
+
- **SolanaAdapter** - Full Solana mainnet/devnet support with sponsored fees
|
|
685
|
+
- **EvmAdapter** - Base, Ethereum, and Arbitrum support via EIP-712 TransferWithAuthorization
|
|
686
|
+
- **Client SDK** (`@dexterai/x402/client`)
|
|
687
|
+
- `createX402Client()` - Wrapped fetch that auto-handles 402 responses
|
|
688
|
+
- Multi-wallet support via `WalletSet`
|
|
689
|
+
- Automatic adapter selection based on payment network
|
|
690
|
+
- **Server SDK** (`@dexterai/x402/server`)
|
|
691
|
+
- `createX402Server()` - Generate 402 responses and verify/settle payments
|
|
692
|
+
- `buildRequirements()` - Build PaymentRequired payloads
|
|
693
|
+
- `verifyPayment()` / `settlePayment()` - Facilitator integration
|
|
694
|
+
- Auto-fetches feePayer and decimals from facilitator
|
|
695
|
+
- **React Hooks** (`@dexterai/x402/react`)
|
|
696
|
+
- `useX402Payment()` - Complete payment state management
|
|
697
|
+
- Multi-wallet balance tracking
|
|
698
|
+
- Real-time connection status per network
|
|
699
|
+
- **Adapters** (`@dexterai/x402/adapters`)
|
|
700
|
+
- `ChainAdapter` interface for extensibility
|
|
701
|
+
- `createSolanaAdapter()` / `createEvmAdapter()` factories
|
|
702
|
+
- Balance fetching for USDC across chains
|
|
703
|
+
- Dual ESM/CJS builds with full TypeScript definitions
|
|
704
|
+
- Comprehensive documentation and examples
|
|
705
|
+
|
|
706
|
+
### Technical Details
|
|
707
|
+
- Uses Dexter's public facilitator at `https://x402.dexter.cash`
|
|
708
|
+
- Solana: Sponsored fees via ComputeBudget instructions (12k CU limit, 1 microlamport priority)
|
|
709
|
+
- EVM: EIP-3009 TransferWithAuthorization for gasless token transfers
|
|
710
|
+
- v2 protocol only (header-based flow with `PAYMENT-REQUIRED` / `PAYMENT-SIGNATURE`)
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
[Unreleased]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v3.4.0...HEAD
|
|
715
|
+
[3.4.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v3.2.0...v3.4.0
|
|
716
|
+
[3.1.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v3.0.0...v3.1.1
|
|
717
|
+
[3.0.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v2.0.0...v3.0.0
|
|
718
|
+
[2.0.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.9.4...v2.0.0
|
|
719
|
+
[1.9.4]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.9.3...v1.9.4
|
|
720
|
+
[1.9.3]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.9.2...v1.9.3
|
|
721
|
+
[1.9.2]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.9.1...v1.9.2
|
|
722
|
+
[1.9.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.9.0...v1.9.1
|
|
723
|
+
[1.9.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.8.2...v1.9.0
|
|
724
|
+
[1.8.2]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.8.1...v1.8.2
|
|
725
|
+
[1.8.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.8.0...v1.8.1
|
|
726
|
+
[1.8.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.7.2...v1.8.0
|
|
727
|
+
[1.7.2]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.7.1...v1.7.2
|
|
728
|
+
[1.7.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.7.0...v1.7.1
|
|
729
|
+
[1.7.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.6.6...v1.7.0
|
|
730
|
+
[1.6.6]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.6.5...v1.6.6
|
|
731
|
+
[1.6.5]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.6.4...v1.6.5
|
|
732
|
+
[1.6.4]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.5.5...v1.6.4
|
|
733
|
+
[1.5.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.4.1...v1.5.0
|
|
734
|
+
[1.4.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.4.0...v1.4.1
|
|
735
|
+
[1.4.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.3.1...v1.4.0
|
|
736
|
+
[1.3.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.3.0...v1.3.1
|
|
737
|
+
[1.3.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.2.5...v1.3.0
|
|
738
|
+
[1.2.4]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.2.1...v1.2.4
|
|
739
|
+
[1.2.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.2.0...v1.2.1
|
|
740
|
+
[1.2.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.1.0...v1.2.0
|
|
741
|
+
[1.1.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.0.4...v1.1.0
|
|
742
|
+
[1.0.4]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.0.3...v1.0.4
|
|
743
|
+
[1.0.3]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.0.2...v1.0.3
|
|
744
|
+
[1.0.2]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.0.1...v1.0.2
|
|
745
|
+
[1.0.1]: https://github.com/Dexter-DAO/dexter-x402-sdk/compare/v1.0.0...v1.0.1
|
|
746
|
+
[1.0.0]: https://github.com/Dexter-DAO/dexter-x402-sdk/releases/tag/v1.0.0
|
|
747
|
+
|
|
748
|
+
[`4d3e881`]: https://github.com/Dexter-DAO/dexter-x402-sdk/commit/4d3e881
|
|
749
|
+
[`58c7eea`]: https://github.com/Dexter-DAO/dexter-x402-sdk/commit/58c7eea
|