mppx 0.8.18 → 0.8.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
package/dist/cli/cli.js
CHANGED
|
@@ -244,7 +244,7 @@ $&`).replace(/(?:^|\n)([\t ].*)(?:([\n\t ]*)\n(?![\n\t ]))?/g,`$1$2`).replace(/\
|
|
|
244
244
|
`)){let t=e.trim();if(t===`[[keys]]`){r?.wallet_address&&n.push(r),r={wallet_type:`local`,wallet_address:``,chain_id:0};continue}if(!r)continue;let i=t.match(/^(\w+)\s*=\s*"?([^"]*)"?$/);if(!i)continue;let[,a,o]=i;a===`wallet_type`?r.wallet_type=o:a===`wallet_address`?r.wallet_address=o:a===`chain_id`&&(r.chain_id=Number.parseInt(o,10))}return r?.wallet_address&&n.push(r),n}catch{return[]}}function iP(e){let t=rP();if(t.length===0)return;let n=e.slice(6);if(n==="default"||n===``)return t[0];let r=Number.parseInt(n,10);if(!Number.isNaN(r)&&r>=0&&r<t.length)return t[r]}function aP(){if(pP!==void 0)return pP;try{p.execFileSync(`which`,[`tempo`],{stdio:`ignore`}),pP=!0}catch{pP=!1}return pP}async function oP(e){return new Promise((t,n)=>{p.execFile(`tempo`,[`mpp`,`sign`,`--challenge`,e],(e,r,i)=>{if(e){let t=i?.trim()||e.message;n(Error(`tempo mpp sign failed: ${t}`));return}let a=r.trim();if(!a){n(Error(`tempo mpp sign returned empty output`));return}t(a)})})}function sP(){let e=sO();if(LD(e.get())&&!aP()&&y.platform()===`darwin`)try{let t=p.execFileSync(`security`,[`dump-keychain`],{encoding:`utf-8`}),n=[];for(let e of t.split(`keychain:`)){let t=e.match(/"svce"<blob>="([^"]*)"/),r=e.match(/"acct"<blob>="([^"]*)"/);t?.[1]===cP&&r?.[1]&&n.push(r[1])}if(n.length>0)return e.set(n[0]),n[0]}catch{}}var cP,lP,uP,dP,fP,pP,mP=I((()=>{rx(),Nw(),ux(),OS(),PN(),XT(),Aj(),hO(),tO(),fk(),cP=`mppx`,lP=f.union([f.boolean(),f.literal(`true`).transform(()=>!0),f.literal(`false`).transform(()=>!1)]),uP=f.object({allowCustomEscrow:f.optional(lP),autoSwap:f.optional(lP),channel:f.optional(f.coerce.string()),deposit:f.optional(f.union([f.string(),f.number()])),payWith:f.optional(f.string()),slippage:f.optional(f.coerce.number()),tokenIn:f.optional(f.string())}),dP=[`allowCustomEscrow`,`autoSwap`,`channel`,`deposit`,`payWith`,`slippage`,`tokenIn`],fP=[`payable`,`unknownBalance`,`insufficientBalance`,`unsupported`]}));bS(),mP();const hP=[RN(),vk(),pk()];function gP(e,t){let n=t?.plugins?.find(t=>bP(t,e));if(n)return{plugin:n};let r=hP.find(t=>bP(t,e));if(r)return{plugin:r};let i=yP(t)?.find(t=>t.name===e.method&&t.intent===e.intent);return i?{method:i}:{}}function _P(e,t){let n=yP(t);if(n?.length){let r=aS(e,n,nS(n,t?.paymentPreferences).entries);return r?{challenge:r.challenge,...gP(r.challenge,t)}:void 0}for(let n of e){let e=gP(n,t);if(e.plugin||e.method)return{challenge:n,...e}}}function vP(e){let t=yP(e);if(t?.length)return nS(t,e?.paymentPreferences).header}function yP(e){return Array.isArray(e?.methods)?e.methods.flat():void 0}function bP(e,t){return e.supports?e.supports(t):e.method===t.method}async function xP(e){let t=SP(e);if(!t)return;let n=await import(t);return{config:n.default??n,path:t}}function SP(t){if(t){let n=s.resolve(t);return e.existsSync(n)?n:void 0}let n=process.env.MPPX_CONFIG?.trim();if(n){let t=s.resolve(n);return e.existsSync(t)?t:void 0}}mP(),Wx(),qj(),qM(),nN(),xD();function CP(e){return e??globalThis.fetch.bind(globalThis)}function wP(e,t){let n=e.request.methodDetails?.chainId;if(n!==void 0&&n!==t.chainId)throw Error(`Close challenge changed the session chain.`);if(Rj(e,t.escrow).toLowerCase()!==t.escrow.toLowerCase())throw Error(`Close challenge changed the session escrow.`);let r=t.paymentScope?.payee??t.descriptor.payee,i=t.paymentScope?.token??t.descriptor.token;if(typeof e.request.recipient!=`string`||e.request.recipient.toLowerCase()!==r.toLowerCase())throw Error(`Close challenge changed the session payee.`);if(typeof e.request.currency!=`string`||e.request.currency.toLowerCase()!==i.toLowerCase())throw Error(`Close challenge changed the session token.`);let a=HE(e);if(a&&a.channelId.toLowerCase()!==t.channelId.toLowerCase())throw Error(`Close challenge changed the session channel.`)}async function TP(e){wP(e.challenge,e.channel);let t=CP(e.fetch),n,r=async(r,i)=>{n&&=(await e.onChallenge?.(n),void 0);let a=await t(r,i);if(a.status!==402)return a;let o=Lx(a).find(BE);if(!o)throw Error(`Refreshed close response did not include tempo/session.`);return wP(o,e.channel),n=o,a},i=tN({...e.manager,bootstrap:!1,escrow:e.channel.escrow,fetch:r});GM(i).rehydrate(e);let a=await i.close();if(!a)throw Error(`Session close response did not include a payment receipt.`);return{manager:i,receipt:a}}Wx(),qj(),$j(),xD(),uj(),Ex();var EP=class extends Error{name=`SessionStateError`;code=`SESSION_STATE_INVALID`;file;constructor(e,t={}){super(e,t.cause===void 0?void 0:{cause:t.cause}),this.file=t.file}},DP=class extends Error{name=`SessionBusyError`;code=`SESSION_BUSY`;exitCode=75;scope;owner;constructor(e,t){super(`Session scope is busy in process ${t.pid} on ${t.hostname}.`),this.scope=e,this.owner=t}};const OP=Y.object({channelId:Sx(),cumulativeAmount:Y.string(),deposit:Y.string(),descriptor:Y.object({payer:xx(),payee:xx(),operator:xx(),token:xx(),salt:Sx(),authorizedSigner:xx(),expiringNonceHash:Sx()}),escrow:xx(),chainId:Y.number(),opened:Y.boolean(),paymentScope:Y.optional(Y.object({payee:xx(),token:xx()}))}),kP=Y.object({name:Y.optional(Y.string()),address:xx()}),AP=Y.object({method:Y.literal(`tempo`),intent:Y.literal(`session`),status:Y.literal(`success`),timestamp:Y.string(),reference:Y.string(),challengeId:Y.string(),channelId:Sx(),acceptedCumulative:Y.string(),spent:Y.string(),units:Y.optional(Y.number()),txHash:Y.optional(Sx())}),jP=Y.object({version:Y.literal(1),method:Y.literal(`tempo`),intent:Y.literal(`session`),status:Y.enum([`opening`,`open`,`closing`,`stale`]),channel:OP,account:kP,endpoint:Y.string(),challenge:Ux,receipt:Y.optional(AP),spent:Y.string(),units:Y.number(),createdAt:Y.string(),updatedAt:Y.string()}),MP=Y.object({version:Y.literal(1),channelId:Sx()}),NP=Y.object({version:Y.literal(1),scope:Y.string(),hostname:Y.string(),pid:Y.number(),token:Y.string(),createdAt:Y.string()});function PP(e,t,n,r){let i=e.safeParse(t);if(!i.success)throw Q(n,r,i.error);return i.data}function FP(e){let t=GP(e);return[t.payer,t.payee,t.token,t.escrow,t.chainId].join(`:`)}function IP(e){return{payer:e.descriptor.payer,payee:e.paymentScope?.payee??e.descriptor.payee,token:e.paymentScope?.token??e.descriptor.token,escrow:e.escrow,chainId:e.chainId}}function LP(e={}){let t=e.stateRoot??zP(),n={root:t,channels:s.join(t,`channels`),locks:s.join(t,`locks`),preferred:s.join(t,`preferred`)},r=e.hostname??y.hostname(),i=e.pid??process.pid,a=e.now??(()=>new Date),o=e.isProcessAlive??_F;async function c(){for(let e of[n.root,n.channels,n.locks,n.preferred])await S.mkdir(e,{recursive:!0,mode:448}),await S.chmod(e,448)}async function l(e){let t=UP(e),r=BP(n,t),i=await cF(r);if(i===void 0)return;let a=$P(i,r);if(a.channel.channelId.toLowerCase()!==t)throw Q(r,`Session filename does not match its channel ID.`);return eF(a)}async function u(){let e;try{e=await S.readdir(n.channels,{withFileTypes:!0})}catch(e){if(yF(e,`ENOENT`))return[];throw Q(n.channels,`Unable to list managed sessions.`,e)}let t=[];for(let n of e){if(!n.isFile()||n.name.includes(`.tmp-`)||!n.name.endsWith(`.json`))continue;let e=n.name.slice(0,-5);UP(e);let r=await l(e);r&&t.push(r)}return t.sort((e,t)=>e.createdAt.localeCompare(t.createdAt))}async function d(e){await c();let t=YP(e.channel),r=UP(t.channelId),i=BP(n,r),o=await cF(i),s=o===void 0?void 0:$P(o,i),l=ZP(e.challenge,i);s&&tF(s,e,i),rF(l,t,i);let u=e.receipt?QP(e.receipt,t.channelId,i):void 0,d=s?Qj(s.channel):void 0,f=sF(t.cumulativeAmount,d?.cumulativeAmount??0n),p=sF(e.spent??0n,u?BigInt(u.spent):0n,s?BigInt(s.spent):0n);if(p>f)throw Q(i,`Session spend exceeds the locally authorized cumulative amount.`);let m=XP(Zj({...t,cumulativeAmount:f}),i),h=oF(s?.updatedAt,a(),i),g=aF(s?.receipt,u),_=JP(e.account,i),v=$P({version:1,method:`tempo`,intent:`session`,status:e.status,channel:m,account:{..._.name===void 0?s?.account.name===void 0?{}:{name:s.account.name}:{name:_.name},address:_.address},endpoint:qP(e.endpoint,i),challenge:l,...g!==void 0&&{receipt:g},spent:p.toString(),units:Math.max(s?.units??0,e.units??0,u?.units??0),createdAt:s?.createdAt??h,updatedAt:h},i);return await lF(i,v),eF(v)}async function f(e){let t=HP(n,e),r=await cF(t);if(r===void 0)return;let{channelId:i}=PP(MP,r,t,`Preferred session is invalid.`),a=await l(i);if(!a)throw Q(t,`Preferred session ${i} does not exist.`);return iF(a.channel,e,t),i}async function p(e,t){let r=UP(t),i=await l(r),a=HP(n,e);if(!i)throw Q(a,`Session ${r} does not exist.`);iF(i.channel,e,a),await lF(a,{version:1,channelId:r})}async function m(e,t){let r=HP(n,e),i=t===void 0?void 0:UP(t),a=await cF(r);if(a===void 0)return;let o=PP(MP,a,r,`Preferred session is invalid.`).channelId;i&&o.toLowerCase()!==i||await hF(r,`Unable to clear preferred session.`)}async function h(e){let t=UP(e),r=await l(t);r&&(await m(IP(r.channel),t),await hF(BP(n,t),`Unable to remove session.`))}async function _(e){await c();let t=VP(n,e);for(let n=0;n<3;n++){let n={version:1,scope:e,hostname:r,pid:i,token:g(),createdAt:a().toISOString()};try{if(await uF(t,n),await pF(fF(t))){await mF(t,n);continue}return{async release(){await mF(t,n)}}}catch(e){if(!yF(e,`EEXIST`))throw e}let s=await cF(t);if(s===void 0)continue;let c=PP(NP,s,t,`Session lock is invalid.`);if(c.scope!==e)throw Q(t,`Session lock scope is invalid.`);if(c.hostname!==r||o(c.pid))throw new DP(e,c);await dF(t,c)}let s=await cF(t);throw s===void 0?Q(t,`Unable to acquire session lock.`):new DP(e,PP(NP,s,t,`Session lock is invalid.`))}async function v(e){return _(FP(e))}return{root:t,get:l,list:u,upsert:d,remove:h,getPreferred:f,setPreferred:p,clearPreferred:m,acquire:v}}function RP(e,t){let n=KP(t.scope),r=t.selection===`auto`||t.selection===`new`?void 0:UP(t.selection);function i(e){if(e.toLowerCase()!==n)throw new EP(`Session manager requested an unexpected payment scope.`)}async function a(n=!0){if(t.selection===`new`&&!r)return;let i=r??await e.getPreferred(t.scope);if(!i)return;let a=await e.get(i);if(!a)throw new EP(`Session ${i} does not exist.`);if(iF(a.channel,t.scope),!(n&&(a.status!==`open`||!a.channel.opened)))return r=i,a}return{async get(e){return i(e),(await a())?.channel},async set(n){if(i(Yj(n)),iF(n,t.scope),r&&r.toLowerCase()!==n.channelId.toLowerCase())throw new EP(`Session manager selected ${r}, but attempted to store ${n.channelId}.`);r||t.onNewChannel?.(n);let a=await e.upsert({...t.context(),channel:n});r=a.channel.channelId,await e.setPreferred(t.scope,a.channel.channelId)},async delete(n){i(n);let o=await a(!1);if(!o)return;let s=t.context();await e.upsert({...o,...s,status:s.status===`closing`?`closing`:`stale`,channel:o.channel,spent:s.spent??o.spent,units:s.units??o.units}),s.status!==`closing`&&await e.clearPreferred(t.scope,o.channel.channelId),r=void 0}}}function zP(){let e=process.env.XDG_STATE_HOME||s.join(y.homedir(),`.local`,`state`);return s.join(e,`mppx`,`sessions`,`v1`)}function BP(e,t){return s.join(e.channels,`${t}.json`)}function VP(e,t){let n=h(`sha256`).update(t).digest(`hex`);return s.join(e.locks,`${n}.lock`)}function HP(e,t){let n=h(`sha256`).update(FP(t)).digest(`hex`);return s.join(e.preferred,`${n}.json`)}function UP(e){return PP(Sx(),e,void 0,`Invalid session channel ID: ${e}.`).toLowerCase()}function WP(e,t,n){return PP(xx(),e,n,`Invalid ${t}.`).toLowerCase()}function GP(e){if(!Number.isSafeInteger(e.chainId)||e.chainId<0)throw new EP(`Invalid session chain ID.`);return{payer:WP(e.payer,`session payer`),payee:WP(e.payee,`session payee`),token:WP(e.token,`session token`),escrow:WP(e.escrow,`session escrow`),chainId:e.chainId}}function KP(e){let t=GP(e);return[t.payee,t.token,t.escrow,t.chainId].join(`:`)}function qP(e,t){if(typeof e!=`string`)throw Q(t,`Session endpoint is invalid.`);let n;try{n=new URL(e)}catch(e){throw Q(t,`Session endpoint is invalid.`,e)}if(n.protocol!==`http:`&&n.protocol!==`https:`)throw Q(t,`Session endpoint must use HTTP or HTTPS.`);if(n.username||n.password)throw Q(t,`Session endpoint must not contain credentials.`);let r=e.indexOf(`#`);return r===-1?e:e.slice(0,r)}function JP(e,t){return PP(kP,e,t,`Session account is invalid.`)}function YP(e){return Qj(XP(Zj(e)))}function XP(e,t){return PP(OP,e,t,`Stored session channel is invalid.`)}function ZP(e,t){let n=Ux.safeParse(e);if(!n.success||!BE(n.data))throw Q(t,`Stored session challenge is invalid.`);return n.data}function QP(e,t,n){let r=PP(AP,e,n,`Stored session receipt is invalid.`);if(r.channelId!==t.toLowerCase())throw Q(n,`Stored session receipt has a different channel ID.`);if(r.reference.toLowerCase()!==t.toLowerCase())throw Q(n,`Stored session receipt has a different reference.`);if(BigInt(r.spent)>BigInt(r.acceptedCumulative))throw Q(n,`Stored session receipt spend exceeds its accepted amount.`);return r}function $P(e,t){let n=PP(jP,e,t,`Stored session is invalid.`),{receipt:r,...i}=n,a=n.channel,o=n.account;if(o.address.toLowerCase()!==a.descriptor.payer.toLowerCase())throw Q(t,`Stored session account does not match the channel payer.`);let s=r?QP(r,a.channelId,t):void 0,c=n.spent,l=BigInt(a.cumulativeAmount);if(BigInt(c)>l)throw Q(t,`Stored session spend exceeds its cumulative authorization.`);if(s&&BigInt(s.acceptedCumulative)>l)throw Q(t,`Stored receipt exceeds the cumulative authorization.`);if(Date.parse(n.updatedAt)<Date.parse(n.createdAt))throw Q(t,`Stored session timestamps are not monotonic.`);let u=qP(n.endpoint,t);if(u!==n.endpoint)throw Q(t,`Stored session endpoint contains a fragment.`);let d=ZP(n.challenge,t);return rF(d,Qj(a),t),{...i,account:o,channel:a,endpoint:u,challenge:d,...s&&{receipt:s}}}function eF(e){return{version:1,status:e.status,channel:Qj(e.channel),account:e.account,endpoint:e.endpoint,challenge:e.challenge,...e.receipt&&{receipt:e.receipt},spent:BigInt(e.spent),units:e.units,createdAt:e.createdAt,updatedAt:e.updatedAt}}function tF(e,t,n){let r=YP(t.channel),i=JP(t.account,n),a=Qj(e.channel);if(JSON.stringify(nF(r))!==JSON.stringify(nF(a)))throw Q(n,`Session update changed immutable channel identity.`);if(i.address.toLowerCase()!==e.account.address.toLowerCase())throw Q(n,`Session update changed the payer account.`)}function nF(e){return{channelId:e.channelId.toLowerCase(),descriptor:Object.fromEntries(Object.entries(e.descriptor).map(([e,t])=>[e,typeof t==`string`?t.toLowerCase():t])),escrow:e.escrow.toLowerCase(),chainId:e.chainId,paymentScope:e.paymentScope?{payee:e.paymentScope.payee.toLowerCase(),token:e.paymentScope.token.toLowerCase()}:void 0}}function rF(e,t,n){if(oj({...t.descriptor,chainId:t.chainId,escrow:t.escrow}).toLowerCase()!==t.channelId.toLowerCase())throw Q(n,`Session channel ID does not match its descriptor.`);let r=WP(e.request.recipient,`challenge recipient`,n),i=WP(e.request.currency,`challenge currency`,n),a=GP(IP(t));if(Rj(e,t.escrow).toLowerCase()!==t.escrow.toLowerCase())throw Q(n,`Session challenge escrow does not match the channel.`);if(vF(e.request.methodDetails)){let r=e.request.methodDetails;if(r.chainId!==void 0&&r.chainId!==t.chainId)throw Q(n,`Session challenge chain does not match the channel.`)}if(r!==a.payee)throw Q(n,`Session challenge payee does not match the channel.`);if(i!==a.token)throw Q(n,`Session challenge token does not match the channel.`)}function iF(e,t,n){if(FP(IP(e))!==FP(t))throw Q(n,`Session channel does not match the selected payment scope.`)}function aF(e,t){return e?t&&Date.parse(t.timestamp)>=Date.parse(e.timestamp)?t:e:t}function oF(e,t,n){if(!Number.isFinite(t.getTime()))throw Q(n,`Session clock is invalid.`);let r=t.toISOString();return!e||Date.parse(r)>=Date.parse(e)?r:e}function sF(...e){return e.reduce((e,t)=>t>e?t:e,0n)}async function cF(e){let t;try{t=await S.readFile(e,`utf8`)}catch(t){if(yF(t,`ENOENT`))return;throw Q(e,`Unable to read session state.`,t)}try{return JSON.parse(t)}catch(t){throw Q(e,`Session state contains invalid JSON.`,t)}}async function lF(e,t){await S.mkdir(s.dirname(e),{recursive:!0,mode:448}),await S.chmod(s.dirname(e),448);let n=`${e}.tmp-${process.pid}-${g()}`,r;try{r=await S.open(n,`wx`,384),await r.writeFile(`${JSON.stringify(t,null,2)}\n`,`utf8`),await r.sync(),await r.close(),r=void 0,await S.rename(n,e),await S.chmod(e,384),await gF(s.dirname(e))}catch(t){throw await r?.close().catch(()=>void 0),await S.unlink(n).catch(()=>void 0),t instanceof EP?t:Q(e,`Unable to write session state.`,t)}}async function uF(e,t){let n;try{n=await S.open(e,`wx`,384),await n.writeFile(`${JSON.stringify(t)}\n`,`utf8`),await n.sync(),await n.close(),n=void 0,await gF(s.dirname(e))}catch(t){throw await n?.close().catch(()=>void 0),n&&await S.unlink(e).catch(()=>void 0),t}}async function dF(e,t){let n=fF(e);try{await S.link(e,n)}catch(t){if(yF(t,`EEXIST`)||yF(t,`ENOENT`))return;throw Q(e,`Unable to claim dead lock.`,t)}try{let r=await cF(n);if(r===void 0||PP(NP,r,n,`Session lock is invalid.`).token!==t.token)return;await hF(e,`Unable to reclaim dead lock.`)}finally{await hF(n,`Unable to release dead lock claim.`)}}function fF(e){return`${e}.reclaim`}async function pF(e){try{return await S.access(e),!0}catch(t){if(yF(t,`ENOENT`))return!1;throw Q(e,`Unable to inspect session lock.`,t)}}async function mF(e,t){let n=await cF(e);n!==void 0&&PP(NP,n,e,`Session lock is invalid.`).token===t.token&&await hF(e,`Unable to release session lock.`)}async function hF(e,t){try{await S.unlink(e),await gF(s.dirname(e))}catch(n){if(!yF(n,`ENOENT`))throw Q(e,t,n)}}async function gF(e){let t=await S.open(e,`r`);try{await t.sync()}finally{await t.close()}}function _F(e){try{return process.kill(e,0),!0}catch(e){if(yF(e,`ESRCH`))return!1;if(yF(e,`EPERM`))return!0;throw e}}function vF(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function yF(e,t){return e instanceof Error&&`code`in e&&e.code===t}function Q(e,t,n){return new EP(t,{...n!==void 0&&{cause:n},file:e})}rx(),Nw(),FM(),bj(),uj(),hO(),tO();const bF=f.object({status:f.enum([`opening`,`open`,`closing`,`stale`]),channelId:f.string(),account:f.string().optional(),payer:f.string(),payee:f.string(),authorizedSigner:f.string(),token:f.string(),escrow:f.string(),chainId:f.number(),cumulativeAmount:f.string(),confirmedSpend:f.string(),deposit:f.string(),units:f.number(),resourceUrl:f.string(),createdAt:f.string(),updatedAt:f.string()}),xF=f.object({channelId:f.string(),status:f.enum([`closed`,`already-closed`]),spent:f.string(),txHash:f.string().optional()}),SF=f.object({closed:f.array(xF),failed:f.array(f.object({channelId:f.string(),message:f.string()}))});function CF(e){return e===`mainnet`?ge.id:_e.id}function wF(e){if(e===ge.id)return`mainnet`;if(e===_e.id)return`testnet`}function TF(e){let t={};for(let n of e??[]){let e=n.indexOf(`:`);if(e===-1)throw new L({code:`INVALID_HEADER`,message:`Invalid header format: ${n}`,exitCode:2});t[n.slice(0,e).trim()]=n.slice(e+1).trim()}return t}function EF(e){return{status:e.status,channelId:e.channel.channelId,...e.account.name&&{account:e.account.name},payer:e.channel.descriptor.payer,payee:e.channel.descriptor.payee,authorizedSigner:e.channel.descriptor.authorizedSigner,token:e.channel.descriptor.token,escrow:e.channel.escrow,chainId:e.channel.chainId,cumulativeAmount:e.channel.cumulativeAmount.toString(),confirmedSpend:e.spent.toString(),deposit:e.channel.deposit.toString(),units:e.units,resourceUrl:e.endpoint,createdAt:e.createdAt,updatedAt:e.updatedAt}}function DF(e,t){throw e instanceof L?e:e instanceof DP?new L({code:e.code,message:e.message,exitCode:e.exitCode,cause:e}):e instanceof EP?new L({code:e.code,message:e.message,exitCode:65,cause:e}):new L({code:t,message:e instanceof Error?e.message:String(e),exitCode:75,...e instanceof Error&&{cause:e}})}async function OF(e,t){let n=await dO(t??e.account.name);if(!yM(n.account,e.channel.descriptor))throw new L({code:`SESSION_ACCOUNT_MISMATCH`,message:`Account ${n.account.address} cannot sign for session ${e.channel.channelId}.`,exitCode:2});return n}async function kF(e,t){if(t.network&&CF(t.network)!==e)throw new L({code:`CHAIN_MISMATCH`,message:`Session uses chainId ${e}, not ${t.network}.`,exitCode:2});let n=t.network??wF(e),r=VD(t.rpcUrl,{network:n}),i=await UD({network:n,rpcUrl:r});if(i.id!==e)throw new L({code:`CHAIN_MISMATCH`,message:`Session uses chainId ${e}, but RPC is chainId ${i.id}.`,exitCode:2});return ne({chain:i,transport:le(r)})}const AF=Ky(`sessions`,{description:`Manage persistent payment sessions (list, view, close)`}).command(`list`,{description:`List persistent payment sessions`,options:f.object({account:f.string().optional().describe(`Filter by account name`),network:f.enum([`mainnet`,`testnet`]).optional().describe(`Filter by Tempo network`)}),output:f.object({sessions:f.array(bF)}),alias:{account:`a`},async run(e){try{let t=(await LP().list()).filter(t=>!(e.options.account&&t.account.name!==e.options.account||e.options.network&&t.channel.chainId!==CF(e.options.network))).map(EF),n={sessions:t};if(e.format===`json`&&e.formatExplicit)return e.ok(n);t.length===0&&console.log(`No sessions.`);for(let[e,n]of t.entries())e>0&&console.log(``),jF(n);return}catch(e){return DF(e,`SESSION_LIST_FAILED`)}}}).command(`view`,{description:`View a persistent payment session`,args:f.object({channelId:f.string().describe(`Full session channel ID`)}),output:bF,async run(e){try{let t=await LP().get(e.args.channelId);if(!t)throw new L({code:`SESSION_NOT_FOUND`,message:`Session ${e.args.channelId} was not found.`,exitCode:2});let n=EF(t);if(e.format===`json`&&e.formatExplicit)return e.ok(n);jF(n);return}catch(e){return DF(e,`SESSION_VIEW_FAILED`)}}}).command(`close`,{description:`Cooperatively close persistent payment sessions`,usage:[{suffix:`<channel-id> [options]`},{suffix:`--all --yes [options]`}],args:f.object({channelId:f.string().optional().describe(`Full session channel ID`)}),options:f.object({account:f.string().optional().describe(`Account name`),all:f.boolean().optional().default(!1).describe(`Close every matching session`),header:f.array(f.string()).optional().describe(`Add close request header (repeatable)`),network:f.enum([`mainnet`,`testnet`]).optional().describe(`Tempo network`),rpcUrl:f.string().optional().describe(`RPC endpoint (env: MPPX_RPC_URL)`),url:f.string().optional().describe(`Override the stored resource URL`),yes:f.boolean().optional().default(!1).describe(`Confirm closing every session`)}),output:f.union([xF,SF]),alias:{account:`a`,header:`H`,rpcUrl:`r`},async run(e){if(e.options.all&&e.args.channelId)return e.error({code:`INVALID_SESSION_CLOSE`,message:`Specify a channel ID or --all, not both.`,exitCode:2});if(!e.options.all&&!e.args.channelId)return e.error({code:`INVALID_SESSION_CLOSE`,message:`Specify a channel ID or --all.`,exitCode:2});if(e.options.all&&!e.options.yes)return e.error({code:`CONFIRMATION_REQUIRED`,message:`Closing all sessions requires --yes.`,exitCode:2});if(e.options.all&&(e.options.header||e.options.rpcUrl||e.options.url))return e.error({code:`INVALID_SESSION_CLOSE`,message:`--header, --rpc-url, and --url only apply to a single session.`,exitCode:2});let t=LP();async function n(e,n={}){let r=await t.get(e);if(!r)throw new L({code:`SESSION_NOT_FOUND`,message:`Session ${e} was not found.`,exitCode:2});let i=IP(r.channel),a=await t.acquire(i);try{let r=await t.get(e);if(!r)throw new L({code:`SESSION_NOT_FOUND`,message:`Session ${e} was not found.`,exitCode:2});let a=await OF(r,n.account),o=await kF(r.channel.chainId,n);if(oj({...r.channel.descriptor,escrow:r.channel.escrow,chainId:r.channel.chainId}).toLowerCase()!==r.channel.channelId.toLowerCase())throw new L({code:`SESSION_STATE_INVALID`,message:`Stored descriptor does not derive the session channel ID.`,exitCode:65});if((await _j(o,r.channel.channelId,r.channel.escrow)).deposit===0n)return await t.remove(r.channel.channelId),{channelId:r.channel.channelId,status:`already-closed`,spent:r.spent.toString()};let s=qP(n.resourceUrl??r.endpoint),c={...a.source===`keychain`&&{name:a.accountName},address:a.account.address},l=(e=r.challenge)=>({status:`closing`,account:c,endpoint:s,challenge:e,...r.receipt&&{receipt:r.receipt},spent:r.spent,units:r.units}),u=await t.upsert({...l(),channel:r.channel}),d=TF(n.headers),f=u.challenge,p=await TP({channel:u.channel,challenge:u.challenge,fetch:async(e,t)=>globalThis.fetch(e,{...t,headers:{...d,...YC(t?.headers)}}),input:s,spent:u.spent,async onChallenge(e){f=e,await t.upsert({...l(e),channel:u.channel})},manager:{account:a.account,client:o,channelStore:RP(t,{scope:i,selection:u.channel.channelId,context:()=>l(f)})}});return await t.remove(u.channel.channelId),{channelId:u.channel.channelId,status:`closed`,spent:p.receipt.spent,txHash:p.receipt.txHash}}finally{await a.release()}}try{if(e.options.all){let r=(await t.list()).filter(t=>(!e.options.account||t.account.name===e.options.account)&&(!e.options.network||t.channel.chainId===CF(e.options.network))),i=[],a=[];for(let t of r)try{i.push(await n(t.channel.channelId,{account:e.options.account,network:e.options.network}))}catch(e){a.push({channelId:t.channel.channelId,message:e instanceof Error?e.message:String(e)})}let o={closed:i,failed:a};if(a.length>0){for(let e of a)process.stderr.write(`${e.channelId}: ${e.message}\n`);process.exitCode=1}if(e.format===`json`&&e.formatExplicit)return e.ok(o);for(let e of i)console.log(`${e.channelId} ${e.status} ${e.spent}`);for(let e of a)console.log(`${e.channelId} failed ${e.message}`);return}let r=await n(e.args.channelId,{account:e.options.account,headers:e.options.header,network:e.options.network,resourceUrl:e.options.url,rpcUrl:e.options.rpcUrl});if(e.format===`json`&&e.formatExplicit)return e.ok(r);console.log(`${r.channelId} ${r.status} ${r.spent}`),r.txHash&&console.log(` transaction ${r.txHash}`);return}catch(e){return DF(e,`SESSION_CLOSE_FAILED`)}}});function jF(e){console.log(e.channelId),console.log(` status ${e.status}`),console.log(` cumulative amount ${e.cumulativeAmount}`),console.log(` confirmed spend ${e.confirmedSpend}`),console.log(` deposit ${e.deposit}`),console.log(` chain ${e.chainId}`),console.log(` payer ${e.payer}`),console.log(` payee ${e.payee}`),console.log(` token ${e.token}`),console.log(` resource ${e.resourceUrl}`)}rx(),FM(),qM(),nN(),XT(),hO(),tO();function MF(e,t){if(t&&e!==`auto`&&t.toLowerCase()!==e.toLowerCase())throw new L({code:`SESSION_SELECTION_CONFLICT`,message:`--session and -M channel= select different sessions.`,exitCode:2});let n=t??e;if(n===`auto`||n===`new`)return n;if(/^0x[0-9a-fA-F]{64}$/.test(n))return n.toLowerCase();throw new L({code:`INVALID_SESSION`,message:`Session must be auto, new, or a 32-byte channel ID.`,exitCode:2})}function NF(e){return typeof e.request.decimals==`number`?e.request.decimals:6}function PF(e){let t=e.allowCustomEscrow;if(t!==void 0){if(t===`true`)return!0;if(t===`false`)return!1;throw new L({code:`INVALID_ALLOW_CUSTOM_ESCROW`,message:`allowCustomEscrow must be true or false.`,exitCode:2})}}function FF(e,t,n){if(t.deposit!==void 0)return t.deposit;let r=e.request.suggestedDeposit;return typeof r==`string`?oe(BigInt(r),NF(e)):n?`10`:void 0}function IF(e,t){if(!e)return;if(e.challengeId!==t.challenge.id)throw Error(`Session receipt challenge does not match the paid request.`);if(e.channelId.toLowerCase()!==t.channelId.toLowerCase())throw Error(`Session receipt channel does not match the selected channel.`);let n=BigInt(e.acceptedCumulative),r=BigInt(e.spent);if(n>t.cumulative)throw Error(`Session receipt exceeds the local cumulative authorization.`);if(r>n)throw Error(`Session receipt spend exceeds its accepted authorization.`);return e}function LF(e,t){return e.channel.channelId.toLowerCase()===t.toLowerCase()}function RF(e){if(e.trim()!==`[DONE]`){if(e.length===0){process.stdout.write(`
|
|
245
245
|
`);return}try{let t=JSON.parse(e);process.stdout.write(t.token??t.choices?.[0]?.delta?.content??e)}catch{process.stdout.write(e)}}}async function zF(e){let{options:t}=e,n=await dO(t.account),r=VD(t.rpcUrl,{network:t.network}),i=await UD({network:t.network,rpcUrl:r}),a=ne({chain:i,transport:le(r)}),o=PF(e.methodOptions),s=await pM({allowCustomEscrow:o,challenge:e.challenge,getClient:async()=>a});if(s.chainId!==i.id)throw new L({code:`CHAIN_MISMATCH`,message:`Challenge requires chainId ${s.chainId}, but RPC is chainId ${i.id}.`,exitCode:2});let c={payer:n.account.address,payee:s.payee,token:s.token,escrow:s.escrow,chainId:s.chainId},l=MF(t.session,e.methodOptions.channel),u=e.registry??LP(),d=await u.acquire(c).catch(e=>{throw e instanceof DP?new L({code:e.code,message:e.message,exitCode:e.exitCode,cause:e}):e});try{let r=l===`auto`?await u.getPreferred(c):l===`new`?void 0:l,s=r?await u.get(r):void 0;if(r&&!s)throw new L({code:`SESSION_NOT_FOUND`,message:`Session ${r} was not found.`,exitCode:2});if(s&&l!==`auto`&&(s.status!==`open`||!s.channel.opened||FP(IP(s.channel))!==FP(c)||!yM(n.account,s.channel.descriptor)))throw new L({code:`SESSION_MISMATCH`,message:`Session ${s.channel.channelId} cannot be used for this account and challenge.`,exitCode:2});let d=s?.status===`open`&&s.channel.opened?s:void 0,f=d?`open`:`opening`,p=e.challenge,m=d?.receipt,h=d?.spent??0n,g=d?.units??0,_=qP(e.endpoint),v={...n.source===`keychain`&&{name:n.accountName},address:n.account.address},y=RP(u,{scope:c,selection:l,context:()=>({status:f,account:v,endpoint:_,challenge:p,...m&&{receipt:m},spent:h,units:g}),onNewChannel(){f=`opening`,m=void 0,h=0n,g=0}}),{signal:b,...x}=e.init,S={...x,...b&&{signal:b},onReceipt(e){m=e,h=h>BigInt(e.spent)?h:BigInt(e.spent),g=Math.max(g,e.units??0)}};if(e.challengeResponse.status!==402||e.challengeResponse.bodyUsed)throw Error(`Session manager requires an unconsumed 402 challenge response.`);let C=!0,w=tN({account:n.account,allowCustomEscrow:o,bootstrap:!1,client:a,channelStore:y,decimals:NF(e.challenge),maxDeposit:FF(e.challenge,e.methodOptions,KD(i)),fetch:async(t,n)=>C?(C=!1,e.challengeResponse):e.fetch(t,n)});d&&GM(w).rehydrate({channel:d.channel,challenge:e.challenge,input:e.fetchInput,spent:d.spent});let{onReceipt:T,...ee}=S,E=await w.fetch(e.fetchInput,ee);if(t.fail&&E.status>=400)throw new L({code:`HTTP_ERROR`,message:`HTTP error ${E.status}`,exitCode:22});if(E.status===402)throw new L({code:`PAYMENT_REJECTED`,message:`Payment rejected.`,exitCode:75});AD(E,{include:!1,verbose:t.include?Math.max(t.verbose,2):t.verbose,silent:t.silent}),p=E.challenge??e.challenge;let D=w.channelId;if(!D)throw Error(`Session manager did not select a channel.`);if(m=IF(E.receipt,{challenge:p,channelId:D,cumulative:w.cumulative})??m,BT(E)){let t=GM(w).consumeSseResponse(e.fetchInput,E,{onReceipt:T,signal:e.init.signal??void 0});for await(let e of t)RF(e)}else process.stdout.write(Buffer.from(await E.arrayBuffer()));let O=await u.get(D);if(!O||!LF(O,D))throw Error(`Session ${D} was not persisted.`);if(m){let e=IF(m,{challenge:p,channelId:D,cumulative:w.cumulative});if(!e)throw Error(`Session receipt validation failed.`);m=e,h=h>BigInt(e.spent)?h:BigInt(e.spent),g=Math.max(g,e.units??0),f=`open`}await u.upsert({status:f,channel:O.channel,account:v,endpoint:_,challenge:p,...m&&{receipt:m},spent:h,units:g}),t.silent||(e.info(`Session retained ${D}\n`),e.info(`Close with: mppx sessions close ${D}\n`))}finally{await d.release()}}tO();function BF(e,t){return t?{label:e,detail:t,severity:`pass`}:{label:e,severity:`pass`}}function $(e,t,n){let r={label:e,severity:`fail`};return t&&(r.detail=t),n&&(r.hint=n),r}function VF(e,t,n){let r={label:e,severity:`warn`};return t&&(r.detail=t),n&&(r.hint=n),r}function HF(e,t,n){let r=t?{label:e,detail:t,severity:`skip`}:{label:e,severity:`skip`};return n&&(r.hint=n),r}const UF={pass:Z.green(`✓`),fail:Z.red(`✗`),warn:Z.yellow(`⚠`),skip:Z.dim(`○`)};function WF(e){let t=UF[e.severity],n=e.detail?`${e.label} (${e.detail})`:e.label;console.log(` ${t} ${n}`),e.hint&&e.severity!==`pass`&&console.log(Z.dim(` → ${e.hint}`))}function GF(e){console.log(`\n${Z.bold(e)}`)}function KF(e,t){for(let n of e)WF(n),n.severity===`pass`?t.passed++:n.severity===`fail`?t.failed++:n.severity===`warn`?t.warnings++:n.severity===`skip`&&t.skipped++}async function qF(e,t,n=15e3){let r=new AbortController,i=setTimeout(()=>r.abort(),n);try{return await fetch(e,{...t,signal:r.signal})}finally{clearTimeout(i)}}function JF(e){return e<1024?`${e}B`:e<1048576?`${(e/1024).toFixed(1)}KB`:`${(e/1048576).toFixed(1)}MB`}const YF=new Set([`get`,`post`,`put`,`patch`,`delete`,`head`,`options`,`trace`]);function XF(e){return typeof e==`string`&&/^0x[0-9a-fA-F]{40}$/.test(e)}function ZF(e){return typeof e==`string`&&/^(0|[1-9][0-9]*)$/.test(e)}function QF(e){let t=e.indexOf(`:`);if(t<1)return null;let n=e.slice(0,t).toLowerCase();if(!YF.has(n))return null;let r=e.slice(t+1);if(!r)return null;let i=r.startsWith(`/`)?r:`/`+r;return{method:n.toUpperCase(),path:i}}function $F(e,t){if(e){try{let n=JSON.parse(e);if(n&&typeof n==`object`&&!Array.isArray(n)){let e=Object.keys(n);if(e.length>0&&e.every(e=>e.startsWith(`/`))){let e=n[t];return e===void 0?void 0:typeof e==`string`?e:JSON.stringify(e)}}}catch{}return e}}function eI(e){if(!e)return{};let t={};for(let n of e){let e=n.indexOf(`:`);e>0&&(t[n.slice(0,e).trim().toLowerCase()]=n.slice(e+1).trim())}return t}async function tI(e){let t=new URL(`openapi.json`,e.replace(/\/?$/,`/`)).href;try{let e=await qF(t,{});if(!e.ok)return{error:`HTTP ${e.status}`};let n=await e.text();return{doc:JSON.parse(n),raw:n}}catch(e){return e instanceof DOMException&&e.name===`AbortError`?{error:`Request timed out after 15s`}:e instanceof SyntaxError?{error:`Invalid JSON`}:{error:e.message}}}function nI(e){let t=[],n=[],r=e.paths;if(!r)return[];for(let[e,i]of Object.entries(r)){let r=aI(i.parameters);for(let[a,o]of Object.entries(i)){if(!YF.has(a)||!o||typeof o!=`object`||Array.isArray(o))continue;let i=o,s=oI(r,aI(i.parameters)),c=s.length>0?s:void 0;if(i[`x-payment-info`]){let n=i[`x-payment-info`];t.push({method:a.toUpperCase(),path:e,amount:n.amount,parameters:c})}else{let t=i.responses;t&&`402`in t&&n.push({method:a.toUpperCase(),path:e,parameters:c})}}}return t.length>0?t:n}function rI(e,t){let n=e.paths;if(!n)return;let r=n[t.path];if(!r)return;let i=r[t.method.toLowerCase()];if(!i?.requestBody)return;let a=i.requestBody.content?.[`application/json`];if(!a)return;if(a.example)return JSON.stringify(a.example);if(a.examples&&typeof a.examples==`object`){let e=Object.values(a.examples)[0];if(e?.value)return JSON.stringify(e.value)}let o=a.schema,s=new Set;if(o=cI(o,e,s),!o||o.type!==`object`)return;let c=lI(o,e,s);if(c&&typeof c==`object`&&Object.keys(c).length>0)return JSON.stringify(c)}function iI(e,t,n){let r=t.path;t.parameters&&(r=sI(r,t.parameters));let i=r.startsWith(`/`)?r.slice(1):r,a=new URL(i,e.replace(/\/?$/,`/`)).href;if(n){let e=new URL(a);for(let t of n){let[n,...r]=t.split(`=`);n&&e.searchParams.set(n,r.join(`=`))}a=e.href}return a}function aI(e){if(!Array.isArray(e))return[];let t=[];for(let n of e){if(!n||typeof n!=`object`)continue;let e=n;e.in===`path`&&typeof e.name==`string`&&t.push(e.schema&&typeof e.schema==`object`?{name:e.name,in:`path`,schema:e.schema,example:e.example}:{name:e.name,in:`path`,example:e.example})}return t}function oI(e,t){let n=[...e];for(let e of t){let t=n.findIndex(t=>t.name===e.name);t>=0?n[t]=e:n.push(e)}return n}function sI(e,t){return e.replace(/\{([^}]+)\}/g,(e,n)=>{let r=t.find(e=>e.name===n&&e.in===`path`);if(!r)return e;let i=r.example??r.schema?.example??r.schema?.default;return i===void 0?e:encodeURIComponent(String(i))})}function cI(e,t,n){if(!e||typeof e.$ref!=`string`)return e;if(n?.has(e.$ref))return;let r=e.$ref.replace(/^#\//,``).split(`/`),i=t;for(let e of r)if(i&&typeof i==`object`)i=i[e];else return;return i}function lI(e,t,n){let r=cI(e,t,n)??e;if(r.const!==void 0)return r.const;if(r.example!==void 0)return r.example;if(r.default!==void 0)return r.default;switch(r.type){case`string`:return r.enum&&Array.isArray(r.enum)?r.enum[0]:r.format===`email`?`test@example.com`:r.format===`uuid`?`00000000-0000-0000-0000-000000000000`:r.format===`uri`||r.format===`url`?`https://example.com`:r.format===`date`?`2026-01-01`:r.pattern===`^\\d{5}(?:-\\d{4})?$`?`10001`:r.pattern===`^[A-Z]{2}$`?`US`:`test`;case`number`:case`integer`:return r.minimum??1;case`boolean`:return!0;case`array`:return[];case`object`:{let e=r.properties;if(!e)return{};let i=r.required||[],a={};for(let r of i){let i=e[r];i&&(a[r]=lI(i,t,n))}return a}default:return null}}Wx(),ux(),DC(),tO();const uI=Object.values(Pe);function dI(e){let t=e.request.methodDetails;return typeof t?.chainId==`number`&&uI.find(e=>e.id===t.chainId)?.testnet===!0}async function fI(e,t,n,r){let i=[],a=iI(e,t,r?.query),o=eI(r?.extraHeaders),s;r?.body&&!r.bodyIsAutogenerated&&(s=r.body,o[`content-type`]||=`application/json`);let c;try{let e={method:t.method};Object.keys(o).length>0&&(e.headers=o),s&&(e.body=s),c=await qF(a,e)}catch(e){return i.push($(`Request failed`,e.message)),{results:i}}if(!s&&(c.status===400||c.status===422)){let e=r?.body??(r?.discoveryDoc?rI(r.discoveryDoc,t):void 0);if(e){n&&console.log(Z.dim(` Retrying with body: ${e}`)),s=e,o[`content-type`]=`application/json`;try{c=await qF(a,{method:t.method,headers:o,body:s})}catch(e){return i.push($(`Request failed`,e.message)),{results:i}}}}if(c.status!==402)return c.status===200?i.push(HF(`Returns 402 without credentials`,`Got 200 (endpoint may not require payment in all cases)`)):c.status===401||c.status===403?i.push(HF(`Returns 402 without credentials`,`Got ${c.status} (endpoint requires auth before payment gate)`)):i.push($(`Returns 402 without credentials`,`Got ${c.status} instead`,c.status===400||c.status===422?`Server requires a valid request body before returning 402. Add a requestBody schema with examples to your OpenAPI doc, or use --body.`:`Endpoints that require payment must return HTTP 402 with a WWW-Authenticate: Payment header when no valid credential is provided.`)),{results:i};i.push(BF(`Returns 402 without credentials`));let l=c.headers.get(J.wwwAuthenticate),u=CI(c);if(!l)return u.length>0?(i.push(HF(`Not an MPP endpoint`,`No WWW-Authenticate header — x402 protocol detected`)),i.push(...u)):i.push(HF(`Not an MPP endpoint`,`No WWW-Authenticate header (may be x402 or other protocol)`)),{results:i};if(u.length>0&&i.push(...u),!l.startsWith(`${ax.payment} `))return i.push(HF(`Not an MPP endpoint`,`WWW-Authenticate scheme is not Payment`)),{results:i};i.push(BF(`WWW-Authenticate header present`,`Payment scheme`));let d;try{d=Lx(c)}catch(e){let t=e.message;i.push($(`Challenge parseable`,t,`The Payment challenge must include a request="<base64url>" parameter containing JSON-encoded payment details.`));let n=l.slice(l.indexOf(` `)+1);return i.push(VF(`Received`,n.length>200?n.slice(0,200)+`...`:n)),{results:i}}if(d.length===0)return i.push($(`Challenge parseable`,`No Payment challenges found in header`)),{results:i};let f=d.map(e=>`${e.method}/${e.intent}`).join(`, `);i.push(BF(`Challenge parseable`,d.length===1?f:`${d.length} methods: ${f}`));let p=new URL(e).hostname;pI(d,i),mI(d,i),hI(d,i),gI(d,p,i);let m=d.length>1;for(let e of d){let t=e.request;_I(e,t,i,m)}if(n)for(let e of d)console.log(Z.dim(` Challenge (${e.method}/${e.intent}): ${JSON.stringify(e,null,2)}`));return{results:i,resolvedBody:s,challenges:d}}function pI(e,t){let n=e.filter(e=>!e.id);n.length===0?t.push(BF(`Challenge has id`)):t.push($(`Challenge has id`,`${n.length} missing`,`Every challenge must include a unique id field.`))}function mI(e,t){let n=e.filter(e=>!e.realm);n.length===0?t.push(BF(`Challenge has realm`)):t.push($(`Challenge has realm`,`${n.length} missing`,`Set realm to your server's hostname.`))}function hI(e,t){let n=new Date;for(let r of e){if(!r.expires){t.push(VF(`Challenge has expiration`,`missing expires field`,`Add an expires field (ISO 8601) to prevent replay attacks.`));return}if(new Date(r.expires)<=n){t.push($(`Challenge expires in the future`,`Expired at ${r.expires}`,`The expires timestamp must be in the future.`));return}}let r=Math.min(...e.map(e=>new Date(e.expires).getTime()-n.getTime()));t.push(BF(`Challenge expires in the future`,`${Math.round(r/6e4)}m from now`))}function gI(e,t,n){let r=[...new Set(e.map(e=>e.realm??``))].filter(e=>e&&e!==t&&!t.endsWith(`.${e}`));r.length>0?n.push(VF(`Realm matches server hostname`,`realm="${r[0]}" vs host="${t}"`,`Set the realm to your production hostname (or base domain) in the challenge.`)):n.push(BF(`Realm matches server hostname`))}function _I(e,t,n,r){let i=r?`[${e.method}] `:``;e.method===ox.tempo?vI(t,i,n,e):e.method===ox.stripe?yI(t,i,n):e.method===ox.evm&&bI(e,t,i,n)}function vI(e,t,n,r){let i=e.methodDetails,a=Array.isArray(i?.splits)&&i.splits.length>0;if(XF(e.recipient)?n.push(BF(`${t}Valid recipient address`)):e.recipient===void 0&&a?n.push(BF(`${t}Uses splits (no single recipient)`)):e.recipient===void 0?n.push($(`${t}Valid recipient address`,`Missing recipient (and no splits defined)`,`Set request.recipient to a valid 0x address, or use methodDetails.splits for multiple recipients.`)):n.push($(`${t}Valid recipient address`,`Got: ${String(e.recipient)}`,`Set request.recipient to a valid 0x-prefixed 40-hex-char address.`)),XF(e.currency)){let e=dI(r)?`testnet`:`mainnet`;n.push(BF(`${t}Valid currency address`,e))}else n.push($(`${t}Valid currency address`,`Got: ${String(e.currency)}`,`Set request.currency to a valid token address.`));xI(e,t,n,`token's smallest unit (e.g. "10000" = $0.01 for 6-decimal tokens)`)}function yI(e,t,n){xI(e,t,n,`currency's smallest unit (e.g. "100" = $1.00 for USD)`);let r=e.currency;typeof r==`string`&&/^[a-z]{3}$/i.test(r)?n.push(BF(`${t}Valid currency code`,r.toUpperCase())):n.push($(`${t}Valid currency code`,r?`Got: ${r}`:`missing`,`Must be a three-letter ISO currency code (e.g. "usd").`));let i=e.methodDetails,a=i?.networkId;a?n.push(BF(`${t}Has networkId`,a.slice(0,20))):n.push($(`${t}Has networkId`,`Missing methodDetails.networkId`,`Set methodDetails.networkId to your Stripe Business Network profile ID.`));let o=i?.paymentMethodTypes;Array.isArray(o)&&o.length>0?n.push(BF(`${t}Has paymentMethodTypes`,o.join(`, `))):n.push($(`${t}Has paymentMethodTypes`,`Missing or empty`,`Set methodDetails.paymentMethodTypes to an array (e.g. ["card"]).`))}function bI(e,t,n,r){if(XF(t.recipient)?r.push(BF(`${n}Valid recipient address`)):r.push($(`${n}Valid recipient address`,`Got: ${String(t.recipient)}`,`Set request.recipient to a valid 0x-prefixed Ethereum address.`)),XF(t.currency)){let t=dI(e)?`testnet`:`mainnet`;r.push(BF(`${n}Valid currency address`,t))}else r.push($(`${n}Valid currency address`,`Got: ${String(t.currency)}`,`Set request.currency to a valid ERC-20 token contract address.`));xI(t,n,r,`token's smallest unit`);let i=t.methodDetails?.chainId;typeof i==`number`&&i>0?r.push(BF(`${n}Has chainId`,String(i))):r.push($(`${n}Has chainId`,`Missing methodDetails.chainId`,`Set methodDetails.chainId to the EVM chain ID.`))}function xI(e,t,n,r){ZF(e.amount)?n.push(BF(`${t}Amount is valid integer string`)):e.amount===void 0||e.amount===null?n.push($(`${t}Amount is valid integer string`,`Missing amount`,`Set request.amount to a string of digits in the ${r}.`)):n.push($(`${t}Amount is valid integer string`,`Got: ${String(e.amount)}`,`request.amount must be a string of digits (no decimals, no prefix).`))}async function SI(e,t,n){let r=[],i=iI(e,t,n?.query),a={[J.authorization]:`${ax.payment} dGhpcyBpcyBnYXJiYWdl`},o;n?.body&&(o=n.body,a[`content-type`]=`application/json`);try{let e=await qF(i,{method:t.method,headers:a,body:o??null});e.status===402?(r.push(BF(`Malformed credential returns 402`,`not 500`)),e.headers.get(J.wwwAuthenticate)?.startsWith(`${ax.payment} `)?r.push(BF(`Error response includes fresh challenge`)):r.push(VF(`Error response includes fresh challenge`,`No WWW-Authenticate header`,`When rejecting an invalid credential, respond with 402 and include a fresh WWW-Authenticate: Payment challenge so the client can retry.`))):e.status>=500?r.push($(`Malformed credential returns 402`,`Got ${e.status} (server error)`,`When the Authorization header contains an invalid credential, respond with 402 (not 500). Catch credential validation errors and return a fresh challenge.`)):r.push(VF(`Malformed credential returns 402`,`Got ${e.status}`,`When the Authorization header contains an invalid Payment credential, respond with 402 and a fresh WWW-Authenticate challenge. Returning ${e.status} prevents the client from retrying with a valid payment.`))}catch(e){r.push($(`Error handling test`,e.message))}return r}function CI(e){let t=[],n=e.headers.get(`payment-required`)??e.headers.get(`x-payment-required`);if(!n)return t;let r=e.headers.get(`payment-required`)?`PAYMENT-REQUIRED`:`X-Payment-Required`;try{let e=xC(n);t.push(BF(`x402 payment challenge`,`${r} with valid x402 v${e.x402Version} payload`))}catch{t.push(VF(`x402 payment challenge`,`${r} header present but failed schema validation`,`Ensure the PAYMENT-REQUIRED header contains a valid base64-encoded JSON payload matching the x402 schema.`))}return t}const wI=[`No discovery document found, endpoints could not be automatically found.`,`MPP servers must serve an OpenAPI document at /openapi.json with x-payment-info extensions.`,`The MPP SDKs can automatically expose this endpoint. See https://mpp.dev/sdk.`,``,`To test a specific endpoint: mppx validate <url> --endpoint POST:/your/path`].join(`
|
|
246
246
|
`);Ex();const TI={method:Y.string(),reference:Y.string(),externalId:Y.optional(Y.string()),subscriptionId:Y.optional(Y.string()),status:Y.literal(`success`),timestamp:_x()};Y.object(TI);const EI=Y.looseObject(TI);function DI(e){let t=E.toString(e);return OI(JSON.parse(t))}function OI(e){return EI.parse(e)}Wx(),ux(),PN(),DD(),hO(),tO();async function kI(e,t,n){try{n||console.log(Z.dim(` Provisioning testnet wallet and funding via faucet...`));let t=pe(),r=he(t),i=ne({chain:_e,transport:le()}),a=await Ae.faucet.fund(i,{account:r});await Promise.all(a.map(e=>De(i,{hash:e}))),n||console.log(Z.dim(` Using wallet: ${r.address}`));let o=e.request.currency;if(typeof o==`string`)for(let e=0;e<10;e++){let e=await Ae.token.getBalance(i,{account:r.address,token:o}).catch(()=>void 0);if(e&&e.amount>0n)break;await new Promise(e=>setTimeout(e,500))}return{methods:[...AN({account:r})]}}catch(e){t&&console.log(Z.dim(` Provisioning failed: ${e.message}`));return}}async function AI(){let e=cO(),{isTempoAccount:t}=await Promise.resolve().then(()=>(tO(),OD)),{resolveTempoAccount:n}=await Promise.resolve().then(()=>(mP(),FN));if(t(e)){let t=n(e);if(t)return t.wallet_address}try{return(await fO()).address}catch{return}}function jI(e){try{let{execSync:t}=p,n=t(`stripe config --list`,{encoding:`utf8`,timeout:5e3}).match(/test_mode_api_key\s*=\s*'([^']+)'/);if(n?.[1])return e&&console.log(Z.dim(` Using Stripe test key from stripe CLI`)),n[1]}catch{}}async function MI(e,t,n){let r=ne({chain:e,transport:le()}),[i,a]=await Promise.all([Se(r,{address:t,abi:ae,functionName:`balanceOf`,args:[n]}),Se(r,{address:t,abi:ae,functionName:`symbol`}).catch(()=>void 0)]);return{balance:i,symbol:a??void 0}}function NI(e){return Object.values(Pe).find(t=>t.id===e)}function PI(e,t){return`$${(Number(e)/10**t).toFixed(2)}`}function FI(e){switch(e.method){case ox.evm:return`no EVM payment plugin yet`;case`solana`:return`no Solana payment plugin yet`;default:return`no plugin for ${e.method}/${e.intent}`}}async function II(e,t,n,r){let i=[],a=iI(e,t,r.query),o=eI(r.extraHeaders),s;r.body&&(s=r.body,o[`content-type`]=`application/json`);let c;try{c=await qF(a,{method:t.method,headers:o,body:s??null})}catch(e){return i.push($(`Payment: fetch challenge`,e.message)),i}if(c.status!==402)return i.push(HF(`Payment: skipped`,`Endpoint returned ${c.status}`)),i;let l;try{l=Lx(c)}catch(e){return i.push($(`Payment: parse challenge`,e.message)),i}if(l.length===0)return i.push($(`Payment: parse challenge`,`No Payment challenges in response`)),i;let u=l.find(e=>{if(e.method!==ox.tempo)return!1;let t=e.request.methodDetails;return typeof t?.chainId==`number`&&t.chainId!==SD.mainnet});if(u){let e=await kI(u,n,r.silent);if(e){let r=new Response(null,{status:402,headers:{[J.wwwAuthenticate]:Ox(u)}});try{let c=await Lw({methods:e.methods,polyfill:!1}).createCredential(r);i.push(BF(`Payment: submitted`,`ephemeral testnet wallet`)),await BI(i,a,t,c,o,s,n,_e)}catch(e){i.push($(`Payment: create credential`,e.message))}}else i.push($(`Payment: auto-provision wallet`,`Failed to create and fund testnet wallet`));r.onResults?.(i)}let d=await xP().catch(()=>void 0),f=r.interactive,p=process.env.MPPX_STRIPE_SECRET_KEY??jI(n),m=p?.startsWith(`sk_test_`)||p?.startsWith(`rk_test_`),h=new Set([ox.tempo,ox.evm,ox.stripe]);for(let e of l){if(e===u||!h.has(e.method))continue;r.silent||console.log(``);let c=i.length,l=()=>{r.onResults&&i.length>c&&r.onResults(i.slice(c))},g=`Payment [${e.method}]`;try{switch(e.method){case ox.tempo:case ox.evm:await LI(e,g,{results:i,url:a,endpoint:t,fetchHeaders:o,fetchBody:s,verbose:n,loaded:d,isInteractive:f,options:r});break;case ox.stripe:await RI(e,g,{results:i,url:a,endpoint:t,fetchHeaders:o,fetchBody:s,verbose:n,loaded:d,isInteractive:f,isStripeTestKey:m??!1,stripeKey:p,options:r})}}finally{l()}}return i}async function LI(e,t,n){let{results:r,url:i,endpoint:a,fetchHeaders:o,fetchBody:s,verbose:c,loaded:l,options:u}=n,d=e.request,f=d.methodDetails,p=ZF(d.amount)?BigInt(d.amount):void 0,m=f?.decimals??d.decimals??6,h=d.currency,g;try{g=await AI()}catch{}if(!g){r.push(HF(t,`no wallet configured. Run "mppx account create" to create one.`));return}let _;if(e.method===ox.tempo)_=ge;else if(e.method===ox.evm){let e=f?.chainId;e&&(_=NI(e))}let v;if(p&&h&&_)try{let n;if(e.method===ox.tempo){let e=await qD(ne({chain:ge,transport:le()}),h,g);n=e.balance,v=e.symbol}else{let e=await MI(_,h,g);n=e.balance,v=e.symbol}if(n<p){let e=PI(p,m),i=PI(n,m),a=v??`tokens`;r.push(HF(t,`insufficient balance (have ${i}, need ${e} ${a} on ${_.name})`,`Fund wallet ${g} with at least ${e} ${a} on ${_.name}.`));return}}catch(e){c&&console.log(Z.dim(` Balance check skipped: ${e.message}`))}let y=p?PI(p,m):`unknown amount`,b=v??(h?.length===3?h.toUpperCase():``),x=_?.name,S=`${y}${b?` ${b}`:``}${x?` on ${x}`:``}`;if(u.silent||console.log(Z.dim(` Attempting payment with wallet ${g}`)),_?.testnet)u.silent||console.log(Z.dim(` Auto-approved: ${S} (testnet)`));else if(!u.yes&&!n.isInteractive){r.push(HF(t,`non-interactive mode, use --yes to approve`));return}else if(u.yes)u.silent||console.log(Z.dim(` Auto-approved: ${S}`));else if(!await zD(` ${Z.yellow(`Pay`)} ${S}. Continue?`,!1)){r.push(HF(t,`declined`));return}let C=gP(e,l?.config),w=C.plugin,T=C.method;if(!w&&!T){r.push(HF(t,FI(e)));return}let ee,E;if(w)try{let t=await w.setup({challenge:e,options:{network:`mainnet`},methodOpts:{}});ee=t.methods,E=t.createCredential}catch(e){r.push(HF(t,e.message));return}else ee=[T];let D=await zI(e,ee,E,t,r);D&&(w?.prepareCredentialRequest?.({challenge:e,credential:D,headers:o}),await BI(r,i,a,D,o,s,c,_))}async function RI(e,t,n){let{results:r,url:i,endpoint:a,fetchHeaders:o,fetchBody:s,verbose:c,loaded:l,options:u,isStripeTestKey:d,stripeKey:f}=n,p=e.request,m=ZF(p.amount)?BigInt(p.amount):void 0,h=p.decimals??2,g=p.currency,_=m?PI(m,h):`unknown amount`,v=g?.length===3?g.toUpperCase():``,y=`${_}${v?` ${v}`:``} via Stripe${d?` (testmode)`:``}`;if(d)u.silent||console.log(Z.dim(` Attempting: ${y}`));else if(!u.yes&&!n.isInteractive){r.push(HF(t,`non-interactive mode, use --yes to approve`));return}else if(u.yes)u.silent||console.log(Z.dim(` Auto-approved: ${y}`));else if(!await zD(` ${Z.yellow(`Pay`)} ${y}. Continue?`,!1)){r.push(HF(t,`declined`));return}let b=gP(e,l?.config).plugin;if(!b){r.push(HF(t,`no Stripe plugin available`));return}let x,S;try{let t={paymentMethod:`pm_card_visa`};f&&(t.secretKey=f);let n=await b.setup({challenge:e,options:{},methodOpts:t});x=n.methods,S=n.createCredential}catch(e){r.push(HF(t,e.message));return}let C=await zI(e,x,S,t,r);if(C){if(b.prepareCredentialRequest?.({challenge:e,credential:C,headers:o}),d){let e=await qF(i,{method:a.method,headers:{...o,[J.authorization]:C},body:s??null},3e4);e.status>=200&&e.status<300?r.push(BF(`${t}: successful`,`HTTP ${e.status}`)):r.push(HF(`${t}: server is in livemode`,void 0,`Run your server with a Stripe test key to automatically validate Stripe payments in testmode.`));return}await BI(r,i,a,C,o,s,c,void 0)}}async function zI(e,t,n,r,i){let a=new Response(null,{status:402,headers:{[J.wwwAuthenticate]:Ox(e)}});try{let e;return e=n?await n(a):await Lw({methods:t,polyfill:!1}).createCredential(a),i.push(BF(`${r}: submitted`)),e}catch(e){let t=e.message;t.toLowerCase().includes(`insufficient`)?i.push(HF(r,`insufficient balance: ${t}`)):i.push($(r,t));return}}async function BI(e,t,n,r,i,a,o,s){let c;try{c=await qF(t,{method:n.method,headers:{...i,[J.authorization]:r},body:a??null},3e4)}catch(t){return e.push($(`Payment: send credential`,t.message)),e}if(c.status===402){let t=await c.text().catch(()=>``),n=`Payment rejected`;try{let e=JSON.parse(t);n=e.detail??e.title??n}catch{}return e.push($(`Payment: accepted`,n,`The server rejected a valid credential. Check that your payment verification logic accepts the credential format and that the payment was processed on-chain.`)),e}if(c.status>=400&&c.status<500)e.push(VF(`Payment: post-payment response`,`Got ${c.status}`,`Payment succeeded but the endpoint returned a client error. The endpoint likely requires request body parameters. Use --body to provide them.`));else if(c.status>=500)return e.push($(`Payment: server response`,`Got ${c.status}`,`Payment was accepted but the server errored while generating the response. Check server logs for the underlying error.`)),e;else e.push(BF(`Payment: successful`,`HTTP ${c.status}`));let l=c.headers.get(J.paymentReceipt);if(!l)e.push($(`Payment-Receipt header present`,void 0,`After accepting payment, include a Payment-Receipt header with a base64url-encoded JSON object containing: method, reference, status ("success"), and timestamp (ISO 8601).`));else{e.push(BF(`Payment-Receipt header present`));try{let t=DI(l);if(e.push(BF(`Receipt parseable`)),t.status===`success`?e.push(BF(`Receipt status is "success"`)):e.push($(`Receipt status is "success"`,`Got: ${t.status}`)),t.reference){let n=/^0x[0-9a-fA-F]{64}$/.test(t.reference),r=t.reference.startsWith(`pi_`);n||r?e.push(BF(`Receipt reference valid`,t.reference.slice(0,20)+`...`)):e.push(VF(`Receipt reference format`,t.reference.slice(0,40)))}else e.push(VF(`Receipt has reference`,`No reference field`));if(t.timestamp){let n=new Date(t.timestamp),r=Date.now()-n.getTime();r<6e4?e.push(BF(`Receipt timestamp recent`,`${Math.round(r/1e3)}s ago`)):e.push(VF(`Receipt timestamp recent`,`${Math.round(r/6e4)}m ago`))}o&&console.log(Z.dim(` Receipt: ${JSON.stringify(t,null,2)}`))}catch(t){e.push($(`Receipt parseable`,t.message))}}let u=c.headers.get(`content-type`)??``,d=await c.text().catch(()=>``);if(d.length>0)e.push(BF(`Response body non-empty`,`${u.split(`;`)[0]}, ${JF(d.length)}`));else{let t=[...c.headers.entries()].filter(([e])=>!e.startsWith(`x-`)&&![`content-type`,`content-length`,`date`,`server`,`connection`,`keep-alive`,`cache-control`,`vary`,`access-control-allow-origin`,`payment-receipt`,`payment-session`,`payment-session-snapshot`].includes(e.toLowerCase()));t.length>0?e.push(VF(`Response body empty -- data may be in headers only`,t.map(([e])=>e).join(`, `))):e.push(VF(`Response body empty`))}if(u?e.push(BF(`Content-Type header set`,u.split(`;`)[0])):e.push(VF(`Content-Type header set`)),l)try{let t=DI(l);if(t.reference&&/^0x[0-9a-fA-F]{64}$/.test(t.reference)){let n=s?.blockExplorers?.default?.url;if(n){let r=n.includes(`tempo`)?`receipt`:`tx`;e.push(BF(`On-chain transaction`,`${n}/${r}/${t.reference}`))}}}catch{}return e}async function*VI(e){let t=e.url.replace(/\/$/,``).replace(/\/openapi\.json$/i,``),n=e.verbose??!1,r=await KI(t,e);yield{phase:`discovery`,discovery:r,results:r.checks};for(let i of r.endpoints){yield{phase:`endpoint`,endpoint:i};let a,o=!1;e.endpoint?a=e.body:(a=$F(e.body,i.path),!a&&r.doc&&(a=rI(r.doc,i),o=!!a));let{results:s,resolvedBody:c,challenges:l}=await fI(t,i,n,{body:a,bodyIsAutogenerated:o,query:e.query,extraHeaders:e.headers,discoveryDoc:r.doc??void 0}),u=c??a,d=s.some(e=>e.severity===`pass`&&e.label===`Challenge parseable`),f=(l??[]).filter(e=>e.method!==`stripe`).map(e=>e.request.methodDetails?.chainId).filter(e=>typeof e==`number`),p=f.some(GI),m=f.some(e=>!GI(e)),h=!d&&s.some(e=>e.label===`Not an MPP endpoint`),g=s.some(e=>e.severity===`pass`&&e.label===`WWW-Authenticate header present`),_=s.some(e=>e.severity===`fail`&&e.label===`Challenge parseable`);if(yield{phase:`challenge`,endpoint:i,results:s,isMpp:d,isTestnet:p,isMainnet:m,isNonMppPayment:h,isMalformedChallenge:!d&&g&&_,methods:l?.map(e=>e.method)??[]},d&&(yield{phase:`errorHandling`,endpoint:i,results:await SI(t,i,{body:u,query:e.query})},!e.skipPayment)){let r=e.onPaymentResults,a=await II(t,i,n,{body:u,query:e.query,extraHeaders:e.headers,yes:e.yes,silent:!r,interactive:e.interactive,...r&&{onResults:r}});yield{phase:`payment`,endpoint:i,results:a,succeeded:a.some(e=>e.severity===`pass`&&e.label===`Payment: successful`)}}}}async function HI(e){let t=e.url.replace(/\/$/,``).replace(/\/openapi\.json$/i,``),n,r=[],i,a=!1,o=!1;for await(let t of VI(e))switch(t.phase){case`discovery`:n=t.discovery;break;case`endpoint`:i={method:t.endpoint.method,path:t.endpoint.path,challenge:[],errorHandling:[],payment:[]},r.push(i);break;case`challenge`:i&&(i.challenge=t.results),t.isMpp&&(t.isTestnet&&(a=!0),t.isMainnet&&(o=!0));break;case`errorHandling`:i&&(i.errorHandling=t.results);break;case`payment`:i&&(i.payment=t.results)}let s={passed:0,failed:0,warnings:0,skipped:0};if(n)for(let e of n.checks)e.severity===`pass`?s.passed++:e.severity===`fail`?s.failed++:e.severity===`warn`?s.warnings++:e.severity===`skip`&&s.skipped++;for(let e of r)for(let t of[...e.challenge,...e.errorHandling,...e.payment])t.severity===`pass`?s.passed++:t.severity===`fail`?s.failed++:t.severity===`warn`?s.warnings++:t.severity===`skip`&&s.skipped++;if(!n)throw Error(`Discovery phase did not complete`);let c=UI(r,n,{sawTestnet:a,sawMainnet:o});return{url:t,discovery:n,endpoints:r,summary:s,suggestions:c}}function UI(e,t,n){let r=[],i=e.flatMap(e=>[...e.challenge,...e.payment]);t.found||r.push(wI);let a=n.sawMainnet,o=n.sawTestnet,s=i.some(e=>e.label.includes(`[stripe]`)&&e.label.includes(`livemode`));return a&&!o?r.push(`Validate your testnet server to test without real funds (Tempo wallets are automatically provisioned).`):o&&!a&&r.push(`Validate your mainnet server to confirm real payments work end-to-end.`),s&&r.push(`Validate your testmode Stripe server to test card payments end-to-end (auto-pays with test card).`),r}const WI=Object.values(Pe);function GI(e){return WI.find(t=>t.id===e)?.testnet===!0}async function KI(e,t){let n=[],r=[],i=null,a=!1,o=!1,s=new URL(e).origin,c;t.discoveryPath?c=[new URL(t.discoveryPath,e+`/`).href.replace(/\/openapi\.json$/i,``)]:(c=[e,s,`${s}/api`],c=[...new Set(c)]);let l,u=[];for(let e of c)if(l=await tI(e),`error`in l)u.push(`${e}/openapi.json: ${l.error}`);else break;if(!l||`error`in l)n.push({label:`Document found`,detail:u.join(`; `),hint:`MPP servers must serve an OpenAPI document at /openapi.json with x-payment-info extensions.`,severity:`fail`});else{a=!0,n.push({label:`Document found and parseable`,severity:`pass`});let e=cT(l.doc),t=e.filter(e=>e.severity===`error`),r=e.filter(e=>e.severity===`warning`);if(t.length>0){n.push({label:`Valid OpenAPI structure`,detail:`${t.length} error(s)`,severity:`fail`});for(let e of t)n.push({label:e.message,detail:e.path,severity:`fail`})}else o=!0,n.push({label:`Valid OpenAPI structure`,severity:`pass`});for(let e of r)n.push({label:e.message,detail:e.path,severity:`warn`});i=l.doc}if(t.endpoint){let e=QF(t.endpoint);e&&r.push(e)}else if(i){r=nI(i);let e=BigInt(`999999999999999999`);r.sort((t,n)=>{let r=ZF(t.amount)?BigInt(t.amount):e,i=ZF(n.amount)?BigInt(n.amount):e;return r<i?-1:+(r>i)}),r.length>0?n.push({label:`Paid endpoints found`,detail:`${r.length} endpoint(s)`,severity:`pass`}):n.push({label:`Paid endpoints found`,detail:`No endpoints with x-payment-info`,severity:`warn`})}return{found:a,valid:o,endpoints:r,checks:n,doc:i}}rx(),tO();const qI=Ky(`validate`,{description:`Validate an MPP server implementation end-to-end`,args:f.object({url:f.string().describe(`Base URL of the MPP server to validate`)}),options:f.object({endpoint:f.string().optional().describe(`Endpoint to test (METHOD:path). Skips discovery.`),body:f.string().optional().describe(`Request body. With --endpoint, used directly. In discovery mode, JSON with / keys is a per-path mapping.`),query:f.array(f.string()).optional().describe(`Query parameter (key=value, repeatable)`),header:f.array(f.string()).optional().describe(`Request header (key:value, repeatable)`),verbose:f.number().default(0).meta({count:!0}).describe(`Verbosity level`),yes:f.boolean().default(!1).describe(`Auto-approve mainnet payments`),outputJson:f.boolean().default(!1).describe(`Output results as JSON (auto-enabled in known agent environments)`)}),alias:{endpoint:`e`,header:`H`,verbose:`v`,yes:`y`,outputJson:`j`},async run(e){if(e.options.outputJson||ID()){let t=await HI({url:e.args.url,endpoint:e.options.endpoint,body:e.options.body,query:e.options.query,headers:e.options.header,verbose:e.options.verbose>0,yes:e.options.yes,interactive:!1});console.log(JSON.stringify(t,null,2));let n=t.endpoints.length===0&&!e.options.endpoint;(t.summary.failed>0||!t.discovery.found||n)&&process.exit(1);return}let t=e.args.url.replace(/\/$/,``).replace(/\/openapi\.json$/i,``);console.log(`\n${Z.bold(`mppx validate`)} ${Z.dim(t)}\n`);let n={passed:0,failed:0,warnings:0,skipped:0},r=!1,i=!1,a=!1,o=!1,s=!1,c=!1,l=!1,u=0;for await(let t of VI({url:e.args.url,endpoint:e.options.endpoint,body:e.options.body,query:e.options.query,headers:e.options.header,verbose:e.options.verbose>0,yes:e.options.yes,interactive:!!process.stdin.isTTY,onPaymentResults:e=>KF(e,n)}))switch(t.phase){case`discovery`:if(GF(`Discovery (/openapi.json)`),KF(t.results,n),l=t.discovery.found,!l&&!e.options.endpoint){console.log(``);let[e,...t]=wI.split(`
|
|
247
|
-
`);console.log(Z.yellow(` ${e}`));for(let e of t)console.log(e?Z.dim(` ${e}`):``);console.log(``),process.exit(1)}t.discovery.endpoints.length===0&&!e.options.endpoint&&l&&(console.log(Z.dim(` Use --endpoint to specify endpoints manually.`)),console.log(``),process.exit(1));break;case`endpoint`:u++,GF(`${t.endpoint.method} ${t.endpoint.path}`);break;case`challenge`:console.log(Z.dim(` Challenge`)),KF(t.results,n),t.isMpp&&(r=!0,t.isTestnet&&(o=!0),t.isMainnet&&(s=!0)),t.isNonMppPayment&&(i=!0),t.isMalformedChallenge&&(a=!0);break;case`errorHandling`:console.log(Z.dim(` Error Handling`)),KF(t.results,n);break;case`payment`:t.succeeded&&(c=!0)}JI(n,{sawMppEndpoint:r,sawNonMppPaymentEndpoint:i,sawMalformedChallenge:a,sawTestnet:o,sawMainnet:s,paymentSucceeded:c},u)}});function JI(e,t,n){!t.sawMppEndpoint&&n>0&&(console.log(``),t.sawMalformedChallenge?(console.log(Z.yellow(` Payment scheme detected but challenge format is invalid on ${n} endpoint(s).`)),console.log(Z.dim(` The server uses WWW-Authenticate: Payment but the challenge parameters do not conform to MPP.`)),console.log(Z.dim(` Fix: encode payment details as base64url JSON in a request="..." parameter. See errors above.`))):t.sawNonMppPaymentEndpoint?(console.log(Z.yellow(` No MPP endpoints found. Tested ${n} endpoint(s) but none use WWW-Authenticate: Payment.`)),console.log(Z.dim(` This server may use x402 or another payment protocol.`))):e.skipped>0&&e.failed===0?(console.log(Z.yellow(` Could not reach payment gate on any endpoint (all returned 401/403/200).`)),console.log(Z.dim(` The server may require authentication before payment. Try providing auth or use --endpoint with a public path.`))):(console.log(Z.yellow(` No MPP endpoints found. Tested ${n} endpoint(s) but none use WWW-Authenticate: Payment.`)),console.log(Z.dim(` This server may use x402 or another payment protocol.`))),console.log(``),process.exit(1)),console.log(``);let r=[];e.passed>0&&r.push(Z.green(`${e.passed} passed`)),e.failed>0&&r.push(Z.red(`${e.failed} failed`)),e.warnings>0&&r.push(Z.yellow(`${e.warnings} warning(s)`)),e.skipped>0&&r.push(Z.yellow(`${e.skipped} skipped`)),console.log(`${Z.bold(`Summary:`)} ${r.join(`, `)}`),t.paymentSucceeded&&t.sawTestnet&&!t.sawMainnet?(console.log(``),console.log(Z.dim(` Tip: also validate your mainnet server to confirm real payments work end-to-end.`))):t.sawMainnet&&!t.sawTestnet&&(console.log(``),console.log(Z.dim(` Tip: also validate your testnet server for free. This CLI automatically provisions and funds a testnet wallet for testing.`))),console.log(``),e.failed>0&&process.exit(1)}function YI(e){return ZI(e)?e.offers:[e]}function XI(e){let{_canonicalRequest:t,intent:n,name:r}=e,i=t.methodDetails??{},a=QI(t.amount)??QI(i.amount)??null,o=QI(t.currency)??QI(i.currency),s=QI(e.description)??QI(t.description),c={amount:a,...o?{currency:o}:{},...s?{description:s}:{},intent:n,method:r},l=new Set([`amount`,`currency`,`description`,`methodDetails`]);for(let[e,n]of Object.entries(t))!l.has(e)&&n!==void 0&&(c[e]=n);return c}function ZI(e){return`offers`in e&&!(`_canonicalRequest`in e)}function QI(e){return typeof e==`string`?e:void 0}var $I=I((()=>{})),eL=Ge({generate:()=>tL,generateProxy:()=>nL});function tL(e,t){let n=e.methods,r=new Map,i={};for(let e of n)r.set(`${e.name}/${e.intent}`,e),i[e.intent]=(i[e.intent]??0)+1;for(let e of n)i[e.intent]===1&&r.set(e.intent,e);let a=t.routes.map(e=>iL(e,r));return rL({info:{title:t.info?.title??e.realm,version:t.info?.version??`1.0.0`},routes:a,serviceInfo:t.serviceInfo})}function nL(e){let t=e.routes.map(t=>({...t,path:aL(e.basePath,t.path)}));return rL({info:{title:e.info?.title??`API Proxy`,version:e.info?.version??`1.0.0`},routes:t,serviceInfo:e.serviceInfo})}function rL(e){let t={};for(let n of e.routes){let e=n.method.toLowerCase(),r={responses:{...n.payment?{402:{description:`Payment Required`}}:{},200:{description:`Successful response`}}};n.payment&&(r[`x-payment-info`]=tT.parse(n.payment)),n.summary&&(r.summary=n.summary),n.requestBody&&(r.requestBody=n.requestBody),t[n.path]||(t[n.path]={}),t[n.path][e]=r}let n={info:e.info,openapi:`3.1.0`,paths:t};return e.serviceInfo&&(n[`x-service-info`]=e.serviceInfo),n}function iL(e,t){if(`handler`in e){let t=e.handler._internal;if(!t)throw Error(`Route ${e.method.toUpperCase()} ${e.path} is missing discovery metadata`);return{method:e.method,path:e.path,payment:{offers:YI(t).map(XI)},...e.requestBody?{requestBody:e.requestBody}:{},...e.summary?{summary:e.summary}:{}}}let n=t.get(e.intent);if(!n)throw Error(`Unknown intent "${e.intent}" for route ${e.method.toUpperCase()} ${e.path}. Available: ${[...t.keys()].join(`, `)}`);let{description:r,...i}=e.options,a={_canonicalRequest:fx(n,i),...typeof r==`string`?{description:r}:{},intent:n.intent,name:n.name};return{method:e.method,path:e.path,payment:XI(a),...e.requestBody?{requestBody:e.requestBody}:{},...e.summary?{summary:e.summary}:{}}}function aL(e,t){if(!e)return t;let n=e.startsWith(`/`)?e:`/${e}`;return`${n.endsWith(`/`)?n.slice(0,-1):n}${t}`}var oL=I((()=>{mx(),sT(),$I()}));rx(),Wx(),Nw(),ux(),xD(),hO(),tO();const sL=`0.8.18`,cL=f.object({address:f.string(),isDefault:f.boolean().optional(),name:f.string(),source:f.string().optional()}),lL=f.object({address:f.string(),balances:f.array(f.string()).optional(),name:f.string(),type:f.string().optional()}),uL=f.object({message:f.string(),path:f.string(),severity:f.string()}),dL=f.object({description:f.string().optional(),id:f.string(),name:f.string().optional(),paidEndpoints:f.number(),status:f.string().optional(),url:f.string().optional()}),fL=f.object({description:f.string().optional(),method:f.string(),path:f.string(),payment:f.unknown().optional()});function pL(e){return e.format===`json`&&e.formatExplicit}function mL(e,t,n){if(pL(e))return e.ok(t);n()}async function hL(e){process.stdout.write(Buffer.from(await e.arrayBuffer()))}function gL(){return process.stdin.isTTY===!1&&process.stdin.listenerCount(`data`)===0&&process.stdin.listenerCount(`readable`)===0}function _L(e){return typeof e==`string`?e:void 0}function vL(e){return Array.isArray(e.endpoints)?e.endpoints.filter(e=>typeof e==`object`&&!!e):[]}function yL(e){let t=vL(e);return{..._L(e.description)?{description:_L(e.description)}:{},id:_L(e.id)??_L(e.name)??`unknown`,..._L(e.name)?{name:_L(e.name)}:{},paidEndpoints:t.filter(e=>e.payment).length,..._L(e.status)?{status:_L(e.status)}:{},..._L(e.serviceUrl)||_L(e.url)?{url:_L(e.serviceUrl)??_L(e.url)}:{}}}function bL(e){return{..._L(e.description)?{description:_L(e.description)}:{},method:_L(e.method)??`GET`,path:_L(e.path)??`/`,...e.payment===void 0?{}:{payment:e.payment}}}function xL(e){if(!e)return`free`;if(typeof e!=`object`)return String(e);let t=e,n=_L(t.amount),r=_L(t.currency),i=_L(t.method),a=_L(t.intent);return[n,r,i&&a?`${i}/${a}`:i??a].filter(Boolean).join(` `)}function SL(e,t){if(!t)return[...e];let n=t.toLowerCase();return e.filter(e=>{let t=e.request.currency;return typeof t==`string`&&t.toLowerCase()===n})}async function CL(){let e=process.env.MPPX_SERVICES_URL??`https://mpp.dev/api/services`,t=await globalThis.fetch(e);if(!t.ok)throw new L({code:`SERVICES_FETCH_FAILED`,message:`Failed to fetch services registry: HTTP ${t.status}`,exitCode:1});let n=await t.json();if(!n||typeof n!=`object`||!Array.isArray(n.services))throw new L({code:`SERVICES_INVALID`,message:`Services registry response did not contain a services array.`,exitCode:1});return n.services}function wL(e,t){let n=t.toLowerCase();return e.find(e=>{let t=_L(e.id)?.toLowerCase(),r=_L(e.name)?.toLowerCase();return t===n||r===n})}const TL=Ky(`mppx`,{mcp:{tools:{discovery:`direct`}},version:sL,description:`Make HTTP requests with automatic payment handling`,usage:[{suffix:`<url> [options]`}],args:f.object({url:f.string().describe(`URL to make request to`)}),options:f.object({account:f.string().optional().describe(`Account name (env: MPPX_ACCOUNT)`),autoSwap:f.boolean().optional().describe(`Auto-swap source tokens into payment currency`),config:f.string().optional().describe(`Path to config file`),confirm:f.boolean().optional().default(!1).describe(`Show confirmation prompts`),currency:f.string().optional().describe(`Payment currency/token address to select`),data:f.string().optional().describe(`Send request body (implies POST unless -X is set)`),fail:f.boolean().optional().describe(`Fail silently on HTTP errors (exit 22)`),header:f.array(f.string()).optional().describe(`Add header (repeatable)`),include:f.boolean().optional().describe(`Include response headers in output`),insecure:f.boolean().optional().describe(`Skip TLS certificate verification (true for localhost/.local)`),jsonBody:f.string().optional().describe(`Send JSON body (sets Content-Type and Accept, implies POST)`),location:f.boolean().optional().describe(`Follow redirects`),method:f.string().optional().describe(`HTTP method`),methodOpt:f.array(f.string()).optional().describe(`Method-specific option (key=value, repeatable)`),network:f.enum([`mainnet`,`testnet`]).optional().describe(`Tempo network`),payWith:f.string().optional().describe(`Source token for Tempo auto-swap`),rpcUrl:f.string().optional().describe(`RPC endpoint, defaults to public RPC for chain (env: MPPX_RPC_URL)`),session:f.string().optional().default(`auto`).refine(e=>e===`auto`||e===`new`||/^0x[0-9a-fA-F]{64}$/.test(e),`Expected auto, new, or a 32-byte channel ID`).describe(`Session selection: auto, new, or channel ID`),silent:f.boolean().default(!1).describe(`Silent mode (suppress progress and info)`),slippage:f.number().optional().describe(`Tempo auto-swap max slippage percentage`),userAgent:f.string().optional().default(`mppx/${sL}`).describe(`Set User-Agent header`),verbose:f.number().default(0).meta({count:!0}).describe(`Verbosity (-v details, -vv headers)`)}),alias:{account:`a`,config:`c`,data:`d`,fail:`f`,header:`H`,include:`i`,insecure:`k`,jsonBody:`J`,location:`L`,method:`X`,methodOpt:`M`,rpcUrl:`r`,silent:`s`,userAgent:`A`,verbose:`v`},examples:[{args:{url:`mpp.dev/api/ping/paid`},description:`Make a payment request`}],async run(e){let t=e.options.silent?e=>{}:e=>process.stderr.write(e),n=await xP(e.options.config);n&&e.options.verbose>=1&&t(`${Z.dim(`Using config`)} ${Z.blue(s.relative(process.cwd(),n.path))}\n`);let r={"User-Agent":e.options.userAgent};if(e.options.header)for(let t of e.options.header){let n=t.indexOf(`:`);if(n===-1)return e.error({code:`INVALID_HEADER`,message:`Invalid header format: ${t}`,exitCode:2});r[t.slice(0,n).trim()]=t.slice(n+1).trim()}let i=vP(n?.config);i&&!Object.keys(r).some(e=>e.toLowerCase()===`accept-payment`)&&(r[`Accept-Payment`]=i);let a=(()=>{let t=/^https?:\/\//.test(e.args.url),n=/^(localhost|.*\.localhost|127\.0\.0\.1|\[::1\])(:\d+)?/.test(e.args.url);return t?e.args.url:`${n?`http`:`https`}://${e.args.url}`})(),{hostname:o}=new URL(a),c=e.options.insecure||o===`localhost`||o.endsWith(`.localhost`)||o.endsWith(`.local`)?async(e,t)=>{let n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;process.env.NODE_TLS_REJECT_UNAUTHORIZED=`0`;try{return await globalThis.fetch(e,t)}finally{n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n}}:globalThis.fetch,l=o.endsWith(`.localhost`)&&o!==`localhost`,u=l?a.replace(o,`127.0.0.1`):a;if(l){let{host:e}=new URL(a);r.Host=e}try{let i=FD(e.options.methodOpt),o=LP(),s={redirect:e.options.location?`follow`:`manual`};e.options.jsonBody?(s.body=e.options.jsonBody,r[`Content-Type`]??=`application/json`,r.Accept??=`application/json`):e.options.data&&(s.body=e.options.data),e.options.method?s.method=e.options.method.toUpperCase():s.body&&(s.method=`POST`),Object.keys(r).length>0&&(s.headers=r);let l={include:e.options.include??!1,verbose:e.options.verbose,silent:e.options.silent};e.options.verbose>=2&&kD(a,s,t);let d=await c(u,s);if(d.status!==402){if(e.options.session!==`auto`)return e.error({code:`UNSUPPORTED_SESSION`,message:`--session requires a tempo/session payment challenge.`,exitCode:2});if(e.options.fail&&d.status>=400)return e.error({code:`HTTP_ERROR`,message:`HTTP error ${d.status}`,exitCode:22});AD(d,l),await hL(d);return}let f=Lx(d),p=SL(f,e.options.currency);if(e.options.currency&&p.length===0){let t=f.map(e=>e.request.currency).filter(e=>typeof e==`string`).join(`, `);return e.error({code:`UNSUPPORTED_CURRENCY`,message:`Server did not offer payment currency ${e.options.currency}.${t?` Offered currencies: ${t}.`:``}`,exitCode:2})}let m=await LN(p,{options:{account:e.options.account,network:e.options.network,rpcUrl:e.options.rpcUrl}}),h=_P(m,n?.config);if(!h){let t=m.map(e=>`${e.method}/${e.intent}`).join(`, `);return e.error({code:`UNSUPPORTED_METHOD`,message:`Unsupported payment method. Server offers: ${t}. Add it to mppx.config.ts using defineConfig().`,exitCode:2})}let{challenge:g,plugin:_,method:v}=h,y=new Response(null,{status:402,headers:{[J.wwwAuthenticate]:Ox(g)}}),b=g.request.currency??``,x=g.request.decimals??6,S,C;_&&(C=await _.setup({challenge:g,options:{account:e.options.account,autoSwap:e.options.autoSwap,network:e.options.network,payWith:e.options.payWith,rpcUrl:e.options.rpcUrl,slippage:e.options.slippage},methodOpts:i}),b=C.tokenSymbol,x=C.tokenDecimals,S=C.explorerUrl);let w=!e.options.silent&&e.options.confirm,T=new Set;{AD(d,g.method===`tempo`&&g.intent===`session`&&e.options.include?{...l,include:!1,verbose:Math.max(l.verbose,2)}:l);let n=(()=>{let e=new Set([`id`,`request`]),t=[];for(let[n,r]of Object.entries(g))e.has(n)||r===void 0||t.push([n,ND(n,r)]);return t.sort(([e],[t])=>e.localeCompare(t))})(),r={tokenSymbol:b,tokenDecimals:x,explorerUrl:S},i=(()=>{let e=new Set([`decimals`,`currency`,`methodDetails`]),t=[];for(let[n,i]of Object.entries(g.request))e.has(n)||i===void 0||t.push([n,jD(n,i,r)]);return t.sort(([e],[t])=>e.localeCompare(t))})(),a=(()=>{let e=g.request.methodDetails;if(!e)return[];let t=[];for(let[n,i]of Object.entries(e))if(i!==void 0){if(n===`memo`&&typeof i==`string`){let e=MD(i);t.push([n,e?`${e}\n${Z.dim(i)}`:i])}else t.push([n,jD(n,i,r)])}return t.sort(([e],[t])=>e.localeCompare(t))})(),o=[[`Challenge`,n],[`Request`,i],...a.length?[[`Details`,a]]:[]];for(let[,e]of o)for(let[t]of e)T.add(t);let s=Math.max(...o.flatMap(([,e])=>e.map(([e])=>e.length))),c=` ${``.padEnd(s)} `;if(e.options.verbose>=1||w){t(`${Z.bold(Z.yellow(`Payment Required`))}\n`);for(let[e,n]of o){t(`${Z.bold(e)}\n`);for(let[e,r]of n){let[n,...i]=r.split(`
|
|
247
|
+
`);console.log(Z.yellow(` ${e}`));for(let e of t)console.log(e?Z.dim(` ${e}`):``);console.log(``),process.exit(1)}t.discovery.endpoints.length===0&&!e.options.endpoint&&l&&(console.log(Z.dim(` Use --endpoint to specify endpoints manually.`)),console.log(``),process.exit(1));break;case`endpoint`:u++,GF(`${t.endpoint.method} ${t.endpoint.path}`);break;case`challenge`:console.log(Z.dim(` Challenge`)),KF(t.results,n),t.isMpp&&(r=!0,t.isTestnet&&(o=!0),t.isMainnet&&(s=!0)),t.isNonMppPayment&&(i=!0),t.isMalformedChallenge&&(a=!0);break;case`errorHandling`:console.log(Z.dim(` Error Handling`)),KF(t.results,n);break;case`payment`:t.succeeded&&(c=!0)}JI(n,{sawMppEndpoint:r,sawNonMppPaymentEndpoint:i,sawMalformedChallenge:a,sawTestnet:o,sawMainnet:s,paymentSucceeded:c},u)}});function JI(e,t,n){!t.sawMppEndpoint&&n>0&&(console.log(``),t.sawMalformedChallenge?(console.log(Z.yellow(` Payment scheme detected but challenge format is invalid on ${n} endpoint(s).`)),console.log(Z.dim(` The server uses WWW-Authenticate: Payment but the challenge parameters do not conform to MPP.`)),console.log(Z.dim(` Fix: encode payment details as base64url JSON in a request="..." parameter. See errors above.`))):t.sawNonMppPaymentEndpoint?(console.log(Z.yellow(` No MPP endpoints found. Tested ${n} endpoint(s) but none use WWW-Authenticate: Payment.`)),console.log(Z.dim(` This server may use x402 or another payment protocol.`))):e.skipped>0&&e.failed===0?(console.log(Z.yellow(` Could not reach payment gate on any endpoint (all returned 401/403/200).`)),console.log(Z.dim(` The server may require authentication before payment. Try providing auth or use --endpoint with a public path.`))):(console.log(Z.yellow(` No MPP endpoints found. Tested ${n} endpoint(s) but none use WWW-Authenticate: Payment.`)),console.log(Z.dim(` This server may use x402 or another payment protocol.`))),console.log(``),process.exit(1)),console.log(``);let r=[];e.passed>0&&r.push(Z.green(`${e.passed} passed`)),e.failed>0&&r.push(Z.red(`${e.failed} failed`)),e.warnings>0&&r.push(Z.yellow(`${e.warnings} warning(s)`)),e.skipped>0&&r.push(Z.yellow(`${e.skipped} skipped`)),console.log(`${Z.bold(`Summary:`)} ${r.join(`, `)}`),t.paymentSucceeded&&t.sawTestnet&&!t.sawMainnet?(console.log(``),console.log(Z.dim(` Tip: also validate your mainnet server to confirm real payments work end-to-end.`))):t.sawMainnet&&!t.sawTestnet&&(console.log(``),console.log(Z.dim(` Tip: also validate your testnet server for free. This CLI automatically provisions and funds a testnet wallet for testing.`))),console.log(``),e.failed>0&&process.exit(1)}function YI(e){return ZI(e)?e.offers:[e]}function XI(e){let{_canonicalRequest:t,intent:n,name:r}=e,i=t.methodDetails??{},a=QI(t.amount)??QI(i.amount)??null,o=QI(t.currency)??QI(i.currency),s=QI(e.description)??QI(t.description),c={amount:a,...o?{currency:o}:{},...s?{description:s}:{},intent:n,method:r},l=new Set([`amount`,`currency`,`description`,`methodDetails`]);for(let[e,n]of Object.entries(t))!l.has(e)&&n!==void 0&&(c[e]=n);return c}function ZI(e){return`offers`in e&&!(`_canonicalRequest`in e)}function QI(e){return typeof e==`string`?e:void 0}var $I=I((()=>{})),eL=Ge({generate:()=>tL,generateProxy:()=>nL});function tL(e,t){let n=e.methods,r=new Map,i={};for(let e of n)r.set(`${e.name}/${e.intent}`,e),i[e.intent]=(i[e.intent]??0)+1;for(let e of n)i[e.intent]===1&&r.set(e.intent,e);let a=t.routes.map(e=>iL(e,r));return rL({info:{title:t.info?.title??e.realm,version:t.info?.version??`1.0.0`},routes:a,serviceInfo:t.serviceInfo})}function nL(e){let t=e.routes.map(t=>({...t,path:aL(e.basePath,t.path)}));return rL({info:{title:e.info?.title??`API Proxy`,version:e.info?.version??`1.0.0`},routes:t,serviceInfo:e.serviceInfo})}function rL(e){let t={};for(let n of e.routes){let e=n.method.toLowerCase(),r={responses:{...n.payment?{402:{description:`Payment Required`}}:{},200:{description:`Successful response`}}};n.payment&&(r[`x-payment-info`]=tT.parse(n.payment)),n.summary&&(r.summary=n.summary),n.requestBody&&(r.requestBody=n.requestBody),t[n.path]||(t[n.path]={}),t[n.path][e]=r}let n={info:e.info,openapi:`3.1.0`,paths:t};return e.serviceInfo&&(n[`x-service-info`]=e.serviceInfo),n}function iL(e,t){if(`handler`in e){let t=e.handler._internal;if(!t)throw Error(`Route ${e.method.toUpperCase()} ${e.path} is missing discovery metadata`);return{method:e.method,path:e.path,payment:{offers:YI(t).map(XI)},...e.requestBody?{requestBody:e.requestBody}:{},...e.summary?{summary:e.summary}:{}}}let n=t.get(e.intent);if(!n)throw Error(`Unknown intent "${e.intent}" for route ${e.method.toUpperCase()} ${e.path}. Available: ${[...t.keys()].join(`, `)}`);let{description:r,...i}=e.options,a={_canonicalRequest:fx(n,i),...typeof r==`string`?{description:r}:{},intent:n.intent,name:n.name};return{method:e.method,path:e.path,payment:XI(a),...e.requestBody?{requestBody:e.requestBody}:{},...e.summary?{summary:e.summary}:{}}}function aL(e,t){if(!e)return t;let n=e.startsWith(`/`)?e:`/${e}`;return`${n.endsWith(`/`)?n.slice(0,-1):n}${t}`}var oL=I((()=>{mx(),sT(),$I()}));rx(),Wx(),Nw(),ux(),xD(),hO(),tO();const sL=`0.8.19`,cL=f.object({address:f.string(),isDefault:f.boolean().optional(),name:f.string(),source:f.string().optional()}),lL=f.object({address:f.string(),balances:f.array(f.string()).optional(),name:f.string(),type:f.string().optional()}),uL=f.object({message:f.string(),path:f.string(),severity:f.string()}),dL=f.object({description:f.string().optional(),id:f.string(),name:f.string().optional(),paidEndpoints:f.number(),status:f.string().optional(),url:f.string().optional()}),fL=f.object({description:f.string().optional(),method:f.string(),path:f.string(),payment:f.unknown().optional()});function pL(e){return e.format===`json`&&e.formatExplicit}function mL(e,t,n){if(pL(e))return e.ok(t);n()}async function hL(e){process.stdout.write(Buffer.from(await e.arrayBuffer()))}function gL(){return process.stdin.isTTY===!1&&process.stdin.listenerCount(`data`)===0&&process.stdin.listenerCount(`readable`)===0}function _L(e){return typeof e==`string`?e:void 0}function vL(e){return Array.isArray(e.endpoints)?e.endpoints.filter(e=>typeof e==`object`&&!!e):[]}function yL(e){let t=vL(e);return{..._L(e.description)?{description:_L(e.description)}:{},id:_L(e.id)??_L(e.name)??`unknown`,..._L(e.name)?{name:_L(e.name)}:{},paidEndpoints:t.filter(e=>e.payment).length,..._L(e.status)?{status:_L(e.status)}:{},..._L(e.serviceUrl)||_L(e.url)?{url:_L(e.serviceUrl)??_L(e.url)}:{}}}function bL(e){return{..._L(e.description)?{description:_L(e.description)}:{},method:_L(e.method)??`GET`,path:_L(e.path)??`/`,...e.payment===void 0?{}:{payment:e.payment}}}function xL(e){if(!e)return`free`;if(typeof e!=`object`)return String(e);let t=e,n=_L(t.amount),r=_L(t.currency),i=_L(t.method),a=_L(t.intent);return[n,r,i&&a?`${i}/${a}`:i??a].filter(Boolean).join(` `)}function SL(e,t){if(!t)return[...e];let n=t.toLowerCase();return e.filter(e=>{let t=e.request.currency;return typeof t==`string`&&t.toLowerCase()===n})}async function CL(){let e=process.env.MPPX_SERVICES_URL??`https://mpp.dev/api/services`,t=await globalThis.fetch(e);if(!t.ok)throw new L({code:`SERVICES_FETCH_FAILED`,message:`Failed to fetch services registry: HTTP ${t.status}`,exitCode:1});let n=await t.json();if(!n||typeof n!=`object`||!Array.isArray(n.services))throw new L({code:`SERVICES_INVALID`,message:`Services registry response did not contain a services array.`,exitCode:1});return n.services}function wL(e,t){let n=t.toLowerCase();return e.find(e=>{let t=_L(e.id)?.toLowerCase(),r=_L(e.name)?.toLowerCase();return t===n||r===n})}const TL=Ky(`mppx`,{mcp:{tools:{discovery:`direct`}},version:sL,description:`Make HTTP requests with automatic payment handling`,usage:[{suffix:`<url> [options]`}],args:f.object({url:f.string().describe(`URL to make request to`)}),options:f.object({account:f.string().optional().describe(`Account name (env: MPPX_ACCOUNT)`),autoSwap:f.boolean().optional().describe(`Auto-swap source tokens into payment currency`),config:f.string().optional().describe(`Path to config file`),confirm:f.boolean().optional().default(!1).describe(`Show confirmation prompts`),currency:f.string().optional().describe(`Payment currency/token address to select`),data:f.string().optional().describe(`Send request body (implies POST unless -X is set)`),fail:f.boolean().optional().describe(`Fail silently on HTTP errors (exit 22)`),header:f.array(f.string()).optional().describe(`Add header (repeatable)`),include:f.boolean().optional().describe(`Include response headers in output`),insecure:f.boolean().optional().describe(`Skip TLS certificate verification (true for localhost/.local)`),jsonBody:f.string().optional().describe(`Send JSON body (sets Content-Type and Accept, implies POST)`),location:f.boolean().optional().describe(`Follow redirects`),method:f.string().optional().describe(`HTTP method`),methodOpt:f.array(f.string()).optional().describe(`Method-specific option (key=value, repeatable)`),network:f.enum([`mainnet`,`testnet`]).optional().describe(`Tempo network`),payWith:f.string().optional().describe(`Source token for Tempo auto-swap`),rpcUrl:f.string().optional().describe(`RPC endpoint, defaults to public RPC for chain (env: MPPX_RPC_URL)`),session:f.string().optional().default(`auto`).refine(e=>e===`auto`||e===`new`||/^0x[0-9a-fA-F]{64}$/.test(e),`Expected auto, new, or a 32-byte channel ID`).describe(`Session selection: auto, new, or channel ID`),silent:f.boolean().default(!1).describe(`Silent mode (suppress progress and info)`),slippage:f.number().optional().describe(`Tempo auto-swap max slippage percentage`),userAgent:f.string().optional().default(`mppx/${sL}`).describe(`Set User-Agent header`),verbose:f.number().default(0).meta({count:!0}).describe(`Verbosity (-v details, -vv headers)`)}),alias:{account:`a`,config:`c`,data:`d`,fail:`f`,header:`H`,include:`i`,insecure:`k`,jsonBody:`J`,location:`L`,method:`X`,methodOpt:`M`,rpcUrl:`r`,silent:`s`,userAgent:`A`,verbose:`v`},examples:[{args:{url:`mpp.dev/api/ping/paid`},description:`Make a payment request`}],async run(e){let t=e.options.silent?e=>{}:e=>process.stderr.write(e),n=await xP(e.options.config);n&&e.options.verbose>=1&&t(`${Z.dim(`Using config`)} ${Z.blue(s.relative(process.cwd(),n.path))}\n`);let r={"User-Agent":e.options.userAgent};if(e.options.header)for(let t of e.options.header){let n=t.indexOf(`:`);if(n===-1)return e.error({code:`INVALID_HEADER`,message:`Invalid header format: ${t}`,exitCode:2});r[t.slice(0,n).trim()]=t.slice(n+1).trim()}let i=vP(n?.config);i&&!Object.keys(r).some(e=>e.toLowerCase()===`accept-payment`)&&(r[`Accept-Payment`]=i);let a=(()=>{let t=/^https?:\/\//.test(e.args.url),n=/^(localhost|.*\.localhost|127\.0\.0\.1|\[::1\])(:\d+)?/.test(e.args.url);return t?e.args.url:`${n?`http`:`https`}://${e.args.url}`})(),{hostname:o}=new URL(a),c=e.options.insecure||o===`localhost`||o.endsWith(`.localhost`)||o.endsWith(`.local`)?async(e,t)=>{let n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;process.env.NODE_TLS_REJECT_UNAUTHORIZED=`0`;try{return await globalThis.fetch(e,t)}finally{n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n}}:globalThis.fetch,l=o.endsWith(`.localhost`)&&o!==`localhost`,u=l?a.replace(o,`127.0.0.1`):a;if(l){let{host:e}=new URL(a);r.Host=e}try{let i=FD(e.options.methodOpt),o=LP(),s={redirect:e.options.location?`follow`:`manual`};e.options.jsonBody?(s.body=e.options.jsonBody,r[`Content-Type`]??=`application/json`,r.Accept??=`application/json`):e.options.data&&(s.body=e.options.data),e.options.method?s.method=e.options.method.toUpperCase():s.body&&(s.method=`POST`),Object.keys(r).length>0&&(s.headers=r);let l={include:e.options.include??!1,verbose:e.options.verbose,silent:e.options.silent};e.options.verbose>=2&&kD(a,s,t);let d=await c(u,s);if(d.status!==402){if(e.options.session!==`auto`)return e.error({code:`UNSUPPORTED_SESSION`,message:`--session requires a tempo/session payment challenge.`,exitCode:2});if(e.options.fail&&d.status>=400)return e.error({code:`HTTP_ERROR`,message:`HTTP error ${d.status}`,exitCode:22});AD(d,l),await hL(d);return}let f=Lx(d),p=SL(f,e.options.currency);if(e.options.currency&&p.length===0){let t=f.map(e=>e.request.currency).filter(e=>typeof e==`string`).join(`, `);return e.error({code:`UNSUPPORTED_CURRENCY`,message:`Server did not offer payment currency ${e.options.currency}.${t?` Offered currencies: ${t}.`:``}`,exitCode:2})}let m=await LN(p,{options:{account:e.options.account,network:e.options.network,rpcUrl:e.options.rpcUrl}}),h=_P(m,n?.config);if(!h){let t=m.map(e=>`${e.method}/${e.intent}`).join(`, `);return e.error({code:`UNSUPPORTED_METHOD`,message:`Unsupported payment method. Server offers: ${t}. Add it to mppx.config.ts using defineConfig().`,exitCode:2})}let{challenge:g,plugin:_,method:v}=h,y=new Response(null,{status:402,headers:{[J.wwwAuthenticate]:Ox(g)}}),b=g.request.currency??``,x=g.request.decimals??6,S,C;_&&(C=await _.setup({challenge:g,options:{account:e.options.account,autoSwap:e.options.autoSwap,network:e.options.network,payWith:e.options.payWith,rpcUrl:e.options.rpcUrl,slippage:e.options.slippage},methodOpts:i}),b=C.tokenSymbol,x=C.tokenDecimals,S=C.explorerUrl);let w=!e.options.silent&&e.options.confirm,T=new Set;{AD(d,g.method===`tempo`&&g.intent===`session`&&e.options.include?{...l,include:!1,verbose:Math.max(l.verbose,2)}:l);let n=(()=>{let e=new Set([`id`,`request`]),t=[];for(let[n,r]of Object.entries(g))e.has(n)||r===void 0||t.push([n,ND(n,r)]);return t.sort(([e],[t])=>e.localeCompare(t))})(),r={tokenSymbol:b,tokenDecimals:x,explorerUrl:S},i=(()=>{let e=new Set([`decimals`,`currency`,`methodDetails`]),t=[];for(let[n,i]of Object.entries(g.request))e.has(n)||i===void 0||t.push([n,jD(n,i,r)]);return t.sort(([e],[t])=>e.localeCompare(t))})(),a=(()=>{let e=g.request.methodDetails;if(!e)return[];let t=[];for(let[n,i]of Object.entries(e))if(i!==void 0){if(n===`memo`&&typeof i==`string`){let e=MD(i);t.push([n,e?`${e}\n${Z.dim(i)}`:i])}else t.push([n,jD(n,i,r)])}return t.sort(([e],[t])=>e.localeCompare(t))})(),o=[[`Challenge`,n],[`Request`,i],...a.length?[[`Details`,a]]:[]];for(let[,e]of o)for(let[t]of e)T.add(t);let s=Math.max(...o.flatMap(([,e])=>e.map(([e])=>e.length))),c=` ${``.padEnd(s)} `;if(e.options.verbose>=1||w){t(`${Z.bold(Z.yellow(`Payment Required`))}\n`);for(let[e,n]of o){t(`${Z.bold(e)}\n`);for(let[e,r]of n){let[n,...i]=r.split(`
|
|
248
248
|
`);t(` ${Z.dim(e.padEnd(s))} ${n}\n`);for(let e of i)t(`${c}${e}\n`)}}}if(w&&(t(`
|
|
249
249
|
`),!await zD(`Proceed with ${g.intent}?`,!0))){t(`Aborted.
|
|
250
250
|
`);return}}let ee=process.env.MPPX_PRIVATE_KEY?.trim()||!LD(cO(e.options.account));if(BE(g)&&ee){try{await zF({challenge:g,challengeResponse:y,endpoint:a,fetch:c,fetchInput:u,init:s,info:t,methodOptions:i,options:{account:e.options.account,fail:e.options.fail,include:e.options.include,network:e.options.network,rpcUrl:e.options.rpcUrl,session:e.options.session,silent:e.options.silent,verbose:e.options.verbose},registry:o})}catch(e){return DF(e,`SESSION_REQUEST_FAILED`)}return}if(e.options.session!==`auto`)return e.error({code:`UNSUPPORTED_SESSION`,message:`--session requires a tempo/session payment challenge.`,exitCode:2});let D;if(C?.createCredential)D=await C.createCredential(y);else if(C)D=await Lw({methods:C.methods,polyfill:!1}).createCredential(y,C.credentialContext);else if(v)D=await Lw({methods:[v],polyfill:!1}).createCredential(y);else throw Error(`unreachable`);let O={...YC(s.headers),Authorization:D};_?.prepareCredentialRequest?.({challenge:g,credential:D,headers:O});let k={...s,headers:O};e.options.verbose>=2&&kD(a,k,t);let te=await c(u,k);if(e.options.fail&&te.status>=400)return e.error({code:`HTTP_ERROR`,message:`HTTP error ${te.status}`,exitCode:22});if(te.status===402){let n=await te.text();t(`${Z.bold(Z.red(`Payment Rejected`))}\n`);try{let e=JSON.parse(n),r=[];for(let[t,n]of Object.entries(e))n!==void 0&&r.push([t,String(n)]);r.sort(([e],[t])=>e.localeCompare(t));let i=Math.max(...r.map(([e])=>e.length));for(let[e,n]of r)t(` ${Z.dim(e.padEnd(i))} ${n}\n`)}catch{n&&t(` ${n}\n`)}return e.error({code:`PAYMENT_REJECTED`,message:`Payment rejected`,exitCode:75})}if(AD(te,l),!await _?.handleResponse?.({challenge:g,credential:D,response:te,fetchUrl:u,fetchInit:s,silent:e.options.silent,verbose:e.options.verbose,confirmEnabled:w,confirm:zD,tokenSymbol:b,tokenDecimals:x,explorerUrl:S,shownKeys:T})){let n=te.headers.get(J.paymentReceipt);if(n&&e.options.verbose>=1)try{let e=JSON.parse(E.toString(n));t(`\n${Z.bold(Z.green(`Payment Receipt`))}\n`);let r=[],i=e.channelId,a=e.reference,o=i&&a&&i===a,s=new Set([`acceptedCumulative`,`spent`]);for(let[t,n]of Object.entries(e)){if(n===void 0||T.has(t)||t===`reference`&&o)continue;let e=_?.formatReceiptField?.(t,n);e===void 0?s.has(t)&&typeof n==`string`?r.push([t,`${n} ${Z.dim(`(${BD(BigInt(n),b,x)})`)}`]):(t===`reference`||t===`txHash`)&&typeof n==`string`&&S?r.push([t,PD(`${S}/tx/${n}`,n)]):r.push([t,String(n)]):r.push([t,e])}r.sort(([e],[t])=>e.localeCompare(t));let c=Math.max(...r.map(([e])=>e.length));for(let[e,n]of r)t(` ${Z.dim(e.padEnd(c))} ${n}\n`);t(`
|