@dexterai/x402 3.3.0 → 3.3.1

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/README.md CHANGED
@@ -207,9 +207,11 @@ const b = await channel.fetch('https://api.example.com/v1/data');
207
207
 
208
208
  console.log(channel.state); // { deposited: '0.3', spent: '0.16', remaining: '0.14' }
209
209
 
210
- // Closethe facilitator claims, settles to the seller, and refunds the rest.
211
- const receipt = await channel.close();
212
- console.log(receipt.settledAmount, receipt.refundedAmount);
210
+ // Done buying signal you're finished with the channel.
211
+ const { closed } = await channel.close();
212
+ // closed === true. This is an intent signal, not a settlement: it does not
213
+ // move funds. The seller's settlement (below) claims what you spent and
214
+ // refunds the rest of your escrow automatically on the normal path.
213
215
  ```
214
216
 
215
217
  Channel state auto-persists (localStorage in the browser, a file under
@@ -219,20 +221,73 @@ transparently resumes the open channel — the channel's state is recovered from
219
221
  storage, or from on-chain state if storage was lost. Pass a custom `store` (any
220
222
  `ChannelStore`) to persist elsewhere.
221
223
 
224
+ #### Escape hatch — `forceWithdraw()` / `finalizeWithdraw()`
225
+
226
+ If the seller never settles, the buyer can reclaim unspent escrow directly via
227
+ the channel contract's timed withdrawal:
228
+
229
+ ```ts
230
+ // 1. Start the on-chain timed withdrawal.
231
+ await channel.forceWithdraw();
232
+
233
+ // 2. After the channel's withdraw delay elapses, finalize it.
234
+ await channel.finalizeWithdraw();
235
+ ```
236
+
237
+ This is a last-resort safety net — **normal operation never needs it**, since
238
+ the seller's settlement returns unspent escrow on the standard path. Unlike
239
+ every other batch-settlement step, the escape hatch **costs the buyer gas**: it
240
+ submits transactions itself, so the buyer's wallet must be transaction-capable
241
+ (it must expose a `sendTransaction` method). A signature-only wallet cannot use
242
+ the escape hatch.
243
+
222
244
  ### Seller
223
245
 
224
- Advertise the scheme from the existing server or middleware with one option —
225
- Dexter operates the delegate authorizer, so the seller manages no signing key:
246
+ `createBatchSettlementSeller(config)` returns a callable object that **is** an
247
+ Express request handler mount it directly. It accepts batch-settlement
248
+ payments (each incoming voucher is verified and persisted to channel storage)
249
+ and collects them (claim → settle → refund). Dexter operates the delegate
250
+ authorizer, so the seller manages no signing key:
251
+
252
+ ```ts
253
+ import { createBatchSettlementSeller } from '@dexterai/x402/batch-settlement/seller';
254
+
255
+ const seller = createBatchSettlementSeller({
256
+ payTo: '0xYourReceivingAddress',
257
+ network: 'eip155:8453', // Base
258
+ price: '0.08', // USDC per call
259
+ });
260
+
261
+ // The seller object IS the Express handler — mount it directly.
262
+ app.use('/api/data', seller);
263
+
264
+ // Auto-settlement runs in the background by default. On shutdown, stop the
265
+ // seller — this flushes a final settle so no collected vouchers are lost.
266
+ process.on('SIGTERM', async () => {
267
+ await seller.stop();
268
+ });
269
+ ```
270
+
271
+ Settlement happens automatically via a background loop (on by default). To
272
+ settle on demand, call `seller.closeChannel(channelId)` for one channel or
273
+ `seller.closeAll()` for every open channel.
274
+
275
+ Mounting via `x402Middleware` also works — with `scheme: 'batch-settlement'` it
276
+ returns the same callable seller object, so you still get a `.stop()` /
277
+ `.closeAll()` / `.closeChannel()` handle:
226
278
 
227
279
  ```ts
228
280
  import { x402Middleware } from '@dexterai/x402/server';
229
281
 
