@dexterai/x402 3.10.0 → 3.11.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.
@@ -1 +1 @@
1
- "use strict";var z=Object.create;var h=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var W=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var H=(e,t)=>{for(var n in t)h(e,n,{get:t[n],enumerable:!0})},x=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of G(t))!Y.call(e,r)&&r!==n&&h(e,r,{get:()=>t[r],enumerable:!(i=F(t,r))||i.enumerable});return e};var v=(e,t,n)=>(n=e!=null?z(W(e)):{},x(t||!e||!e.__esModule?h(n,"default",{value:e,enumerable:!0}):n,e)),Z=e=>x(h({},"__esModule",{value:!0}),e);var me={};H(me,{createSolanaVaultAdapter:()=>ue,deriveChannelId:()=>N,passkeySignerFromP256Keypair:()=>ce});module.exports=Z(me);var m=require("@solana/web3.js");var l=require("@solana/web3.js"),g=new l.PublicKey("Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"),q=new l.PublicKey("Secp256r1SigVerify1111111111111111111111111"),k=new l.PublicKey("Sysvar1nstructions1111111111111111111111111"),j=new Uint8Array([69,94,60,44,49,199,183,233]),X=new Uint8Array([81,192,32,110,104,116,144,151]);function Q(e){let t=new Uint8Array(8);return new DataView(t.buffer).setBigUint64(0,e,!0),t}function ee(e){let t=new Uint8Array(8);return new DataView(t.buffer).setBigInt64(0,e,!0),t}function te(e){let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e>>>0,!0),t}function A(e){let t=new Uint8Array(4+e.length);return new DataView(t.buffer).setUint32(0,e.length>>>0,!0),t.set(e,4),t}function I(...e){let t=e.reduce((r,s)=>r+s.length,0),n=new Uint8Array(t),i=0;for(let r of e)n.set(r,i),i+=r.length;return n}var b=64,w=33,ne=14,y=2;function S(e,t,n){if(e.length!==w)throw new Error(`expected ${w}-byte compressed pubkey`);if(t.length!==b)throw new Error(`expected ${b}-byte signature`);let i=y+ne,r=i+b,s=r+w,c=n.length,u=s+c,o=new Uint8Array(u);o[0]=1,o[1]=0;let a=new DataView(o.buffer);return a.setUint16(y+0,i,!0),a.setUint16(y+2,65535,!0),a.setUint16(y+4,r,!0),a.setUint16(y+6,65535,!0),a.setUint16(y+8,s,!0),a.setUint16(y+10,c,!0),a.setUint16(y+12,65535,!0),o.set(t,i),o.set(e,r),o.set(n,s),new l.TransactionInstruction({keys:[],programId:q,data:Buffer.from(o)})}function E(e){if(e.sessionPubkey.length!==32)throw new Error(`sessionPubkey must be 32 bytes, got ${e.sessionPubkey.length}`);let t=I(j,e.sessionPubkey,Q(e.maxAmount),ee(e.expiresAt),e.allowedCounterparty.toBytes(),te(e.nonce),A(e.clientDataJSON),A(e.authenticatorData));return new l.TransactionInstruction({keys:[{pubkey:e.vaultPda,isSigner:!1,isWritable:!0},{pubkey:k,isSigner:!1,isWritable:!1}],programId:g,data:Buffer.from(t)})}function O(e){let t=I(X,A(e.clientDataJSON),A(e.authenticatorData));return new l.TransactionInstruction({keys:[{pubkey:e.vaultPda,isSigner:!1,isWritable:!0},{pubkey:k,isSigner:!1,isWritable:!1}],programId:g,data:Buffer.from(t)})}var ie=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),re=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();function D(e){if(e.sessionPubkey.length!==32)throw new Error(`sessionPubkey must be 32 bytes, got ${e.sessionPubkey.length}`);let t=new Uint8Array(180),n=new DataView(t.buffer),i=0;if(t.set(ie,i),i+=32,t.set(e.programId.toBytes(),i),i+=32,t.set(e.vaultPda.toBytes(),i),i+=32,t.set(e.sessionPubkey,i),i+=32,n.setBigUint64(i,e.maxAmount,!0),i+=8,n.setBigInt64(i,e.expiresAt,!0),i+=8,t.set(e.allowedCounterparty.toBytes(),i),i+=32,n.setUint32(i,e.nonce>>>0,!0),i+=4,i!==180)throw new Error(`internal: session register message wrong length ${i}, expected 180`);return t}function R(e){if(e.sessionPubkey.length!==32)throw new Error(`sessionPubkey must be 32 bytes, got ${e.sessionPubkey.length}`);let t=new Uint8Array(128),n=0;if(t.set(re,n),n+=32,t.set(e.programId.toBytes(),n),n+=32,t.set(e.vaultPda.toBytes(),n),n+=32,t.set(e.sessionPubkey,n),n+=32,n!==128)throw new Error(`internal: session revoke message wrong length ${n}, expected 128`);return t}function B(e){if(e.channelId.length!==32)throw new Error(`channelId must be 32 bytes, got ${e.channelId.length}`);let t=new Uint8Array(44),n=new DataView(t.buffer),i=0;if(t.set(e.channelId,i),i+=32,n.setBigUint64(i,e.cumulativeAmount,!0),i+=8,n.setUint32(i,e.sequenceNumber>>>0,!0),i+=4,i!==44)throw new Error(`internal: voucher payload wrong length ${i}, expected 44`);return t}var P=v(require("tweetnacl"),1);var C=require("@noble/hashes/sha256");function V(){let e=P.default.sign.keyPair();return{publicKey:e.publicKey,privateKey:e.secretKey}}function T(e,t,n){return{publicKey:e.publicKey,privateKey:e.privateKey,scope:t,registration:n}}function _(e,t,n){if(n.length!==32)throw new Error(`channelIdBytes must be 32 bytes, got ${n.length}`);let i=BigInt(t.cumulativeAmount),r=BigInt(e.scope.maxAmountAtomic);if(i>r)throw new Error(`voucher cumulative ${i} exceeds session cap ${r}`);let s=Math.floor(Date.now()/1e3);if(s>=e.scope.expiresAtUnix)throw new Error(`session expired at ${e.scope.expiresAtUnix}, now ${s}`);let c=B({channelId:n,cumulativeAmount:i,sequenceNumber:t.sequenceNumber}),u=P.default.sign.detached(c,e.privateKey);return{payload:t,sessionPublicKey:e.publicKey,sessionRegistration:e.registration,sessionSignature:u}}function U(e){if(!/^\d+$/.test(e))throw new Error(`atomic amount must be a non-negative integer string, got "${e}"`);return BigInt(e)}function N(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let n=new TextEncoder().encode(e.sellerUrl),i=C.sha256.create();return i.update(e.vaultPda.toBytes()),i.update(n),i.update(t),i.digest()}var M=require("@noble/curves/p256"),d=require("@noble/hashes/sha256"),$="dexter.cash";function se(e){return Buffer.from(e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function oe(e,t=`https://${$}`){let i={type:"webauthn.get",challenge:se(e),origin:t,crossOrigin:!1};return new TextEncoder().encode(JSON.stringify(i))}function ae(e=1){let t=(0,d.sha256)(new TextEncoder().encode($)),n=new Uint8Array(37);return n.set(t,0),n[32]=5,new DataView(n.buffer).setUint32(33,e,!1),n}function J(e,t){let n=(0,d.sha256)(t),i=oe(n),r=ae(1),s=new Uint8Array(r.length+32);s.set(r,0),s.set((0,d.sha256)(i),r.length);let c=(0,d.sha256)(s),o=M.p256.sign(c,e.privateKey,{lowS:!0}).toCompactRawBytes();return{clientDataJSON:i,authenticatorData:r,precompileMessage:s,signature:o}}function ce(e){return{publicKey:e.publicKey,signOperation:async t=>J(e,t)}}var K=class{network="solana:mainnet";swigAddress;vaultPda;connection;vaultPdaKey;passkey;feePayer;confirmOptions;constructor(t){this.connection=t.connection,this.swigAddress=typeof t.swigAddress=="string"?t.swigAddress:t.swigAddress.toBase58(),this.vaultPdaKey=typeof t.vaultPda=="string"?new m.PublicKey(t.vaultPda):t.vaultPda,this.vaultPda=this.vaultPdaKey.toBase58(),this.passkey=t.passkeySigner,this.feePayer=t.feePayer,this.confirmOptions=t.confirmOptions??{commitment:"confirmed"}}async authorizeSession(t){let n=new m.PublicKey(t.allowedCounterparty),i=V(),r=ye(),s=D({programId:g,vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:U(t.maxAmountAtomic),expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:r}),c=await this.passkey.signOperation(s),u=S(this.passkey.publicKey,c.signature,c.precompileMessage),o=E({vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:U(t.maxAmountAtomic),expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:r,clientDataJSON:c.clientDataJSON,authenticatorData:c.authenticatorData}),a=new m.Transaction().add(u,o);a.feePayer=this.feePayer.publicKey;let{blockhash:p}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);a.recentBlockhash=p,a.sign(this.feePayer);let f=await this.connection.sendRawTransaction(a.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:f,blockhash:p,lastValidBlockHeight:(await this.connection.getLatestBlockhash(this.confirmOptions.commitment)).lastValidBlockHeight},this.confirmOptions.commitment),await this.waitForActiveSessionFinalized(i.publicKey),T(i,t,s)}async signWithSession(t,n){let i=await le(n.channelId);return _(t,n,i)}async signOpenTab(t,n){return t.registration}async signCloseTab(t,n,i){let r=R({programId:g,vaultPda:this.vaultPdaKey,sessionPubkey:t.publicKey}),s=await this.passkey.signOperation(r),c=S(this.passkey.publicKey,s.signature,s.precompileMessage),u=O({vaultPda:this.vaultPdaKey,clientDataJSON:s.clientDataJSON,authenticatorData:s.authenticatorData}),o=new m.Transaction().add(c,u);o.feePayer=this.feePayer.publicKey;let{blockhash:a,lastValidBlockHeight:p}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);o.recentBlockhash=a,o.sign(this.feePayer);let f=await this.connection.sendRawTransaction(o.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:f,blockhash:a,lastValidBlockHeight:p},this.confirmOptions.commitment),r}async waitForActiveSessionFinalized(t,n=2e4){let i=Date.now()+n;for(;Date.now()<i;){let r=await this.connection.getAccountInfo(this.vaultPdaKey,"finalized");if(r){let s=r.data,p=84+(s[83]===1?48:0)+32+32;if(s[p]===1){let f=p+1,L=s.slice(f,f+32);if(pe(L,t))return}}await new Promise(s=>setTimeout(s,500))}throw new Error(`register_session_key did not become finalized-visible within ${n}ms`)}};function ue(e){return new K(e)}function ye(){return Math.floor(Math.random()*4294967295)>>>0}async function le(e){if(/^[0-9a-f]{64}$/i.test(e))return fe(e);let{sha256:t}=await import("@noble/hashes/sha256");return t(new TextEncoder().encode(e))}function pe(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 fe(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}0&&(module.exports={createSolanaVaultAdapter,deriveChannelId,passkeySignerFromP256Keypair});
1
+ "use strict";var D=Object.create;var f=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var E=(t,e)=>{for(var n in e)f(t,n,{get:e[n],enumerable:!0})},b=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of T(e))!_.call(t,r)&&r!==n&&f(t,r,{get:()=>e[r],enumerable:!(i=B(e,r))||i.enumerable});return t};var w=(t,e,n)=>(n=t!=null?D(M(t)):{},b(e||!t||!t.__esModule?f(n,"default",{value:t,enumerable:!0}):n,t)),N=t=>b(f({},"__esModule",{value:!0}),t);var j={};E(j,{createSolanaVaultAdapter:()=>H,deriveChannelId:()=>O,passkeySignerFromP256Keypair:()=>F});module.exports=N(j);var d=require("@solana/web3.js");var m=require("@dexterai/vault/instructions"),A=require("@dexterai/vault/precompile"),g=require("@dexterai/vault/constants");var a=require("@dexterai/vault/messages");var P=w(require("tweetnacl"),1);var U=require("@noble/hashes/sha256");function v(){let t=P.default.sign.keyPair();return{publicKey:t.publicKey,privateKey:t.secretKey}}function x(t,e,n){return{publicKey:t.publicKey,privateKey:t.privateKey,scope:e,registration:n}}function k(t,e,n){if(n.length!==32)throw new Error(`channelIdBytes must be 32 bytes, got ${n.length}`);let i=BigInt(e.cumulativeAmount),r=BigInt(t.scope.maxAmountAtomic);if(i>r)throw new Error(`voucher cumulative ${i} exceeds session cap ${r}`);let s=Math.floor(Date.now()/1e3);if(s>=t.scope.expiresAtUnix)throw new Error(`session expired at ${t.scope.expiresAtUnix}, now ${s}`);let o=(0,a.voucherPayloadMessage)({channelId:n,cumulativeAmount:i,sequenceNumber:e.sequenceNumber}),y=P.default.sign.detached(o,t.privateKey);return{payload:e,sessionPublicKey:t.publicKey,sessionRegistration:t.registration,sessionSignature:y}}function S(t){if(!/^\d+$/.test(t))throw new Error(`atomic amount must be a non-negative integer string, got "${t}"`);return BigInt(t)}function O(t){let e=new Uint8Array(8);new DataView(e.buffer).setBigUint64(0,t.nonce,!0);let n=new TextEncoder().encode(t.sellerUrl),i=U.sha256.create();return i.update(t.vaultPda.toBytes()),i.update(n),i.update(e),i.digest()}var I=require("@noble/curves/p256"),h=require("@noble/hashes/sha256"),R="dexter.cash";function $(t){return Buffer.from(t).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function z(t,e=`https://${R}`){let i={type:"webauthn.get",challenge:$(t),origin:e,crossOrigin:!1};return new TextEncoder().encode(JSON.stringify(i))}function J(t=1){let e=(0,h.sha256)(new TextEncoder().encode(R)),n=new Uint8Array(37);return n.set(e,0),n[32]=5,new DataView(n.buffer).setUint32(33,t,!1),n}function V(t,e){let n=(0,h.sha256)(e),i=z(n),r=J(1),s=new Uint8Array(r.length+32);s.set(r,0),s.set((0,h.sha256)(i),r.length);let o=(0,h.sha256)(s),c=I.p256.sign(o,t.privateKey,{lowS:!0}).toCompactRawBytes();return{clientDataJSON:i,authenticatorData:r,precompileMessage:s,signature:c}}function F(t){return{publicKey:t.publicKey,signOperation:async e=>V(t,e)}}var K=class{network="solana:mainnet";swigAddress;vaultPda;connection;vaultPdaKey;passkey;feePayer;confirmOptions;constructor(e){this.connection=e.connection,this.swigAddress=typeof e.swigAddress=="string"?e.swigAddress:e.swigAddress.toBase58(),this.vaultPdaKey=typeof e.vaultPda=="string"?new d.PublicKey(e.vaultPda):e.vaultPda,this.vaultPda=this.vaultPdaKey.toBase58(),this.passkey=e.passkeySigner,this.feePayer=e.feePayer,this.confirmOptions=e.confirmOptions??{commitment:"confirmed"}}async authorizeSession(e){let n=new d.PublicKey(e.allowedCounterparty),i=v(),r=L(),s=(0,a.sessionRegisterMessage)({programId:g.DEXTER_VAULT_PROGRAM_ID,vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:S(e.maxAmountAtomic),expiresAt:BigInt(e.expiresAtUnix),allowedCounterparty:n,nonce:r}),o=await this.passkey.signOperation(s),y=(0,A.buildSecp256r1VerifyInstruction)(this.passkey.publicKey,o.signature,o.precompileMessage),c=(0,m.buildRegisterSessionKeyInstruction)({vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:S(e.maxAmountAtomic),expiresAt:BigInt(e.expiresAtUnix),allowedCounterparty:n,nonce:r,clientDataJSON:o.clientDataJSON,authenticatorData:o.authenticatorData}),u=new d.Transaction().add(y,c);u.feePayer=this.feePayer.publicKey;let{blockhash:l}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);u.recentBlockhash=l,u.sign(this.feePayer);let p=await this.connection.sendRawTransaction(u.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:p,blockhash:l,lastValidBlockHeight:(await this.connection.getLatestBlockhash(this.confirmOptions.commitment)).lastValidBlockHeight},this.confirmOptions.commitment),await this.waitForActiveSessionFinalized(i.publicKey),x(i,e,s)}async signWithSession(e,n){let i=await q(n.channelId);return k(e,n,i)}async signOpenTab(e,n){return e.registration}async signCloseTab(e,n,i){let r=(0,a.sessionRevokeMessage)({programId:g.DEXTER_VAULT_PROGRAM_ID,vaultPda:this.vaultPdaKey,sessionPubkey:e.publicKey}),s=await this.passkey.signOperation(r),o=(0,A.buildSecp256r1VerifyInstruction)(this.passkey.publicKey,s.signature,s.precompileMessage),y=(0,m.buildRevokeSessionKeyInstruction)({vaultPda:this.vaultPdaKey,clientDataJSON:s.clientDataJSON,authenticatorData:s.authenticatorData}),c=new d.Transaction().add(o,y);c.feePayer=this.feePayer.publicKey;let{blockhash:u,lastValidBlockHeight:l}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);c.recentBlockhash=u,c.sign(this.feePayer);let p=await this.connection.sendRawTransaction(c.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:p,blockhash:u,lastValidBlockHeight:l},this.confirmOptions.commitment),r}async waitForActiveSessionFinalized(e,n=2e4){let i=Date.now()+n;for(;Date.now()<i;){let r=await this.connection.getAccountInfo(this.vaultPdaKey,"finalized");if(r){let s=r.data,l=84+(s[83]===1?48:0)+32+32;if(s[l]===1){let p=l+1,C=s.slice(p,p+32);if(G(C,e))return}}await new Promise(s=>setTimeout(s,500))}throw new Error(`register_session_key did not become finalized-visible within ${n}ms`)}};function H(t){return new K(t)}function L(){return Math.floor(Math.random()*4294967295)>>>0}async function q(t){if(/^[0-9a-f]{64}$/i.test(t))return W(t);let{sha256:e}=await import("@noble/hashes/sha256");return e(new TextEncoder().encode(t))}function G(t,e){if(t.length!==e.length)return!1;for(let n=0;n<t.length;n++)if(t[n]!==e[n])return!1;return!0}function W(t){let e=new Uint8Array(t.length/2);for(let n=0;n<e.length;n++)e[n]=parseInt(t.substr(n*2,2),16);return e}0&&(module.exports={createSolanaVaultAdapter,deriveChannelId,passkeySignerFromP256Keypair});
@@ -1,5 +1,6 @@
1
1
  import { PublicKey, Connection, Signer, ConfirmOptions } from '@solana/web3.js';
