@dexterai/x402 5.2.0 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +1 -1
- package/dist/tab/adapters/solana/index.cjs +1 -1
- package/dist/tab/adapters/solana/index.d.cts +150 -5
- package/dist/tab/adapters/solana/index.d.ts +150 -5
- package/dist/tab/adapters/solana/index.js +1 -1
- package/dist/tab/index.cjs +4 -4
- package/dist/tab/index.d.cts +11 -3
- package/dist/tab/index.d.ts +11 -3
- package/dist/tab/index.js +4 -4
- package/dist/tab/seller/index.cjs +4 -4
- package/dist/tab/seller/index.d.cts +48 -2
- package/dist/tab/seller/index.d.ts +48 -2
- package/dist/tab/seller/index.js +4 -4
- package/dist/{types-D5eKDMvo.d.cts → types-CSuISjXA.d.cts} +81 -4
- package/dist/{types-D5eKDMvo.d.ts → types-CSuISjXA.d.ts} +81 -4
- package/dist/{types-CWYzWTwF.d.cts → types-CZHPdVkg.d.cts} +1 -1
- package/dist/{types-rSrCtwS2.d.ts → types-Co5YYhVB.d.ts} +1 -1
- package/package.json +4 -4
- package/assets/openai-pricing.md +0 -385
|
@@ -71,6 +71,17 @@ interface ChannelLedgerEntry {
|
|
|
71
71
|
* pre-Step-4 ledger constructors remain valid without a breaking change.
|
|
72
72
|
*/
|
|
73
73
|
lastCrystallizedCumulativeAtomic?: AtomicAmount;
|
|
74
|
+
/**
|
|
75
|
+
* Gate-refused watermark (cadence spec §5 [A12]): the highest voucher
|
|
76
|
+
* cumulative (atomic) the facilitator's router gate REFUSED with
|
|
77
|
+
* `below_lock_cadence`. The crystallization cadence skips re-attempting
|
|
78
|
+
* any span at or below it — the facilitator's server-side engine already
|
|
79
|
+
* guarantees the protection cadence, so re-asking about the identical
|
|
80
|
+
* refused span on every delivery/close is a retry storm, not protection.
|
|
81
|
+
* A NEW signed voucher (higher cumulative) always re-attempts; a
|
|
82
|
+
* successful lock clears it. Absent on entries that were never refused.
|
|
83
|
+
*/
|
|
84
|
+
gateRefusedCumulativeAtomic?: AtomicAmount;
|
|
74
85
|
/** RESERVED (Step 4): on-chain money ledger snapshot. Unset today. */
|
|
75
86
|
onChain?: OnChainLedgerSnapshot;
|
|
76
87
|
/**
|
|
@@ -205,6 +216,18 @@ interface TabMiddlewareOptions {
|
|
|
205
216
|
* crystallize never blocks or errors the seller's response; a missed lock
|
|
206
217
|
* just widens the seller's unsecured window (their risk dial).
|
|
207
218
|
*
|
|
219
|
+
* ADVISORY as of 5.3.1: the protection cadence is becoming
|
|
220
|
+
* FACILITATOR-owned — a server-side engine that fires locks at the
|
|
221
|
+
* operator's on-chain intent knob (a penny) for every seller, whatever
|
|
222
|
+
* this client-side setting says. This cadence defers to that engine as it
|
|
223
|
+
* rolls out; until it is live on your facilitator, this setting is still
|
|
224
|
+
* your mid-stream protection, and it remains the seller's own
|
|
225
|
+
* lock-more-aggressively dial either way. A cadence-gated
|
|
226
|
+
* facilitator may refuse sub-threshold seller-initiated locks with
|
|
227
|
+
* `below_lock_cadence` — benign (the engine already protected you); the
|
|
228
|
+
* SDK records a gate-refused watermark so the same span is never
|
|
229
|
+
* re-attempted (see `ChannelLedgerEntry.gateRefusedCumulativeAtomic`).
|
|
230
|
+
*
|
|
208
231
|
* Defaults when omitted: `{ thresholdAtomic: humanToAtomic('0.10'),
|
|
209
232
|
* onClose: true }`. Set `thresholdAtomic` higher to crystallize less often
|
|
210
233
|
* (cheaper, wider window) or lower to lock more aggressively. Set
|
|
@@ -401,8 +424,19 @@ declare class OnChainVerificationError extends Error {
|
|
|
401
424
|
readonly reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program';
|
|
402
425
|
constructor(reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program', detail?: string);
|
|
403
426
|
}
|
|
427
|
+
/** The session's on-chain terminal odometers, read as a by-product of the
|
|
428
|
+
* first-voucher verification. `frontierAtomic` = max(spent, crystallized) —
|
|
429
|
+
* the floor below which no voucher can ever settle or lock again. The
|
|
430
|
+
* middleware seeds a FRESH channel's delivered baseline from it so a resumed
|
|
431
|
+
* session can't re-consume budget that already settled/crystallized. */
|
|
432
|
+
interface OnChainSessionFrontier {
|
|
433
|
+
frontierAtomic: AtomicAmount;
|
|
434
|
+
spentAtomic: AtomicAmount;
|
|
435
|
+
crystallizedCumulativeAtomic: AtomicAmount;
|
|
436
|
+
}
|
|
404
437
|
/**
|
|
405
|
-
* Verify a registration against on-chain state. Throws on any mismatch
|
|
438
|
+
* Verify a registration against on-chain state. Throws on any mismatch;
|
|
439
|
+
* on success returns the session's terminal odometers (frontier).
|
|
406
440
|
*
|
|
407
441
|
* V6: a session is its own PDA ([b"session", vault, allowed_counterparty]),
|
|
408
442
|
* NOT an inline field on the vault. We read that SessionAccount and confirm it
|
|
@@ -416,7 +450,7 @@ declare class OnChainVerificationError extends Error {
|
|
|
416
450
|
* configured at the commitment the buyer's registration was confirmed to (the
|
|
417
451
|
* adapter waits for visibility before openTab returns).
|
|
418
452
|
*/
|
|
419
|
-
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<
|
|
453
|
+
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<OnChainSessionFrontier>;
|
|
420
454
|
declare class InvalidVoucherSignatureError extends Error {
|
|
421
455
|
constructor(detail?: string);
|
|
422
456
|
}
|
|
@@ -504,6 +538,18 @@ interface TabOrExactConfig {
|
|
|
504
538
|
perUnit: HumanAmount;
|
|
505
539
|
facilitatorUrl?: string;
|
|
506
540
|
description?: string;
|
|
541
|
+
/**
|
|
542
|
+
* Keyless crystallization cadence for the tab rail — forwarded verbatim to
|
|
543
|
+
* `tabMiddleware` (see `TabMiddlewareOptions.lockCadence`). This is the
|
|
544
|
+
* seller's own on-chain LockVoucher dial (mid-stream protection); ADVISORY
|
|
545
|
+
* as of 5.3.1 — it defers to the facilitator-owned cadence engine as that
|
|
546
|
+
* engine rolls out server-side, and stays your mid-stream protection until
|
|
547
|
+
* it is live on your facilitator. Omitted → armed by default
|
|
548
|
+
* (`thresholdAtomic: humanToAtomic('0.10'), onClose: true`). Pass
|
|
549
|
+
* `{ onClose: false }` to disarm the close-time lock, or `{ thresholdAtomic }`
|
|
550
|
+
* to change the threshold cadence.
|
|
551
|
+
*/
|
|
552
|
+
lockCadence?: TabMiddlewareOptions['lockCadence'];
|
|
507
553
|
}
|
|
508
554
|
declare function tabOrExactMiddleware(config: TabOrExactConfig): RequestHandler;
|
|
509
555
|
|
package/dist/tab/seller/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var S=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};import{promises as V}from"fs";import{join as qe,dirname as ze}from"path";var Ne=new Map;function P(e,t){let n=(Ne.get(e)??Promise.resolve()).then(()=>t(),()=>t());return Ne.set(e,n.then(()=>{},()=>{})),n}var $=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)}async tryAcquireLease(t,r){return P(t,async()=>{let n=this.map.get(t),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(t,{...s,lease:{heldUntilUnixMs:i+r}}),!0})}async releaseLease(t){await P(t,async()=>{let r=this.map.get(t);r&&this.map.set(t,{...r,lease:void 0})})}};function ce(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function le(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}function We(e){return{lastVoucher:e.lastVoucher?{payload:e.lastVoucher.payload,sessionPublicKey:ce(e.lastVoucher.sessionPublicKey),sessionRegistration:ce(e.lastVoucher.sessionRegistration),sessionSignature:ce(e.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:e.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:e.lastCrystallizedCumulativeAtomic,onChain:e.onChain,lease:e.lease}}function Fe(e){return{lastVoucher:e.lastVoucher?{payload:e.lastVoucher.payload,sessionPublicKey:le(e.lastVoucher.sessionPublicKey),sessionRegistration:le(e.lastVoucher.sessionRegistration),sessionSignature:le(e.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:e.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:e.lastCrystallizedCumulativeAtomic??"0",onChain:e.onChain,lease:e.lease}}var ue=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return qe(this.dir,`${t}.json`)}async get(t){try{let r=await V.readFile(this.pathFor(t),"utf8");return Fe(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await V.mkdir(ze(n),{recursive:!0});let i=`${n}.tmp`;await V.writeFile(i,JSON.stringify(We(r))),await V.rename(i,n)}async delete(t){try{await V.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}async tryAcquireLease(t,r){return P(t,async()=>{let n=await this.get(t),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(t,{...s,lease:{heldUntilUnixMs:i+r}}),!0})}async releaseLease(t){await P(t,async()=>{let r=await this.get(t);r&&await this.set(t,{...r,lease:void 0})})}};import{PublicKey as Ze}from"@solana/web3.js";import je from"tweetnacl";import{sha256 as Mt}from"@noble/hashes/sha256";import{p256 as Dt}from"@noble/curves/p256";import{PublicKey as de}from"@solana/web3.js";import{sessionRegisterMessage as Et,sessionRevokeMessage as Ct,voucherPayloadMessage as me,buildVoucherMessage as Pt}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as _t,buildRevokeSessionKeyInstruction as Nt,deriveSwigWalletAddress as It}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as kt}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as pe,SECP256R1_PROGRAM_ID as Vt,INSTRUCTIONS_SYSVAR_ID as $t}from"@dexterai/vault/constants";import{fetchSessionAccount as Xe,isSessionLive as Je}from"@dexterai/vault/session";var ge="OTS_SESSION_REGISTER_V2",E=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function he(e){if(e.length!==188)throw new E("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,ge.length));if(t!==ge)throw new E("wrong_domain",`got "${t}"`);for(let y=ge.length;y<32;y++)if(e[y]!==0)throw new E("wrong_domain",`non-NUL padding at byte ${y}`);let r=new DataView(e.buffer,e.byteOffset,e.byteLength),n=new de(e.slice(32,64)),i=new de(e.slice(64,96)),s=e.slice(96,128),p=r.getBigUint64(128,!0),u=r.getBigInt64(136,!0),o=new de(e.slice(144,176)),d=r.getUint32(176,!0),c=r.getBigUint64(180,!0);if(!n.equals(pe))throw new E("wrong_program",`${n.toBase58()} is not ${pe.toBase58()}`);if(p===0n)throw new E("cap_zero");let a=BigInt(Math.floor(Date.now()/1e3));if(u<=a)throw new E("expiry_in_past",`expires_at=${u}, now=${a}`);return{programId:n,vaultPda:i,sessionPubkey:new Uint8Array(s),maxAmount:p,expiresAt:u,allowedCounterparty:o,nonce:d,maxRevolvingCapacity:c}}var _=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function ye(e,t){let r=await Xe(e,t.vaultPda,t.allowedCounterparty);if(!r||r.version===0)throw new _("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!Je(r))throw new _("session_not_active","SessionAccount PDA is present but expired");if(!Ye(r.session.sessionPubkey,t.sessionPubkey))throw new _("session_pubkey_mismatch",`on-chain ${Ie(r.session.sessionPubkey)} != registration ${Ie(t.sessionPubkey)}`)}var T=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function fe(e,t){if(t.length!==32)throw new T(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new T(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new T(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let r=me({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!je.sign.detached.verify(r,e.sessionSignature,e.sessionPublicKey))throw new T("ed25519 verify rejected")}var x=class extends Error{constructor(r,n){super(`Scope violation: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="ScopeViolationError"}};function Ae(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new x("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=e.registration.expiresAt)throw new x("session_expired",`now=${r} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new x("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let n=BigInt(e.previousCumulativeAtomic);if(t<=n)throw new x("non_monotonic",`cumulative=${t} not > previous=${n}`)}}function Ye(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 Ie(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}import{PublicKey as or}from"@solana/web3.js";import{bytesToHex as cr}from"@noble/hashes/utils";import Yt from"tweetnacl";import{sha256 as Qt}from"@noble/hashes/sha256";var Ue="https://x402.dexter.cash",ke=6;function C(e,t=ke){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 i=n.padEnd(t,"0"),s=`${r}${i}`.replace(/^0+(?=\d)/,"");return s===""?"0":s}function N(e,t=ke){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",i=r.slice(-t).replace(/0+$/,"");return i?`${n}.${i}`:n}import{bytesToHex as be}from"@noble/hashes/utils";var Ge=15e3;async function we(e,t,r,n,i=fetch){let s=e.lastVoucher;if(!s)return{crystallized:!1};if(s.payload.channelId!==t)return{crystallized:!1,error:"channel_id_mismatch"};try{let p=`${r.replace(/\/$/,"")}/tab/lock`,u={channelId:s.payload.channelId,cumulativeAmount:s.payload.cumulativeAmount,sequenceNumber:s.payload.sequenceNumber,sessionPublicKey:be(s.sessionPublicKey),sessionSignature:be(s.sessionSignature),sessionRegistration:be(s.sessionRegistration),network:n},o=await i(p,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(u),signal:AbortSignal.timeout(Ge)}),d=await o.text();if(!o.ok)return{crystallized:!1,error:`tab lock ${o.status}: ${d.slice(0,200)}`};let c;try{let a=JSON.parse(d);a&&typeof a.claimPda=="string"&&(c=a.claimPda)}catch{}return{crystallized:!0,claimPda:c}}catch(p){return{crystallized:!1,error:String(p?.message??p)}}}async function Oe(e,t,r,n,i,s={}){let p=BigInt(e.deliveredCumulativeAtomic),u=BigInt(e.lastCrystallizedCumulativeAtomic??"0"),o=BigInt(i.thresholdAtomic);if(p-u<o)return{crystallized:!1};let d=e.lastVoucher?.payload.cumulativeAmount,c=await we(e,t,r,n,s.fetchImpl);return c.crystallized&&d!==void 0&&(e.lastCrystallizedCumulativeAtomic=d),c}var I="x-tab-voucher",ve=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)}},Se=class{constructor(t,r,n,i,s,p){this.recordDeliveredImpl=s;this.chargeImpl=p;this.channelId=t,this.network=r,this.cumulativeAtomic=n,this.deliveredBaselineAtomic=i}channelId;network;sessionPublicKey=null;cumulativeAtomic;deliveredBaselineAtomic;cumulative(){return N(this.cumulativeAtomic.toString())}deliveredCumulative(){return N(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 Qe(e){if(typeof e!="string"||e.length===0)throw new S("signature_invalid",`missing ${I} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new S("signature_invalid","malformed base64")}let r;try{r=JSON.parse(t)}catch{throw new S("signature_invalid","malformed JSON")}if(!r||typeof r!="object"||!r.payload||!r.sessionPublicKey)throw new S("signature_invalid","missing required fields");return{payload:r.payload,sessionPublicKey:j(r.sessionPublicKey),sessionRegistration:j(r.sessionRegistration),sessionSignature:j(r.sessionSignature)}}function j(e){if(typeof e!="string"||e.length%2!==0)throw new S("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 et(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new S("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return j(e)}function xe(e){let t=e.ledger??new $,r=new ve,n=typeof e.sellerPubkey=="string"?new Ze(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(C(e.perUnit))*100n,s=e.facilitatorUrl??Ue,p={thresholdAtomic:e.lockCadence?.thresholdAtomic??C("0.10"),onClose:e.lockCadence?.onClose??!0};return async(u,o,d)=>{try{let c=Qe(u.headers[I]),a=c.payload.channelId,y=et(a),m=r.get(a);if(!m){let g=he(c.sessionRegistration);await ye(e.connection,g),m={registration:g,lastCumulativeAtomic:"0"},r.set(a,m)}fe(c,y),Ae({registration:m.registration,voucher:c,expectedCounterparty:n,previousCumulativeAtomic:m.lastCumulativeAtomic});let f=BigInt(c.payload.cumulativeAmount),w=BigInt(m.lastCumulativeAtomic),U=f-w;if(U>i)throw new x("cumulative_exceeds_cap",`single voucher increment ${U} exceeds maxPerVoucherAtomic ${i}`);let q=e.leaseTtlMs??3e5;if(!await t.tryAcquireLease(a,q))throw new S("channel_busy","another stream is live on this channel; tabs serve one stream at a time");let z=!1,k=()=>{z||(z=!0,t.releaseLease(a).catch(g=>{console.error("[tab/seller] failed to release channel lease:",g)}))};o.on("close",k),o.on("finish",k);let ae=async g=>{let v=g.lastCrystallizedCumulativeAtomic??"0";await Oe(g,a,s,e.network,p),g.lastCrystallizedCumulativeAtomic!==v&&await P(a,async()=>{let b=await t.get(a);b&&await t.set(a,{...b,lastCrystallizedCumulativeAtomic:g.lastCrystallizedCumulativeAtomic})}).catch(()=>{})},W=!1,F=()=>{!p.onClose||W||(W=!0,(async()=>{let g=await t.get(a);if(!g||!g.lastVoucher)return;let v=g.lastVoucher.payload.cumulativeAmount;(await we(g,a,s,e.network)).crystallized&&await P(a,async()=>{let O=await t.get(a);O&&await t.set(a,{...O,lastCrystallizedCumulativeAtomic:v})})})().catch(()=>{}))};o.on("close",F),o.on("finish",F);let l=await t.get(a),h=l?BigInt(l.deliveredCumulativeAtomic):0n;await P(a,async()=>{let g=await t.get(a);await t.set(a,{...g,lastVoucher:c,deliveredCumulativeAtomic:g?g.deliveredCumulativeAtomic:"0"})}),r.update(a,c.payload.cumulativeAmount);let A=new Se(a,e.network,f,h,async g=>{let v=null;await P(a,async()=>{let b=await t.get(a),O=b?BigInt(b.deliveredCumulativeAtomic):0n,Re=BigInt(g),He=Re>0n?O+Re:O,_e={...b,lastVoucher:b?.lastVoucher??c,deliveredCumulativeAtomic:He.toString(),lastCrystallizedCumulativeAtomic:b?.lastCrystallizedCumulativeAtomic??"0"};await t.set(a,_e),v=_e}),v&&ae(v).catch(()=>{})},async g=>{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.")});A.setSessionPublicKey(c.sessionPublicKey),u.tab=A,d()}catch(c){if(c instanceof S||c instanceof E||c instanceof _||c instanceof T||c instanceof x){o.status(402).json({error:"invalid_voucher",reason:c.reason??"unknown",detail:c.message});return}d(c)}}}function tt(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function rt(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(C(r.cumulative())),i=BigInt(C(r.deliveredCumulative())),s=n-i;s<0n&&(s=0n);let p=t.perUnit?BigInt(C(t.perUnit)):null,u=0n,o=!1;async function d(){await r.recordDelivered(u.toString())}e.on("close",()=>{o||(o=!0,d().catch(m=>{console.error("[tab/seller] terminal persist failed on disconnect:",m)}))});async function c(m=1){if(o)throw new Error("meter ended");if(p===null)throw new Error("charge() needs options.perUnit");let f=p*BigInt(m),w=u+f;if(w>s)throw o=!0,await d(),new x("cumulative_exceeds_cap",`chunk would push delivered to ${N((i+w).toString())} beyond signed cumulative ${N(n.toString())} (per-request budget ${N(s.toString())})`);u=w}function a(m){if(o)throw new Error("meter ended");let w=(typeof m=="string"?m:Buffer.from(m).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${w}
|
|
1
|
+
var x=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};import{promises as K}from"fs";import{join as Xe,dirname as Je}from"path";var Oe=new Map;function T(e,t){let n=(Oe.get(e)??Promise.resolve()).then(()=>t(),()=>t());return Oe.set(e,n.then(()=>{},()=>{})),n}var M=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)}async tryAcquireLease(t,r){return T(t,async()=>{let n=this.map.get(t),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(t,{...s,lease:{heldUntilUnixMs:i+r}}),!0})}async releaseLease(t){await T(t,async()=>{let r=this.map.get(t);r&&this.map.set(t,{...r,lease:void 0})})}};function de(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}function Ge(e){return{lastVoucher:e.lastVoucher?{payload:e.lastVoucher.payload,sessionPublicKey:de(e.lastVoucher.sessionPublicKey),sessionRegistration:de(e.lastVoucher.sessionRegistration),sessionSignature:de(e.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:e.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:e.lastCrystallizedCumulativeAtomic,gateRefusedCumulativeAtomic:e.gateRefusedCumulativeAtomic,onChain:e.onChain,lease:e.lease}}function Ye(e){return{lastVoucher:e.lastVoucher?{payload:e.lastVoucher.payload,sessionPublicKey:pe(e.lastVoucher.sessionPublicKey),sessionRegistration:pe(e.lastVoucher.sessionRegistration),sessionSignature:pe(e.lastVoucher.sessionSignature)}:null,deliveredCumulativeAtomic:e.deliveredCumulativeAtomic,lastCrystallizedCumulativeAtomic:e.lastCrystallizedCumulativeAtomic??"0",gateRefusedCumulativeAtomic:e.gateRefusedCumulativeAtomic,onChain:e.onChain,lease:e.lease}}var ge=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return Xe(this.dir,`${t}.json`)}async get(t){try{let r=await K.readFile(this.pathFor(t),"utf8");return Ye(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await K.mkdir(Je(n),{recursive:!0});let i=`${n}.tmp`;await K.writeFile(i,JSON.stringify(Ge(r))),await K.rename(i,n)}async delete(t){try{await K.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}async tryAcquireLease(t,r){return T(t,async()=>{let n=await this.get(t),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(t,{...s,lease:{heldUntilUnixMs:i+r}}),!0})}async releaseLease(t){await T(t,async()=>{let r=await this.get(t);r&&await this.set(t,{...r,lease:void 0})})}};import{PublicKey as ot}from"@solana/web3.js";import Ze from"tweetnacl";import{sha256 as jt}from"@noble/hashes/sha256";import{p256 as Jt}from"@noble/curves/p256";import{PublicKey as fe}from"@solana/web3.js";import{sessionRegisterMessage as kt,sessionRevokeMessage as Ut,voucherPayloadMessage as he,buildVoucherMessage as Ot}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as Bt,buildRevokeSessionKeyInstruction as Lt,deriveSwigWalletAddress as Kt}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as Dt}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as ye,SECP256R1_PROGRAM_ID as Ht,INSTRUCTIONS_SYSVAR_ID as qt}from"@dexterai/vault/constants";import{fetchSessionAccount as Qe,isSessionLive as et}from"@dexterai/vault/session";var Ae="OTS_SESSION_REGISTER_V2",E=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function be(e){if(e.length!==188)throw new E("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,Ae.length));if(t!==Ae)throw new E("wrong_domain",`got "${t}"`);for(let y=Ae.length;y<32;y++)if(e[y]!==0)throw new E("wrong_domain",`non-NUL padding at byte ${y}`);let r=new DataView(e.buffer,e.byteOffset,e.byteLength),n=new fe(e.slice(32,64)),i=new fe(e.slice(64,96)),s=e.slice(96,128),h=r.getBigUint64(128,!0),c=r.getBigInt64(136,!0),a=new fe(e.slice(144,176)),m=r.getUint32(176,!0),l=r.getBigUint64(180,!0);if(!n.equals(ye))throw new E("wrong_program",`${n.toBase58()} is not ${ye.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 N=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function ve(e,t){let r=await Qe(e,t.vaultPda,t.allowedCounterparty);if(!r||r.version===0)throw new N("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!et(r))throw new N("session_not_active","SessionAccount PDA is present but expired");if(!tt(r.session.sessionPubkey,t.sessionPubkey))throw new N("session_pubkey_mismatch",`on-chain ${$e(r.session.sessionPubkey)} != registration ${$e(t.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(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function we(e,t){if(t.length!==32)throw new _(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new _(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new _(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let r=he({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!Ze.sign.detached.verify(r,e.sessionSignature,e.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 Se(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new C("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=e.registration.expiresAt)throw new C("session_expired",`now=${r} >= 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 n=BigInt(e.previousCumulativeAtomic);if(t<=n)throw new C("non_monotonic",`cumulative=${t} not > previous=${n}`)}}function tt(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 $e(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}import{PublicKey as gr}from"@solana/web3.js";import{bytesToHex as yr}from"@noble/hashes/utils";import ir from"tweetnacl";import{sha256 as ar}from"@noble/hashes/sha256";var Ve="https://x402.dexter.cash",Be=6;function R(e,t=Be){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 i=n.padEnd(t,"0"),s=`${r}${i}`.replace(/^0+(?=\d)/,"");return s===""?"0":s}function O(e,t=Be){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",i=r.slice(-t).replace(/0+$/,"");return i?`${n}.${i}`:n}import{bytesToHex as xe}from"@noble/hashes/utils";var rt=15e3,nt=["claim_already_exists","non_monotonic_cumulative"],it="below_lock_cadence";function J(e){return typeof e=="string"&&e.includes(it)}function st(e){return`${e.slice(0,16)}\u2026`}function Le(e,t,r,n){let i=st(e);if(n.crystallized){console.info(`[tab/seller] crystallize OK channel=${i} cumulative=${t} seq=${r}${n.claimPda?` claimPda=${n.claimPda}`:""} \u2014 LockVoucher landed`);return}if(n.error){if(J(n.error)){console.warn(`[tab/seller] crystallize refused below the facilitator's cadence gate channel=${i} cumulative=${t} 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(nt.some(s=>n.error.includes(s))){console.warn(`[tab/seller] crystallize duplicate channel=${i} cumulative=${t} seq=${r}: ${n.error} \u2014 voucher already secured on-chain (benign, no action)`);return}console.error(`[tab/seller] crystallize FAILED channel=${i} cumulative=${t} 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 Ce(e,t,r,n,i=fetch){let s=e.lastVoucher;if(!s)return{crystallized:!1};if(s.payload.channelId!==t){let c={crystallized:!1,error:"channel_id_mismatch"};return Le(t,s.payload.cumulativeAmount,s.payload.sequenceNumber,c),c}let h=c=>(Le(t,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:xe(s.sessionPublicKey),sessionSignature:xe(s.sessionSignature),sessionRegistration:xe(s.sessionRegistration),network:n},m=await i(c,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(a),signal:AbortSignal.timeout(rt)}),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 Ke(e,t,r,n,i,s={}){let h=BigInt(e.deliveredCumulativeAtomic),c=BigInt(e.lastCrystallizedCumulativeAtomic??"0"),a=BigInt(i.thresholdAtomic);if(h-c<a)return{crystallized:!1};let m=e.lastVoucher?.payload.cumulativeAmount,l=e.gateRefusedCumulativeAtomic;if(m!==void 0&&l!==void 0&&BigInt(m)<=BigInt(l))return{crystallized:!1};let o=await Ce(e,t,r,n,s.fetchImpl);return o.crystallized&&m!==void 0?(e.lastCrystallizedCumulativeAtomic=m,e.gateRefusedCumulativeAtomic=void 0):J(o.error)&&m!==void 0&&(e.gateRefusedCumulativeAtomic=m),o}var $="x-tab-voucher",Ee=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)}},Re=class{constructor(t,r,n,i,s,h){this.recordDeliveredImpl=s;this.chargeImpl=h;this.channelId=t,this.network=r,this.cumulativeAtomic=n,this.deliveredBaselineAtomic=i}channelId;network;sessionPublicKey=null;cumulativeAtomic;deliveredBaselineAtomic;cumulative(){return O(this.cumulativeAtomic.toString())}deliveredCumulative(){return O(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 at(e){if(typeof e!="string"||e.length===0)throw new x("signature_invalid",`missing ${$} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new x("signature_invalid","malformed base64")}let r;try{r=JSON.parse(t)}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:G(r.sessionPublicKey),sessionRegistration:G(r.sessionRegistration),sessionSignature:G(r.sessionSignature)}}function G(e){if(typeof e!="string"||e.length%2!==0)throw new x("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 ct(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new x("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return G(e)}function Pe(e){let t=e.ledger??new M,r=new Ee,n=typeof e.sellerPubkey=="string"?new ot(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(R(e.perUnit))*100n,s=e.facilitatorUrl??Ve,h={thresholdAtomic:e.lockCadence?.thresholdAtomic??R("0.10"),onClose:e.lockCadence?.onClose??!0};return async(c,a,m)=>{try{let l=at(c.headers[$]),o=l.payload.channelId,y=ct(o),d=r.get(o),f=null;if(!d){let p=be(l.sessionRegistration);f=(await ve(e.connection,p))?.frontierAtomic??null,d={registration:p,lastCumulativeAtomic:"0"},r.set(o,d)}we(l,y),Se({registration:d.registration,voucher:l,expectedCounterparty:n,previousCumulativeAtomic:d.lastCumulativeAtomic});let b=BigInt(l.payload.cumulativeAmount),V=BigInt(d.lastCumulativeAtomic),B=b-V;if(B>i)throw new C("cumulative_exceeds_cap",`single voucher increment ${B} exceeds maxPerVoucherAtomic ${i}`);let ue=e.leaseTtlMs??3e5;if(!await t.tryAcquireLease(o,ue))throw new x("channel_busy","another stream is live on this channel; tabs serve one stream at a time");let L=!1,j=()=>{L||(L=!0,t.releaseLease(o).catch(p=>{console.error("[tab/seller] failed to release channel lease:",p)}))};a.on("close",j),a.on("finish",j);let me=async p=>{let P=p.lastCrystallizedCumulativeAtomic??"0",S=p.gateRefusedCumulativeAtomic;await Ke(p,o,s,e.network,h),(p.lastCrystallizedCumulativeAtomic!==P||p.gateRefusedCumulativeAtomic!==S)&&await T(o,async()=>{let v=await t.get(o);v&&await t.set(o,{...v,lastCrystallizedCumulativeAtomic:p.lastCrystallizedCumulativeAtomic,gateRefusedCumulativeAtomic:p.gateRefusedCumulativeAtomic})}).catch(v=>{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):`,v)})},X=!1,u=()=>{!h.onClose||X||(X=!0,(async()=>{let p=await t.get(o);if(!p||!p.lastVoucher)return;let P=p.lastVoucher.payload.cumulativeAmount;if(p.gateRefusedCumulativeAtomic!==void 0&&BigInt(P)<=BigInt(p.gateRefusedCumulativeAtomic))return;let S=await Ce(p,o,s,e.network);S.crystallized?await T(o,async()=>{let v=await t.get(o);v&&await t.set(o,{...v,lastCrystallizedCumulativeAtomic:P,gateRefusedCumulativeAtomic:void 0})}):J(S.error)&&await T(o,async()=>{let v=await t.get(o);v&&await t.set(o,{...v,gateRefusedCumulativeAtomic:P})})})().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 t.get(o),A=!g?.lastVoucher&&BigInt(g?.deliveredCumulativeAtomic??"0")===0n,w=f!==null&&A&&BigInt(f)>0n?f:null;w!==null&&console.info(`[tab/seller] channel ${o.slice(0,16)}\u2026 resumed: seeding delivered baseline from chain frontier ${w} (session already settled/locked up to it \u2014 that span is not deliverable budget)`);let k=w!==null?BigInt(w):g?BigInt(g.deliveredCumulativeAtomic):0n;await T(o,async()=>{let p=await t.get(o);await t.set(o,{...p,lastVoucher:l,deliveredCumulativeAtomic:w??(p?p.deliveredCumulativeAtomic:"0"),lastCrystallizedCumulativeAtomic:w??p?.lastCrystallizedCumulativeAtomic??"0"})}),r.update(o,l.payload.cumulativeAmount);let U=new Re(o,e.network,b,k,async p=>{let P=null;await T(o,async()=>{let S=await t.get(o),v=S?BigInt(S.deliveredCumulativeAtomic):0n,ke=BigInt(p),je=ke>0n?v+ke:v,Ue={...S,lastVoucher:S?.lastVoucher??l,deliveredCumulativeAtomic:je.toString(),lastCrystallizedCumulativeAtomic:S?.lastCrystallizedCumulativeAtomic??"0"};await t.set(o,Ue),P=Ue}),P&&me(P).catch(S=>{console.error(`[tab/seller] crystallize cadence CRASHED channel=${o.slice(0,16)}\u2026 (threshold lock not attempted; retries at the next delivery):`,S)})},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.")});U.setSessionPublicKey(l.sessionPublicKey),c.tab=U,m()}catch(l){if(l instanceof x||l instanceof E||l instanceof N||l instanceof _||l instanceof C){a.status(402).json({error:"invalid_voucher",reason:l.reason??"unknown",detail:l.message});return}m(l)}}}function lt(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function ut(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(R(r.cumulative())),i=BigInt(R(r.deliveredCumulative())),s=n-i;s<0n&&(s=0n);let h=t.perUnit?BigInt(R(t.perUnit)):null,c=0n,a=!1;async function m(){await r.recordDelivered(c.toString())}e.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 ${O((i+b).toString())} beyond signed cumulative ${O(n.toString())} (per-request budget ${O(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(/\n/g,"\\n");e.write(`data: ${b}
|
|
2
2
|
|
|
3
|
-
`)}async function y(){
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}async function y(){a||(a=!0,await m(),e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${c}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:c,send:a,end:y}}import{promises as B}from"fs";import{join as nt,dirname as it}from"path";function st(e){return{payload:e.payload,sessionPublicKey:Ee(e.sessionPublicKey),sessionRegistration:Ee(e.sessionRegistration),sessionSignature:Ee(e.sessionSignature)}}function ot(e){return{payload:e.payload,sessionPublicKey:Ce(e.sessionPublicKey),sessionRegistration:Ce(e.sessionRegistration),sessionSignature:Ce(e.sessionSignature)}}function Ee(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function Ce(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 Pe=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)}},Te=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return nt(this.dir,`${t}.json`)}async get(t){try{let r=await B.readFile(this.pathFor(t),"utf8");return ot(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await B.mkdir(it(n),{recursive:!0});let i=`${n}.tmp`;await B.writeFile(i,JSON.stringify(st(r))),await B.rename(i,n)}async delete(t){try{await B.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}};import{PublicKey as pt}from"@solana/web3.js";var R="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",Ve="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",$e="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var K="eip155:8453",X="eip155:84532",J="eip155:42161",Y="eip155:137",G="eip155:10",Z="eip155:43114",Q="eip155:56",ee="eip155:1187947933",te="eip155:324705682",re="eip155:1";var ne="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var Be="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",at="0x55d398326f99059fF775485246999027B3197955",Ke="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Me={[Q]:Ke,[K]:Be,[X]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[J]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[Y]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[G]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[Z]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[ee]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[te]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[re]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Le={[at]:{symbol:"USDT",decimals:18},[Ke]:{symbol:"USDC",decimals:18}};var Rr={[Q]:56,[K]:8453,[X]:84532,[J]:42161,[Y]:137,[G]:10,[Z]:43114,[ee]:1187947933,[te]:324705682,[re]:1},_r={[R]:"https://api.dexter.cash/api/solana/rpc",[Ve]:"https://api.devnet.solana.com",[$e]:"https://api.testnet.solana.com"},Nr={[Q]:"https://api.dexter.cash/api/evm/bsc/rpc",[K]:"https://api.dexter.cash/api/base/rpc",[X]:"https://sepolia.base.org",[J]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[Y]:"https://api.dexter.cash/api/evm/polygon/rpc",[G]:"https://api.dexter.cash/api/evm/optimism/rpc",[Z]:"https://api.dexter.cash/api/evm/avalanche/rpc",[ee]:"https://skale-base.skalenodes.com/v1/base",[te]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[re]:"https://eth.llamarpc.com"},M="https://x402.dexter.cash";function ie(e){return e.startsWith("solana:")||e==="solana"}function ct(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 lt(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 ct(JSON.stringify(e))}function L(e){return JSON.parse(lt(e))}function ut(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 D=class extends Error{status;body;constructor(t,r){super(`HTTP ${t}`),this.status=t,this.body=r}},oe=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=M,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,i=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(t,{...r,signal:n.signal})}finally{clearTimeout(i)}}async fetchWithRetry(t,r){let n;for(let i=0;i<this.maxRetries;i++)try{let s=await this.fetchWithTimeout(t,r);if(!s.ok&&s.status>=500)throw new D(s.status,await s.text());return s}catch(s){if(n=s,i<this.maxRetries-1&&ut(s)){let p=this.retryBaseMs*Math.pow(2,i);await new Promise(u=>setTimeout(u,p));continue}throw s}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(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval")&&i.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(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval"||i.scheme==="batch-settlement")&&i.network===t)?.extra}async verifyPayment(t,r){try{let n=L(t),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 D?`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=L(t),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 D?`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 mt(e){if(ie(e))return{address:ne,decimals:6};let t=Me[e];if(t){let r=Le[t]?.decimals??6;return{address:t,decimals:r}}return{address:ne,decimals:6}}function De(e){try{let t=L(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function H(e){let{payTo:t,facilitatorUrl:r=M,network:n=R,defaultTimeoutSeconds:i=60}=e,s=e.asset??mt(n),p=e.scheme??"exact";if(p==="tab"&&!ie(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let u=new oe(r),o=null,d=new Map,c=3e4,a=Date.now();function y(l){let h=(l.maxTimeoutSeconds||i)*1e3;if(d.set(l.payTo,{accept:l,expiresAt:Date.now()+h}),Date.now()-a>c){let A=Date.now();for(let[g,v]of d)v.expiresAt<A&&d.delete(g);a=A}}function m(l){let h=d.get(l);if(h){if(h.expiresAt<Date.now()){d.delete(l);return}return h.accept}}async function f(l){return typeof t=="string"?t:t(l||{})}async function w(){if(o||(o=await u.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??s.decimals,name:o?.name,version:o?.version,...p==="batch-settlement"&&o?.receiverAuthorizer?{receiverAuthorizer:o.receiverAuthorizer}:{},...p==="tab"?{voucherHeader:"x-tab-voucher",registrationEncoding:"base64(188-byte sessionRegisterMessage)"}:{}}}async function U(l,h){let{amountAtomic:A,timeoutSeconds:g=i}=h,v=await w(),b={scheme:p,network:n,amount:A,maxAmountRequired:A,asset:s.address,payTo:l,maxTimeoutSeconds:g,extra:v};return y(b),b}async function q(l){let h=await f({amountAtomic:l.amountAtomic,resourceUrl:l.resourceUrl});return U(h,l)}async function z(l){let{resourceUrl:h,description:A,mimeType:g="application/json"}=l,v={url:h,description:A,mimeType:g},b=await q(l);return{x402Version:2,resource:v,accepts:[b],error:"Payment required"}}function k(l){return se(l)}function ae(l){return{status:402,headers:{"PAYMENT-REQUIRED":k(l)},body:{}}}async function W(l,h){if(!h){let A=await f({paymentHeader:l});h=m(A),h||(h=await U(A,{amountAtomic:De(l)??"0",resourceUrl:""}))}return u.verifyPayment(l,h)}async function F(l,h){if(!h){let A=await f({paymentHeader:l});h=m(A),h||(h=await U(A,{amountAtomic:De(l)??"0",resourceUrl:""}))}return u.settlePayment(l,h)}return{buildRequirements:z,encodeRequirements:k,create402Response:ae,verifyPayment:W,settlePayment:F,getPaymentAccept:q,network:n,assetDecimals:s.decimals,facilitator:u}}var dt={"solana:mainnet":R};function gt(e){let t=dt[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new pt(r);let n=H({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),i=C(e.perUnit);return async(s,p,u)=>{if(s.headers[I])return u();try{let o=`${s.protocol}://${s.get("host")}${s.originalUrl}`,d=await n.buildRequirements({amountAtomic:i,resourceUrl:o,description:e.description}),c=n.create402Response(d);p.set(c.headers).status(c.status).json(c.body)}catch(o){let d=o?.message??String(o);p.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:d})}}}import{PublicKey as ht}from"@solana/web3.js";var yt={"solana:mainnet":R};function ft(e){let t=yt[e.network];if(!t)throw new Error(`tabOrExactMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new ht(r);let n=H({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),i=H({payTo:r,network:t,scheme:"exact",facilitatorUrl:e.facilitatorUrl}),s=C(e.perUnit),p=xe({connection:e.connection,sellerPubkey:r,network:e.network,perUnit:e.perUnit,settle:"on-close",facilitatorUrl:e.facilitatorUrl});return async(u,o,d)=>{if(u.headers[I])return p(u,o,d);let c=`${u.protocol}://${u.get("host")}${u.originalUrl}`,a=u.headers["payment-signature"];if(a){let y;try{y=await i.getPaymentAccept({amountAtomic:s,resourceUrl:c,description:e.description})}catch(m){let f=m?.message??String(m);o.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:f});return}try{let m=await i.verifyPayment(a,y);if(!m.isValid){o.status(402).json({error:"Payment verification failed",reason:m.invalidReason});return}let f=await i.settlePayment(a,y);if(!f.success){o.status(402).json({error:"Payment settlement failed",reason:f.errorReason});return}return u.x402={transaction:f.transaction,payer:m.payer??"",network:f.network||t},o.setHeader("PAYMENT-RESPONSE",se({success:!0,transaction:f.transaction,network:f.network||t,payer:m.payer??""})),d()}catch{o.status(500).json({error:"Payment processing error"});return}}try{let y={amountAtomic:s,resourceUrl:c,description:e.description},[m,f]=await Promise.all([n.buildRequirements(y),i.buildRequirements(y)]),w={...m,accepts:[...m.accepts,...f.accepts]};o.set({"PAYMENT-REQUIRED":n.encodeRequirements(w)}).status(402).json({error:"Payment required",accepts:w.accepts,resource:w.resource})}catch(y){let m=y?.message??String(y);o.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:m})}}}export{ue as FileChannelLedger,Te as FileVoucherStore,$ as InMemoryChannelLedger,Pe as InMemoryVoucherStore,E as InvalidRegistrationError,S as InvalidVoucherError,T as InvalidVoucherSignatureError,_ as OnChainVerificationError,x as ScopeViolationError,I as TAB_VOUCHER_HEADER,Ae as enforceScope,rt as openSse,he as parseRegistration,tt as requireTab,gt as tabChallengeMiddleware,xe as tabMiddleware,ft as tabOrExactMiddleware,ye as verifyRegistrationOnChain,fe as verifyVoucherSignature};
|
|
6
|
+
`),e.end())}return{charge:l,send:o,end:y}}import{promises as D}from"fs";import{join as mt,dirname as dt}from"path";function pt(e){return{payload:e.payload,sessionPublicKey:Te(e.sessionPublicKey),sessionRegistration:Te(e.sessionRegistration),sessionSignature:Te(e.sessionSignature)}}function gt(e){return{payload:e.payload,sessionPublicKey:_e(e.sessionPublicKey),sessionRegistration:_e(e.sessionRegistration),sessionSignature:_e(e.sessionSignature)}}function Te(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function _e(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 Ie=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)}},Ne=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return mt(this.dir,`${t}.json`)}async get(t){try{let r=await D.readFile(this.pathFor(t),"utf8");return gt(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await D.mkdir(dt(n),{recursive:!0});let i=`${n}.tmp`;await D.writeFile(i,JSON.stringify(pt(r))),await D.rename(i,n)}async delete(t){try{await D.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}};import{PublicKey as vt}from"@solana/web3.js";var I="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",Me="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",De="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var z="eip155:8453",Y="eip155:84532",Z="eip155:42161",Q="eip155:137",ee="eip155:10",te="eip155:43114",re="eip155:56",ne="eip155:1187947933",ie="eip155:324705682",se="eip155:1";var oe="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var ze="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",ht="0x55d398326f99059fF775485246999027B3197955",He="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",qe={[re]:He,[z]:ze,[Y]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[Z]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[Q]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[ee]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[te]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[ne]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[ie]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[se]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Fe={[ht]:{symbol:"USDT",decimals:18},[He]:{symbol:"USDC",decimals:18}};var Vr={[re]:56,[z]:8453,[Y]:84532,[Z]:42161,[Q]:137,[ee]:10,[te]:43114,[ne]:1187947933,[ie]:324705682,[se]:1},Br={[I]:"https://api.dexter.cash/api/solana/rpc",[Me]:"https://api.devnet.solana.com",[De]:"https://api.testnet.solana.com"},Lr={[re]:"https://api.dexter.cash/api/evm/bsc/rpc",[z]:"https://api.dexter.cash/api/base/rpc",[Y]:"https://sepolia.base.org",[Z]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[Q]:"https://api.dexter.cash/api/evm/polygon/rpc",[ee]:"https://api.dexter.cash/api/evm/optimism/rpc",[te]:"https://api.dexter.cash/api/evm/avalanche/rpc",[ne]:"https://skale-base.skalenodes.com/v1/base",[ie]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[se]:"https://eth.llamarpc.com"},H="https://x402.dexter.cash";function ae(e){return e.startsWith("solana:")||e==="solana"}function yt(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 ft(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 ce(e){return yt(JSON.stringify(e))}function q(e){return JSON.parse(ft(e))}function At(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 F=class extends Error{status;body;constructor(t,r){super(`HTTP ${t}`),this.status=t,this.body=r}},le=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=H,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,i=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(t,{...r,signal:n.signal})}finally{clearTimeout(i)}}async fetchWithRetry(t,r){let n;for(let i=0;i<this.maxRetries;i++)try{let s=await this.fetchWithTimeout(t,r);if(!s.ok&&s.status>=500)throw new F(s.status,await s.text());return s}catch(s){if(n=s,i<this.maxRetries-1&&At(s)){let h=this.retryBaseMs*Math.pow(2,i);await new Promise(c=>setTimeout(c,h));continue}throw s}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(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval")&&i.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(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval"||i.scheme==="batch-settlement")&&i.network===t)?.extra}async verifyPayment(t,r){try{let n=q(t),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 F?`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=q(t),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 F?`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 bt(e){if(ae(e))return{address:oe,decimals:6};let t=qe[e];if(t){let r=Fe[t]?.decimals??6;return{address:t,decimals:r}}return{address:oe,decimals:6}}function We(e){try{let t=q(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function W(e){let{payTo:t,facilitatorUrl:r=H,network:n=I,defaultTimeoutSeconds:i=60}=e,s=e.asset??bt(n),h=e.scheme??"exact";if(h==="tab"&&!ae(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let c=new le(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[w,k]of m)k.expiresAt<A&&m.delete(w);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 t=="string"?t:t(u||{})}async function b(){if(a||(a=await c.getNetworkExtra(n)),ae(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:w=i}=g,k=await b(),U={scheme:h,network:n,amount:A,maxAmountRequired:A,asset:s.address,payTo:u,maxTimeoutSeconds:w,extra:k};return y(U),U}async function B(u){let g=await f({amountAtomic:u.amountAtomic,resourceUrl:u.resourceUrl});return V(g,u)}async function ue(u){let{resourceUrl:g,description:A,mimeType:w="application/json"}=u,k={url:g,description:A,mimeType:w},U=await B(u);return{x402Version:2,resource:k,accepts:[U],error:"Payment required"}}function L(u){return ce(u)}function j(u){return{status:402,headers:{"PAYMENT-REQUIRED":L(u)},body:{}}}async function me(u,g){if(!g){let A=await f({paymentHeader:u});g=d(A),g||(g=await V(A,{amountAtomic:We(u)??"0",resourceUrl:""}))}return c.verifyPayment(u,g)}async function X(u,g){if(!g){let A=await f({paymentHeader:u});g=d(A),g||(g=await V(A,{amountAtomic:We(u)??"0",resourceUrl:""}))}return c.settlePayment(u,g)}return{buildRequirements:ue,encodeRequirements:L,create402Response:j,verifyPayment:me,settlePayment:X,getPaymentAccept:B,network:n,assetDecimals:s.decimals,facilitator:c}}var wt={"solana:mainnet":I};function St(e){let t=wt[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new vt(r);let n=W({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),i=R(e.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:e.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 xt}from"@solana/web3.js";var Ct={"solana:mainnet":I};function Et(e){let t=Ct[e.network];if(!t)throw new Error(`tabOrExactMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new xt(r);let n=W({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),i=W({payTo:r,network:t,scheme:"exact",facilitatorUrl:e.facilitatorUrl}),s=R(e.perUnit),h=Pe({connection:e.connection,sellerPubkey:r,network:e.network,perUnit:e.perUnit,settle:"on-close",facilitatorUrl:e.facilitatorUrl,lockCadence:e.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:e.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||t},a.setHeader("PAYMENT-RESPONSE",ce({success:!0,transaction:f.transaction,network:f.network||t,payer:d.payer??""})),m()}catch{a.status(500).json({error:"Payment processing error"});return}}try{let y={amountAtomic:s,resourceUrl:l,description:e.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{ge as FileChannelLedger,Ne as FileVoucherStore,M as InMemoryChannelLedger,Ie as InMemoryVoucherStore,E as InvalidRegistrationError,x as InvalidVoucherError,_ as InvalidVoucherSignatureError,N as OnChainVerificationError,C as ScopeViolationError,$ as TAB_VOUCHER_HEADER,Se as enforceScope,ut as openSse,be as parseRegistration,lt as requireTab,St as tabChallengeMiddleware,Pe as tabMiddleware,Et as tabOrExactMiddleware,ve as verifyRegistrationOnChain,we as verifyVoucherSignature};
|
|
@@ -27,10 +27,17 @@ interface VaultAdapter {
|
|
|
27
27
|
vaultPda: string;
|
|
28
28
|
/**
|
|
29
29
|
* Use the ROOT signer (passkey) to authorize a fresh session key. This is
|
|
30
|
-
* the only call that prompts the user
|
|
31
|
-
*
|
|
30
|
+
* the only call that prompts the user (twice when atomically replacing a
|
|
31
|
+
* live session — one revoke ceremony + one register ceremony). Returns a
|
|
32
|
+
* session that can be passed to `signWithSession` freely until the scope's
|
|
33
|
+
* cap or expiry is reached.
|
|
34
|
+
*
|
|
35
|
+
* The session PDA is keyed by (vault, counterparty) — re-authorizing
|
|
36
|
+
* against a counterparty you already hold a LIVE session with resolves to
|
|
37
|
+
* the same PDA. The adapter reads it first and applies
|
|
38
|
+
* `opts.onLiveSession` (default `'error'`): see {@link AuthorizeSessionOptions}.
|
|
32
39
|
*/
|
|
33
|
-
authorizeSession(scope: SessionScope): Promise<SessionKey>;
|
|
40
|
+
authorizeSession(scope: SessionScope, opts?: AuthorizeSessionOptions): Promise<SessionKey>;
|
|
34
41
|
/**
|
|
35
42
|
* Use the session key to sign a voucher. Cheap. Never prompts. The seller
|
|
36
43
|
* verifies against the session's registration; the session's registration
|
|
@@ -48,6 +55,28 @@ interface VaultAdapter {
|
|
|
48
55
|
*/
|
|
49
56
|
signCloseTab(session: SessionKey, channelId: string, cumulativeAmount: AtomicAmount): Promise<Uint8Array>;
|
|
50
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Live-session policy for `authorizeSession` / `openTab` (K-T4e).
|
|
60
|
+
*
|
|
61
|
+
* The on-chain program rejects registering over a LIVE session
|
|
62
|
+
* (`SessionAlreadyActive`); the pre-guard program silently overwrote it —
|
|
63
|
+
* stranding any of the old session's signed-but-unsettled vouchers beyond
|
|
64
|
+
* the on-chain frontier (`max(spent, crystallized_cumulative)`). Neither is
|
|
65
|
+
* what a buyer wants by accident, so the adapter decides UP FRONT:
|
|
66
|
+
*
|
|
67
|
+
* - `'error'` (default): throw {@link LiveSessionExistsError} carrying the
|
|
68
|
+
* live session's on-chain evidence. The caller settles the old tab first
|
|
69
|
+
* (`tab.close()` — or POST its last signed voucher to `/tab/settle`) and
|
|
70
|
+
* retries, or acknowledges the replace explicitly.
|
|
71
|
+
* - `'replace'`: compose the ATOMIC same-transaction
|
|
72
|
+
* [secp(revoke), revoke, secp(register), register] so the buyer is never
|
|
73
|
+
* left sessionless mid-flow. Costs a second passkey ceremony. Value
|
|
74
|
+
* already settled or crystallized into LockedClaims survives the replace;
|
|
75
|
+
* anything signed beyond the frontier is voided.
|
|
76
|
+
*/
|
|
77
|
+
interface AuthorizeSessionOptions {
|
|
78
|
+
onLiveSession?: 'error' | 'replace';
|
|
79
|
+
}
|
|
51
80
|
/** Live state of a buyer's tab. All amounts human units. */
|
|
52
81
|
interface TabState {
|
|
53
82
|
/** Whether the tab is currently open (on chain) and accepting vouchers. */
|
|
@@ -165,6 +194,15 @@ interface OpenTabOptions {
|
|
|
165
194
|
sessionDuration?: number;
|
|
166
195
|
/** Facilitator base URL. Default: DEFAULT_FACILITATOR_URL (https://x402.dexter.cash), overridable. */
|
|
167
196
|
facilitatorUrl?: string;
|
|
197
|
+
/**
|
|
198
|
+
* What to do when a LIVE session already exists for this (vault, seller)
|
|
199
|
+
* pair — the session PDA is per-counterparty, so re-opening against the
|
|
200
|
+
* same seller collides with it. Default `'error'` (throw
|
|
201
|
+
* {@link LiveSessionExistsError} — never silently strand the old session's
|
|
202
|
+
* unsettled tail); `'replace'` composes the atomic revoke-then-register.
|
|
203
|
+
* See {@link AuthorizeSessionOptions}.
|
|
204
|
+
*/
|
|
205
|
+
onLiveSession?: 'error' | 'replace';
|
|
168
206
|
}
|
|
169
207
|
/**
|
|
170
208
|
* Options for `resumeTab` — open a handle to a tab that was opened by a
|
|
@@ -199,5 +237,44 @@ declare class TabClosedError extends Error {
|
|
|
199
237
|
readonly channelId: string;
|
|
200
238
|
constructor(channelId: string);
|
|
201
239
|
}
|
|
240
|
+
/** The on-chain evidence a stranding-guard refusal carries. All amounts are
|
|
241
|
+
* atomic strings read from the live SessionAccount PDA. */
|
|
242
|
+
interface LiveSessionDetails {
|
|
243
|
+
/** The seller (counterparty) whose session PDA is live. */
|
|
244
|
+
allowedCounterparty: string;
|
|
245
|
+
/** The LIVE session's ed25519 pubkey (hex) — NOT the one being requested. */
|
|
246
|
+
sessionPubkeyHex: string;
|
|
247
|
+
/** Unix-seconds expiry of the live session (it self-heals here). */
|
|
248
|
+
expiresAtUnix: number;
|
|
249
|
+
/** Cumulative already SETTLED on-chain (USDC moved to the seller). */
|
|
250
|
+
spentAtomic: string;
|
|
251
|
+
/** Cumulative already CRYSTALLIZED into LockedClaims (survives a revoke —
|
|
252
|
+
* claims are separate PDAs and settle independently). */
|
|
253
|
+
crystallizedCumulativeAtomic: string;
|
|
254
|
+
/** The live revolving meter (armed exposure not yet settled/released). */
|
|
255
|
+
currentOutstandingAtomic: string;
|
|
256
|
+
/** max(spent, crystallized) — everything the chain has terminally counted.
|
|
257
|
+
* A replace strands ONLY vouchers signed beyond this frontier. */
|
|
258
|
+
frontierAtomic: string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Thrown by `authorizeSession` / `openTab` when a LIVE session already
|
|
262
|
+
* exists for the target (vault, counterparty) PDA and the caller did not
|
|
263
|
+
* pass `onLiveSession: 'replace'` (K-T4e stranding guard).
|
|
264
|
+
*
|
|
265
|
+
* WHY THIS IS LOUD: revoking (or atomically replacing) a live session zeroes
|
|
266
|
+
* its entire on-chain registration — any voucher the OLD session key signed
|
|
267
|
+
* beyond the frontier (`max(spent, crystallized)`) becomes permanently
|
|
268
|
+
* unsettleable, stranding the seller's unsecured tail. The chain cannot see
|
|
269
|
+
* that tail (signed vouchers live off-chain), so the SDK refuses to replace
|
|
270
|
+
* silently. Remediate by settling the old tab first (`tab.close()`, or POST
|
|
271
|
+
* its last signed voucher to the facilitator's `/tab/settle`), then retry —
|
|
272
|
+
* or acknowledge the replace explicitly if the tail is known-settled or
|
|
273
|
+
* intentionally abandoned.
|
|
274
|
+
*/
|
|
275
|
+
declare class LiveSessionExistsError extends Error {
|
|
276
|
+
readonly details: LiveSessionDetails;
|
|
277
|
+
constructor(details: LiveSessionDetails);
|
|
278
|
+
}
|
|
202
279
|
|
|
203
|
-
export { type OpenTabOptions as O, type ResumeTabOptions as R, SessionScopeExceededError as S, type Tab as T, UnsupportedNetworkError as U, type VaultAdapter as V, type TabState as a, type TabCloseResult as b, TabClosedError as c };
|
|
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 VaultAdapter as V, type TabState as a, type TabCloseResult as b, TabClosedError as c, LiveSessionExistsError as d };
|
|
@@ -27,10 +27,17 @@ interface VaultAdapter {
|
|
|
27
27
|
vaultPda: string;
|
|
28
28
|
/**
|
|
29
29
|
* Use the ROOT signer (passkey) to authorize a fresh session key. This is
|
|
30
|
-
* the only call that prompts the user
|
|
31
|
-
*
|
|
30
|
+
* the only call that prompts the user (twice when atomically replacing a
|
|
31
|
+
* live session — one revoke ceremony + one register ceremony). Returns a
|
|
32
|
+
* session that can be passed to `signWithSession` freely until the scope's
|
|
33
|
+
* cap or expiry is reached.
|
|
34
|
+
*
|
|
35
|
+
* The session PDA is keyed by (vault, counterparty) — re-authorizing
|
|
36
|
+
* against a counterparty you already hold a LIVE session with resolves to
|
|
37
|
+
* the same PDA. The adapter reads it first and applies
|
|
38
|
+
* `opts.onLiveSession` (default `'error'`): see {@link AuthorizeSessionOptions}.
|
|
32
39
|
*/
|
|
33
|
-
authorizeSession(scope: SessionScope): Promise<SessionKey>;
|
|
40
|
+
authorizeSession(scope: SessionScope, opts?: AuthorizeSessionOptions): Promise<SessionKey>;
|
|
34
41
|
/**
|
|
35
42
|
* Use the session key to sign a voucher. Cheap. Never prompts. The seller
|
|
36
43
|
* verifies against the session's registration; the session's registration
|
|
@@ -48,6 +55,28 @@ interface VaultAdapter {
|
|
|
48
55
|
*/
|
|
49
56
|
signCloseTab(session: SessionKey, channelId: string, cumulativeAmount: AtomicAmount): Promise<Uint8Array>;
|
|
50
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Live-session policy for `authorizeSession` / `openTab` (K-T4e).
|
|
60
|
+
*
|
|
61
|
+
* The on-chain program rejects registering over a LIVE session
|
|
62
|
+
* (`SessionAlreadyActive`); the pre-guard program silently overwrote it —
|
|
63
|
+
* stranding any of the old session's signed-but-unsettled vouchers beyond
|
|
64
|
+
* the on-chain frontier (`max(spent, crystallized_cumulative)`). Neither is
|
|
65
|
+
* what a buyer wants by accident, so the adapter decides UP FRONT:
|
|
66
|
+
*
|
|
67
|
+
* - `'error'` (default): throw {@link LiveSessionExistsError} carrying the
|
|
68
|
+
* live session's on-chain evidence. The caller settles the old tab first
|
|
69
|
+
* (`tab.close()` — or POST its last signed voucher to `/tab/settle`) and
|
|
70
|
+
* retries, or acknowledges the replace explicitly.
|
|
71
|
+
* - `'replace'`: compose the ATOMIC same-transaction
|
|
72
|
+
* [secp(revoke), revoke, secp(register), register] so the buyer is never
|
|
73
|
+
* left sessionless mid-flow. Costs a second passkey ceremony. Value
|
|
74
|
+
* already settled or crystallized into LockedClaims survives the replace;
|
|
75
|
+
* anything signed beyond the frontier is voided.
|
|
76
|
+
*/
|
|
77
|
+
interface AuthorizeSessionOptions {
|
|
78
|
+
onLiveSession?: 'error' | 'replace';
|
|
79
|
+
}
|
|
51
80
|
/** Live state of a buyer's tab. All amounts human units. */
|
|
52
81
|
interface TabState {
|
|
53
82
|
/** Whether the tab is currently open (on chain) and accepting vouchers. */
|
|
@@ -165,6 +194,15 @@ interface OpenTabOptions {
|
|
|
165
194
|
sessionDuration?: number;
|
|
166
195
|
/** Facilitator base URL. Default: DEFAULT_FACILITATOR_URL (https://x402.dexter.cash), overridable. */
|
|
167
196
|
facilitatorUrl?: string;
|
|
197
|
+
/**
|
|
198
|
+
* What to do when a LIVE session already exists for this (vault, seller)
|
|
199
|
+
* pair — the session PDA is per-counterparty, so re-opening against the
|
|
200
|
+
* same seller collides with it. Default `'error'` (throw
|
|
201
|
+
* {@link LiveSessionExistsError} — never silently strand the old session's
|
|
202
|
+
* unsettled tail); `'replace'` composes the atomic revoke-then-register.
|
|
203
|
+
* See {@link AuthorizeSessionOptions}.
|
|
204
|
+
*/
|
|
205
|
+
onLiveSession?: 'error' | 'replace';
|
|
168
206
|
}
|
|
169
207
|
/**
|
|
170
208
|
* Options for `resumeTab` — open a handle to a tab that was opened by a
|
|
@@ -199,5 +237,44 @@ declare class TabClosedError extends Error {
|
|
|
199
237
|
readonly channelId: string;
|
|
200
238
|
constructor(channelId: string);
|
|
201
239
|
}
|
|
240
|
+
/** The on-chain evidence a stranding-guard refusal carries. All amounts are
|
|
241
|
+
* atomic strings read from the live SessionAccount PDA. */
|
|
242
|
+
interface LiveSessionDetails {
|
|
243
|
+
/** The seller (counterparty) whose session PDA is live. */
|
|
244
|
+
allowedCounterparty: string;
|
|
245
|
+
/** The LIVE session's ed25519 pubkey (hex) — NOT the one being requested. */
|
|
246
|
+
sessionPubkeyHex: string;
|
|
247
|
+
/** Unix-seconds expiry of the live session (it self-heals here). */
|
|
248
|
+
expiresAtUnix: number;
|
|
249
|
+
/** Cumulative already SETTLED on-chain (USDC moved to the seller). */
|
|
250
|
+
spentAtomic: string;
|
|
251
|
+
/** Cumulative already CRYSTALLIZED into LockedClaims (survives a revoke —
|
|
252
|
+
* claims are separate PDAs and settle independently). */
|
|
253
|
+
crystallizedCumulativeAtomic: string;
|
|
254
|
+
/** The live revolving meter (armed exposure not yet settled/released). */
|
|
255
|
+
currentOutstandingAtomic: string;
|
|
256
|
+
/** max(spent, crystallized) — everything the chain has terminally counted.
|
|
257
|
+
* A replace strands ONLY vouchers signed beyond this frontier. */
|
|
258
|
+
frontierAtomic: string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Thrown by `authorizeSession` / `openTab` when a LIVE session already
|
|
262
|
+
* exists for the target (vault, counterparty) PDA and the caller did not
|
|
263
|
+
* pass `onLiveSession: 'replace'` (K-T4e stranding guard).
|
|
264
|
+
*
|
|
265
|
+
* WHY THIS IS LOUD: revoking (or atomically replacing) a live session zeroes
|
|
266
|
+
* its entire on-chain registration — any voucher the OLD session key signed
|
|
267
|
+
* beyond the frontier (`max(spent, crystallized)`) becomes permanently
|
|
268
|
+
* unsettleable, stranding the seller's unsecured tail. The chain cannot see
|
|
269
|
+
* that tail (signed vouchers live off-chain), so the SDK refuses to replace
|
|
270
|
+
* silently. Remediate by settling the old tab first (`tab.close()`, or POST
|
|
271
|
+
* its last signed voucher to the facilitator's `/tab/settle`), then retry —
|
|
272
|
+
* or acknowledge the replace explicitly if the tail is known-settled or
|
|
273
|
+
* intentionally abandoned.
|
|
274
|
+
*/
|
|
275
|
+
declare class LiveSessionExistsError extends Error {
|
|
276
|
+
readonly details: LiveSessionDetails;
|
|
277
|
+
constructor(details: LiveSessionDetails);
|
|
278
|
+
}
|
|
202
279
|
|
|
203
|
-
export { type OpenTabOptions as O, type ResumeTabOptions as R, SessionScopeExceededError as S, type Tab as T, UnsupportedNetworkError as U, type VaultAdapter as V, type TabState as a, type TabCloseResult as b, TabClosedError as c };
|
|
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 VaultAdapter as V, type TabState as a, type TabCloseResult as b, TabClosedError as c, LiveSessionExistsError as d };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dexterai/x402",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.1",
|
|
4
4
|
"description": "Full-stack x402 SDK - add paid API monetization to any endpoint. Express middleware, React hooks, Access Pass, dynamic pricing. Solana, Base, Polygon, Arbitrum, Optimism, Avalanche, SKALE.",
|
|
5
5
|
"author": "Dexter",
|
|
6
6
|
"license": "MIT",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"README.md",
|
|
63
63
|
"REFERENCE.md",
|
|
64
64
|
"LICENSE",
|
|
65
|
-
"assets"
|
|
65
|
+
"assets/*.svg"
|
|
66
66
|
],
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "tsup",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"tweetnacl": "^1.0.3"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@dexterai/vault": "^0.
|
|
92
|
+
"@dexterai/vault": "^0.34.0",
|
|
93
93
|
"@types/aws-lambda": "^8.10.161",
|
|
94
94
|
"@types/express": "^5.0.6",
|
|
95
95
|
"@types/node": "^22.10.0",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"vitest": "^2.1.8"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@dexterai/vault": ">=0.
|
|
107
|
+
"@dexterai/vault": ">=0.34.0",
|
|
108
108
|
"@solana/wallet-adapter-base": "^0.9.0",
|
|
109
109
|
"react": "^18.0.0 || ^19.0.0",
|
|
110
110
|
"stripe": "^20.0.0",
|