230
- app.use(x402Middleware({
282
+ const seller = x402Middleware({
231
283
  payTo: '0xYourReceivingAddress',
232
284
  amount: '0.08',
233
285
  network: 'eip155:8453',
234
286
  scheme: 'batch-settlement',
235
- }));
287
+ });
288
+
289
+ app.use('/api/data', seller);
290
+ // seller.stop() / seller.closeAll() are available here too.
236
291
  ```
237
292
 
238
293
  ---
@@ -312,9 +367,12 @@ import { createX402Client } from '@dexterai/x402/client';
312
367
  // Client - Node.js (private key wallet)
313
368
  import { wrapFetch, createKeypairWallet } from '@dexterai/x402/client';
314
369
 
315
- // Batch settlement - EVM escrow channel (gas amortization)
370
+ // Batch settlement - EVM escrow channel buyer (gas amortization)
316
371
  import { openBatchChannel } from '@dexterai/x402/batch-settlement';
317
372
 
373
+ // Batch settlement - EVM escrow channel seller runtime
374
+ import { createBatchSettlementSeller } from '@dexterai/x402/batch-settlement/seller';
375
+
318
376
  // React hook
319
377
  import { useX402Payment } from '@dexterai/x402/react';
320
378
 
@@ -1,7 +1,6 @@
1
- import { b as SolanaAdapter, d as EvmAdapter, C as ChainAdapter } from '../types-B3kS1y_t.cjs';
2
- export { A as AdapterConfig, B as BalanceInfo, E as EvmWallet, G as GenericWallet, e as SignedTransaction, S as SolanaWallet, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter, f as isEvmWallet, i as isSolanaWallet } from '../types-B3kS1y_t.cjs';
1
+ import { k as SolanaAdapter, l as EvmAdapter, C as ChainAdapter } from '../types-IqnDBsjL.cjs';
2
+ export { m as AdapterConfig, B as BalanceInfo, E as EvmWallet, G as GenericWallet, n as SignedTransaction, S as SolanaWallet, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter, p as isEvmWallet, o as isSolanaWallet } from '../types-IqnDBsjL.cjs';
3
3
  export { A as ARBITRUM_ONE, l as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, f as BSC_MAINNET, i as BSC_STABLECOIN_ADDRESSES, h as BSC_USDC, g as BSC_USDT, E as ETHEREUM_MAINNET, O as OPTIMISM, P as PERMIT2_ADDRESS, k as POLYGON, m as SKALE_BASE, n as SKALE_BASE_SEPOLIA, d as SOLANA_DEVNET, S as SOLANA_MAINNET, e as SOLANA_TESTNET, o as USDC_ADDRESSES, X as X402_EXACT_PERMIT2_PROXY } from '../constants-qU-4U3L-.cjs';
4
- import '../types-Bcsi5jQb.cjs';
5
4
 
6
5
  /**
7
6
  * Check if an asset address is a known USDC contract (any chain).
@@ -1,7 +1,6 @@
1
- import { b as SolanaAdapter, d as EvmAdapter, C as ChainAdapter } from '../types-HFS_C6RX.js';
2
- export { A as AdapterConfig, B as BalanceInfo, E as EvmWallet, G as GenericWallet, e as SignedTransaction, S as SolanaWallet, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter, f as isEvmWallet, i as isSolanaWallet } from '../types-HFS_C6RX.js';
1
+ import { k as SolanaAdapter, l as EvmAdapter, C as ChainAdapter } from '../types-IqnDBsjL.js';
2
+ export { m as AdapterConfig, B as BalanceInfo, E as EvmWallet, G as GenericWallet, n as SignedTransaction, S as SolanaWallet, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter, p as isEvmWallet, o as isSolanaWallet } from '../types-IqnDBsjL.js';
3
3
  export { A as ARBITRUM_ONE, l as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, f as BSC_MAINNET, i as BSC_STABLECOIN_ADDRESSES, h as BSC_USDC, g as BSC_USDT, E as ETHEREUM_MAINNET, O as OPTIMISM, P as PERMIT2_ADDRESS, k as POLYGON, m as SKALE_BASE, n as SKALE_BASE_SEPOLIA, d as SOLANA_DEVNET, S as SOLANA_MAINNET, e as SOLANA_TESTNET, o as USDC_ADDRESSES, X as X402_EXACT_PERMIT2_PROXY } from '../constants-qU-4U3L-.js';
4
- import '../types-Bcsi5jQb.js';
5
4
 
6
5
  /**
7
6
  * Check if an asset address is a known USDC contract (any chain).
@@ -1 +1 @@
1
- "use strict";var b=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var te=Object.prototype.hasOwnProperty;var ne=(e,t)=>{for(var n in t)b(e,n,{get:t[n],enumerable:!0})},re=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of ee(t))!te.call(e,a)&&a!==n&&b(e,a,{get:()=>t[a],enumerable:!(r=Z(t,a))||r.enumerable});return e};var ae=e=>re(b({},"__esModule",{value:!0}),e);var se={};ne(se,{InsufficientBalanceError:()=>w,UnsupportedNetworkError:()=>d,createFileChannelStore:()=>U,createLocalStorageChannelStore:()=>I,getDefaultChannelStore:()=>S,openBatchChannel:()=>G,resumeBatchChannel:()=>K});module.exports=ae(se);var i=require("viem"),u=require("viem/chains"),N=require("@x402/evm"),x=require("@x402/evm/batch-settlement/client"),k=require("@x402/core/client");var D=require("os"),$=require("path"),M=require("@x402/evm/batch-settlement/client");function U(e){return new M.FileClientChannelStorage({directory:e})}var v="dexter-x402-channel:";function I(e){return{async get(t){let n=e.getItem(v+t);return n?JSON.parse(n):void 0},async set(t,n){e.setItem(v+t,JSON.stringify(n))},async delete(t){e.removeItem(v+t)}}}function S(){let e=globalThis.localStorage;return e?I(e):U((0,$.join)((0,D.homedir)(),".dexter-x402","channels"))}var B=require("viem"),F=require("@x402/core/server"),H=require("@x402/evm/batch-settlement/server"),j=6;async function _(e,t,n){let{claims:r,settle:a}=await e.claimAndSettle();if(r.length===0&&BigInt(n.settledAtomic)>0n)throw new Error(`batch-settlement close inconsistency: channel accounting expected a settled amount of ${n.settledAtomic} atomic units, but the facilitator's claimAndSettle reported no claim transaction (claims was empty)`);let p=(await e.refund([t]))[0];return{claimTx:r[0]?.transaction??"",settleTx:a?.transaction??"",refundTx:p?.transaction??"",settledAmount:(0,B.formatUnits)(BigInt(n.settledAtomic),j),refundedAmount:(0,B.formatUnits)(BigInt(n.refundedAtomic),j)}}function q(e,t,n){let r=new F.HTTPFacilitatorClient({url:e});return new H.BatchSettlementEvmScheme(n).createChannelManager(r,t)}var w=class extends Error{constructor(t){super(t),this.name="InsufficientBalanceError"}},d=class extends Error{constructor(t){super(t),this.name="UnsupportedNetworkError"}};var W={"eip155:8453":{chain:u.base,defaultRpc:"https://mainnet.base.org"},"eip155:42161":{chain:u.arbitrum,defaultRpc:"https://arb1.arbitrum.io/rpc"},"eip155:137":{chain:u.polygon,defaultRpc:"https://polygon-rpc.com"}};function J(e){let t=W[e.network];if(!t)throw new d(`batch-settlement is not available on network "${e.network}" \u2014 supported: ${Object.keys(W).join(", ")}`);let n=e.rpcUrl??t.defaultRpc,r=e.wallet.signTypedData;if(typeof r!="function")throw new Error("batch-settlement requires an EvmWallet that supports signTypedData (EIP-712)");let a=(0,i.createWalletClient)({account:{address:e.wallet.address,type:"json-rpc"},chain:t.chain,transport:(0,i.http)(n)}).extend(i.publicActions),s=Object.assign(a,{address:e.wallet.address,signTypedData:o=>r.call(e.wallet,o)}),p=(0,N.toClientEvmSigner)(s),c=new x.BatchSettlementEvmScheme(p,{storage:e.store,depositPolicy:{depositMultiplier:4},depositStrategy:()=>e.depositAtomic}),l=new k.x402Client;l.register(e.network,c);let R=new k.x402HTTPClient(l);return{scheme:c,x402Cli:l,httpClient:R,rpcUrl:n}}var y=6,X="https://x402.dexter.cash";function oe(e,t){let n=t>e?0n:e-t;return{deposited:(0,i.formatUnits)(e,y),spent:(0,i.formatUnits)(t,y),remaining:(0,i.formatUnits)(n,y)}}function ie(e){let t=e.payload;if(!t||typeof t!="object")return"";let n=t.voucher;if(!n||typeof n!="object")return"";let r=n.channelId;return typeof r=="string"?r:""}function z(e){let{stack:t,store:n,facilitatorUrl:r,network:a}=e,s="",p="",c=e.depositedAtomic,l=0n;async function R(){if(!s)return;let o=await(0,x.getChannel)(n,s);o&&(o.chargedCumulativeAmount!==void 0&&(l=BigInt(o.chargedCumulativeAmount)),c===0n&&o.balance!==void 0&&(c=BigInt(o.balance)))}return{get channelId(){return s},get network(){return a},get state(){return oe(c,l)},async fetch(o,f){let{httpClient:m}=t,h=await fetch(o,f);if(h.status!==402)return h;let E=m.getPaymentRequiredResponse(g=>h.headers.get(g),await h.clone().json().catch(()=>{})),P=E.accepts?.[0];P?.payTo&&(p=P.payTo);let T=2,L;for(let g=1;g<=T;g+=1){let A=await m.createPaymentPayload(E),O=ie(A);O&&(s=O);let Q=m.encodePaymentSignatureHeader(A),C=await fetch(o,{...f,headers:{...f?.headers??{},...Q}});L=C;let{recovered:V}=await m.processPaymentResult(A,Y=>C.headers.get(Y),C.status);if(await R(),!(C.status===402&&V&&g<T))return C}return L},async close(){if(!s)throw new Error("cannot close a channel that has made no requests \u2014 call fetch() at least once first");if(!p)throw new Error("cannot close: the seller payout address is unknown (no 402 was observed)");let o=l.toString(),f=(l>c?0n:c-l).toString(),m=q(r,a,p),h=await _(m,s,{settledAtomic:o,refundedAtomic:f});return await n.delete(s.toLowerCase()),h}}}async function G(e){let t=e.store??S(),n=e.facilitatorUrl??X,r;try{r=(0,i.parseUnits)(e.deposit,y)}catch{throw new Error(`deposit must be a valid USDC amount in decimal units (e.g. "0.30"), got "${e.deposit}"`)}if(r<=0n)throw new Error(`deposit must be a positive amount, got "${e.deposit}"`);let a=J({wallet:e.wallet,network:e.network,rpcUrl:e.rpcUrl,store:t,depositAtomic:r.toString()});return z({stack:a,store:t,facilitatorUrl:n,network:e.network,depositedAtomic:r})}async function K(e){let t=e.store??S(),n=e.facilitatorUrl??X,r=J({wallet:e.wallet,network:e.network,rpcUrl:e.rpcUrl,store:t,depositAtomic:"0"});return z({stack:r,store:t,facilitatorUrl:n,network:e.network,depositedAtomic:0n})}0&&(module.exports={InsufficientBalanceError,UnsupportedNetworkError,createFileChannelStore,createLocalStorageChannelStore,getDefaultChannelStore,openBatchChannel,resumeBatchChannel});
1
+ "use strict";var T=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var nt=Object.getOwnPropertyNames;var at=Object.prototype.hasOwnProperty;var rt=(t,e)=>{for(var n in e)T(t,n,{get:e[n],enumerable:!0})},it=(t,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of nt(e))!at.call(t,r)&&r!==n&&T(t,r,{get:()=>e[r],enumerable:!(a=et(e,r))||a.enumerable});return t};var ot=t=>it(T({},"__esModule",{value:!0}),t);var ut={};rt(ut,{InsufficientBalanceError:()=>k,UnsupportedNetworkError:()=>f,WithdrawNotReadyError:()=>C,createFileChannelStore:()=>P,createLocalStorageChannelStore:()=>B,getDefaultChannelStore:()=>W,openBatchChannel:()=>Q,resumeBatchChannel:()=>V});module.exports=ot(ut);var l=require("viem"),y=require("viem/chains"),X=require("@x402/evm"),v=require("@x402/evm/batch-settlement/client"),I=require("@x402/core/client");var $=require("os"),O=require("path"),N=require("@x402/evm/batch-settlement/client");function P(t){return new N.FileClientChannelStorage({directory:t})}var E="dexter-x402-channel:";function B(t){return{async get(e){let n=t.getItem(E+e);return n?JSON.parse(n):void 0},async set(e,n){t.setItem(E+e,JSON.stringify(n))},async delete(e){t.removeItem(E+e)}}}function W(){let t=globalThis.localStorage;return t?B(t):P((0,O.join)((0,$.homedir)(),".dexter-x402","channels"))}var k=class extends Error{constructor(e){super(e),this.name="InsufficientBalanceError"}},f=class extends Error{constructor(e){super(e),this.name="UnsupportedNetworkError"}};var L=require("viem"),z=require("@x402/evm/batch-settlement/client"),g=require("@x402/evm"),C=class extends Error{constructor(e){super(e),this.name="WithdrawNotReadyError"}};function M(t,e){return t===0?0:t+e}var st=6,j=[{name:"payer",type:"address"},{name:"payerAuthorizer",type:"address"},{name:"receiver",type:"address"},{name:"receiverAuthorizer",type:"address"},{name:"token",type:"address"},{name:"withdrawDelay",type:"uint40"},{name:"salt",type:"bytes32"}],R=[{type:"function",name:"initiateWithdraw",inputs:[{name:"config",type:"tuple",components:j},{name:"amount",type:"uint128"}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"finalizeWithdraw",inputs:[{name:"config",type:"tuple",components:j}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"pendingWithdrawals",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"amount",type:"uint128"},{name:"initiatedAt",type:"uint40"}],stateMutability:"view"},{type:"function",name:"channels",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"balance",type:"uint128"},{name:"totalClaimed",type:"uint128"}],stateMutability:"view"}];function lt(t){if(Array.isArray(t))return{balance:BigInt(t[0]),totalClaimed:BigInt(t[1])};let e=t;return{balance:BigInt(e.balance),totalClaimed:BigInt(e.totalClaimed)}}function q(t){if(Array.isArray(t))return{amount:BigInt(t[0]),initiatedAt:Number(t[1])};let e=t;return{amount:BigInt(e.amount),initiatedAt:Number(e.initiatedAt)}}async function H(t){let{config:e,network:n,client:a,withdrawDelaySecs:r}=t,i=(0,z.computeChannelId)(e,n),s=t.amountAtomic;s===void 0&&(s=lt(await a.readContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"channels",args:[i]})).balance);let c=await a.writeContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"initiateWithdraw",args:[e,s]});await a.waitForTransactionReceipt({hash:c});let d=q(await a.readContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"pendingWithdrawals",args:[i]}));return{initiateTx:c,finalizableAt:M(d.initiatedAt,r)}}async function _(t){let{config:e,network:n,client:a,withdrawDelaySecs:r}=t,i=(0,z.computeChannelId)(e,n),s=q(await a.readContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"pendingWithdrawals",args:[i]}));if(s.initiatedAt===0)throw new C(`no withdrawal is pending for channel ${i} \u2014 call forceWithdraw first`);let c=M(s.initiatedAt,r),d=Math.floor(Date.now()/1e3);if(d<c)throw new C(`withdrawal for channel ${i} is not finalizable until ${c} (unix seconds) \u2014 ${c-d}s remaining`);let o=await a.writeContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"finalizeWithdraw",args:[e]});return await a.waitForTransactionReceipt({hash:o}),{finalizeTx:o,withdrawnAmount:(0,L.formatUnits)(s.amount,st)}}var J={"eip155:8453":{chain:y.base,defaultRpc:"https://mainnet.base.org"},"eip155:42161":{chain:y.arbitrum,defaultRpc:"https://arb1.arbitrum.io/rpc"},"eip155:137":{chain:y.polygon,defaultRpc:"https://polygon-rpc.com"}};function G(t){let e=J[t.network];if(!e)throw new f(`batch-settlement is not available on network "${t.network}" \u2014 supported: ${Object.keys(J).join(", ")}`);let n=t.rpcUrl??e.defaultRpc,a=t.wallet.signTypedData;if(typeof a!="function")throw new Error("batch-settlement requires an EvmWallet that supports signTypedData (EIP-712)");let r=(0,l.createWalletClient)({account:{address:t.wallet.address,type:"json-rpc"},chain:e.chain,transport:(0,l.http)(n)}).extend(l.publicActions),i=t.wallet.sendTransaction,s=typeof i=="function",c=async u=>{let b=u.to??void 0;if(!b)throw new Error("batch-settlement escape hatch: transaction is missing a `to` address");let p=u.data??"0x";if(typeof i=="function")return await i.call(t.wallet,{to:b,data:p,value:u.value});throw new Error("batch-settlement: wallet has no sendTransaction")},d=Object.assign(r,{address:t.wallet.address,signTypedData:u=>a.call(t.wallet,u),sendTransaction:c}),o=(0,X.toClientEvmSigner)(d),m=new v.BatchSettlementEvmScheme(o,{storage:t.store,depositPolicy:{depositMultiplier:4},depositStrategy:()=>t.depositAtomic}),h=new I.x402Client;h.register(t.network,m);let w=new I.x402HTTPClient(h);return{scheme:m,x402Cli:h,httpClient:w,rpcUrl:n,withdrawClient:d,canSubmitTransactions:s}}var A=6;function ct(t,e){let n=e>t?0n:t-e;return{deposited:(0,l.formatUnits)(t,A),spent:(0,l.formatUnits)(e,A),remaining:(0,l.formatUnits)(n,A)}}function dt(t){let e=t.payload;if(!e||typeof e!="object")return"";let n=e.voucher;if(!n||typeof n!="object")return"";let a=n.channelId;return typeof a=="string"?a:""}function ht(t){let e=t.payload;if(!e||typeof e!="object")return;let n=e.channelConfig;if(!(!n||typeof n!="object"))return n}function K(t){let{stack:e,store:n,network:a}=t,r="",i,s=t.depositedAtomic,c=0n;async function d(){if(!r)return;let o=await(0,v.getChannel)(n,r);o&&(o.chargedCumulativeAmount!==void 0&&(c=BigInt(o.chargedCumulativeAmount)),s===0n&&o.balance!==void 0&&(s=BigInt(o.balance)))}return{get channelId(){return r},get network(){return a},get state(){return ct(s,c)},async fetch(o,m){let{httpClient:h}=e,w=await fetch(o,m);if(w.status!==402)return w;let F=h.getPaymentRequiredResponse(p=>w.headers.get(p),await w.clone().json().catch(()=>{})),u=2,b;for(let p=1;p<=u;p+=1){let S=await h.createPaymentPayload(F),D=dt(S);D&&(r=D);let U=ht(S);U&&(i=U);let Y=h.encodePaymentSignatureHeader(S),x=await fetch(o,{...m,headers:{...m?.headers??{},...Y}});b=x;let{recovered:Z}=await h.processPaymentResult(S,tt=>x.headers.get(tt),x.status);if(await d(),!(x.status===402&&Z&&p<u))return x}return b},async close(){return r&&await n.delete(r.toLowerCase()),{closed:!0}},async forceWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement forceWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!i)throw new Error("forceWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return H({config:i,network:a,client:e.withdrawClient,withdrawDelaySecs:i.withdrawDelay})},async finalizeWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement finalizeWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!i)throw new Error("finalizeWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return _({config:i,network:a,client:e.withdrawClient,withdrawDelaySecs:i.withdrawDelay})}}}async function Q(t){let e=t.store??W(),n;try{n=(0,l.parseUnits)(t.deposit,A)}catch{throw new Error(`deposit must be a valid USDC amount in decimal units (e.g. "0.30"), got "${t.deposit}"`)}if(n<=0n)throw new Error(`deposit must be a positive amount, got "${t.deposit}"`);let a=G({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:n.toString()});return K({stack:a,store:e,network:t.network,depositedAtomic:n})}async function V(t){let e=t.store??W(),n=G({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:"0"});return K({stack:n,store:e,network:t.network,depositedAtomic:0n})}0&&(module.exports={InsufficientBalanceError,UnsupportedNetworkError,WithdrawNotReadyError,createFileChannelStore,createLocalStorageChannelStore,getDefaultChannelStore,openBatchChannel,resumeBatchChannel});
@@ -1,83 +1,7 @@
1
- import { ClientChannelStorage } from '@x402/evm/batch-settlement/client';
2
- import { E as EvmWallet } from '../types-B3kS1y_t.cjs';
3
- import '../types-Bcsi5jQb.cjs';
4
-
5
- /**
6
- * Channel persistence. This is the upstream `ClientChannelStorage` interface
7
- * (`get` / `set` / `delete`, keyed by lowercased channelId). The SDK ships
8
- * file-backed and localStorage-backed implementations; a consumer may pass any
9
- * `ClientChannelStorage` (e.g. one backed by their own database).
10
- */
11
- type ChannelStore = ClientChannelStorage;
12
- /** Channel accounting, all amounts USDC human units (e.g. "0.30"). */
13
- interface ChannelState {
14
- /** Total escrowed into the channel. */
15
- deposited: string;
16
- /** Cumulative amount spent via vouchers. */
17
- spent: string;
18
- /** deposited - spent. */
19
- remaining: string;
20
- }
21
- /** Options for opening a fresh (or auto-resumed) channel. */
22
- interface OpenBatchChannelOptions {
23
- /** EVM wallet — any { address, signTypedData }. The same EvmWallet the exact scheme uses. */
24
- wallet: EvmWallet;
25
- /** CAIP-2 network: eip155:8453 (Base), eip155:42161 (Arbitrum), eip155:137 (Polygon). */
26
- network: string;
27
- /** Total escrow for the channel, USDC human units, e.g. "0.30". */
28
- deposit: string;
29
- /** Facilitator base URL. Default: https://x402.dexter.cash */
30
- facilitatorUrl?: string;
31
- /** RPC URL override. Default: per-network. */
32
- rpcUrl?: string;
33
- /** Channel persistence. Default: localStorage (browser) / file (Node). */
34
- store?: ChannelStore;
35
- }
36
- /** Options for explicitly resuming an existing channel. */
37
- interface ResumeBatchChannelOptions {
38
- wallet: EvmWallet;
39
- network: string;
40
- facilitatorUrl?: string;
41
- rpcUrl?: string;
42
- store?: ChannelStore;
43
- }
44
- /** Result of channel.close() — the three settlement tx hashes and final amounts. */
45
- interface CloseReceipt {
46
- /** claimWithSignature tx hash. */
47
- claimTx: string;
48
- /** settle tx hash. */
49
- settleTx: string;
50
- /** refundWithSignature tx hash. */
51
- refundTx: string;
52
- /** Amount paid to the seller, USDC human units. */
53
- settledAmount: string;
54
- /** Unspent amount returned to the buyer, USDC human units. */
55
- refundedAmount: string;
56
- }
57
- /**
58
- * A live escrow channel. Returned by openBatchChannel / resumeBatchChannel.
59
- * Hold this handle for the lifetime of a batching session.
60
- */
61
- interface BatchSettlementChannel {
62
- /** On-chain channel id (bytes32 hex). Empty until the first fetch resolves it. */
63
- readonly channelId: string;
64
- /** CAIP-2 network. */
65
- readonly network: string;
66
- /** Live channel accounting; updated after each fetch. */
67
- readonly state: ChannelState;
68
- /** Drop-in fetch. On a batch-settlement 402, signs a voucher and retries. */
69
- fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
70
- /** Facilitator-driven claim -> settle -> refund. Resumable if interrupted. */
71
- close(): Promise<CloseReceipt>;
72
- }
73
- /** Thrown by openBatchChannel when the buyer wallet lacks USDC for the deposit. */
74
- declare class InsufficientBalanceError extends Error {
75
- constructor(message: string);
76
- }
77
- /** Thrown when a network has no deployed x402BatchSettlement contract. */
78
- declare class UnsupportedNetworkError extends Error {
79
- constructor(message: string);
80
- }
1
+ import { O as OpenBatchChannelOptions, B as BatchSettlementChannel, R as ResumeBatchChannelOptions, C as ChannelStore } from '../types-Bbt_SDZE.cjs';
2
+ export { a as ChannelState, b as CloseReceipt, c as CloseResult, d as FinalizeWithdrawResult, F as ForceWithdrawResult, I as InsufficientBalanceError, U as UnsupportedNetworkError, W as WithdrawNotReadyError } from '../types-Bbt_SDZE.cjs';
3
+ import '@x402/evm/batch-settlement/client';
4
+ import '../types-IqnDBsjL.cjs';
81
5
 