2
- import { f as VaultAdapter } from '../../../types-DIrmhiD-.cjs';
2
+ import { V as VaultAdapter } from '../../../types-BtibqM00.cjs';
3
+ import '@dexterai/vault/types';
3
4
 
4
5
  /**
5
6
  * Session-key lifecycle: generation, voucher signing, in-memory hygiene.
@@ -1,5 +1,6 @@
1
1
  import { PublicKey, Connection, Signer, ConfirmOptions } from '@solana/web3.js';
2
- import { f as VaultAdapter } from '../../../types-DIrmhiD-.js';
2
+ import { V as VaultAdapter } from '../../../types-BtibqM00.js';
3
+ import '@dexterai/vault/types';
3
4
 
4
5
  /**
5
6
  * Session-key lifecycle: generation, voucher signing, in-memory hygiene.
@@ -1 +1 @@
1
- import{PublicKey as _,Transaction as C}from"@solana/web3.js";import{PublicKey as A,TransactionInstruction as b}from"@solana/web3.js";var f=new A("Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"),M=new A("Secp256r1SigVerify1111111111111111111111111"),U=new A("Sysvar1nstructions1111111111111111111111111"),$=new Uint8Array([69,94,60,44,49,199,183,233]),J=new Uint8Array([81,192,32,110,104,116,144,151]);function L(e){let t=new Uint8Array(8);return new DataView(t.buffer).setBigUint64(0,e,!0),t}function z(e){let t=new Uint8Array(8);return new DataView(t.buffer).setBigInt64(0,e,!0),t}function F(e){let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e>>>0,!0),t}function m(e){let t=new Uint8Array(4+e.length);return new DataView(t.buffer).setUint32(0,e.length>>>0,!0),t.set(e,4),t}function K(...e){let t=e.reduce((s,r)=>s+r.length,0),n=new Uint8Array(t),i=0;for(let s of e)n.set(s,i),i+=s.length;return n}var d=64,h=33,G=14,y=2;function w(e,t,n){if(e.length!==h)throw new Error(`expected ${h}-byte compressed pubkey`);if(t.length!==d)throw new Error(`expected ${d}-byte signature`);let i=y+G,s=i+d,r=s+h,c=n.length,u=r+c,o=new Uint8Array(u);o[0]=1,o[1]=0;let a=new DataView(o.buffer);return a.setUint16(y+0,i,!0),a.setUint16(y+2,65535,!0),a.setUint16(y+4,s,!0),a.setUint16(y+6,65535,!0),a.setUint16(y+8,r,!0),a.setUint16(y+10,c,!0),a.setUint16(y+12,65535,!0),o.set(t,i),o.set(e,s),o.set(n,r),new b({keys:[],programId:M,data:Buffer.from(o)})}function x(e){if(e.sessionPubkey.length!==32)throw new Error(`sessionPubkey must be 32 bytes, got ${e.sessionPubkey.length}`);let t=K($,e.sessionPubkey,L(e.maxAmount),z(e.expiresAt),e.allowedCounterparty.toBytes(),F(e.nonce),m(e.clientDataJSON),m(e.authenticatorData));return new b({keys:[{pubkey:e.vaultPda,isSigner:!1,isWritable:!0},{pubkey:U,isSigner:!1,isWritable:!1}],programId:f,data:Buffer.from(t)})}function v(e){let t=K(J,m(e.clientDataJSON),m(e.authenticatorData));return new b({keys:[{pubkey:e.vaultPda,isSigner:!1,isWritable:!0},{pubkey:U,isSigner:!1,isWritable:!1}],programId:f,data:Buffer.from(t)})}var W=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),Y=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();function k(e){if(e.sessionPubkey.length!==32)throw new Error(`sessionPubkey must be 32 bytes, got ${e.sessionPubkey.length}`);let t=new Uint8Array(180),n=new DataView(t.buffer),i=0;if(t.set(W,i),i+=32,t.set(e.programId.toBytes(),i),i+=32,t.set(e.vaultPda.toBytes(),i),i+=32,t.set(e.sessionPubkey,i),i+=32,n.setBigUint64(i,e.maxAmount,!0),i+=8,n.setBigInt64(i,e.expiresAt,!0),i+=8,t.set(e.allowedCounterparty.toBytes(),i),i+=32,n.setUint32(i,e.nonce>>>0,!0),i+=4,i!==180)throw new Error(`internal: session register message wrong length ${i}, expected 180`);return t}function I(e){if(e.sessionPubkey.length!==32)throw new Error(`sessionPubkey must be 32 bytes, got ${e.sessionPubkey.length}`);let t=new Uint8Array(128),n=0;if(t.set(Y,n),n+=32,t.set(e.programId.toBytes(),n),n+=32,t.set(e.vaultPda.toBytes(),n),n+=32,t.set(e.sessionPubkey,n),n+=32,n!==128)throw new Error(`internal: session revoke message wrong length ${n}, expected 128`);return t}function E(e){if(e.channelId.length!==32)throw new Error(`channelId must be 32 bytes, got ${e.channelId.length}`);let t=new Uint8Array(44),n=new DataView(t.buffer),i=0;if(t.set(e.channelId,i),i+=32,n.setBigUint64(i,e.cumulativeAmount,!0),i+=8,n.setUint32(i,e.sequenceNumber>>>0,!0),i+=4,i!==44)throw new Error(`internal: voucher payload wrong length ${i}, expected 44`);return t}import O from"tweetnacl";import{sha256 as H}from"@noble/hashes/sha256";function D(){let e=O.sign.keyPair();return{publicKey:e.publicKey,privateKey:e.secretKey}}function R(e,t,n){return{publicKey:e.publicKey,privateKey:e.privateKey,scope:t,registration:n}}function B(e,t,n){if(n.length!==32)throw new Error(`channelIdBytes must be 32 bytes, got ${n.length}`);let i=BigInt(t.cumulativeAmount),s=BigInt(e.scope.maxAmountAtomic);if(i>s)throw new Error(`voucher cumulative ${i} exceeds session cap ${s}`);let r=Math.floor(Date.now()/1e3);if(r>=e.scope.expiresAtUnix)throw new Error(`session expired at ${e.scope.expiresAtUnix}, now ${r}`);let c=E({channelId:n,cumulativeAmount:i,sequenceNumber:t.sequenceNumber}),u=O.sign.detached(c,e.privateKey);return{payload:t,sessionPublicKey:e.publicKey,sessionRegistration:e.registration,sessionSignature:u}}function S(e){if(!/^\d+$/.test(e))throw new Error(`atomic amount must be a non-negative integer string, got "${e}"`);return BigInt(e)}function Z(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let n=new TextEncoder().encode(e.sellerUrl),i=H.create();return i.update(e.vaultPda.toBytes()),i.update(n),i.update(t),i.digest()}import{p256 as q}from"@noble/curves/p256";import{sha256 as g}from"@noble/hashes/sha256";var V="dexter.cash";function j(e){return Buffer.from(e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function X(e,t=`https://${V}`){let i={type:"webauthn.get",challenge:j(e),origin:t,crossOrigin:!1};return new TextEncoder().encode(JSON.stringify(i))}function Q(e=1){let t=g(new TextEncoder().encode(V)),n=new Uint8Array(37);return n.set(t,0),n[32]=5,new DataView(n.buffer).setUint32(33,e,!1),n}function T(e,t){let n=g(t),i=X(n),s=Q(1),r=new Uint8Array(s.length+32);r.set(s,0),r.set(g(i),s.length);let c=g(r),o=q.sign(c,e.privateKey,{lowS:!0}).toCompactRawBytes();return{clientDataJSON:i,authenticatorData:s,precompileMessage:r,signature:o}}function we(e){return{publicKey:e.publicKey,signOperation:async t=>T(e,t)}}var P=class{network="solana:mainnet";swigAddress;vaultPda;connection;vaultPdaKey;passkey;feePayer;confirmOptions;constructor(t){this.connection=t.connection,this.swigAddress=typeof t.swigAddress=="string"?t.swigAddress:t.swigAddress.toBase58(),this.vaultPdaKey=typeof t.vaultPda=="string"?new _(t.vaultPda):t.vaultPda,this.vaultPda=this.vaultPdaKey.toBase58(),this.passkey=t.passkeySigner,this.feePayer=t.feePayer,this.confirmOptions=t.confirmOptions??{commitment:"confirmed"}}async authorizeSession(t){let n=new _(t.allowedCounterparty),i=D(),s=ee(),r=k({programId:f,vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:S(t.maxAmountAtomic),expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:s}),c=await this.passkey.signOperation(r),u=w(this.passkey.publicKey,c.signature,c.precompileMessage),o=x({vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:S(t.maxAmountAtomic),expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:s,clientDataJSON:c.clientDataJSON,authenticatorData:c.authenticatorData}),a=new C().add(u,o);a.feePayer=this.feePayer.publicKey;let{blockhash:l}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);a.recentBlockhash=l,a.sign(this.feePayer);let p=await this.connection.sendRawTransaction(a.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:p,blockhash:l,lastValidBlockHeight:(await this.connection.getLatestBlockhash(this.confirmOptions.commitment)).lastValidBlockHeight},this.confirmOptions.commitment),await this.waitForActiveSessionFinalized(i.publicKey),R(i,t,r)}async signWithSession(t,n){let i=await te(n.channelId);return B(t,n,i)}async signOpenTab(t,n){return t.registration}async signCloseTab(t,n,i){let s=I({programId:f,vaultPda:this.vaultPdaKey,sessionPubkey:t.publicKey}),r=await this.passkey.signOperation(s),c=w(this.passkey.publicKey,r.signature,r.precompileMessage),u=v({vaultPda:this.vaultPdaKey,clientDataJSON:r.clientDataJSON,authenticatorData:r.authenticatorData}),o=new C().add(c,u);o.feePayer=this.feePayer.publicKey;let{blockhash:a,lastValidBlockHeight:l}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);o.recentBlockhash=a,o.sign(this.feePayer);let p=await this.connection.sendRawTransaction(o.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:p,blockhash:a,lastValidBlockHeight:l},this.confirmOptions.commitment),s}async waitForActiveSessionFinalized(t,n=2e4){let i=Date.now()+n;for(;Date.now()<i;){let s=await this.connection.getAccountInfo(this.vaultPdaKey,"finalized");if(s){let r=s.data,l=84+(r[83]===1?48:0)+32+32;if(r[l]===1){let p=l+1,N=r.slice(p,p+32);if(ne(N,t))return}}await new Promise(r=>setTimeout(r,500))}throw new Error(`register_session_key did not become finalized-visible within ${n}ms`)}};function Se(e){return new P(e)}function ee(){return Math.floor(Math.random()*4294967295)>>>0}async function te(e){if(/^[0-9a-f]{64}$/i.test(e))return ie(e);let{sha256:t}=await import("@noble/hashes/sha256");return t(new TextEncoder().encode(e))}function ne(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 ie(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}export{Se as createSolanaVaultAdapter,Z as deriveChannelId,we as passkeySignerFromP256Keypair};
1
+ import{PublicKey as O,Transaction as I}from"@solana/web3.js";import{buildRegisterSessionKeyInstruction as f,buildRevokeSessionKeyInstruction as A}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as m}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as g,SECP256R1_PROGRAM_ID as L,INSTRUCTIONS_SYSVAR_ID as q}from"@dexterai/vault/constants";import{sessionRegisterMessage as P,sessionRevokeMessage as S,voucherPayloadMessage as K,buildVoucherMessage as j}from"@dexterai/vault/messages";import b from"tweetnacl";import{sha256 as V}from"@noble/hashes/sha256";function w(){let t=b.sign.keyPair();return{publicKey:t.publicKey,privateKey:t.secretKey}}function v(t,e,n){return{publicKey:t.publicKey,privateKey:t.privateKey,scope:e,registration:n}}function x(t,e,n){if(n.length!==32)throw new Error(`channelIdBytes must be 32 bytes, got ${n.length}`);let i=BigInt(e.cumulativeAmount),s=BigInt(t.scope.maxAmountAtomic);if(i>s)throw new Error(`voucher cumulative ${i} exceeds session cap ${s}`);let r=Math.floor(Date.now()/1e3);if(r>=t.scope.expiresAtUnix)throw new Error(`session expired at ${t.scope.expiresAtUnix}, now ${r}`);let o=K({channelId:n,cumulativeAmount:i,sequenceNumber:e.sequenceNumber}),u=b.sign.detached(o,t.privateKey);return{payload:e,sessionPublicKey:t.publicKey,sessionRegistration:t.registration,sessionSignature:u}}function d(t){if(!/^\d+$/.test(t))throw new Error(`atomic amount must be a non-negative integer string, got "${t}"`);return BigInt(t)}function C(t){let e=new Uint8Array(8);new DataView(e.buffer).setBigUint64(0,t.nonce,!0);let n=new TextEncoder().encode(t.sellerUrl),i=V.create();return i.update(t.vaultPda.toBytes()),i.update(n),i.update(e),i.digest()}import{p256 as D}from"@noble/curves/p256";import{sha256 as p}from"@noble/hashes/sha256";var k="dexter.cash";function B(t){return Buffer.from(t).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function T(t,e=`https://${k}`){let i={type:"webauthn.get",challenge:B(t),origin:e,crossOrigin:!1};return new TextEncoder().encode(JSON.stringify(i))}function M(t=1){let e=p(new TextEncoder().encode(k)),n=new Uint8Array(37);return n.set(e,0),n[32]=5,new DataView(n.buffer).setUint32(33,t,!1),n}function U(t,e){let n=p(e),i=T(n),s=M(1),r=new Uint8Array(s.length+32);r.set(s,0),r.set(p(i),s.length);let o=p(r),a=D.sign(o,t.privateKey,{lowS:!0}).toCompactRawBytes();return{clientDataJSON:i,authenticatorData:s,precompileMessage:r,signature:a}}function ue(t){return{publicKey:t.publicKey,signOperation:async e=>U(t,e)}}var h=class{network="solana:mainnet";swigAddress;vaultPda;connection;vaultPdaKey;passkey;feePayer;confirmOptions;constructor(e){this.connection=e.connection,this.swigAddress=typeof e.swigAddress=="string"?e.swigAddress:e.swigAddress.toBase58(),this.vaultPdaKey=typeof e.vaultPda=="string"?new O(e.vaultPda):e.vaultPda,this.vaultPda=this.vaultPdaKey.toBase58(),this.passkey=e.passkeySigner,this.feePayer=e.feePayer,this.confirmOptions=e.confirmOptions??{commitment:"confirmed"}}async authorizeSession(e){let n=new O(e.allowedCounterparty),i=w(),s=_(),r=P({programId:g,vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:d(e.maxAmountAtomic),expiresAt:BigInt(e.expiresAtUnix),allowedCounterparty:n,nonce:s}),o=await this.passkey.signOperation(r),u=m(this.passkey.publicKey,o.signature,o.precompileMessage),a=f({vaultPda:this.vaultPdaKey,sessionPubkey:i.publicKey,maxAmount:d(e.maxAmountAtomic),expiresAt:BigInt(e.expiresAtUnix),allowedCounterparty:n,nonce:s,clientDataJSON:o.clientDataJSON,authenticatorData:o.authenticatorData}),c=new I().add(u,a);c.feePayer=this.feePayer.publicKey;let{blockhash:y}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);c.recentBlockhash=y,c.sign(this.feePayer);let l=await this.connection.sendRawTransaction(c.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:l,blockhash:y,lastValidBlockHeight:(await this.connection.getLatestBlockhash(this.confirmOptions.commitment)).lastValidBlockHeight},this.confirmOptions.commitment),await this.waitForActiveSessionFinalized(i.publicKey),v(i,e,r)}async signWithSession(e,n){let i=await E(n.channelId);return x(e,n,i)}async signOpenTab(e,n){return e.registration}async signCloseTab(e,n,i){let s=S({programId:g,vaultPda:this.vaultPdaKey,sessionPubkey:e.publicKey}),r=await this.passkey.signOperation(s),o=m(this.passkey.publicKey,r.signature,r.precompileMessage),u=A({vaultPda:this.vaultPdaKey,clientDataJSON:r.clientDataJSON,authenticatorData:r.authenticatorData}),a=new I().add(o,u);a.feePayer=this.feePayer.publicKey;let{blockhash:c,lastValidBlockHeight:y}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);a.recentBlockhash=c,a.sign(this.feePayer);let l=await this.connection.sendRawTransaction(a.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:l,blockhash:c,lastValidBlockHeight:y},this.confirmOptions.commitment),s}async waitForActiveSessionFinalized(e,n=2e4){let i=Date.now()+n;for(;Date.now()<i;){let s=await this.connection.getAccountInfo(this.vaultPdaKey,"finalized");if(s){let r=s.data,y=84+(r[83]===1?48:0)+32+32;if(r[y]===1){let l=y+1,R=r.slice(l,l+32);if(N(R,e))return}}await new Promise(r=>setTimeout(r,500))}throw new Error(`register_session_key did not become finalized-visible within ${n}ms`)}};function ye(t){return new h(t)}function _(){return Math.floor(Math.random()*4294967295)>>>0}async function E(t){if(/^[0-9a-f]{64}$/i.test(t))return $(t);let{sha256:e}=await import("@noble/hashes/sha256");return e(new TextEncoder().encode(t))}function N(t,e){if(t.length!==e.length)return!1;for(let n=0;n<t.length;n++)if(t[n]!==e[n])return!1;return!0}function $(t){let e=new Uint8Array(t.length/2);for(let n=0;n<e.length;n++)e[n]=parseInt(t.substr(n*2,2),16);return e}export{ye as createSolanaVaultAdapter,C as deriveChannelId,ue as passkeySignerFromP256Keypair};
@@ -1,6 +1,6 @@
1
- "use strict";var P=Object.create;var y=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var n in t)y(e,n,{get:t[n],enumerable:!0})},f=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of E(t))!$.call(e,o)&&o!==n&&y(e,o,{get:()=>t[o],enumerable:!(r=k(t,o))||r.enumerable});return e};var R=(e,t,n)=>(n=e!=null?P(K(e)):{},f(t||!e||!e.__esModule?y(n,"default",{value:e,enumerable:!0}):n,e)),N=e=>f(y({},"__esModule",{value:!0}),e);var M={};C(M,{DEFAULT_FACILITATOR_URL:()=>A,SessionScopeExceededError:()=>m,TabClosedError:()=>c,UnsupportedNetworkError:()=>l,atomicToHuman:()=>p,humanToAtomic:()=>h,openTab:()=>T,resumeTab:()=>U});module.exports=N(M);var l=class extends Error{constructor(n){super(`Network ${n} is not yet supported by @dexterai/x402/tab`);this.network=n;this.name="UnsupportedNetworkError"}},m=class extends Error{constructor(n,r){super(`Session scope exceeded: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="SessionScopeExceededError"}},c=class extends Error{constructor(n){super(`Tab ${n} is already closed`);this.channelId=n;this.name="TabClosedError"}};var w=require("@solana/web3.js"),u=require("@noble/hashes/utils");var V=R(require("tweetnacl"),1);var F=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),J=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();var S=require("@noble/hashes/sha256");function x(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let n=new TextEncoder().encode(e.sellerUrl),r=S.sha256.create();return r.update(e.vaultPda.toBytes()),r.update(n),r.update(t),r.digest()}var O=3600,A="https://x402.dexter.cash",v=6;function h(e,t=v){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"),s=`${n}${o}`.replace(/^0+(?=\d)/,"");return s===""?"0":s}function p(e,t=v){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 g=class{channelId;network;internals;cumulativeAtomic=0n;sequenceNumber=0;closed=!1;lastSignedVoucher=null;constructor(t){this.internals=t,this.channelId=t.channelIdHex,this.network=t.network}get state(){let t=this.internals.totalCapAtomic-this.cumulativeAtomic,n=Math.floor(Date.now()/1e3);return{isOpen:!this.closed,spent:p(this.cumulativeAtomic.toString()),remaining:p(t.toString()),expiresInSec:Math.max(0,this.internals.expiresAtUnix-n)}}async signNextVoucher(t){if(this.closed)throw new c(this.channelId);let n=BigInt(t);if(n<=0n)throw new Error(`voucher increment must be > 0, got ${t}`);if(n>this.internals.perUnitCapAtomic)throw new m("cap_exceeded",`single voucher increment ${n} exceeds perUnitCap ${this.internals.perUnitCapAtomic}`);let r=this.cumulativeAtomic+n;if(r>this.internals.totalCapAtomic)throw new m("cap_exceeded",`cumulative ${r} would exceed totalCap ${this.internals.totalCapAtomic}`);this.sequenceNumber+=1,this.cumulativeAtomic=r;let o={channelId:this.channelId,cumulativeAmount:this.cumulativeAtomic.toString(),sequenceNumber:this.sequenceNumber},s=await this.internals.vault.signWithSession(this.internals.session,o);return this.lastSignedVoucher=s,s}async stream(t,n){if(this.closed)throw new c(this.channelId);let r=await this.signNextVoucher(this.internals.perUnitCapAtomic.toString()),o=Buffer.from(JSON.stringify({payload:r.payload,sessionPublicKey:(0,u.bytesToHex)(r.sessionPublicKey),sessionRegistration:(0,u.bytesToHex)(r.sessionRegistration),sessionSignature:(0,u.bytesToHex)(r.sessionSignature)}),"utf8").toString("base64"),s=new Headers(n?.headers);s.set("X-Tab-Voucher",o),s.set("Accept","text/event-stream");let i=await fetch(t,{...n,headers:s});if(!i.ok){let a=await i.text().catch(()=>"");throw new Error(`tab.stream HTTP ${i.status}: ${a.slice(0,500)}`)}if(!i.body)throw new Error("tab.stream response has no body");return _(i.body)}async close(){if(this.closed)throw new c(this.channelId);let t="";return this.lastSignedVoucher&&this.cumulativeAtomic>0n&&(t=await B(this.internals.facilitatorUrl,this.lastSignedVoucher,this.internals.network)),await this.internals.vault.signCloseTab(this.internals.session,this.channelId,this.cumulativeAtomic.toString()),this.closed=!0,this.internals.session.privateKey.fill(0),{settledAmount:p(this.cumulativeAtomic.toString()),settleTx:t}}};async function B(e,t,n){let r=`${e.replace(/\/$/,"")}/tab/settle`,o={channelId:t.payload.channelId,cumulativeAmount:t.payload.cumulativeAmount,sequenceNumber:t.payload.sequenceNumber,sessionPublicKey:(0,u.bytesToHex)(t.sessionPublicKey),sessionSignature:(0,u.bytesToHex)(t.sessionSignature),sessionRegistration:(0,u.bytesToHex)(t.sessionRegistration),network:n},s=await fetch(r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(o)}),i=await s.text();if(!s.ok)throw new Error(`tab settle ${s.status}: ${i.slice(0,500)}`);let a;try{a=JSON.parse(i)}catch{throw new Error(`tab settle returned non-JSON: ${i.slice(0,200)}`)}if(!a.settleTx)throw new Error(`tab settle returned no settleTx: ${i.slice(0,200)}`);return a.settleTx}async function T(e){if(e.network!==e.vault.network)throw new l(`options.network (${e.network}) doesn't match vault.network (${e.vault.network})`);if(e.network!=="solana:mainnet")throw new l(e.network);let t=BigInt(Math.floor(Math.random()*4294967295)),n=new w.PublicKey(e.vault.vaultPda),r=x({vaultPda:n,sellerUrl:e.seller,nonce:BigInt(t)}),o=(0,u.bytesToHex)(r),s=BigInt(h(e.perUnitCap)),i=BigInt(h(e.totalCap));if(s<=0n)throw new Error("perUnitCap must be > 0");if(i<s)throw new Error("totalCap must be >= perUnitCap");let a=e.sessionDuration??O,d=Math.floor(Date.now()/1e3)+a,b={channelId:o,maxAmountAtomic:i.toString(),expiresAtUnix:d,allowedCounterparty:H(e.seller)},I=await e.vault.authorizeSession(b);return new g({vault:e.vault,network:e.network,seller:e.seller,session:I,channelIdHex:o,channelIdBytes:r,perUnitCapAtomic:s,totalCapAtomic:i,expiresAtUnix:d,facilitatorUrl:e.facilitatorUrl??A})}async function U(e){throw new Error("resumeTab is Phase 3 work. Session keys are memory-only by design; recovery requires reading active_session on chain and re-authorizing. Tracked in dexter-vault roadmap.")}function H(e){if(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e))try{return new w.PublicKey(e),e}catch{}throw new Error(`seller must be a base58 Solana pubkey for Phase 2 (got "${e}"). URL-based counterparty resolution lands in Phase 3 (seller middleware).`)}async function*_(e){let t=e.getReader(),n=new TextDecoder,r="";try{for(;;){let{done:o,value:s}=await t.read();if(o)break;r+=n.decode(s,{stream:!0});let i;for(;(i=r.indexOf(`
1
+ "use strict";var K=Object.create;var b=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var $=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var O=(e,t)=>{for(var n in t)b(e,n,{get:t[n],enumerable:!0})},v=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of V(t))!N.call(e,s)&&s!==n&&b(e,s,{get:()=>t[s],enumerable:!(r=E(t,s))||r.enumerable});return e};var _=(e,t,n)=>(n=e!=null?K($(e)):{},v(t||!e||!e.__esModule?b(n,"default",{value:e,enumerable:!0}):n,e)),M=e=>v(b({},"__esModule",{value:!0}),e);var J={};O(J,{DEFAULT_FACILITATOR_URL:()=>x,DEXTER_VAULT_PROGRAM_ID:()=>u.DEXTER_VAULT_PROGRAM_ID,INSTRUCTIONS_SYSVAR_ID:()=>u.INSTRUCTIONS_SYSVAR_ID,SECP256R1_PROGRAM_ID:()=>u.SECP256R1_PROGRAM_ID,SessionScopeExceededError:()=>p,TabClosedError:()=>l,UnsupportedNetworkError:()=>m,atomicToHuman:()=>g,buildRegisterSessionKeyInstruction:()=>y.buildRegisterSessionKeyInstruction,buildRevokeSessionKeyInstruction:()=>y.buildRevokeSessionKeyInstruction,buildSecp256r1VerifyInstruction:()=>T.buildSecp256r1VerifyInstruction,buildVoucherMessage:()=>a.buildVoucherMessage,humanToAtomic:()=>A,openTab:()=>k,resumeTab:()=>P,sessionRegisterMessage:()=>a.sessionRegisterMessage,sessionRevokeMessage:()=>a.sessionRevokeMessage,voucherPayloadMessage:()=>a.voucherPayloadMessage});module.exports=M(J);var m=class extends Error{constructor(n){super(`Network ${n} is not yet supported by @dexterai/x402/tab`);this.network=n;this.name="UnsupportedNetworkError"}},p=class extends Error{constructor(n,r){super(`Session scope exceeded: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="SessionScopeExceededError"}},l=class extends Error{constructor(n){super(`Tab ${n} is already closed`);this.channelId=n;this.name="TabClosedError"}};var f=require("@solana/web3.js"),d=require("@noble/hashes/utils");var H=_(require("tweetnacl"),1);var a=require("@dexterai/vault/messages");var I=require("@noble/hashes/sha256");function R(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let n=new TextEncoder().encode(e.sellerUrl),r=I.sha256.create();return r.update(e.vaultPda.toBytes()),r.update(n),r.update(t),r.digest()}var D=3600,x="https://x402.dexter.cash",U=6;function A(e,t=U){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 s=r.padEnd(t,"0"),o=`${n}${s}`.replace(/^0+(?=\d)/,"");return o===""?"0":o}function g(e,t=U){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",s=n.slice(-t).replace(/0+$/,"");return s?`${r}.${s}`:r}var w=class{channelId;network;internals;cumulativeAtomic=0n;sequenceNumber=0;closed=!1;lastSignedVoucher=null;constructor(t){this.internals=t,this.channelId=t.channelIdHex,this.network=t.network}get state(){let t=this.internals.totalCapAtomic-this.cumulativeAtomic,n=Math.floor(Date.now()/1e3);return{isOpen:!this.closed,spent:g(this.cumulativeAtomic.toString()),remaining:g(t.toString()),expiresInSec:Math.max(0,this.internals.expiresAtUnix-n)}}async signNextVoucher(t){if(this.closed)throw new l(this.channelId);let n=BigInt(t);if(n<=0n)throw new Error(`voucher increment must be > 0, got ${t}`);if(n>this.internals.perUnitCapAtomic)throw new p("cap_exceeded",`single voucher increment ${n} exceeds perUnitCap ${this.internals.perUnitCapAtomic}`);let r=this.cumulativeAtomic+n;if(r>this.internals.totalCapAtomic)throw new p("cap_exceeded",`cumulative ${r} would exceed totalCap ${this.internals.totalCapAtomic}`);this.sequenceNumber+=1,this.cumulativeAtomic=r;let s={channelId:this.channelId,cumulativeAmount:this.cumulativeAtomic.toString(),sequenceNumber:this.sequenceNumber},o=await this.internals.vault.signWithSession(this.internals.session,s);return this.lastSignedVoucher=o,o}async stream(t,n){if(this.closed)throw new l(this.channelId);let r=await this.signNextVoucher(this.internals.perUnitCapAtomic.toString()),s=Buffer.from(JSON.stringify({payload:r.payload,sessionPublicKey:(0,d.bytesToHex)(r.sessionPublicKey),sessionRegistration:(0,d.bytesToHex)(r.sessionRegistration),sessionSignature:(0,d.bytesToHex)(r.sessionSignature)}),"utf8").toString("base64"),o=new Headers(n?.headers);o.set("X-Tab-Voucher",s),o.set("Accept","text/event-stream");let i=await fetch(t,{...n,headers:o});if(!i.ok){let c=await i.text().catch(()=>"");throw new Error(`tab.stream HTTP ${i.status}: ${c.slice(0,500)}`)}if(!i.body)throw new Error("tab.stream response has no body");return q(i.body)}async close(){if(this.closed)throw new l(this.channelId);let t="";return this.lastSignedVoucher&&this.cumulativeAtomic>0n&&(t=await B(this.internals.facilitatorUrl,this.lastSignedVoucher,this.internals.network)),await this.internals.vault.signCloseTab(this.internals.session,this.channelId,this.cumulativeAtomic.toString()),this.closed=!0,this.internals.session.privateKey.fill(0),{settledAmount:g(this.cumulativeAtomic.toString()),settleTx:t}}};async function B(e,t,n){let r=`${e.replace(/\/$/,"")}/tab/settle`,s={channelId:t.payload.channelId,cumulativeAmount:t.payload.cumulativeAmount,sequenceNumber:t.payload.sequenceNumber,sessionPublicKey:(0,d.bytesToHex)(t.sessionPublicKey),sessionSignature:(0,d.bytesToHex)(t.sessionSignature),sessionRegistration:(0,d.bytesToHex)(t.sessionRegistration),network:n},o=await fetch(r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)}),i=await o.text();if(!o.ok)throw new Error(`tab settle ${o.status}: ${i.slice(0,500)}`);let c;try{c=JSON.parse(i)}catch{throw new Error(`tab settle returned non-JSON: ${i.slice(0,200)}`)}if(!c.settleTx)throw new Error(`tab settle returned no settleTx: ${i.slice(0,200)}`);return c.settleTx}async function k(e){if(e.network!==e.vault.network)throw new m(`options.network (${e.network}) doesn't match vault.network (${e.vault.network})`);if(e.network!=="solana:mainnet")throw new m(e.network);let t=BigInt(Math.floor(Math.random()*4294967295)),n=new f.PublicKey(e.vault.vaultPda),r=R({vaultPda:n,sellerUrl:e.seller,nonce:BigInt(t)}),s=(0,d.bytesToHex)(r),o=BigInt(A(e.perUnitCap)),i=BigInt(A(e.totalCap));if(o<=0n)throw new Error("perUnitCap must be > 0");if(i<o)throw new Error("totalCap must be >= perUnitCap");let c=e.sessionDuration??D,h=Math.floor(Date.now()/1e3)+c,S={channelId:s,maxAmountAtomic:i.toString(),expiresAtUnix:h,allowedCounterparty:L(e.seller)},C=await e.vault.authorizeSession(S);return new w({vault:e.vault,network:e.network,seller:e.seller,session:C,channelIdHex:s,channelIdBytes:r,perUnitCapAtomic:o,totalCapAtomic:i,expiresAtUnix:h,facilitatorUrl:e.facilitatorUrl??x})}async function P(e){throw new Error("resumeTab is Phase 3 work. Session keys are memory-only by design; recovery requires reading active_session on chain and re-authorizing. Tracked in dexter-vault roadmap.")}function L(e){if(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e))try{return new f.PublicKey(e),e}catch{}throw new Error(`seller must be a base58 Solana pubkey for Phase 2 (got "${e}"). URL-based counterparty resolution lands in Phase 3 (seller middleware).`)}async function*q(e){let t=e.getReader(),n=new TextDecoder,r="";try{for(;;){let{done:s,value:o}=await t.read();if(s)break;r+=n.decode(o,{stream:!0});let i;for(;(i=r.indexOf(`
2
2
 
3
- `))!==-1;){let a=r.slice(0,i);r=r.slice(i+2);let d=D(a);if(d.eventName==="end")return;if(d.data!==null){let b=d.data.replace(/\\n/g,`
4
- `);yield new TextEncoder().encode(b)}}}}finally{t.releaseLock()}}function D(e){let t=null,n=[];for(let r of e.split(`
3
+ `))!==-1;){let c=r.slice(0,i);r=r.slice(i+2);let h=F(c);if(h.eventName==="end")return;if(h.data!==null){let S=h.data.replace(/\\n/g,`
4
+ `);yield new TextEncoder().encode(S)}}}}finally{t.releaseLock()}}function F(e){let t=null,n=[];for(let r of e.split(`
5
5
  `))r.startsWith("event:")?t=r.slice(6).trim():r.startsWith("data:")&&n.push(r.slice(5).trimStart());return{eventName:t,data:n.length?n.join(`
6
- `):null}}0&&(module.exports={DEFAULT_FACILITATOR_URL,SessionScopeExceededError,TabClosedError,UnsupportedNetworkError,atomicToHuman,humanToAtomic,openTab,resumeTab});
6
+ `):null}}var y=require("@dexterai/vault/instructions"),T=require("@dexterai/vault/precompile"),u=require("@dexterai/vault/constants");0&&(module.exports={DEFAULT_FACILITATOR_URL,DEXTER_VAULT_PROGRAM_ID,INSTRUCTIONS_SYSVAR_ID,SECP256R1_PROGRAM_ID,SessionScopeExceededError,TabClosedError,UnsupportedNetworkError,atomicToHuman,buildRegisterSessionKeyInstruction,buildRevokeSessionKeyInstruction,buildSecp256r1VerifyInstruction,buildVoucherMessage,humanToAtomic,openTab,resumeTab,sessionRegisterMessage,sessionRevokeMessage,voucherPayloadMessage});
@@ -1,5 +1,11 @@
1
- import { O as OpenTabOptions, T as Tab, R as ResumeTabOptions, H as HumanAmount, A as AtomicAmount } from '../types-DIrmhiD-.cjs';
2
- export { d as SessionKey, S as SessionScope, g as SessionScopeExceededError, e as SignedVoucher, b as TabCloseResult, h as TabClosedError, c as TabNetworkId, a as TabState, U as UnsupportedNetworkError, f as VaultAdapter, V as VoucherPayload } from '../types-DIrmhiD-.cjs';
1
+ import { O as OpenTabOptions, T as Tab, R as ResumeTabOptions } from '../types-BtibqM00.cjs';
2
+ export { S as SessionScopeExceededError, b as TabCloseResult, c as TabClosedError, a as TabState, U as UnsupportedNetworkError, V as VaultAdapter } from '../types-BtibqM00.cjs';
3
+ import { HumanAmount, AtomicAmount } from '@dexterai/vault/types';
4
+ export { AtomicAmount, HumanAmount, SessionKey, SessionScope, SignedVoucher, TabNetworkId, VoucherPayload } from '@dexterai/vault/types';
5
+ export { SessionRegisterMessageArgs, SessionRevokeMessageArgs, VoucherPayloadBytes, buildVoucherMessage, sessionRegisterMessage, sessionRevokeMessage, voucherPayloadMessage } from '@dexterai/vault/messages';
6
+ export { BuildRegisterSessionKeyArgs, BuildRevokeSessionKeyArgs, buildRegisterSessionKeyInstruction, buildRevokeSessionKeyInstruction } from '@dexterai/vault/instructions';
7
+ export { buildSecp256r1VerifyInstruction } from '@dexterai/vault/precompile';
8
+ export { DEXTER_VAULT_PROGRAM_ID, INSTRUCTIONS_SYSVAR_ID, SECP256R1_PROGRAM_ID } from '@dexterai/vault/constants';
3
9
 
4
10
  /**
5
11
  * The `Tab` runtime — the live object returned by `openTab()`.
@@ -28,4 +34,4 @@ declare function atomicToHuman(atomic: AtomicAmount, decimals?: number): HumanAm
28
34
  declare function openTab(options: OpenTabOptions): Promise<Tab>;
29
35
  declare function resumeTab(_options: ResumeTabOptions): Promise<Tab>;
30
36
 
31
- export { AtomicAmount, DEFAULT_FACILITATOR_URL, HumanAmount, OpenTabOptions, ResumeTabOptions, Tab, atomicToHuman, humanToAtomic, openTab, resumeTab };
37
+ export { DEFAULT_FACILITATOR_URL, OpenTabOptions, ResumeTabOptions, Tab, atomicToHuman, humanToAtomic, openTab, resumeTab };
@@ -1,5 +1,11 @@
1
- import { O as OpenTabOptions, T as Tab, R as ResumeTabOptions, H as HumanAmount, A as AtomicAmount } from '../types-DIrmhiD-.js';
2
- export { d as SessionKey, S as SessionScope, g as SessionScopeExceededError, e as SignedVoucher, b as TabCloseResult, h as TabClosedError, c as TabNetworkId, a as TabState, U as UnsupportedNetworkError, f as VaultAdapter, V as VoucherPayload } from '../types-DIrmhiD-.js';
1
+ import { O as OpenTabOptions, T as Tab, R as ResumeTabOptions } from '../types-BtibqM00.js';
2
+ export { S as SessionScopeExceededError, b as TabCloseResult, c as TabClosedError, a as TabState, U as UnsupportedNetworkError, V as VaultAdapter } from '../types-BtibqM00.js';
3
+ import { HumanAmount, AtomicAmount } from '@dexterai/vault/types';
4
+ export { AtomicAmount, HumanAmount, SessionKey, SessionScope, SignedVoucher, TabNetworkId, VoucherPayload } from '@dexterai/vault/types';
5
+ export { SessionRegisterMessageArgs, SessionRevokeMessageArgs, VoucherPayloadBytes, buildVoucherMessage, sessionRegisterMessage, sessionRevokeMessage, voucherPayloadMessage } from '@dexterai/vault/messages';
6
+ export { BuildRegisterSessionKeyArgs, BuildRevokeSessionKeyArgs, buildRegisterSessionKeyInstruction, buildRevokeSessionKeyInstruction } from '@dexterai/vault/instructions';
7
+ export { buildSecp256r1VerifyInstruction } from '@dexterai/vault/precompile';
8
+ export { DEXTER_VAULT_PROGRAM_ID, INSTRUCTIONS_SYSVAR_ID, SECP256R1_PROGRAM_ID } from '@dexterai/vault/constants';
3
9
 
4
10
  /**
5
11
  * The `Tab` runtime — the live object returned by `openTab()`.
@@ -28,4 +34,4 @@ declare function atomicToHuman(atomic: AtomicAmount, decimals?: number): HumanAm
28
34
  declare function openTab(options: OpenTabOptions): Promise<Tab>;
29
35
  declare function resumeTab(_options: ResumeTabOptions): Promise<Tab>;
30
36
 
31
- export { AtomicAmount, DEFAULT_FACILITATOR_URL, HumanAmount, OpenTabOptions, ResumeTabOptions, Tab, atomicToHuman, humanToAtomic, openTab, resumeTab };
37
+ export { DEFAULT_FACILITATOR_URL, OpenTabOptions, ResumeTabOptions, Tab, atomicToHuman, humanToAtomic, openTab, resumeTab };
package/dist/tab/index.js CHANGED
@@ -1,6 +1,6 @@
1
- var m=class extends Error{constructor(r){super(`Network ${r} is not yet supported by @dexterai/x402/tab`);this.network=r;this.name="UnsupportedNetworkError"}},d=class extends Error{constructor(r,n){super(`Session scope exceeded: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="SessionScopeExceededError"}},c=class extends Error{constructor(r){super(`Tab ${r} is already closed`);this.channelId=r;this.name="TabClosedError"}};import{PublicKey as w}from"@solana/web3.js";import{bytesToHex as u}from"@noble/hashes/utils";import O from"tweetnacl";var $=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),C=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();import{sha256 as x}from"@noble/hashes/sha256";function g(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let r=new TextEncoder().encode(e.sellerUrl),n=x.create();return n.update(e.vaultPda.toBytes()),n.update(r),n.update(t),n.digest()}var v=3600,A="https://x402.dexter.cash",f=6;function h(e,t=f){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"),o=`${r}${i}`.replace(/^0+(?=\d)/,"");return o===""?"0":o}function p(e,t=f){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}var b=class{channelId;network;internals;cumulativeAtomic=0n;sequenceNumber=0;closed=!1;lastSignedVoucher=null;constructor(t){this.internals=t,this.channelId=t.channelIdHex,this.network=t.network}get state(){let t=this.internals.totalCapAtomic-this.cumulativeAtomic,r=Math.floor(Date.now()/1e3);return{isOpen:!this.closed,spent:p(this.cumulativeAtomic.toString()),remaining:p(t.toString()),expiresInSec:Math.max(0,this.internals.expiresAtUnix-r)}}async signNextVoucher(t){if(this.closed)throw new c(this.channelId);let r=BigInt(t);if(r<=0n)throw new Error(`voucher increment must be > 0, got ${t}`);if(r>this.internals.perUnitCapAtomic)throw new d("cap_exceeded",`single voucher increment ${r} exceeds perUnitCap ${this.internals.perUnitCapAtomic}`);let n=this.cumulativeAtomic+r;if(n>this.internals.totalCapAtomic)throw new d("cap_exceeded",`cumulative ${n} would exceed totalCap ${this.internals.totalCapAtomic}`);this.sequenceNumber+=1,this.cumulativeAtomic=n;let i={channelId:this.channelId,cumulativeAmount:this.cumulativeAtomic.toString(),sequenceNumber:this.sequenceNumber},o=await this.internals.vault.signWithSession(this.internals.session,i);return this.lastSignedVoucher=o,o}async stream(t,r){if(this.closed)throw new c(this.channelId);let n=await this.signNextVoucher(this.internals.perUnitCapAtomic.toString()),i=Buffer.from(JSON.stringify({payload:n.payload,sessionPublicKey:u(n.sessionPublicKey),sessionRegistration:u(n.sessionRegistration),sessionSignature:u(n.sessionSignature)}),"utf8").toString("base64"),o=new Headers(r?.headers);o.set("X-Tab-Voucher",i),o.set("Accept","text/event-stream");let s=await fetch(t,{...r,headers:o});if(!s.ok){let a=await s.text().catch(()=>"");throw new Error(`tab.stream HTTP ${s.status}: ${a.slice(0,500)}`)}if(!s.body)throw new Error("tab.stream response has no body");return k(s.body)}async close(){if(this.closed)throw new c(this.channelId);let t="";return this.lastSignedVoucher&&this.cumulativeAtomic>0n&&(t=await T(this.internals.facilitatorUrl,this.lastSignedVoucher,this.internals.network)),await this.internals.vault.signCloseTab(this.internals.session,this.channelId,this.cumulativeAtomic.toString()),this.closed=!0,this.internals.session.privateKey.fill(0),{settledAmount:p(this.cumulativeAtomic.toString()),settleTx:t}}};async function T(e,t,r){let n=`${e.replace(/\/$/,"")}/tab/settle`,i={channelId:t.payload.channelId,cumulativeAmount:t.payload.cumulativeAmount,sequenceNumber:t.payload.sequenceNumber,sessionPublicKey:u(t.sessionPublicKey),sessionSignature:u(t.sessionSignature),sessionRegistration:u(t.sessionRegistration),network:r},o=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i)}),s=await o.text();if(!o.ok)throw new Error(`tab settle ${o.status}: ${s.slice(0,500)}`);let a;try{a=JSON.parse(s)}catch{throw new Error(`tab settle returned non-JSON: ${s.slice(0,200)}`)}if(!a.settleTx)throw new Error(`tab settle returned no settleTx: ${s.slice(0,200)}`);return a.settleTx}async function U(e){if(e.network!==e.vault.network)throw new m(`options.network (${e.network}) doesn't match vault.network (${e.vault.network})`);if(e.network!=="solana:mainnet")throw new m(e.network);let t=BigInt(Math.floor(Math.random()*4294967295)),r=new w(e.vault.vaultPda),n=g({vaultPda:r,sellerUrl:e.seller,nonce:BigInt(t)}),i=u(n),o=BigInt(h(e.perUnitCap)),s=BigInt(h(e.totalCap));if(o<=0n)throw new Error("perUnitCap must be > 0");if(s<o)throw new Error("totalCap must be >= perUnitCap");let a=e.sessionDuration??v,l=Math.floor(Date.now()/1e3)+a,y={channelId:i,maxAmountAtomic:s.toString(),expiresAtUnix:l,allowedCounterparty:P(e.seller)},S=await e.vault.authorizeSession(y);return new b({vault:e.vault,network:e.network,seller:e.seller,session:S,channelIdHex:i,channelIdBytes:n,perUnitCapAtomic:o,totalCapAtomic:s,expiresAtUnix:l,facilitatorUrl:e.facilitatorUrl??A})}async function I(e){throw new Error("resumeTab is Phase 3 work. Session keys are memory-only by design; recovery requires reading active_session on chain and re-authorizing. Tracked in dexter-vault roadmap.")}function P(e){if(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e))try{return new w(e),e}catch{}throw new Error(`seller must be a base58 Solana pubkey for Phase 2 (got "${e}"). URL-based counterparty resolution lands in Phase 3 (seller middleware).`)}async function*k(e){let t=e.getReader(),r=new TextDecoder,n="";try{for(;;){let{done:i,value:o}=await t.read();if(i)break;n+=r.decode(o,{stream:!0});let s;for(;(s=n.indexOf(`
1
+ var d=class extends Error{constructor(r){super(`Network ${r} is not yet supported by @dexterai/x402/tab`);this.network=r;this.name="UnsupportedNetworkError"}},m=class extends Error{constructor(r,n){super(`Session scope exceeded: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="SessionScopeExceededError"}},c=class extends Error{constructor(r){super(`Tab ${r} is already closed`);this.channelId=r;this.name="TabClosedError"}};import{PublicKey as S}from"@solana/web3.js";import{bytesToHex as u}from"@noble/hashes/utils";import F from"tweetnacl";import{sessionRegisterMessage as T,sessionRevokeMessage as v,voucherPayloadMessage as b,buildVoucherMessage as I}from"@dexterai/vault/messages";import{sha256 as R}from"@noble/hashes/sha256";function A(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let r=new TextEncoder().encode(e.sellerUrl),n=R.create();return n.update(e.vaultPda.toBytes()),n.update(r),n.update(t),n.digest()}var U=3600,w="https://x402.dexter.cash",f=6;function y(e,t=f){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 p(e,t=f){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}var g=class{channelId;network;internals;cumulativeAtomic=0n;sequenceNumber=0;closed=!1;lastSignedVoucher=null;constructor(t){this.internals=t,this.channelId=t.channelIdHex,this.network=t.network}get state(){let t=this.internals.totalCapAtomic-this.cumulativeAtomic,r=Math.floor(Date.now()/1e3);return{isOpen:!this.closed,spent:p(this.cumulativeAtomic.toString()),remaining:p(t.toString()),expiresInSec:Math.max(0,this.internals.expiresAtUnix-r)}}async signNextVoucher(t){if(this.closed)throw new c(this.channelId);let r=BigInt(t);if(r<=0n)throw new Error(`voucher increment must be > 0, got ${t}`);if(r>this.internals.perUnitCapAtomic)throw new m("cap_exceeded",`single voucher increment ${r} exceeds perUnitCap ${this.internals.perUnitCapAtomic}`);let n=this.cumulativeAtomic+r;if(n>this.internals.totalCapAtomic)throw new m("cap_exceeded",`cumulative ${n} would exceed totalCap ${this.internals.totalCapAtomic}`);this.sequenceNumber+=1,this.cumulativeAtomic=n;let i={channelId:this.channelId,cumulativeAmount:this.cumulativeAtomic.toString(),sequenceNumber:this.sequenceNumber},s=await this.internals.vault.signWithSession(this.internals.session,i);return this.lastSignedVoucher=s,s}async stream(t,r){if(this.closed)throw new c(this.channelId);let n=await this.signNextVoucher(this.internals.perUnitCapAtomic.toString()),i=Buffer.from(JSON.stringify({payload:n.payload,sessionPublicKey:u(n.sessionPublicKey),sessionRegistration:u(n.sessionRegistration),sessionSignature:u(n.sessionSignature)}),"utf8").toString("base64"),s=new Headers(r?.headers);s.set("X-Tab-Voucher",i),s.set("Accept","text/event-stream");let o=await fetch(t,{...r,headers:s});if(!o.ok){let a=await o.text().catch(()=>"");throw new Error(`tab.stream HTTP ${o.status}: ${a.slice(0,500)}`)}if(!o.body)throw new Error("tab.stream response has no body");return E(o.body)}async close(){if(this.closed)throw new c(this.channelId);let t="";return this.lastSignedVoucher&&this.cumulativeAtomic>0n&&(t=await k(this.internals.facilitatorUrl,this.lastSignedVoucher,this.internals.network)),await this.internals.vault.signCloseTab(this.internals.session,this.channelId,this.cumulativeAtomic.toString()),this.closed=!0,this.internals.session.privateKey.fill(0),{settledAmount:p(this.cumulativeAtomic.toString()),settleTx:t}}};async function k(e,t,r){let n=`${e.replace(/\/$/,"")}/tab/settle`,i={channelId:t.payload.channelId,cumulativeAmount:t.payload.cumulativeAmount,sequenceNumber:t.payload.sequenceNumber,sessionPublicKey:u(t.sessionPublicKey),sessionSignature:u(t.sessionSignature),sessionRegistration:u(t.sessionRegistration),network:r},s=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i)}),o=await s.text();if(!s.ok)throw new Error(`tab settle ${s.status}: ${o.slice(0,500)}`);let a;try{a=JSON.parse(o)}catch{throw new Error(`tab settle returned non-JSON: ${o.slice(0,200)}`)}if(!a.settleTx)throw new Error(`tab settle returned no settleTx: ${o.slice(0,200)}`);return a.settleTx}async function P(e){if(e.network!==e.vault.network)throw new d(`options.network (${e.network}) doesn't match vault.network (${e.vault.network})`);if(e.network!=="solana:mainnet")throw new d(e.network);let t=BigInt(Math.floor(Math.random()*4294967295)),r=new S(e.vault.vaultPda),n=A({vaultPda:r,sellerUrl:e.seller,nonce:BigInt(t)}),i=u(n),s=BigInt(y(e.perUnitCap)),o=BigInt(y(e.totalCap));if(s<=0n)throw new Error("perUnitCap must be > 0");if(o<s)throw new Error("totalCap must be >= perUnitCap");let a=e.sessionDuration??U,l=Math.floor(Date.now()/1e3)+a,h={channelId:i,maxAmountAtomic:o.toString(),expiresAtUnix:l,allowedCounterparty:K(e.seller)},x=await e.vault.authorizeSession(h);return new g({vault:e.vault,network:e.network,seller:e.seller,session:x,channelIdHex:i,channelIdBytes:n,perUnitCapAtomic:s,totalCapAtomic:o,expiresAtUnix:l,facilitatorUrl:e.facilitatorUrl??w})}async function C(e){throw new Error("resumeTab is Phase 3 work. Session keys are memory-only by design; recovery requires reading active_session on chain and re-authorizing. Tracked in dexter-vault roadmap.")}function K(e){if(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e))try{return new S(e),e}catch{}throw new Error(`seller must be a base58 Solana pubkey for Phase 2 (got "${e}"). URL-based counterparty resolution lands in Phase 3 (seller middleware).`)}async function*E(e){let t=e.getReader(),r=new TextDecoder,n="";try{for(;;){let{done:i,value:s}=await t.read();if(i)break;n+=r.decode(s,{stream:!0});let o;for(;(o=n.indexOf(`
2
2
 
3
- `))!==-1;){let a=n.slice(0,s);n=n.slice(s+2);let l=E(a);if(l.eventName==="end")return;if(l.data!==null){let y=l.data.replace(/\\n/g,`
4
- `);yield new TextEncoder().encode(y)}}}}finally{t.releaseLock()}}function E(e){let t=null,r=[];for(let n of e.split(`
3
+ `))!==-1;){let a=n.slice(0,o);n=n.slice(o+2);let l=V(a);if(l.eventName==="end")return;if(l.data!==null){let h=l.data.replace(/\\n/g,`
4
+ `);yield new TextEncoder().encode(h)}}}}finally{t.releaseLock()}}function V(e){let t=null,r=[];for(let n of e.split(`
5
5
  `))n.startsWith("event:")?t=n.slice(6).trim():n.startsWith("data:")&&r.push(n.slice(5).trimStart());return{eventName:t,data:r.length?r.join(`
6
- `):null}}export{A as DEFAULT_FACILITATOR_URL,d as SessionScopeExceededError,c as TabClosedError,m as UnsupportedNetworkError,p as atomicToHuman,h as humanToAtomic,U as openTab,I as resumeTab};
6
+ `):null}}import{buildRegisterSessionKeyInstruction as $,buildRevokeSessionKeyInstruction as N}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as O}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as _,SECP256R1_PROGRAM_ID as M,INSTRUCTIONS_SYSVAR_ID as H}from"@dexterai/vault/constants";export{w as DEFAULT_FACILITATOR_URL,_ as DEXTER_VAULT_PROGRAM_ID,H as INSTRUCTIONS_SYSVAR_ID,M as SECP256R1_PROGRAM_ID,m as SessionScopeExceededError,c as TabClosedError,d as UnsupportedNetworkError,p as atomicToHuman,$ as buildRegisterSessionKeyInstruction,N as buildRevokeSessionKeyInstruction,O as buildSecp256r1VerifyInstruction,I as buildVoucherMessage,y as humanToAtomic,P as openTab,C as resumeTab,T as sessionRegisterMessage,v as sessionRevokeMessage,b as voucherPayloadMessage};
@@ -1,6 +1,6 @@
1
- "use strict";var te=Object.create;var x=Object.defineProperty;var ne=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var ie=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var se=(e,t)=>{for(var n in t)x(e,n,{get:t[n],enumerable:!0})},z=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of re(t))!oe.call(e,i)&&i!==n&&x(e,i,{get:()=>t[i],enumerable:!(r=ne(t,i))||r.enumerable});return e};var F=(e,t,n)=>(n=e!=null?te(ie(e)):{},z(t||!e||!e.__esModule?x(n,"default",{value:e,enumerable:!0}):n,e)),ae=e=>z(x({},"__esModule",{value:!0}),e);var be={};se(be,{FileVoucherStore:()=>_,InMemoryVoucherStore:()=>b,InvalidRegistrationError:()=>d,InvalidVoucherError:()=>l,InvalidVoucherSignatureError:()=>g,OnChainVerificationError:()=>h,ScopeViolationError:()=>c,TAB_VOUCHER_HEADER:()=>$,enforceScope:()=>k,openSse:()=>Q,parseRegistration:()=>I,readVaultState:()=>N,requireTab:()=>X,tabMiddleware:()=>Z,verifyRegistrationOnChain:()=>E,verifyVoucherSignature:()=>T});module.exports=ae(be);var l=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};var W=require("@solana/web3.js");var G=F(require("tweetnacl"),1),ce=require("@noble/hashes/sha256"),ue=require("@noble/curves/p256"),U=require("@solana/web3.js");var ve=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),xe=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();function K(e){if(e.channelId.length!==32)throw new Error(`channelId must be 32 bytes, got ${e.channelId.length}`);let t=new Uint8Array(44),n=new DataView(t.buffer),r=0;if(t.set(e.channelId,r),r+=32,n.setBigUint64(r,e.cumulativeAmount,!0),r+=8,n.setUint32(r,e.sequenceNumber>>>0,!0),r+=4,r!==44)throw new Error(`internal: voucher payload wrong length ${r}, expected 44`);return t}var A=require("@solana/web3.js"),P=new A.PublicKey("Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"),Ue=new A.PublicKey("Secp256r1SigVerify1111111111111111111111111"),Ie=new A.PublicKey("Sysvar1nstructions1111111111111111111111111"),Ee=new Uint8Array([69,94,60,44,49,199,183,233]),Te=new Uint8Array([81,192,32,110,104,116,144,151]);var O="OTS_SESSION_REGISTER_V1",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!==180)throw new d("wrong_length",`expected 180, 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 s=O.length;s<32;s++)if(e[s]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${s}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new U.PublicKey(e.slice(32,64)),i=new U.PublicKey(e.slice(64,96)),u=e.slice(96,128),p=n.getBigUint64(128,!0),f=n.getBigInt64(136,!0),o=new U.PublicKey(e.slice(144,176)),a=n.getUint32(176,!0);if(!r.equals(P))throw new d("wrong_program",`${r.toBase58()} is not ${P.toBase58()}`);if(p===0n)throw new d("cap_zero");let m=BigInt(Math.floor(Date.now()/1e3));if(f<=m)throw new d("expiry_in_past",`expires_at=${f}, now=${m}`);return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(u),maxAmount:p,expiresAt:f,allowedCounterparty:o,nonce:a}}var J=10,h=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 h("vault_not_found",t.toBase58());if(!n.owner.equals(P))throw new h("wrong_program",`owner ${n.owner.toBase58()} is not the vault program`);let r=n.data,i=new Uint8Array(r.slice(J,J+33)),a=84+(r[83]===1?48:0)+32+32;if(r[a]!==1)return{passkeyPubkey:i,activeSessionPubkey:null};let s=a+1,y=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:i,activeSessionPubkey:y}}async function E(e,t){let n=await N(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new h("session_not_active","vault has no active_session \u2014 was it revoked?");if(!le(n.activeSessionPubkey,t.sessionPubkey))throw new h("session_pubkey_mismatch",`on-chain ${j(n.activeSessionPubkey)} != registration ${j(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var g=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function T(e,t){if(t.length!==32)throw new g(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new g(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new g(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=K({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!G.default.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new g("ed25519 verify rejected")}var c=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function k(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 le(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 w=require("fs"),R=require("path");function de(e){return{payload:e.payload,sessionPublicKey:B(e.sessionPublicKey),sessionRegistration:B(e.sessionRegistration),sessionSignature:B(e.sessionSignature)}}function me(e){return{payload:e.payload,sessionPublicKey:D(e.sessionPublicKey),sessionRegistration:D(e.sessionRegistration),sessionSignature:D(e.sessionSignature)}}function B(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function D(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)}},_=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,R.join)(this.dir,`${t}.json`)}async get(t){try{let n=await w.promises.readFile(this.pathFor(t),"utf8");return me(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await w.promises.mkdir((0,R.dirname)(r),{recursive:!0});let i=`${r}.tmp`;await w.promises.writeFile(i,JSON.stringify(de(n))),await w.promises.rename(i,r)}async delete(t){try{await w.promises.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};var ge=require("@solana/web3.js"),he=require("@noble/hashes/utils");var pe=F(require("tweetnacl"),1);var ye=require("@noble/hashes/sha256");var Y=6;function S(e,t=Y){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"),u=`${n}${i}`.replace(/^0+(?=\d)/,"");return u===""?"0":u}function v(e,t=Y){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 $="x-tab-voucher",H=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)}},M=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 v(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function fe(e){if(typeof e!="string"||e.length===0)throw new l("signature_invalid",`missing ${$} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new l("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new l("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new l("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:V(n.sessionPublicKey),sessionRegistration:V(n.sessionRegistration),sessionSignature:V(n.sessionSignature)}}function V(e){if(typeof e!="string"||e.length%2!==0)throw new l("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 we(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new l("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return V(e)}function Z(e){let t=e.store??new b,n=new H,r=typeof e.sellerPubkey=="string"?new W.PublicKey(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(S(e.perUnit))*100n;return async(u,p,f)=>{try{let o=fe(u.headers[$]),a=o.payload.channelId,m=we(a),s=n.get(a);if(!s){let C=I(o.sessionRegistration);await E(e.connection,C),s={registration:C,lastCumulativeAtomic:"0"},n.set(a,s)}T(o,m),k({registration:s.registration,voucher:o,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let y=BigInt(o.payload.cumulativeAmount),ee=BigInt(s.lastCumulativeAtomic),q=y-ee;if(q>i)throw new c("cumulative_exceeds_cap",`single voucher increment ${q} exceeds maxPerVoucherAtomic ${i}`);await t.set(a,o),n.update(a,o.payload.cumulativeAmount);let L=new M(a,e.network,y,async C=>{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.")});L.setSessionPublicKey(o.sessionPublicKey),u.tab=L,f()}catch(o){if(o instanceof l||o instanceof d||o instanceof h||o instanceof g||o instanceof c){p.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}f(o)}}}function X(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(S(n.cumulative())),i=t.perUnit?BigInt(S(t.perUnit)):null,u=0n,p=!1;function f(m=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(m),y=u+s;return y>r?Promise.reject(new c("cumulative_exceeds_cap",`chunk would push request total to ${v(y.toString())} beyond voucher-authorized budget ${v(r.toString())}`)):(u=y,Promise.resolve())}function o(m){if(p)throw new Error("meter ended");let y=(typeof m=="string"?m:Buffer.from(m).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${y}
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})},z=(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 L=(e,t,n)=>(n=e!=null?te(oe(e)):{},z(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),ae=e=>z(P({},"__esModule",{value:!0}),e);var Se={};se(Se,{FileVoucherStore:()=>_,InMemoryVoucherStore:()=>A,InvalidRegistrationError:()=>m,InvalidVoucherError:()=>l,InvalidVoucherSignatureError:()=>g,OnChainVerificationError:()=>y,ScopeViolationError:()=>c,TAB_VOUCHER_HEADER:()=>R,enforceScope:()=>U,openSse:()=>Q,parseRegistration:()=>I,readVaultState:()=>O,requireTab:()=>Z,tabMiddleware:()=>Y,verifyRegistrationOnChain:()=>k,verifyVoucherSignature:()=>V});module.exports=ae(Se);var l=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=L(require("tweetnacl"),1),ue=require("@noble/hashes/sha256"),le=require("@noble/curves/p256"),T=require("@solana/web3.js");var w=require("@dexterai/vault/messages");var F=require("@dexterai/vault/instructions"),ce=require("@dexterai/vault/precompile"),b=require("@dexterai/vault/constants");var K="OTS_SESSION_REGISTER_V1",m=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function I(e){if(e.length!==180)throw new m("wrong_length",`expected 180, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,K.length));if(t!==K)throw new m("wrong_domain",`got "${t}"`);for(let s=K.length;s<32;s++)if(e[s]!==0)throw new m("wrong_domain",`non-NUL padding at byte ${s}`);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)),u=e.slice(96,128),p=n.getBigUint64(128,!0),f=n.getBigInt64(136,!0),i=new T.PublicKey(e.slice(144,176)),a=n.getUint32(176,!0);if(!r.equals(b.DEXTER_VAULT_PROGRAM_ID))throw new m("wrong_program",`${r.toBase58()} is not ${b.DEXTER_VAULT_PROGRAM_ID.toBase58()}`);if(p===0n)throw new m("cap_zero");let d=BigInt(Math.floor(Date.now()/1e3));if(f<=d)throw new m("expiry_in_past",`expires_at=${f}, now=${d}`);return{programId:r,vaultPda:o,sessionPubkey:new Uint8Array(u),maxAmount:p,expiresAt:f,allowedCounterparty:i,nonce:a}}var j=10,y=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function O(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(j,j+33)),a=84+(r[83]===1?48:0)+32+32;if(r[a]!==1)return{passkeyPubkey:o,activeSessionPubkey:null};let s=a+1,h=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:o,activeSessionPubkey:h}}async function k(e,t){let n=await O(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 g=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function V(e,t){if(t.length!==32)throw new g(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new g(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new g(`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 g("ed25519 verify rejected")}var c=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 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"),$=require("path");function de(e){return{payload:e.payload,sessionPublicKey:N(e.sessionPublicKey),sessionRegistration:N(e.sessionRegistration),sessionSignature:N(e.sessionSignature)}}function pe(e){return{payload:e.payload,sessionPublicKey:H(e.sessionPublicKey),sessionRegistration:H(e.sessionRegistration),sessionSignature:H(e.sessionSignature)}}function N(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function H(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)}},_=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,$.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,$.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 he=L(require("tweetnacl"),1);var ge=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"),u=`${n}${o}`.replace(/^0+(?=\d)/,"");return u===""?"0":u}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",B=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)}},M=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 l("signature_invalid",`missing ${R} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new l("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new l("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new l("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:E(n.sessionPublicKey),sessionRegistration:E(n.sessionRegistration),sessionSignature:E(n.sessionSignature)}}function E(e){if(typeof e!="string"||e.length%2!==0)throw new l("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 l("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return E(e)}function Y(e){let t=e.store??new A,n=new B,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(u,p,f)=>{try{let i=we(u.headers[R]),a=i.payload.channelId,d=be(a),s=n.get(a);if(!s){let C=I(i.sessionRegistration);await k(e.connection,C),s={registration:C,lastCumulativeAtomic:"0"},n.set(a,s)}V(i,d),U({registration:s.registration,voucher:i,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let h=BigInt(i.payload.cumulativeAmount),ee=BigInt(s.lastCumulativeAtomic),q=h-ee;if(q>o)throw new c("cumulative_exceeds_cap",`single voucher increment ${q} exceeds maxPerVoucherAtomic ${o}`);await t.set(a,i),n.update(a,i.payload.cumulativeAmount);let D=new M(a,e.network,h,async C=>{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.")});D.setSessionPublicKey(i.sessionPublicKey),u.tab=D,f()}catch(i){if(i instanceof l||i instanceof m||i instanceof y||i instanceof g||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,u=0n,p=!1;function f(d=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(d),h=u+s;return h>r?Promise.reject(new c("cumulative_exceeds_cap",`chunk would push request total to ${x(h.toString())} beyond voucher-authorized budget ${x(r.toString())}`)):(u=h,Promise.resolve())}function i(d){if(p)throw new Error("meter ended");let h=(typeof d=="string"?d:Buffer.from(d).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${h}
2
2
 
3
3
  `)}function a(){p||(p=!0,e.write(`event: end
4
4
  data: {"chargedAtomic":"${u}"}
5
5
 
6
- `),e.end())}return{charge:f,send:o,end:a}}0&&(module.exports={FileVoucherStore,InMemoryVoucherStore,InvalidRegistrationError,InvalidVoucherError,InvalidVoucherSignatureError,OnChainVerificationError,ScopeViolationError,TAB_VOUCHER_HEADER,enforceScope,openSse,parseRegistration,readVaultState,requireTab,tabMiddleware,verifyRegistrationOnChain,verifyVoucherSignature});
6
+ `),e.end())}return{charge:f,send:i,end:a}}0&&(module.exports={FileVoucherStore,InMemoryVoucherStore,InvalidRegistrationError,InvalidVoucherError,InvalidVoucherSignatureError,OnChainVerificationError,ScopeViolationError,TAB_VOUCHER_HEADER,enforceScope,openSse,parseRegistration,readVaultState,requireTab,tabMiddleware,verifyRegistrationOnChain,verifyVoucherSignature});
@@ -1,4 +1,4 @@
1
- import { c as TabNetworkId, H as HumanAmount, e as SignedVoucher, A as AtomicAmount } from '../../types-DIrmhiD-.cjs';
1
+ import { TabNetworkId, HumanAmount, SignedVoucher, AtomicAmount } from '@dexterai/vault/types';
2
2
  import { RequestHandler, Request, Response } from 'express';
3
3
  import { Connection, PublicKey } from '@solana/web3.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { c as TabNetworkId, H as HumanAmount, e as SignedVoucher, A as AtomicAmount } from '../../types-DIrmhiD-.js';
1
+ import { TabNetworkId, HumanAmount, SignedVoucher, AtomicAmount } from '@dexterai/vault/types';
2
2
  import { RequestHandler, Request, Response } from 'express';
3
3
  import { Connection, PublicKey } from '@solana/web3.js';
4
4
 
@@ -1,6 +1,6 @@
1
- var d=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};import{PublicKey as X}from"@solana/web3.js";import J from"tweetnacl";import{sha256 as fe}from"@noble/hashes/sha256";import{p256 as be}from"@noble/curves/p256";import{PublicKey as E}from"@solana/web3.js";var oe=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),se=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();function U(e){if(e.channelId.length!==32)throw new Error(`channelId must be 32 bytes, got ${e.channelId.length}`);let t=new Uint8Array(44),n=new DataView(t.buffer),r=0;if(t.set(e.channelId,r),r+=32,n.setBigUint64(r,e.cumulativeAmount,!0),r+=8,n.setUint32(r,e.sequenceNumber>>>0,!0),r+=4,r!==44)throw new Error(`internal: voucher payload wrong length ${r}, expected 44`);return t}import{PublicKey as I,TransactionInstruction as ue}from"@solana/web3.js";var v=new I("Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"),le=new I("Secp256r1SigVerify1111111111111111111111111"),de=new I("Sysvar1nstructions1111111111111111111111111"),me=new Uint8Array([69,94,60,44,49,199,183,233]),pe=new Uint8Array([81,192,32,110,104,116,144,151]);var T="OTS_SESSION_REGISTER_V1",m=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function k(e){if(e.length!==180)throw new m("wrong_length",`expected 180, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,T.length));if(t!==T)throw new m("wrong_domain",`got "${t}"`);for(let s=T.length;s<32;s++)if(e[s]!==0)throw new m("wrong_domain",`non-NUL padding at byte ${s}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new E(e.slice(32,64)),o=new E(e.slice(64,96)),c=e.slice(96,128),p=n.getBigUint64(128,!0),g=n.getBigInt64(136,!0),i=new E(e.slice(144,176)),a=n.getUint32(176,!0);if(!r.equals(v))throw new m("wrong_program",`${r.toBase58()} is not ${v.toBase58()}`);if(p===0n)throw new m("cap_zero");let l=BigInt(Math.floor(Date.now()/1e3));if(g<=l)throw new m("expiry_in_past",`expires_at=${g}, now=${l}`);return{programId:r,vaultPda:o,sessionPubkey:new Uint8Array(c),maxAmount:p,expiresAt:g,allowedCounterparty:i,nonce:a}}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 L(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,o=new Uint8Array(r.slice(M,M+33)),a=84+(r[83]===1?48:0)+32+32;if(r[a]!==1)return{passkeyPubkey:o,activeSessionPubkey:null};let s=a+1,y=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:o,activeSessionPubkey:y}}async function _(e,t){let n=await L(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new f("session_not_active","vault has no active_session \u2014 was it revoked?");if(!j(n.activeSessionPubkey,t.sessionPubkey))throw new f("session_pubkey_mismatch",`on-chain ${q(n.activeSessionPubkey)} != registration ${q(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var h=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function R(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=U({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!J.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new h("ed25519 verify rejected")}var u=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function V(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new u("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new u("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new u("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new u("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function j(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 G,dirname as Y}from"path";function W(e){return{payload:e.payload,sessionPublicKey:$(e.sessionPublicKey),sessionRegistration:$(e.sessionRegistration),sessionSignature:$(e.sessionSignature)}}function Z(e){return{payload:e.payload,sessionPublicKey:C(e.sessionPublicKey),sessionRegistration:C(e.sessionRegistration),sessionSignature:C(e.sessionSignature)}}function $(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function C(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)}},K=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return G(this.dir,`${t}.json`)}async get(t){try{let n=await w.readFile(this.pathFor(t),"utf8");return Z(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(Y(r),{recursive:!0});let o=`${r}.tmp`;await w.writeFile(o,JSON.stringify(W(n))),await w.rename(o,r)}async delete(t){try{await w.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};import{PublicKey as He}from"@solana/web3.js";import{bytesToHex as qe}from"@noble/hashes/utils";import _e from"tweetnacl";import{sha256 as $e}from"@noble/hashes/sha256";var z=6;function A(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 o=r.padEnd(t,"0"),c=`${n}${o}`.replace(/^0+(?=\d)/,"");return c===""?"0":c}function S(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",o=n.slice(-t).replace(/0+$/,"");return o?`${r}.${o}`:r}var B="x-tab-voucher",O=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)}},N=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 S(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function Q(e){if(typeof e!="string"||e.length===0)throw new d("signature_invalid",`missing ${B} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new d("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new d("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new d("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 d("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 ee(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new d("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return x(e)}function te(e){let t=e.store??new b,n=new O,r=typeof e.sellerPubkey=="string"?new X(e.sellerPubkey):e.sellerPubkey,o=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(A(e.perUnit))*100n;return async(c,p,g)=>{try{let i=Q(c.headers[B]),a=i.payload.channelId,l=ee(a),s=n.get(a);if(!s){let P=k(i.sessionRegistration);await _(e.connection,P),s={registration:P,lastCumulativeAtomic:"0"},n.set(a,s)}R(i,l),V({registration:s.registration,voucher:i,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let y=BigInt(i.payload.cumulativeAmount),F=BigInt(s.lastCumulativeAtomic),D=y-F;if(D>o)throw new u("cumulative_exceeds_cap",`single voucher increment ${D} exceeds maxPerVoucherAtomic ${o}`);await t.set(a,i),n.update(a,i.payload.cumulativeAmount);let H=new N(a,e.network,y,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.")});H.setSessionPublicKey(i.sessionPublicKey),c.tab=H,g()}catch(i){if(i instanceof d||i instanceof m||i instanceof f||i instanceof h||i instanceof u){p.status(402).json({error:"invalid_voucher",reason:i.reason??"unknown",detail:i.message});return}g(i)}}}function ne(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function re(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(A(n.cumulative())),o=t.perUnit?BigInt(A(t.perUnit)):null,c=0n,p=!1;function g(l=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(l),y=c+s;return y>r?Promise.reject(new u("cumulative_exceeds_cap",`chunk would push request total to ${S(y.toString())} beyond voucher-authorized budget ${S(r.toString())}`)):(c=y,Promise.resolve())}function i(l){if(p)throw new Error("meter ended");let y=(typeof l=="string"?l:Buffer.from(l).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${y}
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 F from"tweetnacl";import{sha256 as Se}from"@noble/hashes/sha256";import{p256 as ve}from"@noble/curves/p256";import{PublicKey as I}from"@solana/web3.js";import{sessionRegisterMessage as se,sessionRevokeMessage as ae,voucherPayloadMessage as T,buildVoucherMessage as ce}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as me,buildRevokeSessionKeyInstruction as de}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as he}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as v,SECP256R1_PROGRAM_ID as ye,INSTRUCTIONS_SYSVAR_ID as fe}from"@dexterai/vault/constants";var k="OTS_SESSION_REGISTER_V1",d=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function V(e){if(e.length!==180)throw new d("wrong_length",`expected 180, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,k.length));if(t!==k)throw new d("wrong_domain",`got "${t}"`);for(let s=k.length;s<32;s++)if(e[s]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${s}`);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),g=n.getBigInt64(136,!0),o=new I(e.slice(144,176)),a=n.getUint32(176,!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 l=BigInt(Math.floor(Date.now()/1e3));if(g<=l)throw new d("expiry_in_past",`expires_at=${g}, now=${l}`);return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(c),maxAmount:p,expiresAt:g,allowedCounterparty:o,nonce:a}}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)),a=84+(r[83]===1?48:0)+32+32;if(r[a]!==1)return{passkeyPubkey:i,activeSessionPubkey:null};let s=a+1,h=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:i,activeSessionPubkey:h}}async function U(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(!j(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 _(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(!F.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new y("ed25519 verify rejected")}var u=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 u("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new u("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new u("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new u("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function j(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(e.sessionPublicKey),sessionRegistration:E(e.sessionRegistration),sessionSignature:E(e.sessionSignature)}}function X(e){return{payload:e.payload,sessionPublicKey:R(e.sessionPublicKey),sessionRegistration:R(e.sessionRegistration),sessionSignature:R(e.sessionSignature)}}function E(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)}},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 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 ze}from"@solana/web3.js";import{bytesToHex as Fe}from"@noble/hashes/utils";import Re from"tweetnacl";import{sha256 as Oe}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,g)=>{try{let o=Z(c.headers[N]),a=o.payload.channelId,l=Q(a),s=n.get(a);if(!s){let P=V(o.sessionRegistration);await U(e.connection,P),s={registration:P,lastCumulativeAtomic:"0"},n.set(a,s)}_(o,l),$({registration:s.registration,voucher:o,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let h=BigInt(o.payload.cumulativeAmount),L=BigInt(s.lastCumulativeAtomic),H=h-L;if(H>i)throw new u("cumulative_exceeds_cap",`single voucher increment ${H} exceeds maxPerVoucherAtomic ${i}`);await t.set(a,o),n.update(a,o.payload.cumulativeAmount);let B=new O(a,e.network,h,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,g()}catch(o){if(o instanceof m||o instanceof d||o instanceof f||o instanceof y||o instanceof u){p.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}g(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 g(l=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(l),h=c+s;return h>r?Promise.reject(new u("cumulative_exceeds_cap",`chunk would push request total to ${A(h.toString())} beyond voucher-authorized budget ${A(r.toString())}`)):(c=h,Promise.resolve())}function o(l){if(p)throw new Error("meter ended");let h=(typeof l=="string"?l:Buffer.from(l).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${h}
2
2
 
3
3
  `)}function a(){p||(p=!0,e.write(`event: end
4
4
  data: {"chargedAtomic":"${c}"}
5
5
 
6
- `),e.end())}return{charge:g,send:i,end:a}}export{K as FileVoucherStore,b as InMemoryVoucherStore,m as InvalidRegistrationError,d as InvalidVoucherError,h as InvalidVoucherSignatureError,f as OnChainVerificationError,u as ScopeViolationError,B as TAB_VOUCHER_HEADER,V as enforceScope,re as openSse,k as parseRegistration,L as readVaultState,ne as requireTab,te as tabMiddleware,_ as verifyRegistrationOnChain,R as verifyVoucherSignature};
6
+ `),e.end())}return{charge:g,send:o,end:a}}export{C as FileVoucherStore,b as InMemoryVoucherStore,d as InvalidRegistrationError,m as InvalidVoucherError,y as InvalidVoucherSignatureError,f as OnChainVerificationError,u as ScopeViolationError,N as TAB_VOUCHER_HEADER,$ as enforceScope,ne as openSse,V as parseRegistration,D as readVaultState,te as requireTab,ee as tabMiddleware,U as verifyRegistrationOnChain,_ as verifyVoucherSignature};
@@ -1,87 +1,14 @@
1
+ import { TabNetworkId, HumanAmount, SessionScope, SessionKey, VoucherPayload, SignedVoucher, AtomicAmount } from '@dexterai/vault/types';
2
+
1
3
  /**
2
4
  * @dexterai/x402/tab — type contract for the OTS-backed streaming payment module.
3
5
  *
4
- * Peer of `batch-settlement`. Where `batch-settlement` is for N discrete paid
5
- * requests against one escrow channel, `tab` is for *continuous metered
6
- * consumption* tokens, bytes, frames, seconds settled on close.
7
- *
8
- * Full design: see `docs/DESIGN-tab-streaming.md`. This file is the contract
9
- * lock for Phase 1: the public types and option shapes that downstream phases
10
- * must implement against without drift.
11
- */
12
- /**
13
- * CAIP-2-style network identifier. The buyer-side `openTab` accepts a string
14
- * here so future networks (EVM L2s) require no API change — only a new
15
- * VaultAdapter implementation.
16
- */
17
- type TabNetworkId = 'solana:mainnet' | (string & {});
18
- /**
19
- * Atomic-unit cumulative amount the seller is asking the buyer to authorize
20
- * for a single voucher. Strings to avoid bigint JSON-serialization headaches
21
- * across language boundaries.
6
+ * Session/voucher protocol types moved to @dexterai/vault/types in the v0.1
7
+ * extract. Re-exported here so existing consumers of `@dexterai/x402/tab`
8
+ * see zero import-path changes. Tab-runtime types (VaultAdapter, OpenTabOptions,
9
+ * Tab, errors) stay local — they're HTTP/SSE-shaped, not protocol-shaped.
22
10
  */
