@dexterai/x402 5.4.2 → 6.0.0-rc.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 +19 -4
- package/REFERENCE.md +81 -8
- package/dist/adapters/index.d.cts +3 -3
- package/dist/adapters/index.d.ts +3 -3
- package/dist/batch-settlement/index.d.cts +3 -3
- package/dist/batch-settlement/index.d.ts +3 -3
- package/dist/batch-settlement/seller/index.d.cts +4 -4
- package/dist/batch-settlement/seller/index.d.ts +4 -4
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +6 -6
- package/dist/client/index.d.ts +6 -6
- package/dist/client/index.js +1 -1
- package/dist/{constants-Icc4CXNG.d.cts → constants-BLvApMMl.d.cts} +1 -1
- package/dist/{constants-Icc4CXNG.d.ts → constants-BLvApMMl.d.ts} +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.cts +4 -4
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +1 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.d.cts +5 -5
- package/dist/server/index.d.ts +5 -5
- package/dist/server/index.js +1 -1
- package/dist/{sessions-BG2OYLBi.d.cts → sessions-rPdO1CgK.d.cts} +35 -3
- package/dist/{sessions-BG2OYLBi.d.ts → sessions-rPdO1CgK.d.ts} +35 -3
- package/dist/tab/adapters/solana/index.cjs +1 -1
- package/dist/tab/adapters/solana/index.d.cts +181 -26
- package/dist/tab/adapters/solana/index.d.ts +181 -26
- package/dist/tab/adapters/solana/index.js +1 -1
- package/dist/tab/index.cjs +5 -5
- package/dist/tab/index.d.cts +126 -21
- package/dist/tab/index.d.ts +126 -21
- package/dist/tab/index.js +4 -4
- package/dist/tab/seller/index.cjs +4 -4
- package/dist/tab/seller/index.d.cts +34 -26
- package/dist/tab/seller/index.d.ts +34 -26
- package/dist/tab/seller/index.js +4 -4
- package/dist/{types-BdS_uvNs.d.cts → types-BbvuPNXl.d.cts} +2 -2
- package/dist/{types-xQu1U4xk.d.cts → types-BvQpNtFw.d.cts} +9 -1
- package/dist/{types-xQu1U4xk.d.ts → types-BvQpNtFw.d.ts} +9 -1
- package/dist/{types-DY8xKheW.d.ts → types-CkcNYx1Q.d.ts} +2 -2
- package/dist/{types-Co5YYhVB.d.ts → types-CwLPKV8T.d.ts} +3 -3
- package/dist/{types-CZHPdVkg.d.cts → types-DnhCOjDx.d.cts} +3 -3
- package/dist/{types-_wdHzVG-.d.ts → types-DwVhPqOZ.d.ts} +2 -2
- package/dist/{types-WMqs5xII.d.cts → types-JpkrtFbZ.d.cts} +2 -2
- package/dist/{types-CSuISjXA.d.cts → types-OHNNM1J2.d.cts} +122 -7
- package/dist/{types-CSuISjXA.d.ts → types-OHNNM1J2.d.ts} +122 -7
- package/dist/utils/index.d.cts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/{x402-client-BQKDeNxq.d.cts → x402-client-B8zdDeat.d.cts} +2 -2
- package/dist/{x402-client-BQKDeNxq.d.ts → x402-client-B8zdDeat.d.ts} +2 -2
- package/package.json +7 -6
package/dist/tab/seller/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var x=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};import{promises as M}from"fs";import{join as rt,dirname as nt}from"path";var De=new Map;function P(t,e){let n=(De.get(t)??Promise.resolve()).then(()=>e(),()=>e());return De.set(t,n.then(()=>{},()=>{})),n}var D=class{map=new Map;async get(e){return this.map.get(e)??null}async set(e,r){this.map.set(e,r)}async delete(e){this.map.delete(e)}async tryAcquireLease(e,r){return P(e,async()=>{let n=this.map.get(e),i=Date.now();if(n?.lease&&n.lease.heldUntilUnixMs>i)return!1;let s=n??{lastVoucher:null,deliveredCumulativeAtomic:"0",lastCrystallizedCumulativeAtomic:"0"};return this.map.set(e,{...s,lease:{heldUntilUnixMs:i+r}}),!0})}async releaseLease(e){await P(e,async()=>{let r=this.map.get(e);r&&this.map.set(e,{...r,lease:void 0})})}};function he(t){let e="";for(let r of t)e+=r.toString(16).padStart(2,"0");return e}function ye(t){if(t.length%2!==0)throw new Error(`hex length must be even, got ${t.length}`);let e=new Uint8Array(t.length/2);for(let r=0;r<e.length;r++)e[r]=parseInt(t.substr(r*2,2),16);return e}function Ae(t){return Ke(t)}function be(t){return ze(t)}function Ke(t){return{lastVoucher:t.lastVoucher?{payload:t.lastVoucher.payload,sessionPublicKey:he(t.lastVoucher.sessionPublicKey),sessionRegistration:he(t.lastVoucher.sessionRegistration),sessionSignature:he(t.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:t.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:t.lastCrystallizedCumulativeAtomic,gateRefusedCumulativeAtomic:t.gateRefusedCumulativeAtomic,onChain:t.onChain,lease:t.lease}}function ze(t){return{lastVoucher:t.lastVoucher?{payload:t.lastVoucher.payload,sessionPublicKey:ye(t.lastVoucher.sessionPublicKey),sessionRegistration:ye(t.lastVoucher.sessionRegistration),sessionSignature:ye(t.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:t.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:t.lastCrystallizedCumulativeAtomic??"0",gateRefusedCumulativeAtomic:t.gateRefusedCumulativeAtomic,onChain:t.onChain,lease:t.lease}}var fe=class{constructor(e){this.dir=e}pathFor(e){if(!/^[a-z0-9_-]+$/i.test(e))throw new Error(`unsafe channelId for filesystem: ${e}`);return rt(this.dir,`${e}.json`)}async get(e){try{let r=await M.readFile(this.pathFor(e),"utf8");return ze(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(e,r){let n=this.pathFor(e);await M.mkdir(nt(n),{recursive:!0});let i=`${n}.tmp`;await M.writeFile(i,JSON.stringify(Ke(r))),await M.rename(i,n)}async delete(e){try{await M.unlink(this.pathFor(e))}catch(r){if(r?.code!=="ENOENT")throw r}}async tryAcquireLease(e,r){return P(e,async()=>{let n=await this.get(e),i=Date.now();if(n?.lease&&n.lease.heldUntilUnixMs>i)return!1;let s=n??{lastVoucher:null,deliveredCumulativeAtomic:"0",lastCrystallizedCumulativeAtomic:"0"};return await this.set(e,{...s,lease:{heldUntilUnixMs:i+r}}),!0})}async releaseLease(e){await P(e,async()=>{let r=await this.get(e);r&&await this.set(e,{...r,lease:void 0})})}};import{randomUUID as it}from"crypto";var st='if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end',ve=class{constructor(e,r="tab:"){this.client=e;this.keyPrefix=r}leaseTokens=new Map;ledgerKey(e){return`${this.keyPrefix}ledger:${e}`}leaseKey(e){return`${this.keyPrefix}lease:${e}`}async get(e){let r=await this.client.get(this.ledgerKey(e));return r===null?null:be(JSON.parse(r))}async set(e,r){let n=Ae({...r,lease:void 0});await this.client.set(this.ledgerKey(e),JSON.stringify(n))}async delete(e){this.leaseTokens.delete(e),await this.client.del(this.ledgerKey(e),this.leaseKey(e))}async tryAcquireLease(e,r){let n=it();return await this.client.set(this.leaseKey(e),n,"PX",Math.max(1,Math.floor(r)),"NX")!=="OK"?!1:(this.leaseTokens.set(e,n),!0)}async releaseLease(e){let r=this.leaseTokens.get(e);r!==void 0&&(this.leaseTokens.delete(e),await this.client.eval(st,1,this.leaseKey(e),r))}};import{PublicKey as gt}from"@solana/web3.js";import ot from"tweetnacl";import{sha256 as or}from"@noble/hashes/sha256";import{p256 as cr}from"@noble/curves/p256";import{PublicKey as xe}from"@solana/web3.js";import{sessionRegisterMessage as Ft,sessionRevokeMessage as Wt,voucherPayloadMessage as we,buildVoucherMessage as jt}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as Gt,buildRevokeSessionKeyInstruction as Yt,deriveSwigWalletAddress as Zt}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as er}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as Se,SECP256R1_PROGRAM_ID as rr,INSTRUCTIONS_SYSVAR_ID as nr}from"@dexterai/vault/constants";import{fetchSessionAccount as at,isSessionLive as ct}from"@dexterai/vault/session";var Ce="OTS_SESSION_REGISTER_V2",E=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function Ee(t){if(t.length!==188)throw new E("wrong_length",`expected 188, got ${t.length}`);let e=new TextDecoder().decode(t.slice(0,Ce.length));if(e!==Ce)throw new E("wrong_domain",`got "${e}"`);for(let y=Ce.length;y<32;y++)if(t[y]!==0)throw new E("wrong_domain",`non-NUL padding at byte ${y}`);let r=new DataView(t.buffer,t.byteOffset,t.byteLength),n=new xe(t.slice(32,64)),i=new xe(t.slice(64,96)),s=t.slice(96,128),h=r.getBigUint64(128,!0),c=r.getBigInt64(136,!0),a=new xe(t.slice(144,176)),m=r.getUint32(176,!0),l=r.getBigUint64(180,!0);if(!n.equals(Se))throw new E("wrong_program",`${n.toBase58()} is not ${Se.toBase58()}`);if(h===0n)throw new E("cap_zero");let o=BigInt(Math.floor(Date.now()/1e3));if(c<=o)throw new E("expiry_in_past",`expires_at=${c}, now=${o}`);return{programId:n,vaultPda:i,sessionPubkey:new Uint8Array(s),maxAmount:h,expiresAt:c,allowedCounterparty:a,nonce:m,maxRevolvingCapacity:l}}var k=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function Re(t,e){let r=await at(t,e.vaultPda,e.allowedCounterparty);if(!r||r.version===0)throw new k("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!ct(r))throw new k("session_not_active","SessionAccount PDA is present but expired");if(!lt(r.session.sessionPubkey,e.sessionPubkey))throw new k("session_pubkey_mismatch",`on-chain ${He(r.session.sessionPubkey)} != registration ${He(e.sessionPubkey)}`);let n=r.session.spent,i=r.session.crystallizedCumulative;return{frontierAtomic:(n>i?n:i).toString(),spentAtomic:n.toString(),crystallizedCumulativeAtomic:i.toString()}}var _=class extends Error{constructor(e){super(`Invalid voucher signature${e?`: ${e}`:""}`),this.name="InvalidVoucherSignatureError"}};function Te(t,e){if(e.length!==32)throw new _(`channelIdBytes must be 32 bytes, got ${e.length}`);if(t.sessionPublicKey.length!==32)throw new _(`sessionPublicKey must be 32 bytes, got ${t.sessionPublicKey.length}`);if(t.sessionSignature.length!==64)throw new _(`sessionSignature must be 64 bytes, got ${t.sessionSignature.length}`);let r=we({channelId:e,cumulativeAmount:BigInt(t.payload.cumulativeAmount),sequenceNumber:t.payload.sequenceNumber});if(!ot.sign.detached.verify(r,t.sessionSignature,t.sessionPublicKey))throw new _("ed25519 verify rejected")}var C=class extends Error{constructor(r,n){super(`Scope violation: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="ScopeViolationError"}};function Pe(t){let e=BigInt(t.voucher.payload.cumulativeAmount);if(e>t.registration.maxAmount)throw new C("cumulative_exceeds_cap",`${e} > ${t.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=t.registration.expiresAt)throw new C("session_expired",`now=${r} >= expiresAt=${t.registration.expiresAt}`);if(!t.registration.allowedCounterparty.equals(t.expectedCounterparty))throw new C("wrong_counterparty",`${t.registration.allowedCounterparty.toBase58()} != ${t.expectedCounterparty.toBase58()}`);if(t.previousCumulativeAtomic!==void 0){let n=BigInt(t.previousCumulativeAtomic);if(e<=n)throw new C("non_monotonic",`cumulative=${e} not > previous=${n}`)}}function lt(t,e){if(t.length!==e.length)return!1;for(let r=0;r<t.length;r++)if(t[r]!==e[r])return!1;return!0}function He(t){let e="";for(let r of t)e+=r.toString(16).padStart(2,"0");return e}import{PublicKey as Tr}from"@solana/web3.js";import{bytesToHex as _r}from"@noble/hashes/utils";import fr from"tweetnacl";import{sha256 as vr}from"@noble/hashes/sha256";var qe="https://x402.dexter.cash",Fe=6;function R(t,e=Fe){if(!/^\d+(\.\d+)?$/.test(t))throw new Error(`amount must be a non-negative decimal string, got "${t}"`);let[r,n=""]=t.split(".");if(n.length>e)throw new Error(`amount "${t}" has more than ${e} decimals`);let i=n.padEnd(e,"0"),s=`${r}${i}`.replace(/^0+(?=\d)/,"");return s===""?"0":s}function U(t,e=Fe){if(!/^\d+$/.test(t))throw new Error(`atomic must be a non-negative integer string, got "${t}"`);let r=t.padStart(e+1,"0"),n=r.slice(0,-e).replace(/^0+(?=\d)/,"")||"0",i=r.slice(-e).replace(/0+$/,"");return i?`${n}.${i}`:n}import{bytesToHex as _e}from"@noble/hashes/utils";var ut=15e3,mt=["claim_already_exists","non_monotonic_cumulative"],dt="below_lock_cadence";function ee(t){return typeof t=="string"&&t.includes(dt)}function pt(t){return`${t.slice(0,16)}\u2026`}function We(t,e,r,n){let i=pt(t);if(n.crystallized){console.info(`[tab/seller] crystallize OK channel=${i} cumulative=${e} seq=${r}${n.claimPda?` claimPda=${n.claimPda}`:""} \u2014 LockVoucher landed`);return}if(n.error){if(ee(n.error)){console.warn(`[tab/seller] crystallize refused below the facilitator's cadence gate channel=${i} cumulative=${e} seq=${r}: ${n.error} \u2014 benign: this facilitator's cadence engine owns the protection cadence for the span; gate-refused watermark advanced, re-attempts after the next signed voucher`);return}if(mt.some(s=>n.error.includes(s))){console.warn(`[tab/seller] crystallize duplicate channel=${i} cumulative=${e} seq=${r}: ${n.error} \u2014 voucher already secured on-chain (benign, no action)`);return}console.error(`[tab/seller] crystallize FAILED channel=${i} cumulative=${e} seq=${r}: ${n.error} \u2014 lock NOT secured (degraded: best-effort path, no watermark advance, retries at next threshold/close; seller exposure stays unsecured until it lands)`)}}async function Ne(t,e,r,n,i=fetch){let s=t.lastVoucher;if(!s)return{crystallized:!1};if(s.payload.channelId!==e){let c={crystallized:!1,error:"channel_id_mismatch"};return We(e,s.payload.cumulativeAmount,s.payload.sequenceNumber,c),c}let h=c=>(We(e,s.payload.cumulativeAmount,s.payload.sequenceNumber,c),c);try{let c=`${r.replace(/\/$/,"")}/tab/lock`,a={channelId:s.payload.channelId,cumulativeAmount:s.payload.cumulativeAmount,sequenceNumber:s.payload.sequenceNumber,sessionPublicKey:_e(s.sessionPublicKey),sessionSignature:_e(s.sessionSignature),sessionRegistration:_e(s.sessionRegistration),network:n},m=await i(c,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(a),signal:AbortSignal.timeout(ut)}),l=await m.text();if(!m.ok)return h({crystallized:!1,error:`tab lock ${m.status}: ${l.slice(0,200)}`});let o;try{let y=JSON.parse(l);y&&typeof y.claimPda=="string"&&(o=y.claimPda)}catch{}return h({crystallized:!0,claimPda:o})}catch(c){return h({crystallized:!1,error:String(c?.message??c)})}}async function je(t,e,r,n,i,s={}){let h=BigInt(t.deliveredCumulativeAtomic),c=BigInt(t.lastCrystallizedCumulativeAtomic??"0"),a=BigInt(i.thresholdAtomic);if(h-c<a)return{crystallized:!1};let m=t.lastVoucher?.payload.cumulativeAmount,l=t.gateRefusedCumulativeAtomic;if(m!==void 0&&l!==void 0&&BigInt(m)<=BigInt(l))return{crystallized:!1};let o=await Ne(t,e,r,n,s.fetchImpl);return o.crystallized&&m!==void 0?(t.lastCrystallizedCumulativeAtomic=m,t.gateRefusedCumulativeAtomic=void 0):ee(o.error)&&m!==void 0&&(t.gateRefusedCumulativeAtomic=m),o}var $="x-tab-voucher",ke=class{map=new Map;get(e){return this.map.get(e)}set(e,r){this.map.set(e,r)}update(e,r){let n=this.map.get(e);n&&(n.lastCumulativeAtomic=r)}delete(e){this.map.delete(e)}},Ie=class{constructor(e,r,n,i,s,h){this.recordDeliveredImpl=s;this.chargeImpl=h;this.channelId=e,this.network=r,this.cumulativeAtomic=n,this.deliveredBaselineAtomic=i}channelId;network;sessionPublicKey=null;cumulativeAtomic;deliveredBaselineAtomic;cumulative(){return U(this.cumulativeAtomic.toString())}deliveredCumulative(){return U(this.deliveredBaselineAtomic.toString())}async recordDelivered(e){return this.recordDeliveredImpl(e)}bumpCumulative(e){this.cumulativeAtomic=e}setSessionPublicKey(e){this.sessionPublicKey=e}async charge(e){return this.chargeImpl(e)}};function ht(t){if(typeof t!="string"||t.length===0)throw new x("signature_invalid",`missing ${$} header`);let e;try{e=Buffer.from(t,"base64").toString("utf8")}catch{throw new x("signature_invalid","malformed base64")}let r;try{r=JSON.parse(e)}catch{throw new x("signature_invalid","malformed JSON")}if(!r||typeof r!="object"||!r.payload||!r.sessionPublicKey)throw new x("signature_invalid","missing required fields");return{payload:r.payload,sessionPublicKey:te(r.sessionPublicKey),sessionRegistration:te(r.sessionRegistration),sessionSignature:te(r.sessionSignature)}}function te(t){if(typeof t!="string"||t.length%2!==0)throw new x("signature_invalid",`bad hex: ${typeof t}`);let e=new Uint8Array(t.length/2);for(let r=0;r<e.length;r++)e[r]=parseInt(t.substr(r*2,2),16);return e}function yt(t){if(!/^[0-9a-f]{64}$/i.test(t))throw new x("signature_invalid",`channelId must be 64-char hex, got "${t}"`);return te(t)}function Oe(t){let e=t.ledger??new D,r=new ke,n=typeof t.sellerPubkey=="string"?new gt(t.sellerPubkey):t.sellerPubkey,i=t.maxPerVoucherAtomic?BigInt(t.maxPerVoucherAtomic):BigInt(R(t.perUnit))*100n,s=t.facilitatorUrl??qe,h={thresholdAtomic:t.lockCadence?.thresholdAtomic??R("0.10"),onClose:t.lockCadence?.onClose??!0};return async(c,a,m)=>{try{let l=ht(c.headers[$]),o=l.payload.channelId,y=yt(o),d=r.get(o),f=null;if(!d){let p=Ee(l.sessionRegistration);f=(await Re(t.connection,p))?.frontierAtomic??null;let v=await e.get(o);d={registration:p,lastCumulativeAtomic:v?.lastVoucher?.payload.cumulativeAmount??"0"},r.set(o,d)}Te(l,y),Pe({registration:d.registration,voucher:l,expectedCounterparty:n,previousCumulativeAtomic:d.lastCumulativeAtomic});let b=BigInt(l.payload.cumulativeAmount),V=BigInt(d.lastCumulativeAtomic),L=b-V;if(L>i)throw new C("cumulative_exceeds_cap",`single voucher increment ${L} exceeds maxPerVoucherAtomic ${i}`);let pe=t.leaseTtlMs??3e5;if(!await e.tryAcquireLease(o,pe))throw new x("channel_busy","another stream is live on this channel; tabs serve one stream at a time");let B=!1,Z=()=>{B||(B=!0,e.releaseLease(o).catch(p=>{console.error("[tab/seller] failed to release channel lease:",p)}))};a.on("close",Z),a.on("finish",Z);let ge=async p=>{let T=p.lastCrystallizedCumulativeAtomic??"0",v=p.gateRefusedCumulativeAtomic;await je(p,o,s,t.network,h),(p.lastCrystallizedCumulativeAtomic!==T||p.gateRefusedCumulativeAtomic!==v)&&await P(o,async()=>{let w=await e.get(o);w&&await e.set(o,{...w,lastCrystallizedCumulativeAtomic:p.lastCrystallizedCumulativeAtomic,gateRefusedCumulativeAtomic:p.gateRefusedCumulativeAtomic})}).catch(w=>{console.error(`[tab/seller] crystallize watermark persist FAILED channel=${o.slice(0,16)}\u2026 (expect a benign duplicate/below-cadence warn on the next request):`,w)})},Q=!1,u=()=>{!h.onClose||Q||(Q=!0,(async()=>{let p=await e.get(o);if(!p||!p.lastVoucher)return;let T=p.lastVoucher.payload.cumulativeAmount;if(p.gateRefusedCumulativeAtomic!==void 0&&BigInt(T)<=BigInt(p.gateRefusedCumulativeAtomic))return;let v=await Ne(p,o,s,t.network);v.crystallized?await P(o,async()=>{let w=await e.get(o);w&&await e.set(o,{...w,lastCrystallizedCumulativeAtomic:T,gateRefusedCumulativeAtomic:void 0})}):ee(v.error)&&await P(o,async()=>{let w=await e.get(o);w&&await e.set(o,{...w,gateRefusedCumulativeAtomic:T})})})().catch(p=>{console.error(`[tab/seller] close-path crystallize CRASHED channel=${o.slice(0,16)}\u2026 (final voucher NOT locked; exposure unsecured until the next request retries):`,p)}))};a.on("close",u),a.on("finish",u);let g=await e.get(o),A=!g?.lastVoucher&&BigInt(g?.deliveredCumulativeAtomic??"0")===0n,S=f!==null&&A&&BigInt(f)>0n?f:null;S!==null&&console.info(`[tab/seller] channel ${o.slice(0,16)}\u2026 resumed: seeding delivered baseline from chain frontier ${S} (session already settled/locked up to it \u2014 that span is not deliverable budget)`);let I=S!==null?BigInt(S):g?BigInt(g.deliveredCumulativeAtomic):0n;await P(o,async()=>{let p=await e.get(o);await e.set(o,{...p,lastVoucher:l,deliveredCumulativeAtomic:S??(p?p.deliveredCumulativeAtomic:"0"),lastCrystallizedCumulativeAtomic:S??p?.lastCrystallizedCumulativeAtomic??"0"})}),r.update(o,l.payload.cumulativeAmount);let O=new Ie(o,t.network,b,I,async p=>{let T=null;await P(o,async()=>{let v=await e.get(o),w=v?BigInt(v.deliveredCumulativeAtomic):0n,Be=BigInt(p),tt=Be>0n?w+Be:w,Me={...v,lastVoucher:v?.lastVoucher??l,deliveredCumulativeAtomic:tt.toString(),lastCrystallizedCumulativeAtomic:v?.lastCrystallizedCumulativeAtomic??"0"};await e.set(o,Me),T=Me}),T&&ge(T).catch(v=>{console.error(`[tab/seller] crystallize cadence CRASHED channel=${o.slice(0,16)}\u2026 (threshold lock not attempted; retries at the next delivery):`,v)})},async p=>{throw new Error("SellerTab.charge() is not driven by the route handler; the buyer presents a fresh voucher per chunk. Use openSse(res, tab) for the metered-stream pattern.")});O.setSessionPublicKey(l.sessionPublicKey),c.tab=O,m()}catch(l){if(l instanceof x||l instanceof E||l instanceof k||l instanceof _||l instanceof C){a.status(402).json({error:"invalid_voucher",reason:l.reason??"unknown",detail:l.message});return}m(l)}}}function ft(t){if(!t.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return t.tab}function At(t,e){if(!e.tab)throw new Error("openSse requires options.tab");t.headersSent||(t.setHeader("Content-Type","text/event-stream"),t.setHeader("Cache-Control","no-cache"),t.setHeader("Connection","keep-alive"),typeof t.flushHeaders=="function"&&t.flushHeaders());let r=e.tab,n=BigInt(R(r.cumulative())),i=BigInt(R(r.deliveredCumulative())),s=n-i;s<0n&&(s=0n);let h=e.perUnit?BigInt(R(e.perUnit)):null,c=0n,a=!1;async function m(){await r.recordDelivered(c.toString())}t.on("close",()=>{a||(a=!0,m().catch(d=>{console.error("[tab/seller] terminal persist failed on disconnect:",d)}))});async function l(d=1){if(a)throw new Error("meter ended");if(h===null)throw new Error("charge() needs options.perUnit");let f=h*BigInt(d),b=c+f;if(b>s)throw a=!0,await m(),new C("cumulative_exceeds_cap",`chunk would push delivered to ${U((i+b).toString())} beyond signed cumulative ${U(n.toString())} (per-request budget ${U(s.toString())})`);c=b}function o(d){if(a)throw new Error("meter ended");let b=(typeof d=="string"?d:Buffer.from(d).toString("utf8")).replace(/\\/g,"\\\\").replace(/\n/g,"\\n");t.write(`data: ${b}
|
|
1
|
+
var w=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}reason};import{promises as J}from"fs";import{join as Wt,dirname as Gt}from"path";var mt=new Map;function B(e,t){let r=(mt.get(e)??Promise.resolve()).then(()=>t(),()=>t());return mt.set(e,r.then(()=>{},()=>{})),r}var Y=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,n){this.map.set(t,n)}async delete(t){this.map.delete(t)}async tryAcquireLease(t,n){return B(t,async()=>{let r=this.map.get(t),i=Date.now();if(r?.lease&&r.lease.heldUntilUnixMs>i)return!1;let o=r??{lastVoucher:null,deliveredCumulativeAtomic:"0",lastCrystallizedCumulativeAtomic:"0"};return this.map.set(t,{...o,lease:{heldUntilUnixMs:i+n}}),!0})}async releaseLease(t){await B(t,async()=>{let n=this.map.get(t);n&&this.map.set(t,{...n,lease:void 0})})}};function Ie(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function Ne(e){if(e.length%2!==0)throw new Error(`hex length must be even, got ${e.length}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}function ke(e){return dt(e)}function Be(e){return pt(e)}function dt(e){return{lastVoucher:e.lastVoucher?{payload:e.lastVoucher.payload,sessionPublicKey:Ie(e.lastVoucher.sessionPublicKey),sessionRegistration:Ie(e.lastVoucher.sessionRegistration),sessionSignature:Ie(e.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:e.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:e.lastCrystallizedCumulativeAtomic,gateRefusedCumulativeAtomic:e.gateRefusedCumulativeAtomic,onChain:e.onChain,lease:e.lease}}function pt(e){return{lastVoucher:e.lastVoucher?{payload:e.lastVoucher.payload,sessionPublicKey:Ne(e.lastVoucher.sessionPublicKey),sessionRegistration:Ne(e.lastVoucher.sessionRegistration),sessionSignature:Ne(e.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:e.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:e.lastCrystallizedCumulativeAtomic??"0",gateRefusedCumulativeAtomic:e.gateRefusedCumulativeAtomic,onChain:e.onChain,lease:e.lease}}var Oe=class{constructor(t){this.dir=t}dir;pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return Wt(this.dir,`${t}.json`)}async get(t){try{let n=await J.readFile(this.pathFor(t),"utf8");return pt(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await J.mkdir(Gt(r),{recursive:!0});let i=`${r}.tmp`;await J.writeFile(i,JSON.stringify(dt(n))),await J.rename(i,r)}async delete(t){try{await J.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}async tryAcquireLease(t,n){return B(t,async()=>{let r=await this.get(t),i=Date.now();if(r?.lease&&r.lease.heldUntilUnixMs>i)return!1;let o=r??{lastVoucher:null,deliveredCumulativeAtomic:"0",lastCrystallizedCumulativeAtomic:"0"};return await this.set(t,{...o,lease:{heldUntilUnixMs:i+n}}),!0})}async releaseLease(t){await B(t,async()=>{let n=await this.get(t);n&&await this.set(t,{...n,lease:void 0})})}};import{randomUUID as Xt}from"crypto";var jt='if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end',Ue=class{constructor(t,n="tab:"){this.client=t;this.keyPrefix=n}client;keyPrefix;leaseTokens=new Map;ledgerKey(t){return`${this.keyPrefix}ledger:${t}`}leaseKey(t){return`${this.keyPrefix}lease:${t}`}async get(t){let n=await this.client.get(this.ledgerKey(t));return n===null?null:Be(JSON.parse(n))}async set(t,n){let r=ke({...n,lease:void 0});await this.client.set(this.ledgerKey(t),JSON.stringify(r))}async delete(t){this.leaseTokens.delete(t),await this.client.del(this.ledgerKey(t),this.leaseKey(t))}async tryAcquireLease(t,n){let r=Xt();return await this.client.set(this.leaseKey(t),r,"PX",Math.max(1,Math.floor(n)),"NX")!=="OK"?!1:(this.leaseTokens.set(t,r),!0)}async releaseLease(t){let n=this.leaseTokens.get(t);n!==void 0&&(this.leaseTokens.delete(t),await this.client.eval(jt,1,this.leaseKey(t),n))}};import{PublicKey as Vn}from"@solana/web3.js";import Yt from"tweetnacl";import{sha256 as Cr}from"@noble/hashes/sha256";import{p256 as Vr}from"@noble/curves/p256";import{PublicKey as De}from"@solana/web3.js";import{sessionRegisterMessage as Jt,sessionReplaceV1Message as cr,sessionRevokeMessage as lr,sessionVoucherV2Nonce as ur,sessionVoucherV2AuthorizationNonce as mr,finalVoucherV2Sequence as dr,voucherV2SequenceOrdinal as pr,voucherPayloadMessage as Ke,buildVoucherMessage as gr}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as yr,buildRevokeSessionKeyInstruction as vr,deriveSwigWalletAddress as Ar}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as wr}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as me,SECP256R1_PROGRAM_ID as Sr,INSTRUCTIONS_SYSVAR_ID as xr}from"@dexterai/vault/constants";import{decodeSessionAccount as Zt,deriveSessionPda as ht,isSessionLive as Qt}from"@dexterai/vault/session";import{contextBoundVoucherV2Message as en,sessionVoucherV2AuthorizationNonce as tn,voucherV2SequenceOrdinal as nn}from"@dexterai/vault/messages";var $e="OTS_SESSION_REGISTER_V2";function z(e){return e>=2147483648?2:1}var U=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}reason};function de(e){if(e.length!==188)throw new U("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,$e.length));if(t!==$e)throw new U("wrong_domain",`got "${t}"`);for(let g=$e.length;g<32;g++)if(e[g]!==0)throw new U("wrong_domain",`non-NUL padding at byte ${g}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new De(e.slice(32,64)),i=new De(e.slice(64,96)),o=e.slice(96,128),c=n.getBigUint64(128,!0),a=n.getBigInt64(136,!0),u=new De(e.slice(144,176)),h=n.getUint32(176,!0),d=n.getBigUint64(180,!0);if(!r.equals(me))throw new U("wrong_program",`${r.toBase58()} is not ${me.toBase58()}`);if(c===0n)throw new U("cap_zero");return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(o),maxAmount:c,expiresAt:a,allowedCounterparty:u,nonce:h,maxRevolvingCapacity:d}}var C=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}reason};async function pe(e,t){let[n]=ht(t.vaultPda,t.allowedCounterparty,t.programId),r=await e.getAccountInfo(n,"finalized");if(!r)throw new C("session_not_active","no finalized SessionAccount PDA for this (vault, counterparty) \u2014 reservation may be confirmed-only, revoked, expiry-swept, or never registered");if(!r.owner.equals(t.programId))throw new C("wrong_program",`SessionAccount owner ${r.owner.toBase58()} != ${t.programId.toBase58()}`);let i;try{i=Zt(n,r.data)}catch(s){throw new C("registration_state_mismatch",`finalized SessionAccount decode failed: ${s instanceof Error?s.message:String(s)}`)}if(i.version===0)throw new C("session_not_active","finalized SessionAccount is cleared");if(!Qt(i))throw new C("session_not_active","SessionAccount PDA is present but expired");if(!ft(i.session.sessionPubkey,t.sessionPubkey))throw new C("session_pubkey_mismatch",`on-chain ${gt(i.session.sessionPubkey)} != registration ${gt(t.sessionPubkey)}`);let o=z(t.nonce),c=z(i.session.nonce);if(c!==o)throw new C("wire_version_mismatch",`active SessionAccount is V${c}, voucher registration is V${o}`);let a=Number.isSafeInteger(i.session.expiresAt)&&BigInt(i.session.expiresAt)===t.expiresAt;if(!(i.address===n.toBase58()&&i.vault===t.vaultPda.toBase58()&&i.session.maxAmount===t.maxAmount&&a&&i.session.allowedCounterparty===t.allowedCounterparty.toBase58()&&i.session.nonce===t.nonce&&i.session.maxRevolvingCapacity===t.maxRevolvingCapacity))throw new C("registration_state_mismatch","188-byte registration does not exactly match the active SessionAccount immutable fields");let h=i.session.spent,d=i.session.crystallizedCumulative,g=h>d?h:d;return{sessionAccountVersion:i.version,wireVersion:c,frontierAtomic:g.toString(),spentAtomic:h.toString(),currentOutstandingAtomic:i.session.currentOutstanding.toString(),crystallizedCumulativeAtomic:d.toString()}}var N=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function Me(e,t){if(t.length!==32)throw new N(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new N(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new N(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=de(e.sessionRegistration);if(!ft(n.sessionPubkey,e.sessionPublicKey))throw new N("registration session key does not match voucher session key");let r=n.nonce>=2147483648,i=z(n.nonce),o=z(e.payload.sequenceNumber);if(i!==o)throw new N(`voucher wire V${o} does not match registration wire V${i}`);let c;if(r){tn(n.nonce),nn(e.payload.sequenceNumber);let[u]=ht(n.vaultPda,n.allowedCounterparty,n.programId);c=en({programId:n.programId,vaultPda:n.vaultPda,sessionPda:u,seller:n.allowedCounterparty,sessionNonce:n.nonce,channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber})}else c=Ke({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!Yt.sign.detached.verify(c,e.sessionSignature,e.sessionPublicKey))throw new N("ed25519 verify rejected")}var O=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}reason};function Le(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new O("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new O("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new O("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new O("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function ft(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function gt(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}import{PublicKey as li}from"@solana/web3.js";import{bytesToHex as mi}from"@noble/hashes/utils";import $r from"tweetnacl";import{PublicKey as Lr}from"@solana/web3.js";import{contextBoundVoucherV2Message as qr,finalVoucherV2Sequence as zr,sessionRegisterMessage as Hr,sessionVoucherV2AuthorizationNonce as Wr}from"@dexterai/vault/messages";import{deriveSessionPda as Xr}from"@dexterai/vault/session";import{sha256 as Zr}from"@noble/hashes/sha256";var Jr=(1n<<64n)-1n;import{sha256 as bt}from"@noble/hashes/sha256";import{bytesToHex as X}from"@noble/hashes/utils";var yt=/^[0-9a-f]{64}$/,vt=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/,rn=/^[1-9A-HJ-NP-Za-km-z]{32,100}$/,At="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",wt="dexter-native-tab-v2-reservation/v1",on=`${wt}:`;function Fe(e){if(e===null||typeof e=="string"||typeof e=="boolean")return e;if(typeof e=="number"){if(!Number.isFinite(e))throw new Error("canonical_non_finite_number");return e}if(typeof e=="bigint")return e.toString();if(Array.isArray(e))return e.map(Fe);if(typeof e=="object")return Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>[t,Fe(n)]));throw new Error("canonical_value_unsupported")}function _t(e){return JSON.stringify(Fe(e))}function qe(e){if(e==="solana:mainnet"||e===At)return At;throw new Error("native_tab_v2_reservation_network_unsupported")}function ze(e){return X(bt(new TextEncoder().encode(_t({channelId:e.payload.channelId,cumulativeAmount:e.payload.cumulativeAmount,sequenceNumber:e.payload.sequenceNumber,sessionPublicKey:X(e.sessionPublicKey),sessionSignature:X(e.sessionSignature),sessionRegistration:X(e.sessionRegistration)}))))}function He(e){let t=ze(e);return{voucherDigest:t,idempotencyKey:`native-tab-v2:${t}`}}function sn(e){return X(bt(new TextEncoder().encode(_t({contract:wt,network:qe(e.network),programId:e.programId,buyerSwigAddress:e.buyerSwigAddress,vaultPda:e.vaultPda,sessionPda:e.sessionPda,seller:e.seller,channelId:e.channelId,sessionNonce:e.sessionNonce,reservationAmountAtomic:e.reservationAmountAtomic,previousCumulativeAtomic:e.previousCumulativeAtomic,voucherDigest:e.voucherDigest,cumulativeAmountAtomic:e.cumulativeAmountAtomic,sequenceNumber:e.sequenceNumber}))))}function an(e){let t=ze(e.voucher);return sn({network:e.network,programId:e.programId,buyerSwigAddress:e.buyerSwigAddress,vaultPda:e.vaultPda,sessionPda:e.sessionPda,seller:e.seller,channelId:e.channelId,sessionNonce:e.sessionNonce,reservationAmountAtomic:e.reservationAmountAtomic,previousCumulativeAtomic:e.previousCumulativeAtomic,voucherDigest:t,cumulativeAmountAtomic:e.voucher.payload.cumulativeAmount,sequenceNumber:e.voucher.payload.sequenceNumber})}function St(e){return`${on}${an(e)}`}function x(e){throw new Error(`native_tab_v2_reservation_receipt_invalid:${e}`)}function ge(e,t){(!Number.isSafeInteger(e)||e<0)&&x(t)}function We(e,t){(!t||typeof t!="object")&&x("missing");let n=ze(e.voucher);(!yt.test(e.voucherDigest)||e.voucherDigest!==n)&&x("input_voucher_digest"),e.idempotencyKey!==`native-tab-v2:${n}`&&x("input_idempotency_identity");let r=BigInt(e.voucher.payload.cumulativeAmount),i=BigInt(e.previousCumulativeAtomic),o=BigInt(e.reservationAmountAtomic);(r<=i||r-i!==o||o<=0n)&&x("input_reservation_delta"),(e.voucher.payload.channelId!==e.channelId||(e.voucher.payload.sequenceNumber&2147483648)===0||(e.sessionNonce&2147483648)===0||e.voucher.sessionPublicKey.length!==32||e.voucher.sessionSignature.length!==64||e.voucher.sessionRegistration.length!==188)&&x("input_voucher_identity"),t.contract!=="dexter-native-tab-open-receipt/v1"&&t.contract!=="dexter-native-tab-open-receipt/v2"&&x("contract"),yt.test(t.operationId)||x("operation_id"),vt.test(t.callerOperationId)||x("caller_operation_id"),rn.test(t.transaction)||x("transaction"),t.commitment!=="finalized"&&x("commitment"),ge(t.confirmationSlot,"confirmation_slot"),ge(t.postStateSlot,"post_state_slot"),(t.confirmationSlot===0||t.postStateSlot<t.confirmationSlot)&&x("post_state_slot");let c,a;try{c=qe(e.network),a=qe(t.network)}catch{return x("network")}(a!==c||t.buyerSwigAddress!==e.buyerSwigAddress||t.vaultPda!==e.vaultPda||t.sessionPda!==e.sessionPda||t.seller!==e.seller||t.channelId!==e.channelId||t.sessionPublicKey!==X(e.voucher.sessionPublicKey)||t.voucherDigest!==n||t.cumulativeAmountAtomic!==e.voucher.payload.cumulativeAmount||t.sequenceNumber!==e.voucher.payload.sequenceNumber||!vt.test(t.providerReceiptId)||t.reservationAmountAtomic!==e.reservationAmountAtomic||t.currentOutstandingBeforeAtomic!=="0"||t.currentOutstandingAfterAtomic!==e.reservationAmountAtomic)&&x("economic_identity"),ge(t.pendingVoucherCountBefore,"pending_voucher_count_before"),ge(t.pendingVoucherCountAfter,"pending_voucher_count_after"),t.contract==="dexter-native-tab-open-receipt/v1"?t.callerOperationId!==e.idempotencyKey&&x("idempotency_key"):(t.rootOperationId!==e.idempotencyKey||!Number.isSafeInteger(t.generation)||Number(t.generation)<2||!t.predecessorCallerOperationId||!t.predecessorLifecycleOperationId||!t.predecessorReleaseDigest||!t.stableReservationId||!t.economicEffectDigest)&&x("successor_identity")}import{deriveSessionPda as fi}from"@dexterai/vault/session";var xt="https://x402.dexter.cash",Rt=6;function k(e,t=Rt){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[n,r=""]=e.split(".");if(r.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let i=r.padEnd(t,"0"),o=`${n}${i}`.replace(/^0+(?=\d)/,"");return o===""?"0":o}function H(e,t=Rt){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let n=e.padStart(t+1,"0"),r=n.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",i=n.slice(-t).replace(/0+$/,"");return i?`${r}.${i}`:r}import{PublicKey as M}from"@solana/web3.js";import{bytesToHex as Ge}from"@noble/hashes/utils";import{deriveGraphConfigPda as cn,deriveSwigVaultBindingPda as Xe}from"@dexterai/vault/credit";import{DEXTER_VAULT_PROGRAM_ID as ln,DISCRIMINATORS as un}from"@dexterai/vault/constants";import{deriveSwigWalletAddress as mn}from"@dexterai/vault/instructions";import{decodeVaultFull as dn}from"@dexterai/vault/reader";import{decodeSessionAccount as pn,deriveSessionPda as je}from"@dexterai/vault/session";var gn=Uint8Array.from([56,67,4,209,238,143,0,129]),hn=74,Et=new Set([1,2]),fn=188,yn=new M("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),vn=(()=>{let e=Buffer.alloc(32);return e.write("OTS_SESSION_REGISTER_V2","ascii"),e})(),Z=class extends Error{constructor(n,r){super(`native_tab_v2_solana_reservation_invalid:${n}`+(r?`:${r}`:""));this.code=n;this.name="SolanaFinalVoucherV2ReservationError"}code};function m(e,t){throw new Z(e,t)}function P(e,t){try{return new M(e)}catch{return m(t)}}function he(e,t){return e.length===t.length&&e.every((n,r)=>n===t[r])}async function An(e){let t=await e.connection.getTransaction(e.signature,{commitment:e.commitment,maxSupportedTransactionVersion:0});if(!t)return null;t.meta||m("transaction_meta_missing");let n=t.transaction.message,r=n.version===0?n.getAccountKeys({accountKeysFromLookups:t.meta.loadedAddresses??null}):n.getAccountKeys(),i=(o,c)=>{let a=r.get(o);return a||m(c),a};return{slot:t.slot,err:t.meta.err,signatures:[...t.transaction.signatures],accountKeys:Array.from({length:r.length},(o,c)=>({address:i(c,"transaction_account_key").toBase58(),signer:n.isAccountSigner(c),writable:n.isAccountWritable(c)})),instructions:n.compiledInstructions.map(o=>({programId:i(o.programIdIndex,"transaction_program_id").toBase58(),accounts:o.accountKeyIndexes.map(c=>i(c,"transaction_instruction_account").toBase58()),data:Uint8Array.from(o.data)}))}}function bn(e,t,n,r){r.length!==hn&&m("binding_length"),he(r.subarray(0,8),gn)||m("binding_discriminator");let i=r.readUInt8(8),o=r.readUInt8(9);return Et.has(i)||m("binding_version"),o!==t&&m("binding_bump"),{address:e.toBase58(),owner:n.toBase58(),version:i,bump:o,swig:new M(r.subarray(10,42)).toBase58(),vault:new M(r.subarray(42,74)).toBase58()}}async function wn(e){let t=P(e.input.programId,"program_id"),n=P(e.input.buyerSwigAddress,"buyer_swig"),r=P(e.input.vaultPda,"vault_pda"),i=P(e.input.seller,"seller"),[o,c]=Xe(n,t),[a]=je(r,i,t),u=await e.connection.getMultipleAccountsInfoAndContext([o,r,a],{commitment:"finalized",minContextSlot:e.minimumSlot}),[h,d,g]=u.value;h||m("binding_missing"),d||m("vault_missing"),g||m("session_missing");let s,y;try{s=dn(Buffer.from(d.data)),y=pn(a,g.data)}catch(A){return m("post_state_decode",A instanceof Error?A.message:String(A))}let l=y.session;return{contextSlot:u.context.slot,binding:bn(o,c,h.owner,Buffer.from(h.data)),vault:{owner:d.owner.toBase58(),exists:s.exists,version:s.version,swigAddress:s.swigAddress,dexterAuthority:s.dexterAuthority,pendingVoucherCount:s.pendingVoucherCount},session:{owner:g.owner.toBase58(),version:y.version,bump:y.bump,vault:y.vault,sessionPublicKey:Ge(l.sessionPubkey),maxAmount:l.maxAmount,expiresAt:l.expiresAt,seller:l.allowedCounterparty,nonce:l.nonce,spent:l.spent,currentOutstanding:l.currentOutstanding,maxRevolvingCapacity:l.maxRevolvingCapacity,crystallizedCumulative:l.crystallizedCumulative}}}function _n(e){let t=Buffer.from(e.voucher.sessionRegistration);return t.length!==fn&&m("registration_length"),he(t.subarray(0,32),vn)||m("registration_domain"),{programId:new M(t.subarray(32,64)).toBase58(),vaultPda:new M(t.subarray(64,96)).toBase58(),sessionPublicKey:Ge(t.subarray(96,128)),maxAmount:t.readBigUInt64LE(128),expiresAt:t.readBigInt64LE(136),seller:new M(t.subarray(144,176)).toBase58(),nonce:t.readUInt32LE(176),maxRevolvingCapacity:t.readBigUInt64LE(180)}}function j(e,t,n){let r=e.accountKeys.filter(i=>i.address===t);return r.length!==1&&m(`${n}_account_key`),r[0]}function Sn(e,t,n){(!Number.isSafeInteger(n.slot)||n.slot<=0)&&m("transaction_slot"),n.slot!==t.confirmationSlot&&m("transaction_confirmation_slot"),n.err!==null&&m("transaction_failed"),n.signatures[0]!==t.transaction&&m("transaction_signature"),n.instructions.length!==2&&m("transaction_instruction_count");let r=P(e.programId,"program_id"),i=P(e.buyerSwigAddress,"buyer_swig"),o=P(e.vaultPda,"vault_pda"),c=P(e.seller,"seller"),a=P(e.sessionPda,"session_pda"),[u]=je(o,c,r),h=Xe(i,r)[0],d=mn(i),g=cn(r)[0];a.equals(u)||m("session_pda_derivation");let s=Buffer.from(un.settle_voucher),y=n.instructions.filter(p=>{if(p.programId!==e.programId)return!1;let b=p.data;return b.length>=s.length&&he(b.subarray(0,s.length),s)});y.length!==1&&m("settle_voucher_instruction_count");let l=y[0];n.instructions[0]!==l&&m("settle_voucher_instruction_order");let A=Buffer.from(l.data);A.length!==49&&m("settle_voucher_instruction_length"),A.readBigUInt64LE(8).toString()!==e.reservationAmountAtomic&&m("settle_voucher_amount"),A.readUInt8(16)!==1&&m("settle_voucher_increment"),new M(A.subarray(17,49)).equals(c)||m("settle_voucher_seller"),l.accounts.length<8&&m("settle_voucher_accounts"),[o.toBase58(),null,a.toBase58(),null,i.toBase58(),d.toBase58(),h.toBase58(),g.toBase58()].forEach((p,b)=>{p!==null&&l.accounts[b]!==p&&m(`settle_voucher_account_${b}`)});let V=l.accounts[1];V||m("dexter_authority");let T=j(n,l.accounts[0],"vault"),L=j(n,V,"dexter_authority"),K=j(n,l.accounts[2],"session");(!T.writable||T.signer)&&m("vault_privileges"),L.signer||m("dexter_authority_signature"),(!K.writable||K.signer)&&m("session_privileges");for(let p=3;p<Math.min(l.accounts.length,8);p+=1)j(n,l.accounts[p],`account_${p}`).signer&&m(`settle_voucher_account_${p}_signer`);for(let p=8;p<l.accounts.length;p+=1){let b=j(n,l.accounts[p],`sibling_${p-8}`);(!b.writable||b.signer)&&m("settle_voucher_sibling_privileges")}let I=n.instructions[1];I.programId!==yn.toBase58()&&m("reservation_memo_program"),(I.accounts.length!==1||I.accounts[0]!==V)&&m("reservation_memo_authority"),j(n,V,"reservation_memo_authority").signer||m("reservation_memo_authority_signature");let f=new TextEncoder().encode(St(e));return he(I.data,f)||m("reservation_memo_digest"),V}function xn(e,t,n,r){let i=P(e.programId,"program_id"),o=P(e.buyerSwigAddress,"buyer_swig"),c=P(e.vaultPda,"vault_pda"),a=P(e.seller,"seller"),[u,h]=Xe(o,i),[d,g]=je(c,a,i);(!Number.isSafeInteger(r.contextSlot)||r.contextSlot<t)&&m("post_state_slot"),(r.binding.address!==u.toBase58()||r.binding.owner!==e.programId||r.binding.bump!==h||!Et.has(r.binding.version)||r.binding.swig!==e.buyerSwigAddress||r.binding.vault!==e.vaultPda)&&m("binding_identity"),(r.vault.owner!==e.programId||!r.vault.exists||r.vault.version!==7||r.vault.swigAddress!==e.buyerSwigAddress||r.vault.dexterAuthority!==n)&&m("vault_post_state"),(e.sessionPda!==d.toBase58()||r.session.owner!==e.programId||r.session.version!==1||r.session.bump!==g||r.session.vault!==e.vaultPda||r.session.sessionPublicKey!==Ge(e.voucher.sessionPublicKey)||r.session.seller!==e.seller||r.session.nonce!==e.sessionNonce||r.session.currentOutstanding.toString()!==e.reservationAmountAtomic)&&m("session_post_state");let s=_n(e);(s.programId!==e.programId||s.vaultPda!==e.vaultPda||s.sessionPublicKey!==r.session.sessionPublicKey||s.seller!==e.seller||s.nonce!==e.sessionNonce||s.maxAmount!==r.session.maxAmount||s.expiresAt!==BigInt(r.session.expiresAt)||s.maxRevolvingCapacity!==r.session.maxRevolvingCapacity)&&m("registration_post_state"),(r.session.spent>r.session.crystallizedCumulative?r.session.spent:r.session.crystallizedCumulative).toString()!==e.previousCumulativeAtomic&&m("session_frontier")}async function Ct(e,t,n,r={}){try{We(t,n)}catch(a){return m("provider_receipt",a instanceof Error?a.message:String(a))}t.network!=="solana:mainnet"&&m("network"),t.programId!==ln.toBase58()&&m("program_id");let i=await(r.readTransaction??An)({connection:e,signature:n.transaction,commitment:n.commitment});i||m("transaction_missing");let o=Sn(t,n,i),c=await(r.readPostState??wn)({connection:e,input:t,minimumSlot:i.slot});xn(t,i.slot,o,c)}import{deriveSessionPda as Tn}from"@dexterai/vault/session";import{bytesToHex as Je}from"@noble/hashes/utils";var Rn=15e3,En=["claim_already_exists","non_monotonic_cumulative"],Cn="below_lock_cadence";function fe(e){return typeof e=="string"&&e.includes(Cn)}function Pn(e){return`${e.slice(0,16)}\u2026`}function Pt(e,t,n,r){let i=Pn(e);if(r.crystallized){console.info(`[tab/seller] crystallize OK channel=${i} cumulative=${t} seq=${n}${r.claimPda?` claimPda=${r.claimPda}`:""} \u2014 LockVoucher landed`);return}if(r.error){if(fe(r.error)){console.warn(`[tab/seller] crystallize refused below the facilitator's cadence gate channel=${i} cumulative=${t} seq=${n}: ${r.error} \u2014 benign: this facilitator's cadence engine owns the protection cadence for the span; gate-refused watermark advanced, re-attempts after the next signed voucher`);return}if(En.some(o=>r.error.includes(o))){console.warn(`[tab/seller] crystallize duplicate channel=${i} cumulative=${t} seq=${n}: ${r.error} \u2014 voucher already secured on-chain (benign, no action)`);return}console.error(`[tab/seller] crystallize FAILED channel=${i} cumulative=${t} seq=${n}: ${r.error} \u2014 lock NOT secured (degraded: best-effort path, no watermark advance, retries at next threshold/close; seller exposure stays unsecured until it lands)`)}}async function Ye(e,t,n,r,i=fetch){let o=e.lastVoucher;if(!o)return{crystallized:!1};if(o.payload.channelId!==t){let a={crystallized:!1,error:"channel_id_mismatch"};return Pt(t,o.payload.cumulativeAmount,o.payload.sequenceNumber,a),a}let c=a=>(Pt(t,o.payload.cumulativeAmount,o.payload.sequenceNumber,a),a);try{let a=`${n.replace(/\/$/,"")}/tab/lock`,u={channelId:o.payload.channelId,cumulativeAmount:o.payload.cumulativeAmount,sequenceNumber:o.payload.sequenceNumber,sessionPublicKey:Je(o.sessionPublicKey),sessionSignature:Je(o.sessionSignature),sessionRegistration:Je(o.sessionRegistration),network:r},h=await i(a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(u),signal:AbortSignal.timeout(Rn)}),d=await h.text();if(!h.ok)return c({crystallized:!1,error:`tab lock ${h.status}: ${d.slice(0,200)}`});let g;try{let s=JSON.parse(d);s&&typeof s.claimPda=="string"&&(g=s.claimPda)}catch{}return c({crystallized:!0,claimPda:g})}catch(a){return c({crystallized:!1,error:String(a?.message??a)})}}async function Vt(e,t,n,r,i,o={}){let c=BigInt(e.deliveredCumulativeAtomic),a=BigInt(e.lastCrystallizedCumulativeAtomic??"0"),u=BigInt(i.thresholdAtomic);if(c-a<u)return{crystallized:!1};let h=e.lastVoucher?.payload.cumulativeAmount,d=e.gateRefusedCumulativeAtomic;if(h!==void 0&&d!==void 0&&BigInt(h)<=BigInt(d))return{crystallized:!1};let g=await Ye(e,t,n,r,o.fetchImpl);return g.crystallized&&h!==void 0?(e.lastCrystallizedCumulativeAtomic=h,e.gateRefusedCumulativeAtomic=void 0):fe(g.error)&&h!==void 0&&(e.gateRefusedCumulativeAtomic=h),g}var W="x-tab-voucher",Ze=class{map=new Map;get(t){return this.map.get(t)}set(t,n){this.map.set(t,n)}update(t,n){let r=this.map.get(t);r&&(r.lastCumulativeAtomic=n)}delete(t){this.map.delete(t)}},Qe=class{constructor(t,n,r,i,o,c){this.recordDeliveredImpl=o;this.chargeImpl=c;this.channelId=t,this.network=n,this.cumulativeAtomic=r,this.deliveredBaselineAtomic=i}recordDeliveredImpl;chargeImpl;channelId;network;sessionPublicKey=null;cumulativeAtomic;deliveredBaselineAtomic;cumulative(){return H(this.cumulativeAtomic.toString())}deliveredCumulative(){return H(this.deliveredBaselineAtomic.toString())}async recordDelivered(t){return this.recordDeliveredImpl(t)}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function In(e){if(typeof e!="string"||e.length===0)throw new w("signature_invalid",`missing ${W} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new w("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new w("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new w("signature_invalid","missing required fields");return{voucher:{payload:n.payload,sessionPublicKey:ye(n.sessionPublicKey),sessionRegistration:ye(n.sessionRegistration),sessionSignature:ye(n.sessionSignature)},reservationReceipt:n.reservationReceipt}}function ye(e){if(typeof e!="string"||e.length%2!==0)throw new w("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}function Nn(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new w("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return ye(e)}function et(e){let t=e.ledger??new Y,n=new Ze,r=typeof e.sellerPubkey=="string"?new Vn(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(k(e.perUnit))*100n,o=e.facilitatorUrl??xt,c={thresholdAtomic:e.lockCadence?.thresholdAtomic??k("0.10"),onClose:e.lockCadence?.onClose??!0};return async(a,u,h)=>{try{let d=In(a.headers[W]),g=d.voucher,s=g.payload.channelId,y=Nn(s),l=n.get(s),A=null,R,V=!1;if(l){if(!On(l.registrationBytes,g.sessionRegistration))throw new N("voucher registration does not match the channel's verified registration")}else{let v=de(g.sessionRegistration);R=await pe(e.connection,v),V=!0,A=R?.frontierAtomic??null;let _=await t.get(s);l={registration:v,registrationBytes:g.sessionRegistration.slice(),lastCumulativeAtomic:_?.lastVoucher?.payload.cumulativeAmount??"0"},n.set(s,l)}let T=z(l.registration.nonce),L=z(g.payload.sequenceNumber);if(L!==T)throw new w("wire_version_mismatch",`voucher is V${L}, active registration is V${T}`);let K;if(T===2){if(d.reservationReceipt===void 0)throw new w("reservation_proof_missing","Native Tab V2 requires the verified reservation receipt in the voucher envelope");if(d.reservationReceipt===null||typeof d.reservationReceipt!="object"||Array.isArray(d.reservationReceipt))throw new w("reservation_proof_invalid","reservationReceipt must be an object");K=d.reservationReceipt}T===2&&!V&&(R=await pe(e.connection,l.registration),V=!0,A=R?.frontierAtomic??null),Me(g,y);let I=BigInt(g.payload.cumulativeAmount),f=BigInt(l.lastCumulativeAtomic),p=null;if(T===2){if(R?.wireVersion!==2)throw new w("wire_version_mismatch",`active SessionAccount is V${R?.wireVersion??"unknown"}, voucher is V2`);if(R.sessionAccountVersion!==1||A===null||R.currentOutstandingAtomic===void 0)throw new w("reservation_mismatch","authoritative V2 SessionAccount reservation evidence is incomplete");let v=Tt(A,"frontierAtomic");if(v>f&&(f=v),I<=f)throw new w("voucher_already_covered",`cumulative ${I} is not above covered frontier ${f}`);p=I-f;let _=Tt(R.currentOutstandingAtomic,"currentOutstandingAtomic");if(_!==p)throw new w("reservation_mismatch",`currentOutstanding ${_} does not equal voucher delta ${p}`)}Le({registration:l.registration,voucher:g,expectedCounterparty:r,previousCumulativeAtomic:f.toString()});let b=I-f;if(b>i)throw new O("cumulative_exceeds_cap",`single voucher increment ${b} exceeds maxPerVoucherAtomic ${i}`);if(T===2){if(!K||p===null)throw new w("reservation_proof_missing","Native Tab V2 reservation proof was not carried through admission");let[v]=Tn(l.registration.vaultPda,l.registration.allowedCounterparty,l.registration.programId),_=He(g);try{await Ct(e.connection,{network:e.network,programId:l.registration.programId.toBase58(),buyerSwigAddress:K.buyerSwigAddress,vaultPda:l.registration.vaultPda.toBase58(),sessionPda:v.toBase58(),seller:l.registration.allowedCounterparty.toBase58(),channelId:s,sessionNonce:l.registration.nonce,reservationAmountAtomic:p.toString(),previousCumulativeAtomic:f.toString(),..._,voucher:g},K)}catch(S){throw S instanceof Z?new w("reservation_proof_invalid",S.message):S}}let F=e.leaseTtlMs??3e5;if(!await t.tryAcquireLease(s,F))throw new w("channel_busy","another stream is live on this channel; tabs serve one stream at a time");let $=!1,q=()=>{$||($=!0,t.releaseLease(s).catch(v=>{console.error("[tab/seller] failed to release channel lease:",v)}))};u.on("close",q),u.on("finish",q);let Ft=async v=>{let _=v.lastCrystallizedCumulativeAtomic??"0",S=v.gateRefusedCumulativeAtomic;await Vt(v,s,o,e.network,c),(v.lastCrystallizedCumulativeAtomic!==_||v.gateRefusedCumulativeAtomic!==S)&&await B(s,async()=>{let E=await t.get(s);E&&await t.set(s,{...E,lastCrystallizedCumulativeAtomic:v.lastCrystallizedCumulativeAtomic,gateRefusedCumulativeAtomic:v.gateRefusedCumulativeAtomic})}).catch(E=>{console.error(`[tab/seller] crystallize watermark persist FAILED channel=${s.slice(0,16)}\u2026 (expect a benign duplicate/below-cadence warn on the next request):`,E)})},ot=!1,st=()=>{!c.onClose||ot||(ot=!0,(async()=>{let v=await t.get(s);if(!v||!v.lastVoucher)return;let _=v.lastVoucher.payload.cumulativeAmount;if(v.gateRefusedCumulativeAtomic!==void 0&&BigInt(_)<=BigInt(v.gateRefusedCumulativeAtomic))return;let S=await Ye(v,s,o,e.network);S.crystallized?await B(s,async()=>{let E=await t.get(s);E&&await t.set(s,{...E,lastCrystallizedCumulativeAtomic:_,gateRefusedCumulativeAtomic:void 0})}):fe(S.error)&&await B(s,async()=>{let E=await t.get(s);E&&await t.set(s,{...E,gateRefusedCumulativeAtomic:_})})})().catch(v=>{console.error(`[tab/seller] close-path crystallize CRASHED channel=${s.slice(0,16)}\u2026 (final voucher NOT locked; exposure unsecured until the next request retries):`,v)}))};u.on("close",st),u.on("finish",st);let ue=await t.get(s),at=BigInt(ue?.deliveredCumulativeAtomic??"0"),qt=!ue?.lastVoucher&&at===0n,Te=A===null?null:BigInt(A),G=Te!==null&&Te>at&&(T===2||qt)?Te.toString():null;G!==null&&console.info(`[tab/seller] channel ${s.slice(0,16)}\u2026 resumed: seeding delivered baseline from chain frontier ${G} (session already settled/locked up to it \u2014 that span is not deliverable budget)`);let zt=G!==null?BigInt(G):ue?BigInt(ue.deliveredCumulativeAtomic):0n;await B(s,async()=>{let v=await t.get(s);await t.set(s,{...v,lastVoucher:g,deliveredCumulativeAtomic:G??(v?v.deliveredCumulativeAtomic:"0"),lastCrystallizedCumulativeAtomic:G??v?.lastCrystallizedCumulativeAtomic??"0"})}),n.update(s,g.payload.cumulativeAmount);let ct=new Qe(s,e.network,I,zt,async v=>{let _=null;await B(s,async()=>{let S=await t.get(s),E=S?BigInt(S.deliveredCumulativeAtomic):0n,lt=BigInt(v),Ht=lt>0n?E+lt:E,ut={...S,lastVoucher:S?.lastVoucher??g,deliveredCumulativeAtomic:Ht.toString(),lastCrystallizedCumulativeAtomic:S?.lastCrystallizedCumulativeAtomic??"0"};await t.set(s,ut),_=ut}),_&&Ft(_).catch(S=>{console.error(`[tab/seller] crystallize cadence CRASHED channel=${s.slice(0,16)}\u2026 (threshold lock not attempted; retries at the next delivery):`,S)})},async v=>{throw new Error("SellerTab.charge() is not driven by the route handler; the buyer presents a fresh voucher per chunk. Use openSse(res, tab) for the metered-stream pattern.")});ct.setSessionPublicKey(g.sessionPublicKey),a.tab=ct,h()}catch(d){if(d instanceof w||d instanceof U||d instanceof C||d instanceof N||d instanceof O){u.status(402).json({error:"invalid_voucher",reason:d.reason??"unknown",detail:d.message});return}h(d)}}}function On(e,t){if(e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r+=1)n|=e[r]^t[r];return n===0}function Tt(e,t){if(!/^(0|[1-9][0-9]*)$/.test(e))throw new w("reservation_mismatch",`authoritative ${t} is not a canonical atomic amount`);return BigInt(e)}function kn(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Bn(e,t){if(!t.tab)throw new Error("openSse requires options.tab");e.headersSent||(e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),typeof e.flushHeaders=="function"&&e.flushHeaders());let n=t.tab,r=BigInt(k(n.cumulative())),i=BigInt(k(n.deliveredCumulative())),o=r-i;o<0n&&(o=0n);let c=t.perUnit?BigInt(k(t.perUnit)):null,a=0n,u=!1;async function h(){await n.recordDelivered(a.toString())}e.on("close",()=>{u||(u=!0,h().catch(y=>{console.error("[tab/seller] terminal persist failed on disconnect:",y)}))});async function d(y=1){if(u)throw new Error("meter ended");if(c===null)throw new Error("charge() needs options.perUnit");let l=c*BigInt(y),A=a+l;if(A>o)throw u=!0,await h(),new O("cumulative_exceeds_cap",`chunk would push delivered to ${H((i+A).toString())} beyond signed cumulative ${H(r.toString())} (per-request budget ${H(o.toString())})`);a=A}function g(y){if(u)throw new Error("meter ended");let A=(typeof y=="string"?y:Buffer.from(y).toString("utf8")).replace(/\\/g,"\\\\").replace(/\n/g,"\\n");e.write(`data: ${A}
|
|
2
2
|
|
|
3
|
-
`)}async function
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}async function s(){u||(u=!0,await h(),e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${a}"}
|
|
5
5
|
|
|
6
|
-
`),t.end())}return{charge:l,send:o,end:y}}import{promises as K}from"fs";import{join as bt,dirname as vt}from"path";function wt(t){return{payload:t.payload,sessionPublicKey:Ue(t.sessionPublicKey),sessionRegistration:Ue(t.sessionRegistration),sessionSignature:Ue(t.sessionSignature)}}function St(t){return{payload:t.payload,sessionPublicKey:$e(t.sessionPublicKey),sessionRegistration:$e(t.sessionRegistration),sessionSignature:$e(t.sessionSignature)}}function Ue(t){let e="";for(let r of t)e+=r.toString(16).padStart(2,"0");return e}function $e(t){if(t.length%2!==0)throw new Error(`hex length must be even, got ${t.length}`);let e=new Uint8Array(t.length/2);for(let r=0;r<e.length;r++)e[r]=parseInt(t.substr(r*2,2),16);return e}var Ve=class{map=new Map;async get(e){return this.map.get(e)??null}async set(e,r){this.map.set(e,r)}async delete(e){this.map.delete(e)}},Le=class{constructor(e){this.dir=e}pathFor(e){if(!/^[a-z0-9_-]+$/i.test(e))throw new Error(`unsafe channelId for filesystem: ${e}`);return bt(this.dir,`${e}.json`)}async get(e){try{let r=await K.readFile(this.pathFor(e),"utf8");return St(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(e,r){let n=this.pathFor(e);await K.mkdir(vt(n),{recursive:!0});let i=`${n}.tmp`;await K.writeFile(i,JSON.stringify(wt(r))),await K.rename(i,n)}async delete(e){try{await K.unlink(this.pathFor(e))}catch(r){if(r?.code!=="ENOENT")throw r}}};import{PublicKey as Nt}from"@solana/web3.js";var N="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",Xe="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",Je="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var z="eip155:8453",re="eip155:84532",ne="eip155:42161",ie="eip155:137",se="eip155:10",oe="eip155:43114",ae="eip155:56",H="eip155:480",q="eip155:143",F="eip155:4663",W="eip155:1187947933",j="eip155:324705682",ce="eip155:1";var le="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var Ge="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",xt="0x55d398326f99059fF775485246999027B3197955",Ye="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Ct="0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",Ze={[ae]:Ye,[z]:Ge,[re]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[ne]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[ie]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[se]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[oe]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[H]:"0x79A02482A880bCE3F13e09Da970dC34db4CD24d1",[q]:"0x754704Bc059F8C67012fEd69BC8A327a5aafb603",[F]:Ct,[W]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[j]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[ce]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Qe={[xt]:{symbol:"USDT",decimals:18},[Ye]:{symbol:"USDC",decimals:18}};var Jr={[H]:{name:"USDC",version:"2"},[q]:{name:"USDC",version:"2"},[F]:{name:"Global Dollar",version:"1"},[W]:{name:"Bridged USDC (SKALE Bridge)",version:"2"},[j]:{name:"Bridged USDC (SKALE Bridge)",version:"2"}};var Gr={[ae]:56,[z]:8453,[re]:84532,[ne]:42161,[ie]:137,[se]:10,[oe]:43114,[H]:480,[q]:143,[F]:4663,[W]:1187947933,[j]:324705682,[ce]:1},Yr={[N]:"https://api.dexter.cash/api/solana/rpc",[Xe]:"https://api.devnet.solana.com",[Je]:"https://api.testnet.solana.com"},Et={[ae]:"https://api.dexter.cash/api/evm/bsc/rpc",[z]:"https://api.dexter.cash/api/base/rpc",[re]:"https://sepolia.base.org",[ne]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[ie]:"https://api.dexter.cash/api/evm/polygon/rpc",[se]:"https://api.dexter.cash/api/evm/optimism/rpc",[oe]:"https://api.dexter.cash/api/evm/avalanche/rpc",[H]:"https://worldchain-mainnet.g.alchemy.com/public",[q]:"https://rpc.monad.xyz",[F]:"https://rpc.mainnet.chain.robinhood.com",[W]:"https://skale-base.skalenodes.com/v1/base",[j]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[ce]:"https://eth.llamarpc.com"},X="https://x402.dexter.cash";function ue(t){return t.startsWith("solana:")||t==="solana"}function Rt(t){if(typeof Buffer<"u")return Buffer.from(t,"utf-8").toString("base64");let e=new TextEncoder().encode(t),r="";for(let n=0;n<e.length;n++)r+=String.fromCharCode(e[n]);return btoa(r)}function Tt(t){if(typeof Buffer<"u")return Buffer.from(t,"base64").toString("utf-8");let e=atob(t),r=new Uint8Array(e.length);for(let n=0;n<e.length;n++)r[n]=e.charCodeAt(n);return new TextDecoder().decode(r)}function me(t){return Rt(JSON.stringify(t))}function J(t){return JSON.parse(Tt(t))}function Pt(t){if(t instanceof TypeError)return!0;if(t&&typeof t=="object"&&"status"in t){let e=t.status;return e>=500&&e<600}return!1}var G=class extends Error{status;body;constructor(e,r){super(`HTTP ${e}`),this.status=e,this.body=r}},de=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(e=X,r){this.facilitatorUrl=e.replace(/\/$/,""),this.timeoutMs=r?.timeoutMs??1e4,this.maxRetries=r?.maxRetries??3,this.retryBaseMs=r?.retryBaseMs??500}async fetchWithTimeout(e,r){let n=new AbortController,i=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(e,{...r,signal:n.signal})}finally{clearTimeout(i)}}async fetchWithRetry(e,r){let n;for(let i=0;i<this.maxRetries;i++)try{let s=await this.fetchWithTimeout(e,r);if(!s.ok&&s.status>=500)throw new G(s.status,await s.text());return s}catch(s){if(n=s,i<this.maxRetries-1&&Pt(s)){let h=this.retryBaseMs*Math.pow(2,i);await new Promise(c=>setTimeout(c,h));continue}throw s}throw n}async getSupported(){let e=Date.now();if(this.cachedSupported&&e-this.cacheTime<this.CACHE_TTL_MS)return this.cachedSupported;let r=await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);if(!r.ok)throw new Error(`Facilitator /supported returned ${r.status}`);return this.cachedSupported=await r.json(),this.cacheTime=e,this.cachedSupported}async getFeePayer(e){let n=(await this.getSupported()).kinds.find(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval")&&i.network===e);if(!n)throw new Error(`Facilitator does not support network "${e}" with a recognized scheme`);return n.extra?.feePayer}async getNetworkExtra(e){return(await this.getSupported()).kinds.find(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval"||i.scheme==="batch-settlement")&&i.network===e)?.extra}async verifyPayment(e,r){try{let n=J(e),i=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return i.ok?await i.json():{isValid:!1,invalidReason:`facilitator_error_${i.status}`}}catch(n){return{isValid:!1,invalidReason:n instanceof G?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_verify_error"}}}async settlePayment(e,r){try{let n=J(e),i=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return i.ok?{...await i.json(),network:r.network}:{success:!1,network:r.network,errorReason:`facilitator_error_${i.status}`}}catch(n){let i=n instanceof G?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_settle_error";return{success:!1,network:r.network,errorReason:i}}}};function _t(t){if(ue(t))return{address:le,decimals:6};let e=Ze[t];if(e){let r=Qe[e]?.decimals??6;return{address:e,decimals:r}}return{address:le,decimals:6}}function et(t){try{let e=J(t);return e?.accepted?.amount??e?.accepted?.maxAmountRequired}catch{return}}function Y(t){let{payTo:e,facilitatorUrl:r=X,network:n=N,defaultTimeoutSeconds:i=60}=t,s=t.asset??_t(n),h=t.scheme??"exact";if(h==="tab"&&!ue(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let c=new de(r),a=null,m=new Map,l=3e4,o=Date.now();function y(u){let g=(u.maxTimeoutSeconds||i)*1e3;if(m.set(u.payTo,{accept:u,expiresAt:Date.now()+g}),Date.now()-o>l){let A=Date.now();for(let[S,I]of m)I.expiresAt<A&&m.delete(S);o=A}}function d(u){let g=m.get(u);if(g){if(g.expiresAt<Date.now()){m.delete(u);return}return g.accept}}async function f(u){return typeof e=="string"?e:e(u||{})}async function b(){if(a||(a=await c.getNetworkExtra(n)),ue(n)&&!a?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${n}"`);return{...a?.feePayer?{feePayer:a.feePayer}:{},decimals:a?.decimals??s.decimals,name:a?.name,version:a?.version,...h==="batch-settlement"&&a?.receiverAuthorizer?{receiverAuthorizer:a.receiverAuthorizer}:{},...h==="tab"?{voucherHeader:"x-tab-voucher",registrationEncoding:"base64(188-byte sessionRegisterMessage)"}:{}}}async function V(u,g){let{amountAtomic:A,timeoutSeconds:S=i}=g,I=await b(),O={scheme:h,network:n,amount:A,maxAmountRequired:A,asset:s.address,payTo:u,maxTimeoutSeconds:S,extra:I};return y(O),O}async function L(u){let g=await f({amountAtomic:u.amountAtomic,resourceUrl:u.resourceUrl});return V(g,u)}async function pe(u){let{resourceUrl:g,description:A,mimeType:S="application/json"}=u,I={url:g,description:A,mimeType:S},O=await L(u);return{x402Version:2,resource:I,accepts:[O],error:"Payment required"}}function B(u){return me(u)}function Z(u){return{status:402,headers:{"PAYMENT-REQUIRED":B(u)},body:{}}}async function ge(u,g){if(!g){let A=await f({paymentHeader:u});g=d(A),g||(g=await V(A,{amountAtomic:et(u)??"0",resourceUrl:""}))}return c.verifyPayment(u,g)}async function Q(u,g){if(!g){let A=await f({paymentHeader:u});g=d(A),g||(g=await V(A,{amountAtomic:et(u)??"0",resourceUrl:""}))}return c.settlePayment(u,g)}return{buildRequirements:pe,encodeRequirements:B,create402Response:Z,verifyPayment:ge,settlePayment:Q,getPaymentAccept:L,network:n,assetDecimals:s.decimals,facilitator:c}}var kt={"solana:mainnet":N};function It(t){let e=kt[t.network];if(!e)throw new Error(`tabChallengeMiddleware: unsupported network "${t.network}"`);let r=typeof t.sellerPubkey=="string"?t.sellerPubkey:t.sellerPubkey.toBase58();new Nt(r);let n=Y({payTo:r,network:e,scheme:"tab",facilitatorUrl:t.facilitatorUrl}),i=R(t.perUnit);return async(s,h,c)=>{if(s.headers[$])return c();try{let a=`${s.protocol}://${s.get("host")}${s.originalUrl}`,m=await n.buildRequirements({amountAtomic:i,resourceUrl:a,description:t.description}),l=n.create402Response(m);h.set(l.headers).status(l.status).json(l.body)}catch(a){let m=a?.message??String(a);h.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:m})}}}import{PublicKey as Ot}from"@solana/web3.js";var Ut={"solana:mainnet":N};function $t(t){let e=Ut[t.network];if(!e)throw new Error(`tabOrExactMiddleware: unsupported network "${t.network}"`);let r=typeof t.sellerPubkey=="string"?t.sellerPubkey:t.sellerPubkey.toBase58();new Ot(r);let n=Y({payTo:r,network:e,scheme:"tab",facilitatorUrl:t.facilitatorUrl}),i=Y({payTo:r,network:e,scheme:"exact",facilitatorUrl:t.facilitatorUrl}),s=R(t.perUnit),h=Oe({connection:t.connection,sellerPubkey:r,network:t.network,perUnit:t.perUnit,settle:"on-close",facilitatorUrl:t.facilitatorUrl,lockCadence:t.lockCadence});return async(c,a,m)=>{if(c.headers[$])return h(c,a,m);let l=`${c.protocol}://${c.get("host")}${c.originalUrl}`,o=c.headers["payment-signature"];if(o){let y;try{y=await i.getPaymentAccept({amountAtomic:s,resourceUrl:l,description:t.description})}catch(d){let f=d?.message??String(d);a.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:f});return}try{let d=await i.verifyPayment(o,y);if(!d.isValid){a.status(402).json({error:"Payment verification failed",reason:d.invalidReason});return}let f=await i.settlePayment(o,y);if(!f.success){a.status(402).json({error:"Payment settlement failed",reason:f.errorReason});return}return c.x402={transaction:f.transaction,payer:d.payer??"",network:f.network||e},a.setHeader("PAYMENT-RESPONSE",me({success:!0,transaction:f.transaction,network:f.network||e,payer:d.payer??""})),m()}catch{a.status(500).json({error:"Payment processing error"});return}}try{let y={amountAtomic:s,resourceUrl:l,description:t.description},[d,f]=await Promise.all([n.buildRequirements(y),i.buildRequirements(y)]),b={...d,accepts:[...d.accepts,...f.accepts]};a.set({"PAYMENT-REQUIRED":n.encodeRequirements(b)}).status(402).json({error:"Payment required",accepts:b.accepts,resource:b.resource})}catch(y){let d=y?.message??String(y);a.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:d})}}}export{fe as FileChannelLedger,Le as FileVoucherStore,D as InMemoryChannelLedger,Ve as InMemoryVoucherStore,E as InvalidRegistrationError,x as InvalidVoucherError,_ as InvalidVoucherSignatureError,k as OnChainVerificationError,ve as RedisChannelLedger,C as ScopeViolationError,$ as TAB_VOUCHER_HEADER,be as deserializeChannelLedgerEntry,Pe as enforceScope,At as openSse,Ee as parseRegistration,ft as requireTab,Ae as serializeChannelLedgerEntry,It as tabChallengeMiddleware,Oe as tabMiddleware,$t as tabOrExactMiddleware,Re as verifyRegistrationOnChain,Te as verifyVoucherSignature};
|
|
6
|
+
`),e.end())}return{charge:d,send:g,end:s}}import{promises as Q}from"fs";import{join as Un,dirname as Kn}from"path";function Dn(e){return{payload:e.payload,sessionPublicKey:tt(e.sessionPublicKey),sessionRegistration:tt(e.sessionRegistration),sessionSignature:tt(e.sessionSignature)}}function $n(e){return{payload:e.payload,sessionPublicKey:nt(e.sessionPublicKey),sessionRegistration:nt(e.sessionRegistration),sessionSignature:nt(e.sessionSignature)}}function tt(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function nt(e){if(e.length%2!==0)throw new Error(`hex length must be even, got ${e.length}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}var rt=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,n){this.map.set(t,n)}async delete(t){this.map.delete(t)}},it=class{constructor(t){this.dir=t}dir;pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return Un(this.dir,`${t}.json`)}async get(t){try{let n=await Q.readFile(this.pathFor(t),"utf8");return $n(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await Q.mkdir(Kn(r),{recursive:!0});let i=`${r}.tmp`;await Q.writeFile(i,JSON.stringify(Dn(n))),await Q.rename(i,r)}async delete(t){try{await Q.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};import{PublicKey as Gn}from"@solana/web3.js";var D="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",It="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",Nt="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var ee="eip155:8453",ve="eip155:84532",Ae="eip155:42161",be="eip155:137",we="eip155:10",_e="eip155:43114",Se="eip155:56",te="eip155:480",ne="eip155:143",re="eip155:4663",ie="eip155:1187947933",oe="eip155:324705682",xe="eip155:1";var Re="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var Ot="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",Mn="0x55d398326f99059fF775485246999027B3197955",kt="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Ln="0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",Bt={[Se]:kt,[ee]:Ot,[ve]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[Ae]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[be]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[we]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[_e]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[te]:"0x79A02482A880bCE3F13e09Da970dC34db4CD24d1",[ne]:"0x754704Bc059F8C67012fEd69BC8A327a5aafb603",[re]:Ln,[ie]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[oe]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[xe]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Ut={[Mn]:{symbol:"USDT",decimals:18},[kt]:{symbol:"USDC",decimals:18}};var ji={[te]:{name:"USDC",version:"2"},[ne]:{name:"USDC",version:"2"},[re]:{name:"Global Dollar",version:"1"},[ie]:{name:"Bridged USDC (SKALE Bridge)",version:"2"},[oe]:{name:"Bridged USDC (SKALE Bridge)",version:"2"}};var Ji={[Se]:56,[ee]:8453,[ve]:84532,[Ae]:42161,[be]:137,[we]:10,[_e]:43114,[te]:480,[ne]:143,[re]:4663,[ie]:1187947933,[oe]:324705682,[xe]:1},Yi={[D]:"https://api.dexter.cash/api/solana/rpc",[It]:"https://api.devnet.solana.com",[Nt]:"https://api.testnet.solana.com"},Fn={[Se]:"https://api.dexter.cash/api/evm/bsc/rpc",[ee]:"https://api.dexter.cash/api/base/rpc",[ve]:"https://sepolia.base.org",[Ae]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[be]:"https://api.dexter.cash/api/evm/polygon/rpc",[we]:"https://api.dexter.cash/api/evm/optimism/rpc",[_e]:"https://api.dexter.cash/api/evm/avalanche/rpc",[te]:"https://worldchain-mainnet.g.alchemy.com/public",[ne]:"https://rpc.monad.xyz",[re]:"https://rpc.mainnet.chain.robinhood.com",[ie]:"https://skale-base.skalenodes.com/v1/base",[oe]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[xe]:"https://eth.llamarpc.com"},se="https://x402.dexter.cash";var Kt="dexter-tab-hosted-pay-before-delivery/v1",Dt="pay_before_delivery_seller_2xx",$t="x-tab-voucher",Mt="base64(188-byte sessionRegisterMessage)";function Ee(e){return e.startsWith("solana:")||e==="solana"}function qn(e){if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");let t=new TextEncoder().encode(e),n="";for(let r=0;r<t.length;r++)n+=String.fromCharCode(t[r]);return btoa(n)}function zn(e){if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");let t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=t.charCodeAt(r);return new TextDecoder().decode(n)}function Ce(e){return qn(JSON.stringify(e))}function ae(e){return JSON.parse(zn(e))}function Hn(e){if(e instanceof TypeError)return!0;if(e&&typeof e=="object"&&"status"in e){let t=e.status;return t>=500&&t<600}return!1}var ce=class extends Error{status;body;constructor(t,n){super(`HTTP ${t}`),this.status=t,this.body=n}},Pe=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=se,n){this.facilitatorUrl=t.replace(/\/$/,""),this.timeoutMs=n?.timeoutMs??1e4,this.maxRetries=n?.maxRetries??3,this.retryBaseMs=n?.retryBaseMs??500}async fetchWithTimeout(t,n){let r=new AbortController,i=setTimeout(()=>r.abort(),this.timeoutMs);try{return await fetch(t,{...n,signal:r.signal})}finally{clearTimeout(i)}}async fetchWithRetry(t,n){let r;for(let i=0;i<this.maxRetries;i++)try{let o=await this.fetchWithTimeout(t,n);if(!o.ok&&o.status>=500)throw new ce(o.status,await o.text());return o}catch(o){if(r=o,i<this.maxRetries-1&&Hn(o)){let c=this.retryBaseMs*Math.pow(2,i);await new Promise(a=>setTimeout(a,c));continue}throw o}throw r}async getSupported(){let t=Date.now();if(this.cachedSupported&&t-this.cacheTime<this.CACHE_TTL_MS)return this.cachedSupported;let n=await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);if(!n.ok)throw new Error(`Facilitator /supported returned ${n.status}`);return this.cachedSupported=await n.json(),this.cacheTime=t,this.cachedSupported}async getFeePayer(t){let r=(await this.getSupported()).kinds.find(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval")&&i.network===t);if(!r)throw new Error(`Facilitator does not support network "${t}" with a recognized scheme`);return r.extra?.feePayer}async getNetworkExtra(t){return(await this.getSupported()).kinds.find(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval"||i.scheme==="batch-settlement")&&i.network===t)?.extra}async verifyPayment(t,n){try{let r=ae(t),i=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:r,paymentRequirements:n})});return i.ok?await i.json():{isValid:!1,invalidReason:`facilitator_error_${i.status}`}}catch(r){return{isValid:!1,invalidReason:r instanceof ce?`facilitator_error_${r.status}`:r instanceof Error&&r.name==="AbortError"?"facilitator_timeout":r instanceof Error?r.message:"unexpected_verify_error"}}}async settlePayment(t,n){try{let r=ae(t),i=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:r,paymentRequirements:n})});return i.ok?{...await i.json(),network:n.network}:{success:!1,network:n.network,errorReason:`facilitator_error_${i.status}`}}catch(r){let i=r instanceof ce?`facilitator_error_${r.status}`:r instanceof Error&&r.name==="AbortError"?"facilitator_timeout":r instanceof Error?r.message:"unexpected_settle_error";return{success:!1,network:n.network,errorReason:i}}}};function Wn(e){if(Ee(e))return{address:Re,decimals:6};let t=Bt[e];if(t){let n=Ut[t]?.decimals??6;return{address:t,decimals:n}}return{address:Re,decimals:6}}function Lt(e){try{let t=ae(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function le(e){let{payTo:t,facilitatorUrl:n=se,network:r=D,defaultTimeoutSeconds:i=60}=e,o=e.asset??Wn(r),c=e.scheme??"exact";if(c==="tab"&&!Ee(r))throw new Error(`scheme 'tab' is SVM-only; got network "${r}"`);let a=new Pe(n),u=null,h=new Map,d=3e4,g=Date.now();function s(f){let p=(f.maxTimeoutSeconds||i)*1e3;if(h.set(f.payTo,{accept:f,expiresAt:Date.now()+p}),Date.now()-g>d){let b=Date.now();for(let[F,$]of h)$.expiresAt<b&&h.delete(F);g=b}}function y(f){let p=h.get(f);if(p){if(p.expiresAt<Date.now()){h.delete(f);return}return p.accept}}async function l(f){return typeof t=="string"?t:t(f||{})}async function A(){if(u||(u=await a.getNetworkExtra(r)),Ee(r)&&!u?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${r}"`);return{...u?.feePayer?{feePayer:u.feePayer}:{},decimals:u?.decimals??o.decimals,name:u?.name,version:u?.version,...c==="batch-settlement"&&u?.receiverAuthorizer?{receiverAuthorizer:u.receiverAuthorizer}:{},...c==="tab"?{voucherHeader:$t,registrationEncoding:Mt,termsVersion:Kt,acceptanceRule:Dt}:{}}}async function R(f,p){let{amountAtomic:b,timeoutSeconds:F=i}=p,$=await A(),q={scheme:c,network:r,amount:b,maxAmountRequired:b,asset:o.address,payTo:f,maxTimeoutSeconds:F,extra:$};return s(q),q}async function V(f){let p=await l({amountAtomic:f.amountAtomic,resourceUrl:f.resourceUrl});return R(p,f)}async function T(f){let{resourceUrl:p,description:b,mimeType:F="application/json"}=f,$={url:p,description:b,mimeType:F},q=await V(f);return{x402Version:2,resource:$,accepts:[q],error:"Payment required"}}function L(f){return Ce(f)}function K(f){return{status:402,headers:{"PAYMENT-REQUIRED":L(f)},body:{}}}async function I(f,p){if(!p){let b=await l({paymentHeader:f});p=y(b),p||(p=await R(b,{amountAtomic:Lt(f)??"0",resourceUrl:""}))}return a.verifyPayment(f,p)}async function Ve(f,p){if(!p){let b=await l({paymentHeader:f});p=y(b),p||(p=await R(b,{amountAtomic:Lt(f)??"0",resourceUrl:""}))}return a.settlePayment(f,p)}return{buildRequirements:T,encodeRequirements:L,create402Response:K,verifyPayment:I,settlePayment:Ve,getPaymentAccept:V,network:r,assetDecimals:o.decimals,facilitator:a}}var Xn={"solana:mainnet":D};function jn(e){let t=Xn[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let n=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new Gn(n);let r=le({payTo:n,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),i=k(e.perUnit);return async(o,c,a)=>{if(o.headers[W])return a();try{let u=`${o.protocol}://${o.get("host")}${o.originalUrl}`,h=await r.buildRequirements({amountAtomic:i,resourceUrl:u,description:e.description}),d=r.create402Response(h);c.set(d.headers).status(d.status).json(d.body)}catch(u){let h=u?.message??String(u);c.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:h})}}}import{PublicKey as Jn}from"@solana/web3.js";var Yn={"solana:mainnet":D};function Zn(e){let t=Yn[e.network];if(!t)throw new Error(`tabOrExactMiddleware: unsupported network "${e.network}"`);let n=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new Jn(n);let r=le({payTo:n,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),i=le({payTo:n,network:t,scheme:"exact",facilitatorUrl:e.facilitatorUrl}),o=k(e.perUnit),c=et({connection:e.connection,sellerPubkey:n,network:e.network,perUnit:e.perUnit,settle:"on-close",facilitatorUrl:e.facilitatorUrl,lockCadence:e.lockCadence});return async(a,u,h)=>{if(a.headers[W])return c(a,u,h);let d=`${a.protocol}://${a.get("host")}${a.originalUrl}`,g=a.headers["payment-signature"];if(g){let s;try{s=await i.getPaymentAccept({amountAtomic:o,resourceUrl:d,description:e.description})}catch(y){let l=y?.message??String(y);u.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:l});return}try{let y=await i.verifyPayment(g,s);if(!y.isValid){u.status(402).json({error:"Payment verification failed",reason:y.invalidReason});return}let l=await i.settlePayment(g,s);if(!l.success){u.status(402).json({error:"Payment settlement failed",reason:l.errorReason});return}return a.x402={transaction:l.transaction,payer:y.payer??"",network:l.network||t},u.setHeader("PAYMENT-RESPONSE",Ce({success:!0,transaction:l.transaction,network:l.network||t,payer:y.payer??""})),h()}catch{u.status(500).json({error:"Payment processing error"});return}}try{let s={amountAtomic:o,resourceUrl:d,description:e.description},[y,l]=await Promise.all([r.buildRequirements(s),i.buildRequirements(s)]),A={...y,accepts:[...y.accepts,...l.accepts]};u.set({"PAYMENT-REQUIRED":r.encodeRequirements(A)}).status(402).json({error:"Payment required",accepts:A.accepts,resource:A.resource})}catch(s){let y=s?.message??String(s);u.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:y})}}}export{Oe as FileChannelLedger,it as FileVoucherStore,Y as InMemoryChannelLedger,rt as InMemoryVoucherStore,U as InvalidRegistrationError,w as InvalidVoucherError,N as InvalidVoucherSignatureError,C as OnChainVerificationError,Ue as RedisChannelLedger,O as ScopeViolationError,W as TAB_VOUCHER_HEADER,Be as deserializeChannelLedgerEntry,Le as enforceScope,Bn as openSse,de as parseRegistration,kn as requireTab,ke as serializeChannelLedgerEntry,jn as tabChallengeMiddleware,et as tabMiddleware,Zn as tabOrExactMiddleware,pe as verifyRegistrationOnChain,Me as verifyVoucherSignature};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClientChannelStorage } from '@x402/evm/batch-settlement/client';
|
|
2
|
-
import {
|
|
2
|
+
import { a as EvmWallet } from './types-BvQpNtFw.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Buyer withdrawal escape hatch for batch-settlement escrow channels.
|
|
@@ -162,4 +162,4 @@ declare class UnsupportedNetworkError extends Error {
|
|
|
162
162
|
constructor(message: string);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
export { type BatchSettlementChannel as B, type ChannelStore as C, type
|
|
165
|
+
export { type BatchSettlementChannel as B, type ChannelStore as C, type FinalizeWithdrawResult as F, InsufficientBalanceError as I, type OpenBatchChannelOptions as O, type ResumeBatchChannelOptions as R, UnsupportedNetworkError as U, WithdrawNotReadyError as W, type ChannelState as a, type CloseReceipt as b, type CloseResult as c, type ForceWithdrawResult as d };
|
|
@@ -72,6 +72,14 @@ interface AcceptsExtra {
|
|
|
72
72
|
* Provided by the facilitator's batch-settlement kind. EVM only.
|
|
73
73
|
*/
|
|
74
74
|
receiverAuthorizer?: string;
|
|
75
|
+
/** Tab seller-wire header advertised by the default hosted scheme. */
|
|
76
|
+
voucherHeader?: string;
|
|
77
|
+
/** Tab registration encoding carried inside each seller voucher. */
|
|
78
|
+
registrationEncoding?: string;
|
|
79
|
+
/** Immutable commercial-terms version for this Tab offer. */
|
|
80
|
+
termsVersion?: string;
|
|
81
|
+
/** Event that makes usage accepted under the advertised terms version. */
|
|
82
|
+
acceptanceRule?: string;
|
|
75
83
|
/** Additional chain-specific fields */
|
|
76
84
|
[key: string]: unknown;
|
|
77
85
|
}
|
|
@@ -637,4 +645,4 @@ interface BalanceInfo {
|
|
|
637
645
|
asset: string;
|
|
638
646
|
}
|
|
639
647
|
|
|
640
|
-
export { type
|
|
648
|
+
export { type AdapterConfig as A, type BalanceInfo as B, type ChainAdapter as C, EvmAdapter as E, type GenericWallet as G, type PaymentAccept as P, SolanaAdapter as S, type VerifyResponse as V, type WalletSet as W, X402Error as X, type EvmWallet as a, type SignedTransaction as b, type SolanaWallet as c, createEvmAdapter as d, createSolanaAdapter as e, isSolanaWallet as f, type SettlementProbe as g, type AccessPassClientConfig as h, isEvmWallet as i, type AccessPassInfo as j, type AccessPassTier as k, type SettleResponse as l, type PaymentRequired as m, type PayToProvider as n, type AccessPassClaims as o, type PayToContext as p, type PayToProviderDefaults as q };
|
|
@@ -72,6 +72,14 @@ interface AcceptsExtra {
|
|
|
72
72
|
* Provided by the facilitator's batch-settlement kind. EVM only.
|
|
73
73
|
*/
|
|
74
74
|
receiverAuthorizer?: string;
|
|
75
|
+
/** Tab seller-wire header advertised by the default hosted scheme. */
|
|
76
|
+
voucherHeader?: string;
|
|
77
|
+
/** Tab registration encoding carried inside each seller voucher. */
|
|
78
|
+
registrationEncoding?: string;
|
|
79
|
+
/** Immutable commercial-terms version for this Tab offer. */
|
|
80
|
+
termsVersion?: string;
|
|
81
|
+
/** Event that makes usage accepted under the advertised terms version. */
|
|
82
|
+
acceptanceRule?: string;
|
|
75
83
|
/** Additional chain-specific fields */
|
|
76
84
|
[key: string]: unknown;
|
|
77
85
|
}
|
|
@@ -637,4 +645,4 @@ interface BalanceInfo {
|
|
|
637
645
|
asset: string;
|
|
638
646
|
}
|
|
639
647
|
|
|
640
|
-
export { type
|
|
648
|
+
export { type AdapterConfig as A, type BalanceInfo as B, type ChainAdapter as C, EvmAdapter as E, type GenericWallet as G, type PaymentAccept as P, SolanaAdapter as S, type VerifyResponse as V, type WalletSet as W, X402Error as X, type EvmWallet as a, type SignedTransaction as b, type SolanaWallet as c, createEvmAdapter as d, createSolanaAdapter as e, isSolanaWallet as f, type SettlementProbe as g, type AccessPassClientConfig as h, isEvmWallet as i, type AccessPassInfo as j, type AccessPassTier as k, type SettleResponse as l, type PaymentRequired as m, type PayToProvider as n, type AccessPassClaims as o, type PayToContext as p, type PayToProviderDefaults as q };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
2
|
import { ChannelStorage } from '@x402/evm/batch-settlement/server';
|
|
3
|
-
import { b as CloseReceipt } from './types-
|
|
3
|
+
import { b as CloseReceipt } from './types-DwVhPqOZ.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Result of closing one channel from the seller side. Either a settlement
|
|
@@ -57,4 +57,4 @@ interface BatchSettlementSeller extends RequestHandler {
|
|
|
57
57
|
stop(): Promise<void>;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export type {
|
|
60
|
+
export type { BatchSettlementSellerConfig as B, SellerCloseResult as S, BatchSettlementSeller as a };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WalletSet } from './types-
|
|
2
|
-
import { T as Tab } from './types-
|
|
1
|
+
import { W as WalletSet } from './types-BvQpNtFw.js';
|
|
2
|
+
import { T as Tab } from './types-OHNNM1J2.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shared contract for the x402 version seam. Both the v1 and v2 strategy
|
|
@@ -151,4 +151,4 @@ interface PaymentStrategy {
|
|
|
151
151
|
pay(url: string, requestInit: RequestInit, challenge: PaymentChallenge, wallets: WalletSet, opts: PayAndFetchOptions): Promise<PayResult>;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export type { ChallengeOption as C, NetworkRef as N,
|
|
154
|
+
export type { ChallengeOption as C, NetworkRef as N, PaymentStrategy as P, PayAndFetchOptions as a, PayResult as b, PaymentChallenge as c };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WalletSet } from './types-
|
|
2
|
-
import { T as Tab } from './types-
|
|
1
|
+
import { W as WalletSet } from './types-BvQpNtFw.cjs';
|
|
2
|
+
import { T as Tab } from './types-OHNNM1J2.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shared contract for the x402 version seam. Both the v1 and v2 strategy
|
|
@@ -151,4 +151,4 @@ interface PaymentStrategy {
|
|
|
151
151
|
pay(url: string, requestInit: RequestInit, challenge: PaymentChallenge, wallets: WalletSet, opts: PayAndFetchOptions): Promise<PayResult>;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export type { ChallengeOption as C, NetworkRef as N,
|
|
154
|
+
export type { ChallengeOption as C, NetworkRef as N, PaymentStrategy as P, PayAndFetchOptions as a, PayResult as b, PaymentChallenge as c };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClientChannelStorage } from '@x402/evm/batch-settlement/client';
|
|
2
|
-
import {
|
|
2
|
+
import { a as EvmWallet } from './types-BvQpNtFw.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Buyer withdrawal escape hatch for batch-settlement escrow channels.
|
|
@@ -162,4 +162,4 @@ declare class UnsupportedNetworkError extends Error {
|
|
|
162
162
|
constructor(message: string);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
export { type BatchSettlementChannel as B, type ChannelStore as C, type
|
|
165
|
+
export { type BatchSettlementChannel as B, type ChannelStore as C, type FinalizeWithdrawResult as F, InsufficientBalanceError as I, type OpenBatchChannelOptions as O, type ResumeBatchChannelOptions as R, UnsupportedNetworkError as U, WithdrawNotReadyError as W, type ChannelState as a, type CloseReceipt as b, type CloseResult as c, type ForceWithdrawResult as d };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
2
|
import { ChannelStorage } from '@x402/evm/batch-settlement/server';
|
|
3
|
-
import { b as CloseReceipt } from './types-
|
|
3
|
+
import { b as CloseReceipt } from './types-BbvuPNXl.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Result of closing one channel from the seller side. Either a settlement
|
|
@@ -57,4 +57,4 @@ interface BatchSettlementSeller extends RequestHandler {
|
|
|
57
57
|
stop(): Promise<void>;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export type {
|
|
60
|
+
export type { BatchSettlementSellerConfig as B, SellerCloseResult as S, BatchSettlementSeller as a };
|
|
@@ -25,10 +25,17 @@ interface VaultAdapter {
|
|
|
25
25
|
swigAddress: string;
|
|
26
26
|
/** Program/contract account holding the OTS gate state. */
|
|
27
27
|
vaultPda: string;
|
|
28
|
+
/**
|
|
29
|
+
* Voucher generation this adapter issues. V6 requires `2` for buyer-side
|
|
30
|
+
* open/recovery. The `1` discriminator remains only so a historical adapter
|
|
31
|
+
* is rejected explicitly instead of being mistaken for V2 or silently
|
|
32
|
+
* falling through after an obligation may exist.
|
|
33
|
+
*/
|
|
34
|
+
readonly sessionVoucherVersion: 1 | 2;
|
|
28
35
|
/**
|
|
29
36
|
* Use the ROOT signer (passkey) to authorize a fresh session key. This is
|
|
30
|
-
* the only call that prompts the user
|
|
31
|
-
*
|
|
37
|
+
* the only call that prompts the user. V7 live replacement binds retirement
|
|
38
|
+
* and replacement into one ceremony. Returns a
|
|
32
39
|
* session that can be passed to `signWithSession` freely until the scope's
|
|
33
40
|
* cap or expiry is reached.
|
|
34
41
|
*
|
|
@@ -54,7 +61,90 @@ interface VaultAdapter {
|
|
|
54
61
|
* facilitator settles via `settle_voucher(amount, increment: false)`.
|
|
55
62
|
*/
|
|
56
63
|
signCloseTab(session: SessionKey, channelId: string, cumulativeAmount: AtomicAmount): Promise<Uint8Array>;
|
|
64
|
+
/**
|
|
65
|
+
* V2-only independent postcondition check. The reservation provider returns
|
|
66
|
+
* a voucher-bound receipt; the adapter must then prove the corresponding
|
|
67
|
+
* finalized on-chain reservation and authority-signed voucher-binding Memo
|
|
68
|
+
* from its own chain connection before the voucher may leave this process.
|
|
69
|
+
* V1 adapters omit this method.
|
|
70
|
+
*/
|
|
71
|
+
verifyFinalVoucherV2Reservation?: VerifyFinalVoucherV2Reservation;
|
|
72
|
+
}
|
|
73
|
+
/** Exact durable release fence for a buyer-signed FINAL V2 voucher. */
|
|
74
|
+
interface FinalVoucherV2ReservationInput {
|
|
75
|
+
network: TabNetworkId;
|
|
76
|
+
programId: string;
|
|
77
|
+
buyerSwigAddress: string;
|
|
78
|
+
vaultPda: string;
|
|
79
|
+
sessionPda: string;
|
|
80
|
+
seller: string;
|
|
81
|
+
channelId: string;
|
|
82
|
+
sessionNonce: number;
|
|
83
|
+
reservationAmountAtomic: AtomicAmount;
|
|
84
|
+
previousCumulativeAtomic: AtomicAmount;
|
|
85
|
+
/** SHA-256 of the canonical complete voucher identity. */
|
|
86
|
+
voucherDigest: string;
|
|
87
|
+
/** SDK retry identity. Exact-byte retries retain this value; provider
|
|
88
|
+
* lifecycle and receipt identities remain provider-owned and distinct. */
|
|
89
|
+
idempotencyKey: string;
|
|
90
|
+
voucher: SignedVoucher;
|
|
57
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Provider attestation returned only after its durable transaction lifecycle
|
|
94
|
+
* has finalized the exact reservation and read back the exact post-state.
|
|
95
|
+
* The SDK validates every voucher/session field and the VaultAdapter proves
|
|
96
|
+
* both the reservation and its authority-signed voucher-binding Memo from the
|
|
97
|
+
* transaction itself; this is deliberately not a boolean ack.
|
|
98
|
+
*/
|
|
99
|
+
interface FinalVoucherV2ReservationReceipt {
|
|
100
|
+
contract: 'dexter-native-tab-open-receipt/v1' | 'dexter-native-tab-open-receipt/v2';
|
|
101
|
+
operationId: string;
|
|
102
|
+
callerOperationId: string;
|
|
103
|
+
network: string;
|
|
104
|
+
transaction: string;
|
|
105
|
+
/** FINAL vouchers are released only after the exact reservation transaction
|
|
106
|
+
* reaches Solana finalized commitment. A merely confirmed fork is not a
|
|
107
|
+
* durable capacity guarantee. */
|
|
108
|
+
commitment: 'finalized';
|
|
109
|
+
confirmationSlot: number;
|
|
110
|
+
postStateSlot: number;
|
|
111
|
+
buyerSwigAddress: string;
|
|
112
|
+
vaultPda: string;
|
|
113
|
+
sessionPda: string;
|
|
114
|
+
seller: string;
|
|
115
|
+
channelId: string;
|
|
116
|
+
sessionPublicKey: string;
|
|
117
|
+
voucherDigest: string;
|
|
118
|
+
cumulativeAmountAtomic: string;
|
|
119
|
+
sequenceNumber: number;
|
|
120
|
+
providerReceiptId: string;
|
|
121
|
+
reservationAmountAtomic: string;
|
|
122
|
+
pendingVoucherCountBefore: number;
|
|
123
|
+
pendingVoucherCountAfter: number;
|
|
124
|
+
currentOutstandingBeforeAtomic: '0';
|
|
125
|
+
currentOutstandingAfterAtomic: string;
|
|
126
|
+
rootOperationId?: string;
|
|
127
|
+
generation?: number;
|
|
128
|
+
predecessorCallerOperationId?: string;
|
|
129
|
+
predecessorLifecycleOperationId?: string;
|
|
130
|
+
predecessorReleaseDigest?: string;
|
|
131
|
+
stableReservationId?: string;
|
|
132
|
+
economicEffectDigest?: string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Voucher released by a live Tab handle. Historical V1 vouchers omit the
|
|
136
|
+
* receipt. Every V2 voucher carries the complete provider receipt that the
|
|
137
|
+
* buyer already verified before release; sellers still treat that receipt as
|
|
138
|
+
* untrusted evidence and independently prove its finalized transaction.
|
|
139
|
+
*
|
|
140
|
+
* This extends the existing SignedVoucher shape so existing callers that only
|
|
141
|
+
* consume the four signed fields remain source-compatible.
|
|
142
|
+
*/
|
|
143
|
+
interface TabSignedVoucher extends SignedVoucher {
|
|
144
|
+
readonly reservationReceipt?: FinalVoucherV2ReservationReceipt;
|
|
145
|
+
}
|
|
146
|
+
type ReserveFinalVoucherV2 = (input: FinalVoucherV2ReservationInput) => Promise<FinalVoucherV2ReservationReceipt>;
|
|
147
|
+
type VerifyFinalVoucherV2Reservation = (input: FinalVoucherV2ReservationInput, receipt: FinalVoucherV2ReservationReceipt) => Promise<void>;
|
|
58
148
|
/**
|
|
59
149
|
* Live-session policy for `authorizeSession` / `openTab` (K-T4e).
|
|
60
150
|
*
|
|
@@ -69,8 +159,7 @@ interface VaultAdapter {
|
|
|
69
159
|
* (`tab.close()` — or POST its last signed voucher to `/tab/settle`) and
|
|
70
160
|
* retries, or acknowledges the replace explicitly.
|
|
71
161
|
* - `'replace'`: compose the ATOMIC same-transaction
|
|
72
|
-
* [secp(
|
|
73
|
-
* left sessionless mid-flow. Costs a second passkey ceremony. Value
|
|
162
|
+
* [secp(replace), replace] so the buyer is never left sessionless. Value
|
|
74
163
|
* already settled or crystallized into LockedClaims survives the replace;
|
|
75
164
|
* anything signed beyond the frontier is voided.
|
|
76
165
|
*/
|
|
@@ -106,6 +195,14 @@ interface TabState {
|
|
|
106
195
|
interface Tab {
|
|
107
196
|
/** Deterministic channel id derived from buyer/seller/scope/salt. */
|
|
108
197
|
readonly channelId: string;
|
|
198
|
+
/**
|
|
199
|
+
* Voucher contract used by this live handle. V2 FINAL vouchers are fenced
|
|
200
|
+
* by a durable reservation and therefore may never fall through to another
|
|
201
|
+
* payment rail after an indeterminate signing/reservation error.
|
|
202
|
+
*
|
|
203
|
+
* Required in v6. An absent generation is not safely equivalent to V1.
|
|
204
|
+
*/
|
|
205
|
+
readonly voucherVersion: 1 | 2;
|
|
109
206
|
/** Which network the underlying vault lives on. */
|
|
110
207
|
readonly network: TabNetworkId;
|
|
111
208
|
/**
|
|
@@ -124,7 +221,7 @@ interface Tab {
|
|
|
124
221
|
* Same counter, same scope enforcement as stream() — throws
|
|
125
222
|
* SessionScopeExceededError past the cap.
|
|
126
223
|
*/
|
|
127
|
-
signNextVoucher(incrementAtomic: AtomicAmount): Promise<
|
|
224
|
+
signNextVoucher(incrementAtomic: AtomicAmount): Promise<TabSignedVoucher>;
|
|
128
225
|
/**
|
|
129
226
|
* Streamed paid request. Returns an async iterable of chunks. Voucher
|
|
130
227
|
* signing is internal: the seller demands a fresh session-signed voucher
|
|
@@ -179,7 +276,7 @@ interface OpenTabOptions {
|
|
|
179
276
|
vault: VaultAdapter;
|
|
180
277
|
/** CAIP-2-style network the vault lives on; cross-checked against vault.network. */
|
|
181
278
|
network: TabNetworkId;
|
|
182
|
-
/** Seller's
|
|
279
|
+
/** Seller's base58 Solana public key for the counterparty binding. */
|
|
183
280
|
seller: string;
|
|
184
281
|
/** Max amount per voucher — caps how aggressive a single charge can be. */
|
|
185
282
|
perUnitCap: HumanAmount;
|
|
@@ -203,6 +300,12 @@ interface OpenTabOptions {
|
|
|
203
300
|
* See {@link AuthorizeSessionOptions}.
|
|
204
301
|
*/
|
|
205
302
|
onLiveSession?: 'error' | 'replace';
|
|
303
|
+
/**
|
|
304
|
+
* Required by V2-capable adapters. The callback must durably persist and
|
|
305
|
+
* establish the exact FINAL voucher reservation before resolving. It must
|
|
306
|
+
* be idempotent for identical voucher bytes; a timeout is retried exactly.
|
|
307
|
+
*/
|
|
308
|
+
reserveFinalVoucherV2?: ReserveFinalVoucherV2;
|
|
206
309
|
}
|
|
207
310
|
/**
|
|
208
311
|
* Options for `resumeTab` — open a handle to a tab that was opened by a
|
|
@@ -227,6 +330,18 @@ declare class UnsupportedNetworkError extends Error {
|
|
|
227
330
|
readonly network: string;
|
|
228
331
|
constructor(network: string);
|
|
229
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Thrown before buyer-side I/O when v6 is asked to open or reconstruct a
|
|
335
|
+
* historical V1 tab. The coupled v6 facilitator has no compatible V1 arming
|
|
336
|
+
* endpoint and the Vault-wide pending counter cannot prove which historical
|
|
337
|
+
* session owns an existing reservation. Seller-side verification of already
|
|
338
|
+
* issued V1 vouchers remains available so those obligations can be settled.
|
|
339
|
+
*/
|
|
340
|
+
declare class HistoricalV1MigrationRequiredError extends Error {
|
|
341
|
+
readonly surface: 'armTabOpen' | 'openTab' | 'tabFromGrant';
|
|
342
|
+
readonly code = "native_tab_v1_migration_required";
|
|
343
|
+
constructor(surface: 'armTabOpen' | 'openTab' | 'tabFromGrant');
|
|
344
|
+
}
|
|
230
345
|
/** Thrown by a buyer call when the session-key cap or expiry would be exceeded. */
|
|
231
346
|
declare class SessionScopeExceededError extends Error {
|
|
232
347
|
readonly reason: 'cap_exceeded' | 'expired' | 'wrong_counterparty';
|
|
@@ -277,4 +392,4 @@ declare class LiveSessionExistsError extends Error {
|
|
|
277
392
|
constructor(details: LiveSessionDetails);
|
|
278
393
|
}
|
|
279
394
|
|
|
280
|
-
export { type AuthorizeSessionOptions as A, type LiveSessionDetails as L, type OpenTabOptions as O, type ResumeTabOptions as R, SessionScopeExceededError as S, type Tab as T, UnsupportedNetworkError as U, type
|
|
395
|
+
export { type AuthorizeSessionOptions as A, type FinalVoucherV2ReservationInput as F, HistoricalV1MigrationRequiredError as H, type LiveSessionDetails as L, type OpenTabOptions as O, type ResumeTabOptions as R, SessionScopeExceededError as S, type Tab as T, UnsupportedNetworkError as U, type VerifyFinalVoucherV2Reservation as V, type FinalVoucherV2ReservationReceipt as a, type VaultAdapter as b, LiveSessionExistsError as c, type TabSignedVoucher as d, type ReserveFinalVoucherV2 as e, type TabCloseResult as f, TabClosedError as g, type TabState as h };
|