82
6
  /**
83
7
  * Opens a fresh batch-settlement escrow channel. No network call happens here:
@@ -123,4 +47,4 @@ declare function createLocalStorageChannelStore(storage: Storage): ChannelStore;
123
47
  */
124
48
  declare function getDefaultChannelStore(): ChannelStore;
125
49
 
126
- export { type BatchSettlementChannel, type ChannelState, type ChannelStore, type CloseReceipt, InsufficientBalanceError, type OpenBatchChannelOptions, type ResumeBatchChannelOptions, UnsupportedNetworkError, createFileChannelStore, createLocalStorageChannelStore, getDefaultChannelStore, openBatchChannel, resumeBatchChannel };
50
+ export { BatchSettlementChannel, ChannelStore, OpenBatchChannelOptions, ResumeBatchChannelOptions, createFileChannelStore, createLocalStorageChannelStore, getDefaultChannelStore, openBatchChannel, resumeBatchChannel };
@@ -1,83 +1,7 @@
1
- import { ClientChannelStorage } from '@x402/evm/batch-settlement/client';
2
- import { E as EvmWallet } from '../types-HFS_C6RX.js';
3
- import '../types-Bcsi5jQb.js';
4
-
5
- /**
6
- * Channel persistence. This is the upstream `ClientChannelStorage` interface
7
- * (`get` / `set` / `delete`, keyed by lowercased channelId). The SDK ships
8
- * file-backed and localStorage-backed implementations; a consumer may pass any
9
- * `ClientChannelStorage` (e.g. one backed by their own database).
10
- */
11
- type ChannelStore = ClientChannelStorage;
12
- /** Channel accounting, all amounts USDC human units (e.g. "0.30"). */
13
- interface ChannelState {
14
- /** Total escrowed into the channel. */
15
- deposited: string;
16
- /** Cumulative amount spent via vouchers. */
17
- spent: string;
18
- /** deposited - spent. */
19
- remaining: string;
20
- }
21
- /** Options for opening a fresh (or auto-resumed) channel. */
22
- interface OpenBatchChannelOptions {
23
- /** EVM wallet — any { address, signTypedData }. The same EvmWallet the exact scheme uses. */
24
- wallet: EvmWallet;
25
- /** CAIP-2 network: eip155:8453 (Base), eip155:42161 (Arbitrum), eip155:137 (Polygon). */
26
- network: string;
27
- /** Total escrow for the channel, USDC human units, e.g. "0.30". */
28
- deposit: string;
29
- /** Facilitator base URL. Default: https://x402.dexter.cash */
30
- facilitatorUrl?: string;
31
- /** RPC URL override. Default: per-network. */
32
- rpcUrl?: string;
33
- /** Channel persistence. Default: localStorage (browser) / file (Node). */
34
- store?: ChannelStore;
35
- }
36
- /** Options for explicitly resuming an existing channel. */
37
- interface ResumeBatchChannelOptions {
38
- wallet: EvmWallet;
39
- network: string;
40
- facilitatorUrl?: string;
41
- rpcUrl?: string;
42
- store?: ChannelStore;
43
- }
44
- /** Result of channel.close() — the three settlement tx hashes and final amounts. */
45
- interface CloseReceipt {
46
- /** claimWithSignature tx hash. */
47
- claimTx: string;
48
- /** settle tx hash. */
49
- settleTx: string;
50
- /** refundWithSignature tx hash. */
51
- refundTx: string;
52
- /** Amount paid to the seller, USDC human units. */
53
- settledAmount: string;
54
- /** Unspent amount returned to the buyer, USDC human units. */
55
- refundedAmount: string;
56
- }
57
- /**
58
- * A live escrow channel. Returned by openBatchChannel / resumeBatchChannel.
59
- * Hold this handle for the lifetime of a batching session.
60
- */
61
- interface BatchSettlementChannel {
62
- /** On-chain channel id (bytes32 hex). Empty until the first fetch resolves it. */
63
- readonly channelId: string;
64
- /** CAIP-2 network. */
65
- readonly network: string;
66
- /** Live channel accounting; updated after each fetch. */
67
- readonly state: ChannelState;
68
- /** Drop-in fetch. On a batch-settlement 402, signs a voucher and retries. */
69
- fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
70
- /** Facilitator-driven claim -> settle -> refund. Resumable if interrupted. */
71
- close(): Promise<CloseReceipt>;
72
- }
73
- /** Thrown by openBatchChannel when the buyer wallet lacks USDC for the deposit. */
74
- declare class InsufficientBalanceError extends Error {
75
- constructor(message: string);
76
- }
77
- /** Thrown when a network has no deployed x402BatchSettlement contract. */
78
- declare class UnsupportedNetworkError extends Error {
79
- constructor(message: string);
80
- }
1
+ import { O as OpenBatchChannelOptions, B as BatchSettlementChannel, R as ResumeBatchChannelOptions, C as ChannelStore } from '../types-BIINnfB4.js';
2
+ export { a as ChannelState, b as CloseReceipt, c as CloseResult, d as FinalizeWithdrawResult, F as ForceWithdrawResult, I as InsufficientBalanceError, U as UnsupportedNetworkError, W as WithdrawNotReadyError } from '../types-BIINnfB4.js';
3
+ import '@x402/evm/batch-settlement/client';
4
+ import '../types-IqnDBsjL.js';
81
5
 