23
- type AtomicAmount = string;
24
- /**
25
- * Human-readable amount (e.g. "0.001" USDC). Used at SDK boundaries; converted
26
- * to atomic units internally per the vault's token decimals.
27
- */
28
- type HumanAmount = string;
29
- /**
30
- * Scope of a session key — the limits the passkey embeds into its
31
- * registration signature. The on-chain program (via Swig) and the seller's
32
- * middleware (locally) both enforce these.
33
- */
34
- interface SessionScope {
35
- /** The specific tab this session is bound to. */
36
- channelId: string;
37
- /** Cumulative cap, atomic units. The session-key cannot sign beyond this. */
38
- maxAmountAtomic: AtomicAmount;
39
- /** Wall-clock expiry (unix seconds). Hard deadline regardless of usage. */
40
- expiresAtUnix: number;
41
- /** Counterparty restriction — typically the seller's address. */
42
- allowedCounterparty: string;
43
- }
44
- /**
45
- * In-memory session key. NEVER persisted to disk. A crashed process forfeits
46
- * the session and re-prompts the passkey on the next attempt — this is the
47
- * right default because a session key on disk is a real attack surface.
48
- */
49
- interface SessionKey {
50
- /** Public key the seller verifies signatures against. */
51
- publicKey: Uint8Array;
52
- /** Private key — in-memory only. */
53
- privateKey: Uint8Array;
54
- /** Limits this session may operate within. */
55
- scope: SessionScope;
56
- /** The passkey signature authorizing this session. The seller verifies it
57
- * against the vault's registered passkey on every voucher. */
58
- registration: Uint8Array;
59
- }
60
- /**
61
- * What the buyer signs per stream chunk, and what the seller verifies before
62
- * delivering. Cumulative-amount semantics: each voucher represents the TOTAL
63
- * owed so far, not the incremental amount. Replay-resistant because vouchers
64
- * monotonically increase.
65
- */
66
- interface VoucherPayload {
67
- channelId: string;
68
- /** Total owed so far, atomic units. Must strictly exceed the prior voucher. */
69
- cumulativeAmount: AtomicAmount;
70
- /** Monotonic sequence number. Replay protection within a tab. */
71
- sequenceNumber: number;
72
- }
73
- /**
74
- * The full voucher as sent over the wire: payload + session signature +
75
- * the registration that authorizes the signing session key. The seller's
76
- * middleware verifies the registration's passkey signature once per session,
77
- * caches the result, and verifies only the session-key signature per chunk.
78
- */
79
- interface SignedVoucher {
80
- payload: VoucherPayload;
81
- sessionPublicKey: Uint8Array;
82
- sessionRegistration: Uint8Array;
83
- sessionSignature: Uint8Array;
84
- }
11
+
85
12
  /**
86
13
  * Adapter for a specific chain's OTS vault implementation. The SDK calls into
87
14
  * `authorizeSession()` ONCE per tab and `signWithSession()` many times. The
@@ -231,4 +158,4 @@ declare class TabClosedError extends Error {
231
158
  constructor(channelId: string);
232
159
  }
233
160
 
234
- export { type AtomicAmount as A, type HumanAmount as H, type OpenTabOptions as O, type ResumeTabOptions as R, type SessionScope as S, type Tab as T, UnsupportedNetworkError as U, type VoucherPayload as V, type TabState as a, type TabCloseResult as b, type TabNetworkId as c, type SessionKey as d, type SignedVoucher as e, type VaultAdapter as f, SessionScopeExceededError as g, TabClosedError as h };
161
+ 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 };
@@ -1,87 +1,14 @@
1
+ import { TabNetworkId, HumanAmount, SessionScope, SessionKey, VoucherPayload, SignedVoucher, AtomicAmount } from '@dexterai/vault/types';
2
+
1
3
  /**
2
4
  * @dexterai/x402/tab — type contract for the OTS-backed streaming payment module.
3
5
  *
4
- * Peer of `batch-settlement`. Where `batch-settlement` is for N discrete paid
5
- * requests against one escrow channel, `tab` is for *continuous metered
6
- * consumption* tokens, bytes, frames, seconds settled on close.
7
- *
8
- * Full design: see `docs/DESIGN-tab-streaming.md`. This file is the contract
9
- * lock for Phase 1: the public types and option shapes that downstream phases
10
- * must implement against without drift.
11
- */
12
- /**
13
- * CAIP-2-style network identifier. The buyer-side `openTab` accepts a string
14
- * here so future networks (EVM L2s) require no API change — only a new
15
- * VaultAdapter implementation.
16
- */
17
- type TabNetworkId = 'solana:mainnet' | (string & {});
18
- /**
19
- * Atomic-unit cumulative amount the seller is asking the buyer to authorize
20
- * for a single voucher. Strings to avoid bigint JSON-serialization headaches
21
- * across language boundaries.
6
+ * Session/voucher protocol types moved to @dexterai/vault/types in the v0.1
7
+ * extract. Re-exported here so existing consumers of `@dexterai/x402/tab`
8
+ * see zero import-path changes. Tab-runtime types (VaultAdapter, OpenTabOptions,
9
+ * Tab, errors) stay local — they're HTTP/SSE-shaped, not protocol-shaped.
22
10
  */
