@dexterai/x402 3.14.0 → 3.16.0
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 +44 -1
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +3 -152
- package/dist/client/index.d.ts +3 -152
- package/dist/client/index.js +1 -1
- package/dist/tab/adapters/solana/index.cjs +1 -1
- package/dist/tab/adapters/solana/index.d.cts +4 -0
- package/dist/tab/adapters/solana/index.d.ts +4 -0
- package/dist/tab/adapters/solana/index.js +1 -1
- package/dist/tab/index.cjs +5 -5
- package/dist/tab/index.d.cts +78 -3
- package/dist/tab/index.d.ts +78 -3
- package/dist/tab/index.js +5 -5
- package/dist/tab/seller/index.cjs +4 -4
- package/dist/tab/seller/index.d.cts +42 -25
- package/dist/tab/seller/index.d.ts +42 -25
- package/dist/tab/seller/index.js +4 -4
- package/dist/types-B1wGPP7B.d.cts +154 -0
- package/dist/types-ZjcxOAbW.d.ts +154 -0
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var te=Object.create;var P=Object.defineProperty;var ne=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var oe=Object.getPrototypeOf,ie=Object.prototype.hasOwnProperty;var se=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},L=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of re(t))!ie.call(e,o)&&o!==n&&P(e,o,{get:()=>t[o],enumerable:!(r=ne(t,o))||r.enumerable});return e};var j=(e,t,n)=>(n=e!=null?te(oe(e)):{},L(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),ae=e=>L(P({},"__esModule",{value:!0}),e);var Se={};se(Se,{FileVoucherStore:()=>C,InMemoryVoucherStore:()=>A,InvalidRegistrationError:()=>d,InvalidVoucherError:()=>m,InvalidVoucherSignatureError:()=>h,OnChainVerificationError:()=>y,ScopeViolationError:()=>c,TAB_VOUCHER_HEADER:()=>R,enforceScope:()=>_,openSse:()=>Q,parseRegistration:()=>I,readVaultState:()=>N,requireTab:()=>Z,tabMiddleware:()=>Y,verifyRegistrationOnChain:()=>V,verifyVoucherSignature:()=>k});module.exports=ae(Se);var m=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};var X=require("@solana/web3.js");var G=j(require("tweetnacl"),1),ce=require("@noble/hashes/sha256"),le=require("@noble/curves/p256"),T=require("@solana/web3.js");var w=require("@dexterai/vault/messages");var K=require("@dexterai/vault/instructions"),ue=require("@dexterai/vault/precompile"),b=require("@dexterai/vault/constants");var O="OTS_SESSION_REGISTER_V2",d=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function I(e){if(e.length!==188)throw new d("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,O.length));if(t!==O)throw new d("wrong_domain",`got "${t}"`);for(let a=O.length;a<32;a++)if(e[a]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${a}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new T.PublicKey(e.slice(32,64)),o=new T.PublicKey(e.slice(64,96)),l=e.slice(96,128),p=n.getBigUint64(128,!0),f=n.getBigInt64(136,!0),i=new T.PublicKey(e.slice(144,176)),u=n.getUint32(176,!0),g=n.getBigUint64(180,!0);if(!r.equals(b.DEXTER_VAULT_PROGRAM_ID))throw new d("wrong_program",`${r.toBase58()} is not ${b.DEXTER_VAULT_PROGRAM_ID.toBase58()}`);if(p===0n)throw new d("cap_zero");let s=BigInt(Math.floor(Date.now()/1e3));if(f<=s)throw new d("expiry_in_past",`expires_at=${f}, now=${s}`);return{programId:r,vaultPda:o,sessionPubkey:new Uint8Array(l),maxAmount:p,expiresAt:f,allowedCounterparty:i,nonce:u,maxRevolvingCapacity:g}}var F=10,y=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function N(e,t){let n=await e.getAccountInfo(t,"finalized");if(!n)throw new y("vault_not_found",t.toBase58());if(!n.owner.equals(b.DEXTER_VAULT_PROGRAM_ID))throw new y("wrong_program",`owner ${n.owner.toBase58()} is not the vault program`);let r=n.data,o=new Uint8Array(r.slice(F,F+33)),u=84+(r[83]===1?48:0)+32+32;if(r[u]!==1)return{passkeyPubkey:o,activeSessionPubkey:null};let s=u+1,a=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:o,activeSessionPubkey:a}}async function V(e,t){let n=await N(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new y("session_not_active","vault has no active_session \u2014 was it revoked?");if(!me(n.activeSessionPubkey,t.sessionPubkey))throw new y("session_pubkey_mismatch",`on-chain ${J(n.activeSessionPubkey)} != registration ${J(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var h=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function k(e,t){if(t.length!==32)throw new h(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new h(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new h(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=(0,w.voucherPayloadMessage)({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!G.default.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new h("ed25519 verify rejected")}var c=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function _(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new c("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new c("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new c("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new c("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function me(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 J(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}var S=require("fs"),U=require("path");function de(e){return{payload:e.payload,sessionPublicKey:H(e.sessionPublicKey),sessionRegistration:H(e.sessionRegistration),sessionSignature:H(e.sessionSignature)}}function pe(e){return{payload:e.payload,sessionPublicKey:B(e.sessionPublicKey),sessionRegistration:B(e.sessionRegistration),sessionSignature:B(e.sessionSignature)}}function H(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function B(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 A=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)}},C=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return(0,U.join)(this.dir,`${t}.json`)}async get(t){try{let n=await S.promises.readFile(this.pathFor(t),"utf8");return pe(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await S.promises.mkdir((0,U.dirname)(r),{recursive:!0});let o=`${r}.tmp`;await S.promises.writeFile(o,JSON.stringify(de(n))),await S.promises.rename(o,r)}async delete(t){try{await S.promises.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};var ye=require("@solana/web3.js"),fe=require("@noble/hashes/utils");var ge=j(require("tweetnacl"),1);var he=require("@noble/hashes/sha256");var W=6;function v(e,t=W){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 o=r.padEnd(t,"0"),l=`${n}${o}`.replace(/^0+(?=\d)/,"");return l===""?"0":l}function x(e,t=W){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",o=n.slice(-t).replace(/0+$/,"");return o?`${r}.${o}`:r}var R="x-tab-voucher",M=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)}},q=class{constructor(t,n,r,o){this.chargeImpl=o;this.channelId=t,this.network=n,this.cumulativeAtomic=r}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return x(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function we(e){if(typeof e!="string"||e.length===0)throw new m("signature_invalid",`missing ${R} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new m("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new m("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new m("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:$(n.sessionPublicKey),sessionRegistration:$(n.sessionRegistration),sessionSignature:$(n.sessionSignature)}}function $(e){if(typeof e!="string"||e.length%2!==0)throw new m("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 be(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new m("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return $(e)}function Y(e){let t=e.store??new A,n=new M,r=typeof e.sellerPubkey=="string"?new X.PublicKey(e.sellerPubkey):e.sellerPubkey,o=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(v(e.perUnit))*100n;return async(l,p,f)=>{try{let i=we(l.headers[R]),u=i.payload.channelId,g=be(u),s=n.get(u);if(!s){let E=I(i.sessionRegistration);await V(e.connection,E),s={registration:E,lastCumulativeAtomic:"0"},n.set(u,s)}k(i,g),_({registration:s.registration,voucher:i,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let a=BigInt(i.payload.cumulativeAmount),ee=BigInt(s.lastCumulativeAtomic),D=a-ee;if(D>o)throw new c("cumulative_exceeds_cap",`single voucher increment ${D} exceeds maxPerVoucherAtomic ${o}`);await t.set(u,i),n.update(u,i.payload.cumulativeAmount);let z=new q(u,e.network,a,async E=>{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.")});z.setSessionPublicKey(i.sessionPublicKey),l.tab=z,f()}catch(i){if(i instanceof m||i instanceof d||i instanceof y||i instanceof h||i instanceof c){p.status(402).json({error:"invalid_voucher",reason:i.reason??"unknown",detail:i.message});return}f(i)}}}function Z(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Q(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(v(n.cumulative())),o=t.perUnit?BigInt(v(t.perUnit)):null,l=0n,p=!1;function f(g=1){if(p)return Promise.reject(new Error("meter ended"));if(o===null)return Promise.reject(new Error("charge() needs options.perUnit"));let s=o*BigInt(g),a=l+s;return a>r?Promise.reject(new c("cumulative_exceeds_cap",`chunk would push request total to ${x(a.toString())} beyond voucher-authorized budget ${x(r.toString())}`)):(l=a,Promise.resolve())}function i(g){if(p)throw new Error("meter ended");let a=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${a}
|
|
1
|
+
"use strict";var Me=Object.create;var M=Object.defineProperty;var He=Object.getOwnPropertyDescriptor;var qe=Object.getOwnPropertyNames;var Le=Object.getPrototypeOf,We=Object.prototype.hasOwnProperty;var Fe=(e,t)=>{for(var r in t)M(e,r,{get:t[r],enumerable:!0})},fe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of qe(t))!We.call(e,s)&&s!==r&&M(e,s,{get:()=>t[s],enumerable:!(n=He(t,s))||n.enumerable});return e};var ye=(e,t,r)=>(r=e!=null?Me(Le(e)):{},fe(t||!e||!e.__esModule?M(r,"default",{value:e,enumerable:!0}):r,e)),je=e=>fe(M({},"__esModule",{value:!0}),e);var pt={};Fe(pt,{FileVoucherStore:()=>X,InMemoryVoucherStore:()=>R,InvalidRegistrationError:()=>A,InvalidVoucherError:()=>y,InvalidVoucherSignatureError:()=>b,OnChainVerificationError:()=>S,ScopeViolationError:()=>f,TAB_VOUCHER_HEADER:()=>C,enforceScope:()=>j,openSse:()=>Ee,parseRegistration:()=>L,requireTab:()=>ve,tabChallengeMiddleware:()=>ke,tabMiddleware:()=>xe,verifyRegistrationOnChain:()=>W,verifyVoucherSignature:()=>F});module.exports=je(pt);var y=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};var we=require("@solana/web3.js");var be=ye(require("tweetnacl"),1),Je=require("@noble/hashes/sha256"),ze=require("@noble/curves/p256"),H=require("@solana/web3.js");var x=require("@dexterai/vault/messages");var ce=require("@dexterai/vault/instructions"),Xe=require("@dexterai/vault/precompile"),_=require("@dexterai/vault/constants");var q=require("@dexterai/vault/session"),ue="OTS_SESSION_REGISTER_V2",A=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function L(e){if(e.length!==188)throw new A("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,ue.length));if(t!==ue)throw new A("wrong_domain",`got "${t}"`);for(let g=ue.length;g<32;g++)if(e[g]!==0)throw new A("wrong_domain",`non-NUL padding at byte ${g}`);let r=new DataView(e.buffer,e.byteOffset,e.byteLength),n=new H.PublicKey(e.slice(32,64)),s=new H.PublicKey(e.slice(64,96)),i=e.slice(96,128),l=r.getBigUint64(128,!0),p=r.getBigInt64(136,!0),o=new H.PublicKey(e.slice(144,176)),u=r.getUint32(176,!0),m=r.getBigUint64(180,!0);if(!n.equals(_.DEXTER_VAULT_PROGRAM_ID))throw new A("wrong_program",`${n.toBase58()} is not ${_.DEXTER_VAULT_PROGRAM_ID.toBase58()}`);if(l===0n)throw new A("cap_zero");let d=BigInt(Math.floor(Date.now()/1e3));if(p<=d)throw new A("expiry_in_past",`expires_at=${p}, now=${d}`);return{programId:n,vaultPda:s,sessionPubkey:new Uint8Array(i),maxAmount:l,expiresAt:p,allowedCounterparty:o,nonce:u,maxRevolvingCapacity:m}}var S=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function W(e,t){let r=await(0,q.fetchSessionAccount)(e,t.vaultPda,t.allowedCounterparty);if(!r||r.version===0)throw new S("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!(0,q.isSessionLive)(r))throw new S("session_not_active","SessionAccount PDA is present but expired");if(!Ge(r.session.sessionPubkey,t.sessionPubkey))throw new S("session_pubkey_mismatch",`on-chain ${Ae(r.session.sessionPubkey)} != registration ${Ae(t.sessionPubkey)}`)}var b=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function F(e,t){if(t.length!==32)throw new b(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new b(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new b(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let r=(0,x.voucherPayloadMessage)({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!be.default.sign.detached.verify(r,e.sessionSignature,e.sessionPublicKey))throw new b("ed25519 verify rejected")}var f=class extends Error{constructor(r,n){super(`Scope violation: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="ScopeViolationError"}};function j(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new f("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=e.registration.expiresAt)throw new f("session_expired",`now=${r} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new f("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let n=BigInt(e.previousCumulativeAtomic);if(t<=n)throw new f("non_monotonic",`cumulative=${t} not > previous=${n}`)}}function Ge(e,t){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return!1;return!0}function Ae(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}var P=require("fs"),J=require("path");function Ye(e){return{payload:e.payload,sessionPublicKey:le(e.sessionPublicKey),sessionRegistration:le(e.sessionRegistration),sessionSignature:le(e.sessionSignature)}}function Ze(e){return{payload:e.payload,sessionPublicKey:pe(e.sessionPublicKey),sessionRegistration:pe(e.sessionRegistration),sessionSignature:pe(e.sessionSignature)}}function le(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function pe(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 r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}var R=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,r){this.map.set(t,r)}async delete(t){this.map.delete(t)}},X=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return(0,J.join)(this.dir,`${t}.json`)}async get(t){try{let r=await P.promises.readFile(this.pathFor(t),"utf8");return Ze(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await P.promises.mkdir((0,J.dirname)(n),{recursive:!0});let s=`${n}.tmp`;await P.promises.writeFile(s,JSON.stringify(Ye(r))),await P.promises.rename(s,n)}async delete(t){try{await P.promises.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}};var tt=require("@solana/web3.js"),rt=require("@noble/hashes/utils");var Qe=ye(require("tweetnacl"),1);var et=require("@noble/hashes/sha256");var Se=6;function v(e,t=Se){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[r,n=""]=e.split(".");if(n.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let s=n.padEnd(t,"0"),i=`${r}${s}`.replace(/^0+(?=\d)/,"");return i===""?"0":i}function U(e,t=Se){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let r=e.padStart(t+1,"0"),n=r.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",s=r.slice(-t).replace(/0+$/,"");return s?`${n}.${s}`:n}var C="x-tab-voucher",me=class{map=new Map;get(t){return this.map.get(t)}set(t,r){this.map.set(t,r)}update(t,r){let n=this.map.get(t);n&&(n.lastCumulativeAtomic=r)}delete(t){this.map.delete(t)}},de=class{constructor(t,r,n,s){this.chargeImpl=s;this.channelId=t,this.network=r,this.cumulativeAtomic=n}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return U(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function nt(e){if(typeof e!="string"||e.length===0)throw new y("signature_invalid",`missing ${C} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new y("signature_invalid","malformed base64")}let r;try{r=JSON.parse(t)}catch{throw new y("signature_invalid","malformed JSON")}if(!r||typeof r!="object"||!r.payload||!r.sessionPublicKey)throw new y("signature_invalid","missing required fields");return{payload:r.payload,sessionPublicKey:z(r.sessionPublicKey),sessionRegistration:z(r.sessionRegistration),sessionSignature:z(r.sessionSignature)}}function z(e){if(typeof e!="string"||e.length%2!==0)throw new y("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}function st(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new y("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return z(e)}function xe(e){let t=e.store??new R,r=new me,n=typeof e.sellerPubkey=="string"?new we.PublicKey(e.sellerPubkey):e.sellerPubkey,s=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(v(e.perUnit))*100n;return async(i,l,p)=>{try{let o=nt(i.headers[C]),u=o.payload.channelId,m=st(u),d=r.get(u);if(!d){let w=L(o.sessionRegistration);await W(e.connection,w),d={registration:w,lastCumulativeAtomic:"0"},r.set(u,d)}F(o,m),j({registration:d.registration,voucher:o,expectedCounterparty:n,previousCumulativeAtomic:d.lastCumulativeAtomic});let g=BigInt(o.payload.cumulativeAmount),K=BigInt(d.lastCumulativeAtomic),T=g-K;if(T>s)throw new f("cumulative_exceeds_cap",`single voucher increment ${T} exceeds maxPerVoucherAtomic ${s}`);await t.set(u,o),r.update(u,o.payload.cumulativeAmount);let B=new de(u,e.network,g,async w=>{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.")});B.setSessionPublicKey(o.sessionPublicKey),i.tab=B,p()}catch(o){if(o instanceof y||o instanceof A||o instanceof S||o instanceof b||o instanceof f){l.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}p(o)}}}function ve(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Ee(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 r=t.tab,n=BigInt(v(r.cumulative())),s=t.perUnit?BigInt(v(t.perUnit)):null,i=0n,l=!1;function p(m=1){if(l)return Promise.reject(new Error("meter ended"));if(s===null)return Promise.reject(new Error("charge() needs options.perUnit"));let d=s*BigInt(m),g=i+d;return g>n?Promise.reject(new f("cumulative_exceeds_cap",`chunk would push request total to ${U(g.toString())} beyond voucher-authorized budget ${U(n.toString())}`)):(i=g,Promise.resolve())}function o(m){if(l)throw new Error("meter ended");let g=(typeof m=="string"?m:Buffer.from(m).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${g}
|
|
2
2
|
|
|
3
|
-
`)}function u(){
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}function u(){l||(l=!0,e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${i}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:
|
|
6
|
+
`),e.end())}return{charge:p,send:o,end:u}}var Ve=require("@solana/web3.js");var E="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",Te="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",_e="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var O="eip155:8453",G="eip155:84532",Y="eip155:42161",Z="eip155:137",Q="eip155:10",ee="eip155:43114",te="eip155:56",re="eip155:1187947933",ne="eip155:324705682",se="eip155:1";var oe="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var Pe="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",ot="0x55d398326f99059fF775485246999027B3197955",Re="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Ce={[te]:Re,[O]:Pe,[G]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[Y]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[Z]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[Q]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[ee]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[re]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[ne]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[se]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Ne={[ot]:{symbol:"USDT",decimals:18},[Re]:{symbol:"USDC",decimals:18}};var Mt={[te]:56,[O]:8453,[G]:84532,[Y]:42161,[Z]:137,[Q]:10,[ee]:43114,[re]:1187947933,[ne]:324705682,[se]:1},Ht={[E]:"https://api.dexter.cash/api/solana/rpc",[Te]:"https://api.devnet.solana.com",[_e]:"https://api.testnet.solana.com"},qt={[te]:"https://api.dexter.cash/api/evm/bsc/rpc",[O]:"https://api.dexter.cash/api/base/rpc",[G]:"https://sepolia.base.org",[Y]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[Z]:"https://api.dexter.cash/api/evm/polygon/rpc",[Q]:"https://api.dexter.cash/api/evm/optimism/rpc",[ee]:"https://api.dexter.cash/api/evm/avalanche/rpc",[re]:"https://skale-base.skalenodes.com/v1/base",[ne]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[se]:"https://eth.llamarpc.com"},V="https://x402.dexter.cash";function ie(e){return e.startsWith("solana:")||e==="solana"}function it(e){if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");let t=new TextEncoder().encode(e),r="";for(let n=0;n<t.length;n++)r+=String.fromCharCode(t[n]);return btoa(r)}function at(e){if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return new TextDecoder().decode(r)}function Ie(e){return it(JSON.stringify(e))}function k(e){return JSON.parse(at(e))}function ct(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 $=class extends Error{status;body;constructor(t,r){super(`HTTP ${t}`),this.status=t,this.body=r}},ae=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=V,r){this.facilitatorUrl=t.replace(/\/$/,""),this.timeoutMs=r?.timeoutMs??1e4,this.maxRetries=r?.maxRetries??3,this.retryBaseMs=r?.retryBaseMs??500}async fetchWithTimeout(t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(t,{...r,signal:n.signal})}finally{clearTimeout(s)}}async fetchWithRetry(t,r){let n;for(let s=0;s<this.maxRetries;s++)try{let i=await this.fetchWithTimeout(t,r);if(!i.ok&&i.status>=500)throw new $(i.status,await i.text());return i}catch(i){if(n=i,s<this.maxRetries-1&&ct(i)){let l=this.retryBaseMs*Math.pow(2,s);await new Promise(p=>setTimeout(p,l));continue}throw i}throw n}async getSupported(){let t=Date.now();if(this.cachedSupported&&t-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=t,this.cachedSupported}async getFeePayer(t){let n=(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval")&&s.network===t);if(!n)throw new Error(`Facilitator does not support network "${t}" with a recognized scheme`);return n.extra?.feePayer}async getNetworkExtra(t){return(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval"||s.scheme==="batch-settlement")&&s.network===t)?.extra}async verifyPayment(t,r){try{let n=k(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?await s.json():{isValid:!1,invalidReason:`facilitator_error_${s.status}`}}catch(n){return{isValid:!1,invalidReason:n instanceof $?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_verify_error"}}}async settlePayment(t,r){try{let n=k(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?{...await s.json(),network:r.network}:{success:!1,network:r.network,errorReason:`facilitator_error_${s.status}`}}catch(n){let s=n instanceof $?`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:s}}}};function ut(e){if(ie(e))return{address:oe,decimals:6};let t=Ce[e];if(t){let r=Ne[t]?.decimals??6;return{address:t,decimals:r}}return{address:oe,decimals:6}}function Ue(e){try{let t=k(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function Oe(e){let{payTo:t,facilitatorUrl:r=V,network:n=E,defaultTimeoutSeconds:s=60}=e,i=e.asset??ut(n),l=e.scheme??"exact";if(l==="tab"&&!ie(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let p=new ae(r),o=null,u=new Map,m=3e4,d=Date.now();function g(a){let c=(a.maxTimeoutSeconds||s)*1e3;if(u.set(a.payTo,{accept:a,expiresAt:Date.now()+c}),Date.now()-d>m){let h=Date.now();for(let[N,I]of u)I.expiresAt<h&&u.delete(N);d=h}}function K(a){let c=u.get(a);if(c){if(c.expiresAt<Date.now()){u.delete(a);return}return c.accept}}async function T(a){return typeof t=="string"?t:t(a||{})}async function B(){if(o||(o=await p.getNetworkExtra(n)),ie(n)&&!o?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${n}"`);return{...o?.feePayer?{feePayer:o.feePayer}:{},decimals:o?.decimals??i.decimals,name:o?.name,version:o?.version,...l==="batch-settlement"&&o?.receiverAuthorizer?{receiverAuthorizer:o.receiverAuthorizer}:{},...l==="tab"?{voucherHeader:"x-tab-voucher",registrationEncoding:"base64(188-byte sessionRegisterMessage)"}:{}}}async function w(a,c){let{amountAtomic:h,timeoutSeconds:N=s}=c,I=await B(),D={scheme:l,network:n,amount:h,maxAmountRequired:h,asset:i.address,payTo:a,maxTimeoutSeconds:N,extra:I};return g(D),D}async function ge(a){let c=await T({amountAtomic:a.amountAtomic,resourceUrl:a.resourceUrl});return w(c,a)}async function $e(a){let{resourceUrl:c,description:h,mimeType:N="application/json"}=a,I={url:c,description:h,mimeType:N},D=await ge(a);return{x402Version:2,resource:I,accepts:[D],error:"Payment required"}}function he(a){return Ie(a)}function Ke(a){return{status:402,headers:{"PAYMENT-REQUIRED":he(a)},body:{}}}async function Be(a,c){if(!c){let h=await T({paymentHeader:a});c=K(h),c||(c=await w(h,{amountAtomic:Ue(a)??"0",resourceUrl:""}))}return p.verifyPayment(a,c)}async function De(a,c){if(!c){let h=await T({paymentHeader:a});c=K(h),c||(c=await w(h,{amountAtomic:Ue(a)??"0",resourceUrl:""}))}return p.settlePayment(a,c)}return{buildRequirements:$e,encodeRequirements:he,create402Response:Ke,verifyPayment:Be,settlePayment:De,getPaymentAccept:ge,network:n,assetDecimals:i.decimals,facilitator:p}}var lt={"solana:mainnet":E};function ke(e){let t=lt[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new Ve.PublicKey(r);let n=Oe({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),s=v(e.perUnit);return async(i,l,p)=>{if(i.headers[C])return p();try{let o=`${i.protocol}://${i.get("host")}${i.originalUrl}`,u=await n.buildRequirements({amountAtomic:s,resourceUrl:o,description:e.description}),m=n.create402Response(u);l.set(m.headers).status(m.status).json(m.body)}catch(o){let u=o?.message??String(o);l.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:u})}}}0&&(module.exports={FileVoucherStore,InMemoryVoucherStore,InvalidRegistrationError,InvalidVoucherError,InvalidVoucherSignatureError,OnChainVerificationError,ScopeViolationError,TAB_VOUCHER_HEADER,enforceScope,openSse,parseRegistration,requireTab,tabChallengeMiddleware,tabMiddleware,verifyRegistrationOnChain,verifyVoucherSignature});
|
|
@@ -231,38 +231,26 @@ declare class InvalidRegistrationError extends Error {
|
|
|
231
231
|
* passkey signature check is a separate on-chain step.
|
|
232
232
|
*/
|
|
233
233
|
declare function parseRegistration(registration: Uint8Array): ParsedRegistration;
|
|
234
|
-
interface OnChainVaultState {
|
|
235
|
-
passkeyPubkey: Uint8Array;
|
|
236
|
-
activeSessionPubkey: Uint8Array | null;
|
|
237
|
-
}
|
|
238
234
|
declare class OnChainVerificationError extends Error {
|
|
239
235
|
readonly reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program';
|
|
240
236
|
constructor(reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program', detail?: string);
|
|
241
237
|
}
|
|
242
238
|
/**
|
|
243
|
-
*
|
|
239
|
+
* Verify a registration against on-chain state. Throws on any mismatch.
|
|
244
240
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Verify a registration against on-chain state. Returns the vault's
|
|
254
|
-
* passkey pubkey (caller can cache it). Throws on any mismatch.
|
|
241
|
+
* V6: a session is its own PDA ([b"session", vault, allowed_counterparty]),
|
|
242
|
+
* NOT an inline field on the vault. We read that SessionAccount and confirm it
|
|
243
|
+
* is live (version 1 + unexpired) AND carries the same session pubkey the
|
|
244
|
+
* registration claims. If the program accepted the register_session_key tx
|
|
245
|
+
* (which is what wrote the PDA), the passkey signature was already verified by
|
|
246
|
+
* the secp256r1 precompile inside that tx — the seller just confirms the
|
|
247
|
+
* on-chain witness still holds.
|
|
255
248
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* in the first place), then the passkey signature was verified by the
|
|
260
|
-
* secp256r1 precompile inside that tx. The seller doesn't need to redo
|
|
261
|
-
* that work; they just need to confirm the on-chain witness still holds.
|
|
249
|
+
* fetchSessionAccount reads at the connection's commitment; pass a connection
|
|
250
|
+
* configured at the commitment the buyer's registration was confirmed to (the
|
|
251
|
+
* adapter waits for visibility before openTab returns).
|
|
262
252
|
*/
|
|
263
|
-
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<
|
|
264
|
-
passkeyPubkey: Uint8Array;
|
|
265
|
-
}>;
|
|
253
|
+
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<void>;
|
|
266
254
|
declare class InvalidVoucherSignatureError extends Error {
|
|
267
255
|
constructor(detail?: string);
|
|
268
256
|
}
|
|
@@ -289,4 +277,33 @@ declare function enforceScope(args: {
|
|
|
289
277
|
previousCumulativeAtomic?: AtomicAmount;
|
|
290
278
|
}): void;
|
|
291
279
|
|
|
292
|
-
|
|
280
|
+
/**
|
|
281
|
+
* The discovery half of a tab seller: answer voucher-LESS requests with a
|
|
282
|
+
* standard x402 v2 402 challenge advertising scheme 'tab', so a stranger's
|
|
283
|
+
* agent can resolve the counterparty off the wire. Compose BEFORE
|
|
284
|
+
* tabMiddleware:
|
|
285
|
+
*
|
|
286
|
+
* app.get('/paid/x',
|
|
287
|
+
* tabChallengeMiddleware({ sellerPubkey, network, perUnit, facilitatorUrl }),
|
|
288
|
+
* tabMiddleware({ ... }),
|
|
289
|
+
* handler);
|
|
290
|
+
*
|
|
291
|
+
* Requests carrying x-tab-voucher fall through to tabMiddleware untouched.
|
|
292
|
+
* The challenge emits the CAIP-2 network form (x402 v2) — the SDK-internal
|
|
293
|
+
* 'solana:mainnet' alias is NOT standard and buyers drop it.
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface TabChallengeConfig {
|
|
297
|
+
/** Seller pubkey — advertised as the tab counterparty (payTo). */
|
|
298
|
+
sellerPubkey: string | PublicKey;
|
|
299
|
+
/** Tab network id ('solana:mainnet'); mapped to CAIP-2 on the wire. */
|
|
300
|
+
network: TabNetworkId;
|
|
301
|
+
/** Per-request price in human units; advertised as maxAmountRequired. */
|
|
302
|
+
perUnit: HumanAmount;
|
|
303
|
+
/** Facilitator base URL (the challenge embeds its feePayer extra). */
|
|
304
|
+
facilitatorUrl?: string;
|
|
305
|
+
description?: string;
|
|
306
|
+
}
|
|
307
|
+
declare function tabChallengeMiddleware(config: TabChallengeConfig): RequestHandler;
|
|
308
|
+
|
|
309
|
+
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError, OnChainVerificationError, type OpenSseOptions, type ParsedRegistration, ScopeViolationError, type SellerTab, type SseMeter, TAB_VOUCHER_HEADER, type TabChallengeConfig, type TabMiddlewareConfig, type TabMiddlewareOptions, type VoucherStore, enforceScope, openSse, parseRegistration, requireTab, tabChallengeMiddleware, tabMiddleware, verifyRegistrationOnChain, verifyVoucherSignature };
|
|
@@ -231,38 +231,26 @@ declare class InvalidRegistrationError extends Error {
|
|
|
231
231
|
* passkey signature check is a separate on-chain step.
|
|
232
232
|
*/
|
|
233
233
|
declare function parseRegistration(registration: Uint8Array): ParsedRegistration;
|
|
234
|
-
interface OnChainVaultState {
|
|
235
|
-
passkeyPubkey: Uint8Array;
|
|
236
|
-
activeSessionPubkey: Uint8Array | null;
|
|
237
|
-
}
|
|
238
234
|
declare class OnChainVerificationError extends Error {
|
|
239
235
|
readonly reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program';
|
|
240
236
|
constructor(reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program', detail?: string);
|
|
241
237
|
}
|
|
242
238
|
/**
|
|
243
|
-
*
|
|
239
|
+
* Verify a registration against on-chain state. Throws on any mismatch.
|
|
244
240
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Verify a registration against on-chain state. Returns the vault's
|
|
254
|
-
* passkey pubkey (caller can cache it). Throws on any mismatch.
|
|
241
|
+
* V6: a session is its own PDA ([b"session", vault, allowed_counterparty]),
|
|
242
|
+
* NOT an inline field on the vault. We read that SessionAccount and confirm it
|
|
243
|
+
* is live (version 1 + unexpired) AND carries the same session pubkey the
|
|
244
|
+
* registration claims. If the program accepted the register_session_key tx
|
|
245
|
+
* (which is what wrote the PDA), the passkey signature was already verified by
|
|
246
|
+
* the secp256r1 precompile inside that tx — the seller just confirms the
|
|
247
|
+
* on-chain witness still holds.
|
|
255
248
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* in the first place), then the passkey signature was verified by the
|
|
260
|
-
* secp256r1 precompile inside that tx. The seller doesn't need to redo
|
|
261
|
-
* that work; they just need to confirm the on-chain witness still holds.
|
|
249
|
+
* fetchSessionAccount reads at the connection's commitment; pass a connection
|
|
250
|
+
* configured at the commitment the buyer's registration was confirmed to (the
|
|
251
|
+
* adapter waits for visibility before openTab returns).
|
|
262
252
|
*/
|
|
263
|
-
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<
|
|
264
|
-
passkeyPubkey: Uint8Array;
|
|
265
|
-
}>;
|
|
253
|
+
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<void>;
|
|
266
254
|
declare class InvalidVoucherSignatureError extends Error {
|
|
267
255
|
constructor(detail?: string);
|
|
268
256
|
}
|
|
@@ -289,4 +277,33 @@ declare function enforceScope(args: {
|
|
|
289
277
|
previousCumulativeAtomic?: AtomicAmount;
|
|
290
278
|
}): void;
|
|
291
279
|
|
|
292
|
-
|
|
280
|
+
/**
|
|
281
|
+
* The discovery half of a tab seller: answer voucher-LESS requests with a
|
|
282
|
+
* standard x402 v2 402 challenge advertising scheme 'tab', so a stranger's
|
|
283
|
+
* agent can resolve the counterparty off the wire. Compose BEFORE
|
|
284
|
+
* tabMiddleware:
|
|
285
|
+
*
|
|
286
|
+
* app.get('/paid/x',
|
|
287
|
+
* tabChallengeMiddleware({ sellerPubkey, network, perUnit, facilitatorUrl }),
|
|
288
|
+
* tabMiddleware({ ... }),
|
|
289
|
+
* handler);
|
|
290
|
+
*
|
|
291
|
+
* Requests carrying x-tab-voucher fall through to tabMiddleware untouched.
|
|
292
|
+
* The challenge emits the CAIP-2 network form (x402 v2) — the SDK-internal
|
|
293
|
+
* 'solana:mainnet' alias is NOT standard and buyers drop it.
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface TabChallengeConfig {
|
|
297
|
+
/** Seller pubkey — advertised as the tab counterparty (payTo). */
|
|
298
|
+
sellerPubkey: string | PublicKey;
|
|
299
|
+
/** Tab network id ('solana:mainnet'); mapped to CAIP-2 on the wire. */
|
|
300
|
+
network: TabNetworkId;
|
|
301
|
+
/** Per-request price in human units; advertised as maxAmountRequired. */
|
|
302
|
+
perUnit: HumanAmount;
|
|
303
|
+
/** Facilitator base URL (the challenge embeds its feePayer extra). */
|
|
304
|
+
facilitatorUrl?: string;
|
|
305
|
+
description?: string;
|
|
306
|
+
}
|
|
307
|
+
declare function tabChallengeMiddleware(config: TabChallengeConfig): RequestHandler;
|
|
308
|
+
|
|
309
|
+
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError, OnChainVerificationError, type OpenSseOptions, type ParsedRegistration, ScopeViolationError, type SellerTab, type SseMeter, TAB_VOUCHER_HEADER, type TabChallengeConfig, type TabMiddlewareConfig, type TabMiddlewareOptions, type VoucherStore, enforceScope, openSse, parseRegistration, requireTab, tabChallengeMiddleware, tabMiddleware, verifyRegistrationOnChain, verifyVoucherSignature };
|
package/dist/tab/seller/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var m=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};import{PublicKey as Y}from"@solana/web3.js";import j from"tweetnacl";import{sha256 as Ae}from"@noble/hashes/sha256";import{p256 as xe}from"@noble/curves/p256";import{PublicKey as I}from"@solana/web3.js";import{sessionRegisterMessage as se,sessionRevokeMessage as ae,voucherPayloadMessage as T,buildVoucherMessage as ue}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as me,buildRevokeSessionKeyInstruction as de,deriveSwigWalletAddress as pe}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as he}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as v,SECP256R1_PROGRAM_ID as fe,INSTRUCTIONS_SYSVAR_ID as we}from"@dexterai/vault/constants";var V="OTS_SESSION_REGISTER_V2",d=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function k(e){if(e.length!==188)throw new d("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,V.length));if(t!==V)throw new d("wrong_domain",`got "${t}"`);for(let a=V.length;a<32;a++)if(e[a]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${a}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new I(e.slice(32,64)),i=new I(e.slice(64,96)),c=e.slice(96,128),p=n.getBigUint64(128,!0),h=n.getBigInt64(136,!0),o=new I(e.slice(144,176)),u=n.getUint32(176,!0),g=n.getBigUint64(180,!0);if(!r.equals(v))throw new d("wrong_program",`${r.toBase58()} is not ${v.toBase58()}`);if(p===0n)throw new d("cap_zero");let s=BigInt(Math.floor(Date.now()/1e3));if(h<=s)throw new d("expiry_in_past",`expires_at=${h}, now=${s}`);return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(c),maxAmount:p,expiresAt:h,allowedCounterparty:o,nonce:u,maxRevolvingCapacity:g}}var M=10,f=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function D(e,t){let n=await e.getAccountInfo(t,"finalized");if(!n)throw new f("vault_not_found",t.toBase58());if(!n.owner.equals(v))throw new f("wrong_program",`owner ${n.owner.toBase58()} is not the vault program`);let r=n.data,i=new Uint8Array(r.slice(M,M+33)),u=84+(r[83]===1?48:0)+32+32;if(r[u]!==1)return{passkeyPubkey:i,activeSessionPubkey:null};let s=u+1,a=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:i,activeSessionPubkey:a}}async function _(e,t){let n=await D(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new f("session_not_active","vault has no active_session \u2014 was it revoked?");if(!F(n.activeSessionPubkey,t.sessionPubkey))throw new f("session_pubkey_mismatch",`on-chain ${q(n.activeSessionPubkey)} != registration ${q(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var y=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function C(e,t){if(t.length!==32)throw new y(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new y(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new y(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=T({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!j.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new y("ed25519 verify rejected")}var l=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function U(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new l("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new l("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new l("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new l("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function F(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 q(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}import{promises as w}from"fs";import{join as J,dirname as G}from"path";function W(e){return{payload:e.payload,sessionPublicKey:$(e.sessionPublicKey),sessionRegistration:$(e.sessionRegistration),sessionSignature:$(e.sessionSignature)}}function X(e){return{payload:e.payload,sessionPublicKey:R(e.sessionPublicKey),sessionRegistration:R(e.sessionRegistration),sessionSignature:R(e.sessionSignature)}}function $(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function R(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 b=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)}},E=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return J(this.dir,`${t}.json`)}async get(t){try{let n=await w.readFile(this.pathFor(t),"utf8");return X(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await w.mkdir(G(r),{recursive:!0});let i=`${r}.tmp`;await w.writeFile(i,JSON.stringify(W(n))),await w.rename(i,r)}async delete(t){try{await w.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};import{PublicKey as Le}from"@solana/web3.js";import{bytesToHex as Fe}from"@noble/hashes/utils";import Ee from"tweetnacl";import{sha256 as Ne}from"@noble/hashes/sha256";var z=6;function S(e,t=z){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"),c=`${n}${i}`.replace(/^0+(?=\d)/,"");return c===""?"0":c}function A(e,t=z){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}var N="x-tab-voucher",K=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)}},O=class{constructor(t,n,r,i){this.chargeImpl=i;this.channelId=t,this.network=n,this.cumulativeAtomic=r}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return A(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function Z(e){if(typeof e!="string"||e.length===0)throw new m("signature_invalid",`missing ${N} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new m("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new m("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new m("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:x(n.sessionPublicKey),sessionRegistration:x(n.sessionRegistration),sessionSignature:x(n.sessionSignature)}}function x(e){if(typeof e!="string"||e.length%2!==0)throw new m("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 Q(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new m("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return x(e)}function ee(e){let t=e.store??new b,n=new K,r=typeof e.sellerPubkey=="string"?new Y(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(S(e.perUnit))*100n;return async(c,p,h)=>{try{let o=Z(c.headers[N]),u=o.payload.channelId,g=Q(u),s=n.get(u);if(!s){let P=k(o.sessionRegistration);await _(e.connection,P),s={registration:P,lastCumulativeAtomic:"0"},n.set(u,s)}C(o,g),U({registration:s.registration,voucher:o,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let a=BigInt(o.payload.cumulativeAmount),L=BigInt(s.lastCumulativeAtomic),H=a-L;if(H>i)throw new l("cumulative_exceeds_cap",`single voucher increment ${H} exceeds maxPerVoucherAtomic ${i}`);await t.set(u,o),n.update(u,o.payload.cumulativeAmount);let B=new O(u,e.network,a,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.")});B.setSessionPublicKey(o.sessionPublicKey),c.tab=B,h()}catch(o){if(o instanceof m||o instanceof d||o instanceof f||o instanceof y||o instanceof l){p.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}h(o)}}}function te(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function ne(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(S(n.cumulative())),i=t.perUnit?BigInt(S(t.perUnit)):null,c=0n,p=!1;function h(g=1){if(p)return Promise.reject(new Error("meter ended"));if(i===null)return Promise.reject(new Error("charge() needs options.perUnit"));let s=i*BigInt(g),a=c+s;return a>r?Promise.reject(new l("cumulative_exceeds_cap",`chunk would push request total to ${A(a.toString())} beyond voucher-authorized budget ${A(r.toString())}`)):(c=a,Promise.resolve())}function o(g){if(p)throw new Error("meter ended");let a=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${a}
|
|
1
|
+
var y=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};import{PublicKey as ke}from"@solana/web3.js";import Pe from"tweetnacl";import{sha256 as dt}from"@noble/hashes/sha256";import{p256 as ht}from"@noble/curves/p256";import{PublicKey as Q}from"@solana/web3.js";import{sessionRegisterMessage as Ze,sessionRevokeMessage as Qe,voucherPayloadMessage as Y,buildVoucherMessage as et}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as nt,buildRevokeSessionKeyInstruction as st,deriveSwigWalletAddress as ot}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as at}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as Z,SECP256R1_PROGRAM_ID as ut,INSTRUCTIONS_SYSVAR_ID as lt}from"@dexterai/vault/constants";import{fetchSessionAccount as Re,isSessionLive as Ce}from"@dexterai/vault/session";var ee="OTS_SESSION_REGISTER_V2",A=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function te(e){if(e.length!==188)throw new A("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,ee.length));if(t!==ee)throw new A("wrong_domain",`got "${t}"`);for(let g=ee.length;g<32;g++)if(e[g]!==0)throw new A("wrong_domain",`non-NUL padding at byte ${g}`);let r=new DataView(e.buffer,e.byteOffset,e.byteLength),n=new Q(e.slice(32,64)),s=new Q(e.slice(64,96)),i=e.slice(96,128),l=r.getBigUint64(128,!0),p=r.getBigInt64(136,!0),o=new Q(e.slice(144,176)),u=r.getUint32(176,!0),m=r.getBigUint64(180,!0);if(!n.equals(Z))throw new A("wrong_program",`${n.toBase58()} is not ${Z.toBase58()}`);if(l===0n)throw new A("cap_zero");let d=BigInt(Math.floor(Date.now()/1e3));if(p<=d)throw new A("expiry_in_past",`expires_at=${p}, now=${d}`);return{programId:n,vaultPda:s,sessionPubkey:new Uint8Array(i),maxAmount:l,expiresAt:p,allowedCounterparty:o,nonce:u,maxRevolvingCapacity:m}}var S=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function re(e,t){let r=await Re(e,t.vaultPda,t.allowedCounterparty);if(!r||r.version===0)throw new S("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!Ce(r))throw new S("session_not_active","SessionAccount PDA is present but expired");if(!Ne(r.session.sessionPubkey,t.sessionPubkey))throw new S("session_pubkey_mismatch",`on-chain ${me(r.session.sessionPubkey)} != registration ${me(t.sessionPubkey)}`)}var b=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function ne(e,t){if(t.length!==32)throw new b(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new b(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new b(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let r=Y({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!Pe.sign.detached.verify(r,e.sessionSignature,e.sessionPublicKey))throw new b("ed25519 verify rejected")}var f=class extends Error{constructor(r,n){super(`Scope violation: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="ScopeViolationError"}};function se(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new f("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=e.registration.expiresAt)throw new f("session_expired",`now=${r} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new f("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let n=BigInt(e.previousCumulativeAtomic);if(t<=n)throw new f("non_monotonic",`cumulative=${t} not > previous=${n}`)}}function Ne(e,t){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return!1;return!0}function me(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}import{promises as P}from"fs";import{join as Ie,dirname as Ue}from"path";function Oe(e){return{payload:e.payload,sessionPublicKey:oe(e.sessionPublicKey),sessionRegistration:oe(e.sessionRegistration),sessionSignature:oe(e.sessionSignature)}}function Ve(e){return{payload:e.payload,sessionPublicKey:ie(e.sessionPublicKey),sessionRegistration:ie(e.sessionRegistration),sessionSignature:ie(e.sessionSignature)}}function oe(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function ie(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 r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}var R=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,r){this.map.set(t,r)}async delete(t){this.map.delete(t)}},ae=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return Ie(this.dir,`${t}.json`)}async get(t){try{let r=await P.readFile(this.pathFor(t),"utf8");return Ve(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await P.mkdir(Ue(n),{recursive:!0});let s=`${n}.tmp`;await P.writeFile(s,JSON.stringify(Oe(r))),await P.rename(s,n)}async delete(t){try{await P.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}};import{PublicKey as Kt}from"@solana/web3.js";import{bytesToHex as Dt}from"@noble/hashes/utils";import Pt from"tweetnacl";import{sha256 as Nt}from"@noble/hashes/sha256";var de=6;function x(e,t=de){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[r,n=""]=e.split(".");if(n.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let s=n.padEnd(t,"0"),i=`${r}${s}`.replace(/^0+(?=\d)/,"");return i===""?"0":i}function C(e,t=de){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let r=e.padStart(t+1,"0"),n=r.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",s=r.slice(-t).replace(/0+$/,"");return s?`${n}.${s}`:n}var N="x-tab-voucher",ce=class{map=new Map;get(t){return this.map.get(t)}set(t,r){this.map.set(t,r)}update(t,r){let n=this.map.get(t);n&&(n.lastCumulativeAtomic=r)}delete(t){this.map.delete(t)}},ue=class{constructor(t,r,n,s){this.chargeImpl=s;this.channelId=t,this.network=r,this.cumulativeAtomic=n}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return C(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function $e(e){if(typeof e!="string"||e.length===0)throw new y("signature_invalid",`missing ${N} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new y("signature_invalid","malformed base64")}let r;try{r=JSON.parse(t)}catch{throw new y("signature_invalid","malformed JSON")}if(!r||typeof r!="object"||!r.payload||!r.sessionPublicKey)throw new y("signature_invalid","missing required fields");return{payload:r.payload,sessionPublicKey:B(r.sessionPublicKey),sessionRegistration:B(r.sessionRegistration),sessionSignature:B(r.sessionSignature)}}function B(e){if(typeof e!="string"||e.length%2!==0)throw new y("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}function Ke(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new y("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return B(e)}function Be(e){let t=e.store??new R,r=new ce,n=typeof e.sellerPubkey=="string"?new ke(e.sellerPubkey):e.sellerPubkey,s=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(x(e.perUnit))*100n;return async(i,l,p)=>{try{let o=$e(i.headers[N]),u=o.payload.channelId,m=Ke(u),d=r.get(u);if(!d){let w=te(o.sessionRegistration);await re(e.connection,w),d={registration:w,lastCumulativeAtomic:"0"},r.set(u,d)}ne(o,m),se({registration:d.registration,voucher:o,expectedCounterparty:n,previousCumulativeAtomic:d.lastCumulativeAtomic});let g=BigInt(o.payload.cumulativeAmount),k=BigInt(d.lastCumulativeAtomic),E=g-k;if(E>s)throw new f("cumulative_exceeds_cap",`single voucher increment ${E} exceeds maxPerVoucherAtomic ${s}`);await t.set(u,o),r.update(u,o.payload.cumulativeAmount);let $=new ue(u,e.network,g,async w=>{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.")});$.setSessionPublicKey(o.sessionPublicKey),i.tab=$,p()}catch(o){if(o instanceof y||o instanceof A||o instanceof S||o instanceof b||o instanceof f){l.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}p(o)}}}function De(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Me(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 r=t.tab,n=BigInt(x(r.cumulative())),s=t.perUnit?BigInt(x(t.perUnit)):null,i=0n,l=!1;function p(m=1){if(l)return Promise.reject(new Error("meter ended"));if(s===null)return Promise.reject(new Error("charge() needs options.perUnit"));let d=s*BigInt(m),g=i+d;return g>n?Promise.reject(new f("cumulative_exceeds_cap",`chunk would push request total to ${C(g.toString())} beyond voucher-authorized budget ${C(n.toString())}`)):(i=g,Promise.resolve())}function o(m){if(l)throw new Error("meter ended");let g=(typeof m=="string"?m:Buffer.from(m).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${g}
|
|
2
2
|
|
|
3
|
-
`)}function u(){
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}function u(){l||(l=!0,e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${i}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:
|
|
6
|
+
`),e.end())}return{charge:p,send:o,end:u}}import{PublicKey as je}from"@solana/web3.js";var v="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",ge="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",he="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var I="eip155:8453",D="eip155:84532",M="eip155:42161",H="eip155:137",q="eip155:10",L="eip155:43114",W="eip155:56",F="eip155:1187947933",j="eip155:324705682",X="eip155:1";var J="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var fe="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",He="0x55d398326f99059fF775485246999027B3197955",ye="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Ae={[W]:ye,[I]:fe,[D]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[M]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[H]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[q]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[L]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[F]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[j]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[X]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},be={[He]:{symbol:"USDT",decimals:18},[ye]:{symbol:"USDC",decimals:18}};var Qt={[W]:56,[I]:8453,[D]:84532,[M]:42161,[H]:137,[q]:10,[L]:43114,[F]:1187947933,[j]:324705682,[X]:1},er={[v]:"https://api.dexter.cash/api/solana/rpc",[ge]:"https://api.devnet.solana.com",[he]:"https://api.testnet.solana.com"},tr={[W]:"https://api.dexter.cash/api/evm/bsc/rpc",[I]:"https://api.dexter.cash/api/base/rpc",[D]:"https://sepolia.base.org",[M]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[H]:"https://api.dexter.cash/api/evm/polygon/rpc",[q]:"https://api.dexter.cash/api/evm/optimism/rpc",[L]:"https://api.dexter.cash/api/evm/avalanche/rpc",[F]:"https://skale-base.skalenodes.com/v1/base",[j]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[X]:"https://eth.llamarpc.com"},U="https://x402.dexter.cash";function z(e){return e.startsWith("solana:")||e==="solana"}function qe(e){if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");let t=new TextEncoder().encode(e),r="";for(let n=0;n<t.length;n++)r+=String.fromCharCode(t[n]);return btoa(r)}function Le(e){if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return new TextDecoder().decode(r)}function Se(e){return qe(JSON.stringify(e))}function O(e){return JSON.parse(Le(e))}function We(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 V=class extends Error{status;body;constructor(t,r){super(`HTTP ${t}`),this.status=t,this.body=r}},G=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=U,r){this.facilitatorUrl=t.replace(/\/$/,""),this.timeoutMs=r?.timeoutMs??1e4,this.maxRetries=r?.maxRetries??3,this.retryBaseMs=r?.retryBaseMs??500}async fetchWithTimeout(t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(t,{...r,signal:n.signal})}finally{clearTimeout(s)}}async fetchWithRetry(t,r){let n;for(let s=0;s<this.maxRetries;s++)try{let i=await this.fetchWithTimeout(t,r);if(!i.ok&&i.status>=500)throw new V(i.status,await i.text());return i}catch(i){if(n=i,s<this.maxRetries-1&&We(i)){let l=this.retryBaseMs*Math.pow(2,s);await new Promise(p=>setTimeout(p,l));continue}throw i}throw n}async getSupported(){let t=Date.now();if(this.cachedSupported&&t-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=t,this.cachedSupported}async getFeePayer(t){let n=(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval")&&s.network===t);if(!n)throw new Error(`Facilitator does not support network "${t}" with a recognized scheme`);return n.extra?.feePayer}async getNetworkExtra(t){return(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval"||s.scheme==="batch-settlement")&&s.network===t)?.extra}async verifyPayment(t,r){try{let n=O(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?await s.json():{isValid:!1,invalidReason:`facilitator_error_${s.status}`}}catch(n){return{isValid:!1,invalidReason:n instanceof V?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_verify_error"}}}async settlePayment(t,r){try{let n=O(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?{...await s.json(),network:r.network}:{success:!1,network:r.network,errorReason:`facilitator_error_${s.status}`}}catch(n){let s=n instanceof V?`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:s}}}};function Fe(e){if(z(e))return{address:J,decimals:6};let t=Ae[e];if(t){let r=be[t]?.decimals??6;return{address:t,decimals:r}}return{address:J,decimals:6}}function we(e){try{let t=O(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function xe(e){let{payTo:t,facilitatorUrl:r=U,network:n=v,defaultTimeoutSeconds:s=60}=e,i=e.asset??Fe(n),l=e.scheme??"exact";if(l==="tab"&&!z(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let p=new G(r),o=null,u=new Map,m=3e4,d=Date.now();function g(a){let c=(a.maxTimeoutSeconds||s)*1e3;if(u.set(a.payTo,{accept:a,expiresAt:Date.now()+c}),Date.now()-d>m){let h=Date.now();for(let[T,_]of u)_.expiresAt<h&&u.delete(T);d=h}}function k(a){let c=u.get(a);if(c){if(c.expiresAt<Date.now()){u.delete(a);return}return c.accept}}async function E(a){return typeof t=="string"?t:t(a||{})}async function $(){if(o||(o=await p.getNetworkExtra(n)),z(n)&&!o?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${n}"`);return{...o?.feePayer?{feePayer:o.feePayer}:{},decimals:o?.decimals??i.decimals,name:o?.name,version:o?.version,...l==="batch-settlement"&&o?.receiverAuthorizer?{receiverAuthorizer:o.receiverAuthorizer}:{},...l==="tab"?{voucherHeader:"x-tab-voucher",registrationEncoding:"base64(188-byte sessionRegisterMessage)"}:{}}}async function w(a,c){let{amountAtomic:h,timeoutSeconds:T=s}=c,_=await $(),K={scheme:l,network:n,amount:h,maxAmountRequired:h,asset:i.address,payTo:a,maxTimeoutSeconds:T,extra:_};return g(K),K}async function le(a){let c=await E({amountAtomic:a.amountAtomic,resourceUrl:a.resourceUrl});return w(c,a)}async function ve(a){let{resourceUrl:c,description:h,mimeType:T="application/json"}=a,_={url:c,description:h,mimeType:T},K=await le(a);return{x402Version:2,resource:_,accepts:[K],error:"Payment required"}}function pe(a){return Se(a)}function Ee(a){return{status:402,headers:{"PAYMENT-REQUIRED":pe(a)},body:{}}}async function Te(a,c){if(!c){let h=await E({paymentHeader:a});c=k(h),c||(c=await w(h,{amountAtomic:we(a)??"0",resourceUrl:""}))}return p.verifyPayment(a,c)}async function _e(a,c){if(!c){let h=await E({paymentHeader:a});c=k(h),c||(c=await w(h,{amountAtomic:we(a)??"0",resourceUrl:""}))}return p.settlePayment(a,c)}return{buildRequirements:ve,encodeRequirements:pe,create402Response:Ee,verifyPayment:Te,settlePayment:_e,getPaymentAccept:le,network:n,assetDecimals:i.decimals,facilitator:p}}var Xe={"solana:mainnet":v};function Je(e){let t=Xe[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new je(r);let n=xe({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),s=x(e.perUnit);return async(i,l,p)=>{if(i.headers[N])return p();try{let o=`${i.protocol}://${i.get("host")}${i.originalUrl}`,u=await n.buildRequirements({amountAtomic:s,resourceUrl:o,description:e.description}),m=n.create402Response(u);l.set(m.headers).status(m.status).json(m.body)}catch(o){let u=o?.message??String(o);l.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:u})}}}export{ae as FileVoucherStore,R as InMemoryVoucherStore,A as InvalidRegistrationError,y as InvalidVoucherError,b as InvalidVoucherSignatureError,S as OnChainVerificationError,f as ScopeViolationError,N as TAB_VOUCHER_HEADER,se as enforceScope,Me as openSse,te as parseRegistration,De as requireTab,Je as tabChallengeMiddleware,Be as tabMiddleware,re as verifyRegistrationOnChain,ne as verifyVoucherSignature};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { W as WalletSet } from './types-xQu1U4xk.cjs';
|
|
2
|
+
import { T as Tab } from './types-DEnVPFxF.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shared contract for the x402 version seam. Both the v1 and v2 strategy
|
|
6
|
+
* modules implement PaymentStrategy. Callers depend ONLY on this file —
|
|
7
|
+
* never on a specific version module.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** A network reference, kept in BOTH forms so neither version loses info. */
|
|
11
|
+
interface NetworkRef {
|
|
12
|
+
/** CAIP-2 form, e.g. "eip155:8453", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp". */
|
|
13
|
+
caip2: string;
|
|
14
|
+
/** Bare form, e.g. "base", "solana". */
|
|
15
|
+
bare: string;
|
|
16
|
+
/** "evm" | "svm" — which signer family. */
|
|
17
|
+
family: 'evm' | 'svm';
|
|
18
|
+
}
|
|
19
|
+
/** One payment option parsed from a 402 challenge, version-normalised. */
|
|
20
|
+
interface ChallengeOption {
|
|
21
|
+
scheme: string;
|
|
22
|
+
network: NetworkRef;
|
|
23
|
+
/** Atomic amount as a string (e.g. "2000"). */
|
|
24
|
+
amount: string;
|
|
25
|
+
asset: string;
|
|
26
|
+
payTo: string;
|
|
27
|
+
/** Optional — v1 challenges may omit it; a strategy supplies a default when absent. */
|
|
28
|
+
maxTimeoutSeconds?: number;
|
|
29
|
+
/** Scheme-specific extras, passed through verbatim from the merchant. */
|
|
30
|
+
extra?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
/** A 402 challenge, normalised across v1 and v2. */
|
|
33
|
+
interface PaymentChallenge {
|
|
34
|
+
x402Version: 1 | 2;
|
|
35
|
+
options: ChallengeOption[];
|
|
36
|
+
resourceUrl?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Result of a paid fetch. Never throws for an expected failure.
|
|
40
|
+
*
|
|
41
|
+
* The `ok: true` branch is further discriminated by `paid`:
|
|
42
|
+
* - `paid: true` — the endpoint demanded payment and we paid; `amountPaid`
|
|
43
|
+
* and `network` are present, `txSignature` optional.
|
|
44
|
+
* `response` is usually the merchant's response, but is
|
|
45
|
+
* `undefined` when the payment settled and the merchant
|
|
46
|
+
* never delivered a response before the deadline (a
|
|
47
|
+
* confirmed-but-unanswered payment — see `payment_unconfirmed`
|
|
48
|
+
* below for the unconfirmed counterpart).
|
|
49
|
+
* - `paid: false` — the endpoint returned a non-402 directly; no payment
|
|
50
|
+
* was attempted. Only `response` is present, because no
|
|
51
|
+
* payment-related fields are meaningful in that case.
|
|
52
|
+
*
|
|
53
|
+
* Callers should narrow on `paid` before reading payment fields. Previously
|
|
54
|
+
* (3.8.x and earlier) the dispatcher returned a phantom `network` placeholder
|
|
55
|
+
* on the unpaid branch; the discriminator forces a correct read.
|
|
56
|
+
*/
|
|
57
|
+
type PayResult = {
|
|
58
|
+
ok: true;
|
|
59
|
+
paid: true;
|
|
60
|
+
/**
|
|
61
|
+
* The merchant's response. `undefined` when the payment was confirmed
|
|
62
|
+
* settled but the merchant did not respond before the deadline — you
|
|
63
|
+
* paid, the merchant never answered. Always check before use.
|
|
64
|
+
*/
|
|
65
|
+
response: Response | undefined;
|
|
66
|
+
/** Atomic amount actually paid. */
|
|
67
|
+
amountPaid: string;
|
|
68
|
+
network: NetworkRef;
|
|
69
|
+
txSignature?: string;
|
|
70
|
+
} | {
|
|
71
|
+
ok: true;
|
|
72
|
+
paid: false;
|
|
73
|
+
response: Response;
|
|
74
|
+
} | {
|
|
75
|
+
ok: false;
|
|
76
|
+
reason: 'unsupported_network' | 'insufficient_funds'
|
|
77
|
+
/** The merchant rejected the payment itself — bad/declined payload,
|
|
78
|
+
* failed verification. Our side: check the payment. */
|
|
79
|
+
| 'merchant_rejected'
|
|
80
|
+
/** The merchant ACCEPTED the payment shape but their own settlement
|
|
81
|
+
* failed (their facilitator errored). Not our payload — a
|
|
82
|
+
* merchant-side defect. `detail` carries their verbatim error. */
|
|
83
|
+
| 'settlement_failed' | 'no_payment_options'
|
|
84
|
+
/** No payment was sent before the deadline — the unpaid probe (or
|
|
85
|
+
* build/sign) ran past the pre-payment timeout. No money moved;
|
|
86
|
+
* safe to retry. */
|
|
87
|
+
| 'timeout'
|
|
88
|
+
/** The payment authorization WAS sent to the merchant, the merchant
|
|
89
|
+
* did not respond before the deadline, and settlement could not be
|
|
90
|
+
* confirmed. The payment MAY have settled on-chain. DO NOT
|
|
91
|
+
* blind-retry — a retry signs a fresh authorization and can pay
|
|
92
|
+
* again. `detail` explains the state. */
|
|
93
|
+
| 'payment_unconfirmed' | 'budget_exceeded' | 'error';
|
|
94
|
+
detail?: string;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** Options for a paid fetch. */
|
|
98
|
+
interface PayAndFetchOptions {
|
|
99
|
+
/** Max total atomic spend for this call. */
|
|
100
|
+
maxAmountAtomic?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Pre-payment timeout in ms — the deadline for the unpaid probe and the
|
|
103
|
+
* build/sign step, i.e. everything BEFORE the payment authorization is
|
|
104
|
+
* sent. Exceeding it yields `reason: 'timeout'` (no money moved, safe to
|
|
105
|
+
* retry). Default 15000.
|
|
106
|
+
*
|
|
107
|
+
* This does NOT bound the wait for the merchant's response once payment
|
|
108
|
+
* has been dispatched — see `responseTimeoutMs`. The two phases have
|
|
109
|
+
* separate deadlines on purpose: once the payment is out the door,
|
|
110
|
+
* aborting the wait does not un-spend the money.
|
|
111
|
+
*/
|
|
112
|
+
timeoutMs?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Post-payment timeout in ms — the deadline for the merchant's response
|
|
115
|
+
* AFTER the payment authorization has been sent. Exceeding it does not
|
|
116
|
+
* yield `'timeout'`; it yields `'payment_unconfirmed'` (or, once on-chain
|
|
117
|
+
* confirmation lands, a confirmed `paid: true`). Default 120000.
|
|
118
|
+
*
|
|
119
|
+
* Generous by design: research / scout / agent endpoints routinely take
|
|
120
|
+
* tens of seconds, and the money is already committed once this phase
|
|
121
|
+
* begins — there is no benefit to a tight deadline here.
|
|
122
|
+
*/
|
|
123
|
+
responseTimeoutMs?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Solana RPC endpoint for v1 SVM payment signing. v1 Solana `exact`
|
|
126
|
+
* signing builds a real transaction and needs RPC access (mint lookup,
|
|
127
|
+
* recent blockhash). Ignored for EVM-only flows. Defaults to the public
|
|
128
|
+
* Solana RPC when omitted — callers should pass their own for
|
|
129
|
+
* reliability.
|
|
130
|
+
*/
|
|
131
|
+
solanaRpcUrl?: string;
|
|
132
|
+
/**
|
|
133
|
+
* An open spend-tab to pay `tab`-scheme accepts entries with. Used only
|
|
134
|
+
* when the 402 offers scheme "tab" AND the option's payTo matches the
|
|
135
|
+
* counterparty this tab was opened against — otherwise ignored and the
|
|
136
|
+
* normal exact/batch path runs.
|
|
137
|
+
*/
|
|
138
|
+
tab?: Tab;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The contract each version module implements.
|
|
142
|
+
*
|
|
143
|
+
* parseChallenge: given a raw 402 Response, extract the challenge — or
|
|
144
|
+
* null if this strategy does not recognise it as its version.
|
|
145
|
+
* pay: given a parsed challenge, sign + send the paid request, return
|
|
146
|
+
* the merchant's response.
|
|
147
|
+
*/
|
|
148
|
+
interface PaymentStrategy {
|
|
149
|
+
readonly version: 1 | 2;
|
|
150
|
+
parseChallenge(res: Response): Promise<PaymentChallenge | null>;
|
|
151
|
+
pay(url: string, requestInit: RequestInit, challenge: PaymentChallenge, wallets: WalletSet, opts: PayAndFetchOptions): Promise<PayResult>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export type { ChallengeOption as C, NetworkRef as N, PayAndFetchOptions as P, PayResult as a, PaymentStrategy as b, PaymentChallenge as c };
|