82
6
  /**
83
7
  * Opens a fresh batch-settlement escrow channel. No network call happens here:
@@ -123,4 +47,4 @@ declare function createLocalStorageChannelStore(storage: Storage): ChannelStore;
123
47
  */
124
48
  declare function getDefaultChannelStore(): ChannelStore;
125
49
 
126
- export { type BatchSettlementChannel, type ChannelState, type ChannelStore, type CloseReceipt, InsufficientBalanceError, type OpenBatchChannelOptions, type ResumeBatchChannelOptions, UnsupportedNetworkError, createFileChannelStore, createLocalStorageChannelStore, getDefaultChannelStore, openBatchChannel, resumeBatchChannel };
50
+ export { BatchSettlementChannel, ChannelStore, OpenBatchChannelOptions, ResumeBatchChannelOptions, createFileChannelStore, createLocalStorageChannelStore, getDefaultChannelStore, openBatchChannel, resumeBatchChannel };
@@ -1 +1 @@
1
- import{createWalletClient as X,http as z,publicActions as G,parseUnits as K,formatUnits as k}from"viem";import{base as Q,arbitrum as V,polygon as Y}from"viem/chains";import{toClientEvmSigner as Z}from"@x402/evm";import{BatchSettlementEvmScheme as ee,getChannel as te}from"@x402/evm/batch-settlement/client";import{x402Client as ne,x402HTTPClient as re}from"@x402/core/client";import{homedir as _}from"os";import{join as q}from"path";import{FileClientChannelStorage as W}from"@x402/evm/batch-settlement/client";function I(e){return new W({directory:e})}var y="dexter-x402-channel:";function B(e){return{async get(t){let n=e.getItem(y+t);return n?JSON.parse(n):void 0},async set(t,n){e.setItem(y+t,JSON.stringify(n))},async delete(t){e.removeItem(y+t)}}}function g(){let e=globalThis.localStorage;return e?B(e):I(q(_(),".dexter-x402","channels"))}import{formatUnits as E}from"viem";import{HTTPFacilitatorClient as N}from"@x402/core/server";import{BatchSettlementEvmScheme as J}from"@x402/evm/batch-settlement/server";var P=6;async function T(e,t,n){let{claims:r,settle:i}=await e.claimAndSettle();if(r.length===0&&BigInt(n.settledAtomic)>0n)throw new Error(`batch-settlement close inconsistency: channel accounting expected a settled amount of ${n.settledAtomic} atomic units, but the facilitator's claimAndSettle reported no claim transaction (claims was empty)`);let c=(await e.refund([t]))[0];return{claimTx:r[0]?.transaction??"",settleTx:i?.transaction??"",refundTx:c?.transaction??"",settledAmount:E(BigInt(n.settledAtomic),P),refundedAmount:E(BigInt(n.refundedAtomic),P)}}function L(e,t,n){let r=new N({url:e});return new J(n).createChannelManager(r,t)}var x=class extends Error{constructor(t){super(t),this.name="InsufficientBalanceError"}},f=class extends Error{constructor(t){super(t),this.name="UnsupportedNetworkError"}};var O={"eip155:8453":{chain:Q,defaultRpc:"https://mainnet.base.org"},"eip155:42161":{chain:V,defaultRpc:"https://arb1.arbitrum.io/rpc"},"eip155:137":{chain:Y,defaultRpc:"https://polygon-rpc.com"}};function D(e){let t=O[e.network];if(!t)throw new f(`batch-settlement is not available on network "${e.network}" \u2014 supported: ${Object.keys(O).join(", ")}`);let n=e.rpcUrl??t.defaultRpc,r=e.wallet.signTypedData;if(typeof r!="function")throw new Error("batch-settlement requires an EvmWallet that supports signTypedData (EIP-712)");let i=X({account:{address:e.wallet.address,type:"json-rpc"},chain:t.chain,transport:z(n)}).extend(G),o=Object.assign(i,{address:e.wallet.address,signTypedData:a=>r.call(e.wallet,a)}),c=Z(o),l=new ee(c,{storage:e.store,depositPolicy:{depositMultiplier:4},depositStrategy:()=>e.depositAtomic}),s=new ne;s.register(e.network,l);let S=new re(s);return{scheme:l,x402Cli:s,httpClient:S,rpcUrl:n}}var C=6,$="https://x402.dexter.cash";function ae(e,t){let n=t>e?0n:e-t;return{deposited:k(e,C),spent:k(t,C),remaining:k(n,C)}}function oe(e){let t=e.payload;if(!t||typeof t!="object")return"";let n=t.voucher;if(!n||typeof n!="object")return"";let r=n.channelId;return typeof r=="string"?r:""}function M(e){let{stack:t,store:n,facilitatorUrl:r,network:i}=e,o="",c="",l=e.depositedAtomic,s=0n;async function S(){if(!o)return;let a=await te(n,o);a&&(a.chargedCumulativeAmount!==void 0&&(s=BigInt(a.chargedCumulativeAmount)),l===0n&&a.balance!==void 0&&(l=BigInt(a.balance)))}return{get channelId(){return o},get network(){return i},get state(){return ae(l,s)},async fetch(a,h){let{httpClient:p}=t,m=await fetch(a,h);if(m.status!==402)return m;let R=p.getPaymentRequiredResponse(d=>m.headers.get(d),await m.clone().json().catch(()=>{})),A=R.accepts?.[0];A?.payTo&&(c=A.payTo);let b=2,v;for(let d=1;d<=b;d+=1){let w=await p.createPaymentPayload(R),U=oe(w);U&&(o=U);let j=p.encodePaymentSignatureHeader(w),u=await fetch(a,{...h,headers:{...h?.headers??{},...j}});v=u;let{recovered:F}=await p.processPaymentResult(w,H=>u.headers.get(H),u.status);if(await S(),!(u.status===402&&F&&d<b))return u}return v},async close(){if(!o)throw new Error("cannot close a channel that has made no requests \u2014 call fetch() at least once first");if(!c)throw new Error("cannot close: the seller payout address is unknown (no 402 was observed)");let a=s.toString(),h=(s>l?0n:l-s).toString(),p=L(r,i,c),m=await T(p,o,{settledAtomic:a,refundedAtomic:h});return await n.delete(o.toLowerCase()),m}}}async function ie(e){let t=e.store??g(),n=e.facilitatorUrl??$,r;try{r=K(e.deposit,C)}catch{throw new Error(`deposit must be a valid USDC amount in decimal units (e.g. "0.30"), got "${e.deposit}"`)}if(r<=0n)throw new Error(`deposit must be a positive amount, got "${e.deposit}"`);let i=D({wallet:e.wallet,network:e.network,rpcUrl:e.rpcUrl,store:t,depositAtomic:r.toString()});return M({stack:i,store:t,facilitatorUrl:n,network:e.network,depositedAtomic:r})}async function se(e){let t=e.store??g(),n=e.facilitatorUrl??$,r=D({wallet:e.wallet,network:e.network,rpcUrl:e.rpcUrl,store:t,depositAtomic:"0"});return M({stack:r,store:t,facilitatorUrl:n,network:e.network,depositedAtomic:0n})}export{x as InsufficientBalanceError,f as UnsupportedNetworkError,I as createFileChannelStore,B as createLocalStorageChannelStore,g as getDefaultChannelStore,ie as openBatchChannel,se as resumeBatchChannel};
1
+ import{createWalletClient as Q,http as V,publicActions as Y,parseUnits as Z,formatUnits as A}from"viem";import{base as tt,arbitrum as et,polygon as nt}from"viem/chains";import{toClientEvmSigner as at}from"@x402/evm";import{BatchSettlementEvmScheme as rt,getChannel as it}from"@x402/evm/batch-settlement/client";import{x402Client as ot,x402HTTPClient as st}from"@x402/core/client";import{homedir as H}from"os";import{join as _}from"path";import{FileClientChannelStorage as J}from"@x402/evm/batch-settlement/client";function E(t){return new J({directory:t})}var R="dexter-x402-channel:";function P(t){return{async get(e){let n=t.getItem(R+e);return n?JSON.parse(n):void 0},async set(e,n){t.setItem(R+e,JSON.stringify(n))},async delete(e){t.removeItem(R+e)}}}function x(){let t=globalThis.localStorage;return t?P(t):E(_(H(),".dexter-x402","channels"))}var k=class extends Error{constructor(e){super(e),this.name="InsufficientBalanceError"}},C=class extends Error{constructor(e){super(e),this.name="UnsupportedNetworkError"}};import{formatUnits as X}from"viem";import{computeChannelId as z}from"@x402/evm/batch-settlement/client";import{BATCH_SETTLEMENT_ADDRESS as y}from"@x402/evm";var S=class extends Error{constructor(e){super(e),this.name="WithdrawNotReadyError"}};function F(t,e){return t===0?0:t+e}var G=6,B=[{name:"payer",type:"address"},{name:"payerAuthorizer",type:"address"},{name:"receiver",type:"address"},{name:"receiverAuthorizer",type:"address"},{name:"token",type:"address"},{name:"withdrawDelay",type:"uint40"},{name:"salt",type:"bytes32"}],b=[{type:"function",name:"initiateWithdraw",inputs:[{name:"config",type:"tuple",components:B},{name:"amount",type:"uint128"}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"finalizeWithdraw",inputs:[{name:"config",type:"tuple",components:B}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"pendingWithdrawals",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"amount",type:"uint128"},{name:"initiatedAt",type:"uint40"}],stateMutability:"view"},{type:"function",name:"channels",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"balance",type:"uint128"},{name:"totalClaimed",type:"uint128"}],stateMutability:"view"}];function K(t){if(Array.isArray(t))return{balance:BigInt(t[0]),totalClaimed:BigInt(t[1])};let e=t;return{balance:BigInt(e.balance),totalClaimed:BigInt(e.totalClaimed)}}function D(t){if(Array.isArray(t))return{amount:BigInt(t[0]),initiatedAt:Number(t[1])};let e=t;return{amount:BigInt(e.amount),initiatedAt:Number(e.initiatedAt)}}async function U(t){let{config:e,network:n,client:a,withdrawDelaySecs:s}=t,r=z(e,n),o=t.amountAtomic;o===void 0&&(o=K(await a.readContract({address:y,abi:b,functionName:"channels",args:[r]})).balance);let l=await a.writeContract({address:y,abi:b,functionName:"initiateWithdraw",args:[e,o]});await a.waitForTransactionReceipt({hash:l});let c=D(await a.readContract({address:y,abi:b,functionName:"pendingWithdrawals",args:[r]}));return{initiateTx:l,finalizableAt:F(c.initiatedAt,s)}}async function $(t){let{config:e,network:n,client:a,withdrawDelaySecs:s}=t,r=z(e,n),o=D(await a.readContract({address:y,abi:b,functionName:"pendingWithdrawals",args:[r]}));if(o.initiatedAt===0)throw new S(`no withdrawal is pending for channel ${r} \u2014 call forceWithdraw first`);let l=F(o.initiatedAt,s),c=Math.floor(Date.now()/1e3);if(c<l)throw new S(`withdrawal for channel ${r} is not finalizable until ${l} (unix seconds) \u2014 ${l-c}s remaining`);let i=await a.writeContract({address:y,abi:b,functionName:"finalizeWithdraw",args:[e]});return await a.waitForTransactionReceipt({hash:i}),{finalizeTx:i,withdrawnAmount:X(o.amount,G)}}var O={"eip155:8453":{chain:tt,defaultRpc:"https://mainnet.base.org"},"eip155:42161":{chain:et,defaultRpc:"https://arb1.arbitrum.io/rpc"},"eip155:137":{chain:nt,defaultRpc:"https://polygon-rpc.com"}};function N(t){let e=O[t.network];if(!e)throw new C(`batch-settlement is not available on network "${t.network}" \u2014 supported: ${Object.keys(O).join(", ")}`);let n=t.rpcUrl??e.defaultRpc,a=t.wallet.signTypedData;if(typeof a!="function")throw new Error("batch-settlement requires an EvmWallet that supports signTypedData (EIP-712)");let s=Q({account:{address:t.wallet.address,type:"json-rpc"},chain:e.chain,transport:V(n)}).extend(Y),r=t.wallet.sendTransaction,o=typeof r=="function",l=async h=>{let w=h.to??void 0;if(!w)throw new Error("batch-settlement escape hatch: transaction is missing a `to` address");let u=h.data??"0x";if(typeof r=="function")return await r.call(t.wallet,{to:w,data:u,value:h.value});throw new Error("batch-settlement: wallet has no sendTransaction")},c=Object.assign(s,{address:t.wallet.address,signTypedData:h=>a.call(t.wallet,h),sendTransaction:l}),i=at(c),p=new rt(i,{storage:t.store,depositPolicy:{depositMultiplier:4},depositStrategy:()=>t.depositAtomic}),d=new ot;d.register(t.network,p);let m=new st(d);return{scheme:p,x402Cli:d,httpClient:m,rpcUrl:n,withdrawClient:c,canSubmitTransactions:o}}var W=6;function lt(t,e){let n=e>t?0n:t-e;return{deposited:A(t,W),spent:A(e,W),remaining:A(n,W)}}function ct(t){let e=t.payload;if(!e||typeof e!="object")return"";let n=e.voucher;if(!n||typeof n!="object")return"";let a=n.channelId;return typeof a=="string"?a:""}function dt(t){let e=t.payload;if(!e||typeof e!="object")return;let n=e.channelConfig;if(!(!n||typeof n!="object"))return n}function j(t){let{stack:e,store:n,network:a}=t,s="",r,o=t.depositedAtomic,l=0n;async function c(){if(!s)return;let i=await it(n,s);i&&(i.chargedCumulativeAmount!==void 0&&(l=BigInt(i.chargedCumulativeAmount)),o===0n&&i.balance!==void 0&&(o=BigInt(i.balance)))}return{get channelId(){return s},get network(){return a},get state(){return lt(o,l)},async fetch(i,p){let{httpClient:d}=e,m=await fetch(i,p);if(m.status!==402)return m;let v=d.getPaymentRequiredResponse(u=>m.headers.get(u),await m.clone().json().catch(()=>{})),h=2,w;for(let u=1;u<=h;u+=1){let f=await d.createPaymentPayload(v),I=ct(f);I&&(s=I);let T=dt(f);T&&(r=T);let L=d.encodePaymentSignatureHeader(f),g=await fetch(i,{...p,headers:{...p?.headers??{},...L}});w=g;let{recovered:M}=await d.processPaymentResult(f,q=>g.headers.get(q),g.status);if(await c(),!(g.status===402&&M&&u<h))return g}return w},async close(){return s&&await n.delete(s.toLowerCase()),{closed:!0}},async forceWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement forceWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!r)throw new Error("forceWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return U({config:r,network:a,client:e.withdrawClient,withdrawDelaySecs:r.withdrawDelay})},async finalizeWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement finalizeWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!r)throw new Error("finalizeWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return $({config:r,network:a,client:e.withdrawClient,withdrawDelaySecs:r.withdrawDelay})}}}async function ht(t){let e=t.store??x(),n;try{n=Z(t.deposit,W)}catch{throw new Error(`deposit must be a valid USDC amount in decimal units (e.g. "0.30"), got "${t.deposit}"`)}if(n<=0n)throw new Error(`deposit must be a positive amount, got "${t.deposit}"`);let a=N({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:n.toString()});return j({stack:a,store:e,network:t.network,depositedAtomic:n})}async function ut(t){let e=t.store??x(),n=N({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:"0"});return j({stack:n,store:e,network:t.network,depositedAtomic:0n})}export{k as InsufficientBalanceError,C as UnsupportedNetworkError,S as WithdrawNotReadyError,E as createFileChannelStore,P as createLocalStorageChannelStore,x as getDefaultChannelStore,ht as openBatchChannel,ut as resumeBatchChannel};
@@ -0,0 +1 @@
1
+ "use strict";var R=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var D=(e,r)=>{for(var s in r)R(e,s,{get:r[s],enumerable:!0})},z=(e,r,s,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of O(r))!_.call(e,n)&&n!==s&&R(e,n,{get:()=>r[n],enumerable:!(o=N(r,n))||o.enumerable});return e};var Q=e=>z(R({},"__esModule",{value:!0}),e);var W={};D(W,{createBatchSettlementSeller:()=>E});module.exports=Q(W);var B=require("os"),U=require("path"),$=require("@x402/evm/batch-settlement/server");var C=require("@x402/core/server"),x=require("@x402/core/http"),A=require("@x402/evm/batch-settlement/server");function b(e){let r=e.verbose?console.log.bind(console,"[batch-settlement:seller]"):()=>{},s=new C.HTTPFacilitatorClient({url:e.facilitatorUrl}),o=new A.BatchSettlementEvmScheme(e.payTo,{storage:e.channelStore}),n=new C.x402ResourceServer(s).register(e.network,o),l=new x.x402HTTPResourceServer(n,{[e.route]:{accepts:{scheme:"batch-settlement",payTo:e.payTo,price:e.price,network:e.network},description:"batch-settlement protected route",mimeType:"application/json"}}),i=null;function u(){if(i)return i;let t=l.initialize();return t.catch(a=>{i===t&&(i=null),e.verbose?r("resource server initialize() failed:",a):console.error("[batch-settlement:seller] resource server initialize() failed:",a)}),i=t,t}let h=u();function d(t,a){if(t.headersSent)return;for(let[g,v]of Object.entries(a.headers))t.setHeader(g,v);t.status(a.status);let{body:m}=a;m==null?t.end():typeof m=="string"?t.send(m):t.json(m)}return{scheme:o,facilitator:s,handler:async(t,a,m)=>{try{await u();let g=t.get("host")??"",v=`${t.baseUrl}${t.path}`||"/",M={getHeader:y=>t.headers[y.toLowerCase()],getMethod:()=>t.method,getPath:()=>v,getUrl:()=>`${t.protocol}://${g}${t.originalUrl}`,getAcceptHeader:()=>t.headers.accept??"",getUserAgent:()=>t.headers["user-agent"]??"",getBody:()=>t.body??{},getQueryParams:()=>t.query,getQueryParam:y=>{let f=t.query[y];if(typeof f=="string"||Array.isArray(f))return f}},F=t.headers["payment-signature"]??t.headers["x-payment"],w={adapter:M,path:v,method:t.method,paymentHeader:F},p=await l.processHTTPRequest(w);if(r("processHTTPRequest ->",p.type),p.type==="no-payment-required"){m();return}if(p.type==="payment-error"){d(a,p.response);return}let j={request:w,responseBody:Buffer.alloc(0)},S=await l.processSettlement(p.paymentPayload,p.paymentRequirements,p.declaredExtensions,j);if(r("processSettlement ->",S.success?"success":`failure:${S.errorReason}`),!S.success){d(a,S.response);return}for(let[y,f]of Object.entries(S.headers))a.headersSent||a.setHeader(y,f);m()}catch(g){r("handler error:",g),a.headersSent||a.status(500).json({error:"Payment processing error"})}},ready:h}}var P=require("viem"),k=6;async function T(e){let{manager:r,store:s,channelId:o}=e,n=await s.get(o),l=BigInt(n?.chargedCumulativeAmount??"0"),i=BigInt(n?.balance??"0"),u=i>l?i-l:0n,{claims:h,settle:d}=await r.claimAndSettle(),c=await r.refund([o]),t=c.find(a=>a.channel===o)??c[0];return{claimTx:h[0]?.transaction??"",settleTx:d?.transaction??"",refundTx:t?.transaction??"",settledAmount:(0,P.formatUnits)(l,k),refundedAmount:(0,P.formatUnits)(u,k)}}async function I(e){let r=await e.store.list(),s=[];for(let o of r)try{let n=await T({manager:e.manager,store:e.store,channelId:o.channelId});s.push({channelId:o.channelId,...n})}catch(n){s.push({channelId:o.channelId,error:n instanceof Error?n.message:String(n)})}return s}function L(e){let r=!1,s=async()=>{try{await e.claimAndSettle()}catch(n){e.onError?.(n)}},o=setInterval(()=>{r||s()},e.claimIntervalMs);return typeof o.unref=="function"&&o.unref(),{async stop(){r||(r=!0,clearInterval(o),await s())}}}var q="https://x402.dexter.cash",G="GET /",H=new Set(["eip155:8453","eip155:42161","eip155:137"]);function K(e){return e===!1?null:e===void 0||e===!0?3e5:(e.claimIntervalSecs??300)*1e3}function E(e){if(!H.has(e.network))throw new Error(`batch-settlement is not supported on network "${e.network}" \u2014 supported: ${[...H].join(", ")}`);let r=e.facilitatorUrl??q,s=e.channelStore??new $.FileChannelStorage({directory:(0,U.join)((0,B.homedir)(),".dexter-x402","seller-channels")}),o=b({payTo:e.payTo,network:e.network,price:e.price,route:e.route??G,facilitatorUrl:r,channelStore:s,verbose:e.verbose}),n=o.scheme.createChannelManager(o.facilitator,e.network),l=async()=>{await n.claimAndSettle()},i=K(e.autoSettle),u=null;i!==null&&(u=L({claimAndSettle:l,claimIntervalMs:i,onError:t=>console.error("[batch-settlement:seller] auto-loop claim pass failed",t)}));let h=s,d=(t,a,m)=>{o.handler(t,a,m)},c=d;return c.middleware=()=>d,c.closeChannel=t=>T({manager:n,store:h,channelId:t}),c.closeAll=()=>I({manager:n,store:h}),c.stop=async()=>{u&&await u.stop()},c}0&&(module.exports={createBatchSettlementSeller});
@@ -0,0 +1,17 @@
1
+ import { a as BatchSettlementSellerConfig, B as BatchSettlementSeller } from '../../types-BBhXpBwI.cjs';
2
+ export { S as SellerCloseResult } from '../../types-BBhXpBwI.cjs';
3
+ import 'express';
4
+ import '@x402/evm/batch-settlement/server';
5
+ import '../../types-Bbt_SDZE.cjs';
6
+ import '@x402/evm/batch-settlement/client';
7
+ import '../../types-IqnDBsjL.cjs';
8
+
9
+ /**
10
+ * Creates a batch-settlement seller runtime. The returned object is callable
11
+ * (usable directly as an Express RequestHandler) and exposes lifecycle +
12
+ * settlement methods. The auto-settlement loop starts immediately unless
13
+ * disabled.
14
+ */
15
+ declare function createBatchSettlementSeller(config: BatchSettlementSellerConfig): BatchSettlementSeller;
16
+
17
+ export { BatchSettlementSeller, BatchSettlementSellerConfig, createBatchSettlementSeller };
@@ -0,0 +1,17 @@
1
+ import { a as BatchSettlementSellerConfig, B as BatchSettlementSeller } from '../../types-CwK4mPWV.js';
2
+ export { S as SellerCloseResult } from '../../types-CwK4mPWV.js';
3
+ import 'express';
4
+ import '@x402/evm/batch-settlement/server';
5
+ import '../../types-BIINnfB4.js';
6
+ import '@x402/evm/batch-settlement/client';
7
+ import '../../types-IqnDBsjL.js';
8
+
9
+ /**
10
+ * Creates a batch-settlement seller runtime. The returned object is callable
11
+ * (usable directly as an Express RequestHandler) and exposes lifecycle +
12
+ * settlement methods. The auto-settlement loop starts immediately unless
13
+ * disabled.
14
+ */
15
+ declare function createBatchSettlementSeller(config: BatchSettlementSellerConfig): BatchSettlementSeller;
16
+
17
+ export { BatchSettlementSeller, BatchSettlementSellerConfig, createBatchSettlementSeller };
@@ -0,0 +1 @@
1
+ import{homedir as E}from"os";import{join as M}from"path";import{FileChannelStorage as F}from"@x402/evm/batch-settlement/server";import{HTTPFacilitatorClient as H,x402ResourceServer as B}from"@x402/core/server";import{x402HTTPResourceServer as U}from"@x402/core/http";import{BatchSettlementEvmScheme as $}from"@x402/evm/batch-settlement/server";function P(e){let s=e.verbose?console.log.bind(console,"[batch-settlement:seller]"):()=>{},a=new H({url:e.facilitatorUrl}),r=new $(e.payTo,{storage:e.channelStore}),o=new B(a).register(e.network,r),l=new U(o,{[e.route]:{accepts:{scheme:"batch-settlement",payTo:e.payTo,price:e.price,network:e.network},description:"batch-settlement protected route",mimeType:"application/json"}}),i=null;function u(){if(i)return i;let t=l.initialize();return t.catch(n=>{i===t&&(i=null),e.verbose?s("resource server initialize() failed:",n):console.error("[batch-settlement:seller] resource server initialize() failed:",n)}),i=t,t}let h=u();function d(t,n){if(t.headersSent)return;for(let[g,v]of Object.entries(n.headers))t.setHeader(g,v);t.status(n.status);let{body:m}=n;m==null?t.end():typeof m=="string"?t.send(m):t.json(m)}return{scheme:r,facilitator:a,handler:async(t,n,m)=>{try{await u();let g=t.get("host")??"",v=`${t.baseUrl}${t.path}`||"/",k={getHeader:y=>t.headers[y.toLowerCase()],getMethod:()=>t.method,getPath:()=>v,getUrl:()=>`${t.protocol}://${g}${t.originalUrl}`,getAcceptHeader:()=>t.headers.accept??"",getUserAgent:()=>t.headers["user-agent"]??"",getBody:()=>t.body??{},getQueryParams:()=>t.query,getQueryParam:y=>{let f=t.query[y];if(typeof f=="string"||Array.isArray(f))return f}},I=t.headers["payment-signature"]??t.headers["x-payment"],R={adapter:k,path:v,method:t.method,paymentHeader:I},p=await l.processHTTPRequest(R);if(s("processHTTPRequest ->",p.type),p.type==="no-payment-required"){m();return}if(p.type==="payment-error"){d(n,p.response);return}let L={request:R,responseBody:Buffer.alloc(0)},S=await l.processSettlement(p.paymentPayload,p.paymentRequirements,p.declaredExtensions,L);if(s("processSettlement ->",S.success?"success":`failure:${S.errorReason}`),!S.success){d(n,S.response);return}for(let[y,f]of Object.entries(S.headers))n.headersSent||n.setHeader(y,f);m()}catch(g){s("handler error:",g),n.headersSent||n.status(500).json({error:"Payment processing error"})}},ready:h}}import{formatUnits as T}from"viem";var w=6;async function C(e){let{manager:s,store:a,channelId:r}=e,o=await a.get(r),l=BigInt(o?.chargedCumulativeAmount??"0"),i=BigInt(o?.balance??"0"),u=i>l?i-l:0n,{claims:h,settle:d}=await s.claimAndSettle(),c=await s.refund([r]),t=c.find(n=>n.channel===r)??c[0];return{claimTx:h[0]?.transaction??"",settleTx:d?.transaction??"",refundTx:t?.transaction??"",settledAmount:T(l,w),refundedAmount:T(u,w)}}async function x(e){let s=await e.store.list(),a=[];for(let r of s)try{let o=await C({manager:e.manager,store:e.store,channelId:r.channelId});a.push({channelId:r.channelId,...o})}catch(o){a.push({channelId:r.channelId,error:o instanceof Error?o.message:String(o)})}return a}function A(e){let s=!1,a=async()=>{try{await e.claimAndSettle()}catch(o){e.onError?.(o)}},r=setInterval(()=>{s||a()},e.claimIntervalMs);return typeof r.unref=="function"&&r.unref(),{async stop(){s||(s=!0,clearInterval(r),await a())}}}var j="https://x402.dexter.cash",N="GET /",b=new Set(["eip155:8453","eip155:42161","eip155:137"]);function O(e){return e===!1?null:e===void 0||e===!0?3e5:(e.claimIntervalSecs??300)*1e3}function _(e){if(!b.has(e.network))throw new Error(`batch-settlement is not supported on network "${e.network}" \u2014 supported: ${[...b].join(", ")}`);let s=e.facilitatorUrl??j,a=e.channelStore??new F({directory:M(E(),".dexter-x402","seller-channels")}),r=P({payTo:e.payTo,network:e.network,price:e.price,route:e.route??N,facilitatorUrl:s,channelStore:a,verbose:e.verbose}),o=r.scheme.createChannelManager(r.facilitator,e.network),l=async()=>{await o.claimAndSettle()},i=O(e.autoSettle),u=null;i!==null&&(u=A({claimAndSettle:l,claimIntervalMs:i,onError:t=>console.error("[batch-settlement:seller] auto-loop claim pass failed",t)}));let h=a,d=(t,n,m)=>{r.handler(t,n,m)},c=d;return c.middleware=()=>d,c.closeChannel=t=>C({manager:o,store:h,channelId:t}),c.closeAll=()=>x({manager:o,store:h}),c.stop=async()=>{u&&await u.stop()},c}export{_ as createBatchSettlementSeller};
@@ -1,9 +1,7 @@
1
- export { P as PaymentReceipt, a as X402Client, X as X402ClientConfig, c as createX402Client, f as fireImpressionBeacon, g as getPaymentReceipt, d as getSponsoredAccessInfo, b as getSponsoredRecommendations } from '../sponsored-access-BEufXQ6c.cjs';
2
- import { A as AccessPassClientConfig, P as PaymentAccept } from '../types-Bcsi5jQb.cjs';
3
- export { b as AccessPassInfo, a as AccessPassTier, X as X402Error } from '../types-Bcsi5jQb.cjs';
1
+ export { P as PaymentReceipt, a as X402Client, X as X402ClientConfig, c as createX402Client, f as fireImpressionBeacon, g as getPaymentReceipt, d as getSponsoredAccessInfo, b as getSponsoredRecommendations } from '../sponsored-access-B2UCVgj3.cjs';
2
+ import { A as AccessPassClientConfig, P as PaymentAccept, S as SolanaWallet, E as EvmWallet } from '../types-IqnDBsjL.cjs';
3
+ export { d as AccessPassInfo, b as AccessPassTier, C as ChainAdapter, W as WalletSet, X as X402Error, a as createEvmAdapter, c as createSolanaAdapter } from '../types-IqnDBsjL.cjs';
4
4
  import { Keypair } from '@solana/web3.js';