23
- type AtomicAmount = string;
24
- /**
25
- * Human-readable amount (e.g. "0.001" USDC). Used at SDK boundaries; converted
26
- * to atomic units internally per the vault's token decimals.
27
- */
28
- type HumanAmount = string;
29
- /**
30
- * Scope of a session key — the limits the passkey embeds into its
31
- * registration signature. The on-chain program (via Swig) and the seller's
32
- * middleware (locally) both enforce these.
33
- */
34
- interface SessionScope {
35
- /** The specific tab this session is bound to. */
36
- channelId: string;
37
- /** Cumulative cap, atomic units. The session-key cannot sign beyond this. */
38
- maxAmountAtomic: AtomicAmount;
39
- /** Wall-clock expiry (unix seconds). Hard deadline regardless of usage. */
40
- expiresAtUnix: number;
41
- /** Counterparty restriction — typically the seller's address. */
42
- allowedCounterparty: string;
43
- }
44
- /**
45
- * In-memory session key. NEVER persisted to disk. A crashed process forfeits
46
- * the session and re-prompts the passkey on the next attempt — this is the
47
- * right default because a session key on disk is a real attack surface.
48
- */
49
- interface SessionKey {
50
- /** Public key the seller verifies signatures against. */
51
- publicKey: Uint8Array;
52
- /** Private key — in-memory only. */
53
- privateKey: Uint8Array;
54
- /** Limits this session may operate within. */
55
- scope: SessionScope;
56
- /** The passkey signature authorizing this session. The seller verifies it
57
- * against the vault's registered passkey on every voucher. */
58
- registration: Uint8Array;
59
- }
60
- /**
61
- * What the buyer signs per stream chunk, and what the seller verifies before
62
- * delivering. Cumulative-amount semantics: each voucher represents the TOTAL
63
- * owed so far, not the incremental amount. Replay-resistant because vouchers
64
- * monotonically increase.
65
- */
66
- interface VoucherPayload {
67
- channelId: string;
68
- /** Total owed so far, atomic units. Must strictly exceed the prior voucher. */
69
- cumulativeAmount: AtomicAmount;
70
- /** Monotonic sequence number. Replay protection within a tab. */
71
- sequenceNumber: number;
72
- }
73
- /**
74
- * The full voucher as sent over the wire: payload + session signature +
75
- * the registration that authorizes the signing session key. The seller's
76
- * middleware verifies the registration's passkey signature once per session,
77
- * caches the result, and verifies only the session-key signature per chunk.
78
- */
79
- interface SignedVoucher {
80
- payload: VoucherPayload;
81
- sessionPublicKey: Uint8Array;
82
- sessionRegistration: Uint8Array;
83
- sessionSignature: Uint8Array;
84
- }
11
+
85
12
  /**
86
13
  * Adapter for a specific chain's OTS vault implementation. The SDK calls into
87
14
  * `authorizeSession()` ONCE per tab and `signWithSession()` many times. The
@@ -231,4 +158,4 @@ declare class TabClosedError extends Error {
231
158
  constructor(channelId: string);
232
159
  }
233
160
 
234
- export { type AtomicAmount as A, type HumanAmount as H, type OpenTabOptions as O, type ResumeTabOptions as R, type SessionScope as S, type Tab as T, UnsupportedNetworkError as U, type VoucherPayload as V, type TabState as a, type TabCloseResult as b, type TabNetworkId as c, type SessionKey as d, type SignedVoucher as e, type VaultAdapter as f, SessionScopeExceededError as g, TabClosedError as h };
161
+ 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexterai/x402",
3
- "version": "3.10.0",
3
+ "version": "3.11.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",
@@ -76,6 +76,7 @@
76
76
  "release:major": "npm version major && npm publish --access public"
77
77
  },
78
78
  "dependencies": {
79
+ "@dexterai/vault": "^0.1.3",
79
80
  "@dexterai/x402-ads-types": "^0.2.0",
80
81
  "@dexterai/x402-core": "^1.4.0",
81
82
  "@noble/curves": "^1.9.7",