5
- import { S as SolanaWallet, E as EvmWallet } from '../types-B3kS1y_t.cjs';
6
- export { C as ChainAdapter, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter } from '../types-B3kS1y_t.cjs';
7
5
  export { FormattedResource as CapabilityAPI, CapabilitySearchOptions, CapabilitySearchResult, NoMatchReason, capabilitySearch } from '@dexterai/x402-core';
8
6
  export { B as BASE_MAINNET, D as DEXTER_FACILITATOR_URL, S as SOLANA_MAINNET, U as USDC_MINT } from '../constants-qU-4U3L-.cjs';
9
7
  export { SponsoredAccessSettlementInfo, SponsoredRecommendation } from '@dexterai/x402-ads-types';
@@ -1,9 +1,7 @@
1
- export { P as PaymentReceipt, a as X402Client, X as X402ClientConfig, c as createX402Client, f as fireImpressionBeacon, g as getPaymentReceipt, d as getSponsoredAccessInfo, b as getSponsoredRecommendations } from '../sponsored-access-4wVjCYrH.js';
2
- import { A as AccessPassClientConfig, P as PaymentAccept } from '../types-Bcsi5jQb.js';
3
- export { b as AccessPassInfo, a as AccessPassTier, X as X402Error } from '../types-Bcsi5jQb.js';
1
+ export { P as PaymentReceipt, a as X402Client, X as X402ClientConfig, c as createX402Client, f as fireImpressionBeacon, g as getPaymentReceipt, d as getSponsoredAccessInfo, b as getSponsoredRecommendations } from '../sponsored-access-B2USBiVp.js';
2
+ import { A as AccessPassClientConfig, P as PaymentAccept, S as SolanaWallet, E as EvmWallet } from '../types-IqnDBsjL.js';
3
+ export { d as AccessPassInfo, b as AccessPassTier, C as ChainAdapter, W as WalletSet, X as X402Error, a as createEvmAdapter, c as createSolanaAdapter } from '../types-IqnDBsjL.js';
4
4
  import { Keypair } from '@solana/web3.js';
5
- import { S as SolanaWallet, E as EvmWallet } from '../types-HFS_C6RX.js';
6
- export { C as ChainAdapter, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter } from '../types-HFS_C6RX.js';
7
5
  export { FormattedResource as CapabilityAPI, CapabilitySearchOptions, CapabilitySearchResult, NoMatchReason, capabilitySearch } from '@dexterai/x402-core';
8
6
  export { B as BASE_MAINNET, D as DEXTER_FACILITATOR_URL, S as SOLANA_MAINNET, U as USDC_MINT } from '../constants-qU-4U3L-.js';
9
7
  export { SponsoredAccessSettlementInfo, SponsoredRecommendation } from '@dexterai/x402-ads-types';
@@ -1,10 +1,9 @@
1
- import { a as X402Client } from '../sponsored-access-BEufXQ6c.cjs';
2
- export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-BEufXQ6c.cjs';
3
- import { W as WalletSet, B as BalanceInfo } from '../types-B3kS1y_t.cjs';
1
+ import { a as X402Client } from '../sponsored-access-B2UCVgj3.cjs';
2
+ export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-B2UCVgj3.cjs';
3
+ import { W as WalletSet, B as BalanceInfo, b as AccessPassTier } from '../types-IqnDBsjL.cjs';
4
+ export { A as AccessPassClientConfig, d as AccessPassInfo, X as X402Error } from '../types-IqnDBsjL.cjs';
4
5
  import { SponsoredRecommendation } from '@dexterai/x402-ads-types';
5
6
  export { SponsoredRecommendation } from '@dexterai/x402-ads-types';
6
- import { a as AccessPassTier } from '../types-Bcsi5jQb.cjs';
7
- export { A as AccessPassClientConfig, b as AccessPassInfo, X as X402Error } from '../types-Bcsi5jQb.cjs';
8
7
 
9
8
  /**
10
9
  * React Hook for x402 v2 Payments
@@ -1,10 +1,9 @@
1
- import { a as X402Client } from '../sponsored-access-4wVjCYrH.js';
2
- export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-4wVjCYrH.js';
3
- import { W as WalletSet, B as BalanceInfo } from '../types-HFS_C6RX.js';
1
+ import { a as X402Client } from '../sponsored-access-B2USBiVp.js';
2
+ export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-B2USBiVp.js';
3
+ import { W as WalletSet, B as BalanceInfo, b as AccessPassTier } from '../types-IqnDBsjL.js';
4
+ export { A as AccessPassClientConfig, d as AccessPassInfo, X as X402Error } from '../types-IqnDBsjL.js';
4
5
  import { SponsoredRecommendation } from '@dexterai/x402-ads-types';
5
6
  export { SponsoredRecommendation } from '@dexterai/x402-ads-types';
6
- import { a as AccessPassTier } from '../types-Bcsi5jQb.js';
7
- export { A as AccessPassClientConfig, b as AccessPassInfo, X as X402Error } from '../types-Bcsi5jQb.js';
8
7
 
9
8
  /**
10
9
  * React Hook for x402 v2 Payments