@mixrpay/agent-sdk 0.11.3 → 0.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ yarn add @mixrpay/agent-sdk
|
|
|
12
12
|
pnpm add @mixrpay/agent-sdk
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
The CLI binary is `mixrpay`, but the package name is **`@mixrpay/agent-sdk`**. Bare `npx mixrpay` can resolve to a different package on npm—use **`npx --package @mixrpay/agent-sdk mixrpay …`** for one-off runs, or **`npm install -g @mixrpay/agent-sdk`** so `mixrpay` is on your `PATH`.
|
|
16
|
+
|
|
15
17
|
## Getting Started
|
|
16
18
|
|
|
17
19
|
MixrPay lets your AI agents use real non-custodial wallets with micropayment capabilities on Base and Solana.
|
|
@@ -19,7 +21,7 @@ MixrPay lets your AI agents use real non-custodial wallets with micropayment cap
|
|
|
19
21
|
#### Option 1: Quick Start (Recommended)
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
|
-
npx mixrpay init --name "MyAgent"
|
|
24
|
+
npx --package @mixrpay/agent-sdk mixrpay init --name "MyAgent"
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
This sets up your agent and wallet locally. Fund with USDC on Base (or use an invite code) before using paid tools.
|
|
@@ -31,8 +33,9 @@ For a guided experience (especially useful when working inside Cursor or Claude)
|
|
|
31
33
|
Follow the steps to get your agent credentials, then run:
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
|
-
npx mixrpay install
|
|
35
|
-
mixrpay status
|
|
36
|
+
npx --package @mixrpay/agent-sdk mixrpay install
|
|
37
|
+
npx --package @mixrpay/agent-sdk mixrpay status
|
|
38
|
+
# or: npm i -g @mixrpay/agent-sdk then mixrpay install && mixrpay status
|
|
36
39
|
```
|
|
37
40
|
|
|
38
41
|
Your agent is then ready to use with `mixrpay run` or via the SDK.
|
|
@@ -203,16 +206,16 @@ for (const block of response.content) {
|
|
|
203
206
|
## MCP Server (Standalone)
|
|
204
207
|
|
|
205
208
|
```bash
|
|
206
|
-
MIXRPAY_API_KEY=agt_live_... npx mixrpay-mcp
|
|
209
|
+
MIXRPAY_API_KEY=agt_live_... npx --package @mixrpay/agent-sdk mixrpay-mcp
|
|
207
210
|
```
|
|
208
211
|
|
|
209
212
|
## CLI
|
|
210
213
|
|
|
211
214
|
```bash
|
|
212
|
-
npx mixrpay login
|
|
213
|
-
npx mixrpay whoami
|
|
214
|
-
npx mixrpay status
|
|
215
|
-
npx mixrpay logout
|
|
215
|
+
npx --package @mixrpay/agent-sdk mixrpay login
|
|
216
|
+
npx --package @mixrpay/agent-sdk mixrpay whoami
|
|
217
|
+
npx --package @mixrpay/agent-sdk mixrpay status
|
|
218
|
+
npx --package @mixrpay/agent-sdk mixrpay logout
|
|
216
219
|
```
|
|
217
220
|
|
|
218
221
|
## Error Handling
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export{g as AgentWallet,c as DEFAULT_BASE_URL,d as DEFAULT_FACILITATOR_URL,e as DEFAULT_TIMEOUT,f as NETWORKS,b as SDK_VERSION}from'./chunk-
|
|
2
|
+
export{g as AgentWallet,c as DEFAULT_BASE_URL,d as DEFAULT_FACILITATOR_URL,e as DEFAULT_TIMEOUT,f as NETWORKS,b as SDK_VERSION}from'./chunk-TOPWZWOK.js';
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {fileURLToPath}from'url';import {join,dirname}from'path';import {privateKeyToAccount,signMessage,generatePrivateKey,signTypedData}from'viem/accounts';import {z as z$1}from'zod';import {createWalletClient,http,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';import {existsSync,readFileSync,mkdirSync,writeFileSync,chmodSync}from'fs';import {homedir}from'os';var l=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},v=class extends l{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},R=class extends l{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},T=class extends l{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,i=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${i}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},A=class extends l{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},x=class extends l{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},P=class extends l{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},D=class extends l{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},U=class extends l{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},I=class extends l{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},C=class extends l{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},E=class extends l{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}};var Se={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},xe={name:"USD Coin",version:"2"},Ae={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},O=class c{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new x("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let i=`0x${a}`;return new c(i,n==="test")}catch(i){throw new x(`Failed to decode session key: ${i}`)}}async signTransferAuthorization(e,t){return signTypedData({privateKey:this.privateKey,domain:e,types:Ae,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function q(c){let e=Se[c.chainId];if(!e)throw new Error(`USDC not supported on chain ${c.chainId}`);let t={...xe,chainId:c.chainId,verifyingContract:e},s={from:c.fromAddress,to:c.toAddress,value:c.value,validAfter:c.validAfter,validBefore:c.validBefore,nonce:c.nonce};return {domain:t,message:s}}function j(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function ke(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function B(c){let e=Date.now(),t=ke(e,c.address),s=await c.signMessage(t);return {address:c.address,timestamp:e,signature:s}}var J=z$1.object({query:z$1.string().describe('Search query (e.g. "web scraping", "email", "database")')}),G=z$1.object({tool_name:z$1.string().describe('Tool name in "merchant/tool" format'),arguments:z$1.record(z$1.unknown()).optional().describe("Arguments to pass to the tool")}),X=z$1.object({url:z$1.string().url().describe("The merchant API URL to call"),merchant_public_key:z$1.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:z$1.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:z$1.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:z$1.number().optional().describe("Expected price in USD for client-side validation")}),z=z$1.object({skill_id:z$1.string().describe("The skill ID to execute"),input:z$1.record(z$1.unknown()).optional().describe("Input parameters for the skill")}),Y=z$1.object({skill_id:z$1.string().describe("The skill ID to check")}),V=z$1.object({glama_id:z$1.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:z$1.string().describe('Glama namespace (e.g. "notion")'),glama_slug:z$1.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:z$1.string().describe("Human-readable name for the tool"),tool_description:z$1.string().optional().describe("Optional description"),env_vars:z$1.record(z$1.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:z$1.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),Z=z$1.object({status:z$1.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),Q=z$1.object({instance_id:z$1.string().describe("The instance ID to stop")}),ee=z$1.object({to:z$1.string().describe("Recipient address (0x...)"),amount_usdc:z$1.number().positive().describe("Amount in USDC (e.g. 10.5)")}),te=z$1.object({name:z$1.string().describe("Name for the child agent"),budget_usd:z$1.number().positive().describe("Budget to delegate in USD"),budget_period:z$1.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:z$1.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:z$1.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),se=z$1.object({title:z$1.string().describe("Task title"),description:z$1.string().describe("Detailed task description"),budget_usd:z$1.number().positive().describe("Budget for the task in USD"),skills_required:z$1.array(z$1.string()).optional().describe("Required skill IDs")}),ne=z$1.object({status:z$1.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:z$1.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function ae(c){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await c.getBalance(),network:c.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:J,handler:async s=>{let{query:n}=J.parse(s);return c.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:G,handler:async s=>{let{tool_name:n,arguments:a}=G.parse(s);return c.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:X,handler:async s=>{let{url:n,merchant_public_key:a,method:i,body:r,price_usd:o}=X.parse(s),d=await c.callMerchantApi({url:n,merchantPublicKey:a,method:i,body:r,priceUsd:o}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:z,handler:async s=>{let{skill_id:n,input:a}=z.parse(s);return c.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:Y,handler:async s=>{let{skill_id:n}=Y.parse(s);return c.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:V,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:i,tool_name:r,tool_description:o,env_vars:d,ttl_hours:g}=V.parse(s);return c.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:i,toolName:r,toolDescription:o,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:Z,handler:async s=>{let{status:n}=Z.parse(s);return c.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:Q,handler:async s=>{let{instance_id:n}=Q.parse(s);return await c.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:ee,handler:async s=>{let{to:n,amount_usdc:a}=ee.parse(s);if(!await c.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await c.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:te,handler:async s=>{let{name:n,budget_usd:a,budget_period:i,max_per_tx_usd:r,expires_in_days:o}=te.parse(s);return c.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:i,maxPerTxUsd:r,expiresInDays:o})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:se,handler:async s=>{let{title:n,description:a,budget_usd:i,skills_required:r}=se.parse(s);return c.createTask({title:n,description:a,budgetUsd:i,skillsRequired:r})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:ne,handler:async s=>{let{status:n,limit:a}=ne.parse(s);return c.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(i=>i.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let i=await a.handler(n);return JSON.stringify(i,null,2)}catch(i){let r=i instanceof Error?i.message:String(i);throw new Error(r)}}}}function ie(c){if(c instanceof z$1.ZodObject){let e=c._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let i=a;t[n]=K(i),!(i instanceof z$1.ZodOptional)&&!(i instanceof z$1.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function K(c){let e=c;e instanceof z$1.ZodOptional&&(e=e._def.innerType),e instanceof z$1.ZodDefault&&(e=e._def.innerType);let t=c._def.description;if(e instanceof z$1.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof z$1.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof z$1.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof z$1.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof z$1.ZodArray)return {type:"array",items:K(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:K(e._def.valueType),...t&&{description:t}};if(e instanceof z$1.ZodObject){let s=e._def.shape(),n={};for(let[a,i]of Object.entries(s))n[a]=K(i);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ce="0.9.5",re=".config/mixrpay",$e="wallet.json";function oe(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,re):join(homedir(),re)}function N(){return join(oe(),$e)}async function le(c,e){let t=oe(),s=N();existsSync(t)||mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:c,createdAt:new Date().toISOString(),sdkVersion:Ce};writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{chmodSync(s,384);}catch{}}async function L(){let c=process.env.MIXRPAY_WALLET_KEY;if(c){if(c.startsWith("0x")&&c.length===66)return c;if(c.length===64)return `0x${c}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=N();if(!existsSync(e))return null;try{let t=readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function ce(){let c=process.env.MIXRPAY_WALLET_KEY;return c&&(c.length===64||c.startsWith("0x")&&c.length===66)?true:existsSync(N())}async function de(c){let e=null,t=c.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=c.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await c.json();}catch{}if(!e)throw new P("Could not parse payment requirements from 402 response");if(!e.recipient)throw new P("Missing recipient in payment requirements");if(!e.amount)throw new P("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||j().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function ue(c,e,t){let s=c.nonce.length===64?`0x${c.nonce}`:j(),a=BigInt(Math.floor(Date.now()/1e3))-60n,i=BigInt(c.expiresAt),{domain:r,message:o}=q({fromAddress:t,toAddress:c.recipient,value:c.amount,validAfter:a,validBefore:i,nonce:s,chainId:c.chainId}),d=await e.signTransferAuthorization(r,o),g={x402Version:1,scheme:"exact",network:c.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:c.recipient,value:c.amount.toString(),validAfter:a.toString(),validBefore:i.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function ge(c){return Date.now()/1e3>c.expiresAt}function F(c){return Number(c.amount)/1e6}var Ne="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://mixr.network",gt="https://x402.org/facilitator",Le=3e4,me={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},he={debug:0,info:1,warn:2,error:3,none:4},W=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return he[e]>=he[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},ye=class c{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=O.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||_).replace(/\/$/,""),this.timeout=e.timeout||Le,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new W(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new x("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new x(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new x(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new x("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new l("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new E(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let i=a.substring(2);if(s.endsWith(`.${i}`)&&s!==i)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(t).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=register`);if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:i,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),b="";u.status===503?b=" The service may be temporarily unavailable. Please try again later.":u.status===500?b=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(b=" This may indicate an SDK bug. Please update to the latest version.");let $=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l($)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||_).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:i}=e,r=(e.baseUrl||_).replace(/\/$/,""),d=privateKeyToAccount(t).address,g=await fetch(`${r}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new l(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await signMessage({message:p,privateKey:t}),f=await fetch(`${r}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:i})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new l(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||_).replace(/\/$/,""),a=privateKeyToAccount(t).address,i=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:r,message:o}=await i.json(),d=await signMessage({message:o,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${r}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new l(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(t).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=revoke`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:i,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new l(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(t).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=withdraw`);if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:i,signature:g,to_address:i,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(s).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=claim-invite`);if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:o,agent_wallet_address:i,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new l(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||_).replace(/\/$/,""),n=new c({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),i=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!i.ok){let o=await i.json().catch(()=>({}));throw new l(o.error||`Activation failed: ${i.status}`)}let r=await i.json();return {wallet:n,budget:{maxTotalUsd:r.budget.max_total_usd,maxDailyUsd:r.budget.max_daily_usd,maxPerTxUsd:r.budget.max_per_tx_usd,spentUsd:r.budget.spent_usd,remainingUsd:r.budget.remaining_usd},capabilities:{executeTransactions:r.capabilities.execute_transactions,gasSponsored:r.capabilities.gas_sponsored,batchedTx:r.capabilities.batched_tx},skills:r.skills||[],tools:r.tools||[],gatewayProviders:r.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||_).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new c({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new c({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let i=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(i&&(i.startsWith("agt_live_")||i.startsWith("agt_test_")))return c.fromApiKey(i,{baseUrl:t,logLevel:s});let r=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(r)return c.fromAccessCode(r,{baseUrl:t,logLevel:s});let o=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(o&&d)return c.fromMasterKey(o,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await import('./credentials-ILS4YAGF.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return c.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return c.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return c.deviceFlowLogin({baseUrl:t,logLevel:s});throw new l(`No MixrPay credentials found. Options:
|
|
3
|
-
1. Set MIXRPAY_SESSION_KEY environment variable
|
|
4
|
-
2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)
|
|
5
|
-
3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)
|
|
6
|
-
4. Pass sessionKey or accessCode to connect()
|
|
7
|
-
5. Run \`npx mixrpay login\` to cache credentials
|
|
8
|
-
6. Use connect({ interactive: true }) for browser login`)}static async fromApiKey(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new l(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let o=await n.json().catch(()=>({}));throw new l(o.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),i=a.session_key;if(!i)throw new l("No session_key in API response");let r=new c({sessionKey:i,baseUrl:s,logLevel:t?.logLevel});return r.setApiKey(e),a.agent_instance_id&&r.setAgentInstanceId(a.agent_instance_id),r}static async fromAccessCode(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new l(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new l((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),i=a.session_key,r=a.token,o=a.agent_id;if(!i)throw new l("No session_key in access code response");try{let{saveCredentials:g}=await import('./credentials-ILS4YAGF.js');g({sessionKey:i,apiToken:r,baseUrl:s});}catch{}let d=new c({sessionKey:i,baseUrl:s,logLevel:t?.logLevel});return r&&(d.apiKey=r),o&&(d.agentInstanceId=o),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new l("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(g.error||`Failed to get session from master key: ${a.status}`)}let i=await a.json(),r=i.session_key,o=i.session_key_id;if(!r)throw new l("No session_key in master key response");let d=new c({sessionKey:r,sessionKeyId:o,baseUrl:n,logLevel:s?.logLevel});return i.agent?.id&&(d.agentInstanceId=i.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||_).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new l(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:i,verification_uri:r,verification_uri_complete:o,expires_in:d,interval:g}=n;console.log(`
|
|
2
|
+
import {fileURLToPath}from'url';import {join,dirname}from'path';import {privateKeyToAccount,signMessage,generatePrivateKey,signTypedData}from'viem/accounts';import {z as z$1}from'zod';import {createWalletClient,http,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';import {existsSync,readFileSync,mkdirSync,writeFileSync,chmodSync}from'fs';import {homedir}from'os';var l=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},v=class extends l{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},R=class extends l{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},T=class extends l{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,i=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${i}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},A=class extends l{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},S=class extends l{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},P=class extends l{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},D=class extends l{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},U=class extends l{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},I=class extends l{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},C=class extends l{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},E=class extends l{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}};var xe={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Se={name:"USD Coin",version:"2"},Ae={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},O=class c{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new S("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let i=`0x${a}`;return new c(i,n==="test")}catch(i){throw new S(`Failed to decode session key: ${i}`)}}async signTransferAuthorization(e,t){return signTypedData({privateKey:this.privateKey,domain:e,types:Ae,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function q(c){let e=xe[c.chainId];if(!e)throw new Error(`USDC not supported on chain ${c.chainId}`);let t={...Se,chainId:c.chainId,verifyingContract:e},s={from:c.fromAddress,to:c.toAddress,value:c.value,validAfter:c.validAfter,validBefore:c.validBefore,nonce:c.nonce};return {domain:t,message:s}}function j(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function ke(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function B(c){let e=Date.now(),t=ke(e,c.address),s=await c.signMessage(t);return {address:c.address,timestamp:e,signature:s}}var J=z$1.object({query:z$1.string().describe('Search query (e.g. "web scraping", "email", "database")')}),G=z$1.object({tool_name:z$1.string().describe('Tool name in "merchant/tool" format'),arguments:z$1.record(z$1.unknown()).optional().describe("Arguments to pass to the tool")}),X=z$1.object({url:z$1.string().url().describe("The merchant API URL to call"),merchant_public_key:z$1.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:z$1.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:z$1.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:z$1.number().optional().describe("Expected price in USD for client-side validation")}),z=z$1.object({skill_id:z$1.string().describe("The skill ID to execute"),input:z$1.record(z$1.unknown()).optional().describe("Input parameters for the skill")}),Y=z$1.object({skill_id:z$1.string().describe("The skill ID to check")}),V=z$1.object({glama_id:z$1.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:z$1.string().describe('Glama namespace (e.g. "notion")'),glama_slug:z$1.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:z$1.string().describe("Human-readable name for the tool"),tool_description:z$1.string().optional().describe("Optional description"),env_vars:z$1.record(z$1.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:z$1.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),Z=z$1.object({status:z$1.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),Q=z$1.object({instance_id:z$1.string().describe("The instance ID to stop")}),ee=z$1.object({to:z$1.string().describe("Recipient address (0x...)"),amount_usdc:z$1.number().positive().describe("Amount in USDC (e.g. 10.5)")}),te=z$1.object({name:z$1.string().describe("Name for the child agent"),budget_usd:z$1.number().positive().describe("Budget to delegate in USD"),budget_period:z$1.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:z$1.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:z$1.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),se=z$1.object({title:z$1.string().describe("Task title"),description:z$1.string().describe("Detailed task description"),budget_usd:z$1.number().positive().describe("Budget for the task in USD"),skills_required:z$1.array(z$1.string()).optional().describe("Required skill IDs")}),ne=z$1.object({status:z$1.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:z$1.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function ae(c){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await c.getBalance(),network:c.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:J,handler:async s=>{let{query:n}=J.parse(s);return c.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:G,handler:async s=>{let{tool_name:n,arguments:a}=G.parse(s);return c.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:X,handler:async s=>{let{url:n,merchant_public_key:a,method:i,body:r,price_usd:o}=X.parse(s),d=await c.callMerchantApi({url:n,merchantPublicKey:a,method:i,body:r,priceUsd:o}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:z,handler:async s=>{let{skill_id:n,input:a}=z.parse(s);return c.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:Y,handler:async s=>{let{skill_id:n}=Y.parse(s);return c.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:V,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:i,tool_name:r,tool_description:o,env_vars:d,ttl_hours:g}=V.parse(s);return c.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:i,toolName:r,toolDescription:o,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:Z,handler:async s=>{let{status:n}=Z.parse(s);return c.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:Q,handler:async s=>{let{instance_id:n}=Q.parse(s);return await c.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:ee,handler:async s=>{let{to:n,amount_usdc:a}=ee.parse(s);if(!await c.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await c.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:te,handler:async s=>{let{name:n,budget_usd:a,budget_period:i,max_per_tx_usd:r,expires_in_days:o}=te.parse(s);return c.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:i,maxPerTxUsd:r,expiresInDays:o})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:se,handler:async s=>{let{title:n,description:a,budget_usd:i,skills_required:r}=se.parse(s);return c.createTask({title:n,description:a,budgetUsd:i,skillsRequired:r})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:ne,handler:async s=>{let{status:n,limit:a}=ne.parse(s);return c.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(i=>i.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let i=await a.handler(n);return JSON.stringify(i,null,2)}catch(i){let r=i instanceof Error?i.message:String(i);throw new Error(r)}}}}function ie(c){if(c instanceof z$1.ZodObject){let e=c._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let i=a;t[n]=K(i),!(i instanceof z$1.ZodOptional)&&!(i instanceof z$1.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function K(c){let e=c;e instanceof z$1.ZodOptional&&(e=e._def.innerType),e instanceof z$1.ZodDefault&&(e=e._def.innerType);let t=c._def.description;if(e instanceof z$1.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof z$1.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof z$1.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof z$1.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof z$1.ZodArray)return {type:"array",items:K(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:K(e._def.valueType),...t&&{description:t}};if(e instanceof z$1.ZodObject){let s=e._def.shape(),n={};for(let[a,i]of Object.entries(s))n[a]=K(i);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ce="0.9.5",re=".config/mixrpay",$e="wallet.json";function oe(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,re):join(homedir(),re)}function N(){return join(oe(),$e)}async function le(c,e){let t=oe(),s=N();existsSync(t)||mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:c,createdAt:new Date().toISOString(),sdkVersion:Ce};writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{chmodSync(s,384);}catch{}}async function L(){let c=process.env.MIXRPAY_WALLET_KEY;if(c){if(c.startsWith("0x")&&c.length===66)return c;if(c.length===64)return `0x${c}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=N();if(!existsSync(e))return null;try{let t=readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function ce(){let c=process.env.MIXRPAY_WALLET_KEY;return c&&(c.length===64||c.startsWith("0x")&&c.length===66)?true:existsSync(N())}async function de(c){let e=null,t=c.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=c.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await c.json();}catch{}if(!e)throw new P("Could not parse payment requirements from 402 response");if(!e.recipient)throw new P("Missing recipient in payment requirements");if(!e.amount)throw new P("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||j().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function ue(c,e,t){let s=c.nonce.length===64?`0x${c.nonce}`:j(),a=BigInt(Math.floor(Date.now()/1e3))-60n,i=BigInt(c.expiresAt),{domain:r,message:o}=q({fromAddress:t,toAddress:c.recipient,value:c.amount,validAfter:a,validBefore:i,nonce:s,chainId:c.chainId}),d=await e.signTransferAuthorization(r,o),g={x402Version:1,scheme:"exact",network:c.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:c.recipient,value:c.amount.toString(),validAfter:a.toString(),validBefore:i.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function ge(c){return Date.now()/1e3>c.expiresAt}function F(c){return Number(c.amount)/1e6}var Ne="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://mixr.network",gt="https://x402.org/facilitator",Le=3e4,me={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},he={debug:0,info:1,warn:2,error:3,none:4},W=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return he[e]>=he[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},ye=class c{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=O.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||_).replace(/\/$/,""),this.timeout=e.timeout||Le,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new W(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new S("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new S(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new S(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new S("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new l("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new E(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let i=a.substring(2);if(s.endsWith(`.${i}`)&&s!==i)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(t).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=register`);if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:i,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),b="";u.status===503?b=" The service may be temporarily unavailable. Please try again later.":u.status===500?b=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(b=" This may indicate an SDK bug. Please update to the latest version.");let $=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l($)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||_).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:i}=e,r=(e.baseUrl||_).replace(/\/$/,""),d=privateKeyToAccount(t).address,g=await fetch(`${r}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new l(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await signMessage({message:p,privateKey:t}),f=await fetch(`${r}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:i})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new l(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||_).replace(/\/$/,""),a=privateKeyToAccount(t).address,i=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:r,message:o}=await i.json(),d=await signMessage({message:o,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${r}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new l(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(t).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=revoke`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:i,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new l(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(t).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=withdraw`);if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:i,signature:g,to_address:i,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),i=privateKeyToAccount(s).address,r=await fetch(`${n}/api/v1/agent/challenge?wallet=${i}&action=claim-invite`);if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${r.status}`)}let{challenge:o,message:d}=await r.json(),g=await signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:o,agent_wallet_address:i,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new l(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||_).replace(/\/$/,""),n=new c({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),i=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!i.ok){let o=await i.json().catch(()=>({}));throw new l(o.error||`Activation failed: ${i.status}`)}let r=await i.json();return {wallet:n,budget:{maxTotalUsd:r.budget.max_total_usd,maxDailyUsd:r.budget.max_daily_usd,maxPerTxUsd:r.budget.max_per_tx_usd,spentUsd:r.budget.spent_usd,remainingUsd:r.budget.remaining_usd},capabilities:{executeTransactions:r.capabilities.execute_transactions,gasSponsored:r.capabilities.gas_sponsored,batchedTx:r.capabilities.batched_tx},skills:r.skills||[],tools:r.tools||[],gatewayProviders:r.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||_).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new c({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new c({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let i=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(i&&(i.startsWith("agt_live_")||i.startsWith("agt_test_")))return c.fromApiKey(i,{baseUrl:t,logLevel:s});let r=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(r)return c.fromAccessCode(r,{baseUrl:t,logLevel:s});let o=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(o&&d)return c.fromMasterKey(o,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await import('./credentials-ILS4YAGF.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return c.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return c.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return c.deviceFlowLogin({baseUrl:t,logLevel:s});throw new l("No MixrPay credentials found. Options:\n 1. Set MIXRPAY_SESSION_KEY environment variable\n 2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)\n 3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)\n 4. Pass sessionKey or accessCode to connect()\n 5. Run `npx --package @mixrpay/agent-sdk mixrpay login` (or `npm i -g @mixrpay/agent-sdk` then `mixrpay login`)\n 6. Use connect({ interactive: true }) for browser login")}static async fromApiKey(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new l(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let o=await n.json().catch(()=>({}));throw new l(o.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),i=a.session_key;if(!i)throw new l("No session_key in API response");let r=new c({sessionKey:i,baseUrl:s,logLevel:t?.logLevel});return r.setApiKey(e),a.agent_instance_id&&r.setAgentInstanceId(a.agent_instance_id),r}static async fromAccessCode(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new l(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new l((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),i=a.session_key,r=a.token,o=a.agent_id;if(!i)throw new l("No session_key in access code response");try{let{saveCredentials:g}=await import('./credentials-ILS4YAGF.js');g({sessionKey:i,apiToken:r,baseUrl:s});}catch{}let d=new c({sessionKey:i,baseUrl:s,logLevel:t?.logLevel});return r&&(d.apiKey=r),o&&(d.agentInstanceId=o),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new l("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(g.error||`Failed to get session from master key: ${a.status}`)}let i=await a.json(),r=i.session_key,o=i.session_key_id;if(!r)throw new l("No session_key in master key response");let d=new c({sessionKey:r,sessionKeyId:o,baseUrl:n,logLevel:s?.logLevel});return i.agent?.id&&(d.agentInstanceId=i.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||_).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new l(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:i,verification_uri:r,verification_uri_complete:o,expires_in:d,interval:g}=n;console.log(`
|
|
9
3
|
\u{1F510} MixrPay Login
|
|
10
4
|
`),console.log(`Visit: ${o||r}`),console.log(`Enter code: ${i}
|
|
11
5
|
`),console.log(`Waiting for authentication...
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {b as b$1,a as a$1,e,d as d$1,c as c$1}from'./chunk-KXMATINK.js';import {c,g,a}from'./chunk-
|
|
2
|
+
import {b as b$1,a as a$1,e,d as d$1,c as c$1}from'./chunk-KXMATINK.js';import {c,g,a}from'./chunk-TOPWZWOK.js';import {privateKeyToAccount,generatePrivateKey}from'viem/accounts';import {createWalletClient,http,createPublicClient,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';async function u(e){let r=e.baseUrl||e.url||c;try{return await g.connect({baseUrl:r})}catch(s){throw s instanceof a&&(console.error("Authentication required."),console.error("\nRun `mixrpay login` or set MIXRPAY_SESSION_KEY environment variable.")),s}}function d(e,r){console.log(JSON.stringify(e,null,2));}function b(e){return e.length<=16?e.slice(0,8)+"...":e.slice(0,12)+"..."+e.slice(-4)}function R(e,r){let s;try{s=JSON.parse(e);}catch{console.error(`Error: ${r}`),process.exit(1);}(typeof s!="object"||s===null||Array.isArray(s))&&(console.error(`Error: ${r} - expected a JSON object`),process.exit(1));let o=s;return ("__proto__"in o||"constructor"in o||"prototype"in o)&&(console.error("Error: Invalid JSON - contains forbidden keys"),process.exit(1)),o}function H(e,r){let s;try{s=JSON.parse(e);}catch{console.error(`Error: ${r}`),process.exit(1);}Array.isArray(s)||(console.error(`Error: ${r} - expected a JSON array`),process.exit(1));for(let o of s){(typeof o!="object"||o===null||Array.isArray(o))&&(console.error(`Error: ${r} - array elements must be objects`),process.exit(1));let t=o;("__proto__"in t||"constructor"in t||"prototype"in t)&&(console.error("Error: Invalid JSON - contains forbidden keys"),process.exit(1));}return s}function Y(e){let r={command:"",flags:{},positionals:[]},s=0;for(;s<e.length;){let o=e[s];if(o.startsWith("--")){let[t,n]=o.slice(2).split("=");n!==void 0?r.flags[t]=n:s+1<e.length&&!e[s+1].startsWith("-")?r.flags[t]=e[++s]:r.flags[t]=true;}else if(o.startsWith("-")){let t=o.slice(1);s+1<e.length&&!e[s+1].startsWith("-")?r.flags[t]=e[++s]:r.flags[t]=true;}else r.command?r.positionals.push(o):r.command=o;s++;}return r}async function V(e$1){if(e$1.help||e$1.h){console.log(`
|
|
3
3
|
mixrpay login - Authenticate via browser
|
|
4
4
|
|
|
5
5
|
USAGE
|
|
@@ -691,7 +691,7 @@ USAGE
|
|
|
691
691
|
mixrpay tool <provider> <tool_name> '<json_arguments>'
|
|
692
692
|
mixrpay tool list
|
|
693
693
|
|
|
694
|
-
For full documentation, run: npx mixrpay-tool --help
|
|
694
|
+
For full documentation, run: npx --package @mixrpay/agent-sdk mixrpay-tool --help
|
|
695
695
|
|
|
696
696
|
QUICK EXAMPLES
|
|
697
697
|
# Web search
|
|
@@ -1005,9 +1005,9 @@ EXAMPLES
|
|
|
1005
1005
|
|
|
1006
1006
|
TOOL CLI
|
|
1007
1007
|
For full tool gateway access, use:
|
|
1008
|
-
npx mixrpay-tool <provider> <tool_name> '<json>'
|
|
1009
|
-
npx mixrpay-tool list
|
|
1010
|
-
npx mixrpay-tool help <provider>
|
|
1008
|
+
npx --package @mixrpay/agent-sdk mixrpay-tool <provider> <tool_name> '<json>'
|
|
1009
|
+
npx --package @mixrpay/agent-sdk mixrpay-tool list
|
|
1010
|
+
npx --package @mixrpay/agent-sdk mixrpay-tool help <provider>
|
|
1011
1011
|
|
|
1012
1012
|
ENVIRONMENT VARIABLES
|
|
1013
1013
|
MIXRPAY_SESSION_KEY Session key for authentication
|
|
@@ -1017,4 +1017,4 @@ ENVIRONMENT VARIABLES
|
|
|
1017
1017
|
AGENT_WALLET_KEY Agent's wallet private key
|
|
1018
1018
|
|
|
1019
1019
|
For more info, visit: https://docs.mixrpay.com/cli
|
|
1020
|
-
`);}function To(){import('./agent-wallet-
|
|
1020
|
+
`);}function To(){import('./agent-wallet-7CS7WY4F.js').then(({SDK_VERSION:e})=>{console.log(`mixrpay v${e}`);});}async function Uo(){let e=Y(process.argv.slice(2));if(!e.command&&(e.flags.help||e.flags.h)){D();return}if(e.flags.version||e.flags.v){To();return}switch(e.command){case "init":await oe(e.flags);break;case "install":await ee(e.flags);break;case "login":await V(e.flags);break;case "logout":await z();break;case "whoami":await Q(e.flags);break;case "register":await Z(e.flags);break;case "status":await te(e.flags);break;case "wallet":await ge(e.flags,e.positionals);break;case "budget":await fe(e.flags);break;case "creds":case "credentials":case "vault":await be(e.flags,e.positionals);break;case "spawn":await me(e.flags);break;case "children":await ye(e.flags);break;case "sessions":await Oe(e.flags,e.positionals);break;case "complete":await ke(e.flags,e.positionals);break;case "run":await ve(e.flags,e.positionals);break;case "tool":await ze(e.flags,e.positionals);break;case "search":await Qe(e.flags,e.positionals);break;case "mcp":await Me(e.flags,e.positionals);break;case "skills":await Be(e.flags,e.positionals);break;case "agent":await Ve(e.flags,e.positionals);break;case "task":await co(e.flags,e.positionals);break;case "defi":await fo(e.flags,e.positionals);break;case "plan":await ko(e.flags,e.positionals);break;case "approval":await Io(e.flags,e.positionals);break;case "diagnostics":await $e(e.flags);break;case "health":await Ae(e.flags);break;case "siwe":await Ee(e.flags);break;case "":case "help":D();break;default:console.error(`Unknown command: ${e.command}`),console.error("\nRun `mixrpay --help` for usage information."),process.exit(1);}}Uo().catch(e=>{console.error("Fatal error:",e),process.exit(1);});
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
'use strict';var b=require('fs'),D=require('path'),M=require('os'),url=require('url'),accounts=require('viem/accounts'),zod=require('zod'),viem=require('viem'),chains=require('viem/chains');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var b__namespace=/*#__PURE__*/_interopNamespace(b);var D__namespace=/*#__PURE__*/_interopNamespace(D);var M__namespace=/*#__PURE__*/_interopNamespace(M);var Ke=Object.defineProperty;var je=(o,e)=>()=>(o&&(e=o(o=0)),e);var Me=(o,e)=>{for(var t in e)Ke(o,t,{get:e[t],enumerable:true});};var J={};Me(J,{deleteCredentials:()=>Ue,getCredentialsFilePath:()=>Ce,hasCredentials:()=>Ie,loadCredentials:()=>B,saveCredentials:()=>Pe});function ve(){if(M__namespace.platform()==="win32"){let t=process.env.APPDATA||D__namespace.join(M__namespace.homedir(),"AppData","Roaming");return D__namespace.join(t,"mixrpay")}let e=process.env.XDG_CONFIG_HOME||D__namespace.join(M__namespace.homedir(),".config");return D__namespace.join(e,"mixrpay")}function q(){return D__namespace.join(ve(),"credentials.json")}function nt(){let o=ve();b__namespace.existsSync(o)||b__namespace.mkdirSync(o,{recursive:true,mode:448});}function Te(o){try{b__namespace.chmodSync(o,384);}catch{}}function Pe(o){try{nt();let e=q(),t={};if(b__namespace.existsSync(e))try{let a=b__namespace.readFileSync(e,"utf-8");t=JSON.parse(a);}catch{t={};}let s={...t,...o,updatedAt:new Date().toISOString()},n=Object.fromEntries(Object.entries(s).filter(([a,r])=>r!==void 0));return b__namespace.writeFileSync(e,JSON.stringify(n,null,2),{mode:384}),Te(e),!0}catch(e){return console.error("[MixrPay] Failed to save credentials:",e),false}}function B(){try{let o=q();if(!b__namespace.existsSync(o))return {success:!0,credentials:{}};let e=b__namespace.readFileSync(o,"utf-8");return {success:!0,credentials:JSON.parse(e)}}catch(o){return {success:false,error:o instanceof Error?o.message:"Failed to load credentials"}}}function Ue(o){try{let e=q();if(!b__namespace.existsSync(e))return !0;if(!o)return b__namespace.unlinkSync(e),!0;let t=B();if(!t.success)return !1;let s={...t.credentials};for(let n of o)delete s[n];return Object.keys(s).length===0?b__namespace.unlinkSync(e):(b__namespace.writeFileSync(e,JSON.stringify(s,null,2),{mode:384}),Te(e)),!0}catch(e){return console.error("[MixrPay] Failed to delete credentials:",e),false}}function Ie(){let o=B();if(!o.success)return false;let{credentials:e}=o;return !!(e.sessionKey||e.apiToken||e.masterKey)}function Ce(){return q()}var H=je(()=>{});var c=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},v=class extends c{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},E=class extends c{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},T=class extends c{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,r=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${r}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},k=class extends c{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},x=class extends c{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},P=class extends c{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},O=class extends c{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},I=class extends c{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},C=class extends c{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},R=class extends c{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},K=class extends c{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}},G=class extends c{constructor(e=6e4,t){super(t||`Rate limit exceeded. Please wait ${Math.ceil(e/1e3)} seconds before retrying.`,"RATE_LIMIT_EXCEEDED",e),this.name="RateLimitError";}isRetryable(){return true}},X=class extends c{reason;constructor(e,t){super(`Network error: ${e}. Check your connection and try again.`,"NETWORK_ERROR",5e3),this.name="NetworkError",this.reason=e,t?.stack&&(this.stack=t.stack);}isRetryable(){return true}},z=class extends c{reason;statusCode;constructor(e,t=401){super(`Authentication failed: ${e}`,t===401?"UNAUTHORIZED":"FORBIDDEN"),this.name="AuthenticationError",this.reason=e,this.statusCode=t;}isRetryable(){return false}};function He(o){return o instanceof c}function Ne(o){return o instanceof c||o instanceof Error?o.message:String(o)}var qe={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Be={name:"USD Coin",version:"2"},Je={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},L=class o{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=accounts.privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new x("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let r=`0x${a}`;return new o(r,n==="test")}catch(r){throw new x(`Failed to decode session key: ${r}`)}}async signTransferAuthorization(e,t){return accounts.signTypedData({privateKey:this.privateKey,domain:e,types:Je,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return accounts.signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function ne(o){let e=qe[o.chainId];if(!e)throw new Error(`USDC not supported on chain ${o.chainId}`);let t={...Be,chainId:o.chainId,verifyingContract:e},s={from:o.fromAddress,to:o.toAddress,value:o.value,validAfter:o.validAfter,validBefore:o.validBefore,nonce:o.nonce};return {domain:t,message:s}}function Y(){let o=new Uint8Array(32);return crypto.getRandomValues(o),`0x${Array.from(o).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ge(o,e){return `MixrPay:${o}:${e.toLowerCase()}`}async function ae(o){let e=Date.now(),t=Ge(e,o.address),s=await o.signMessage(t);return {address:o.address,timestamp:e,signature:s}}var re=zod.z.object({query:zod.z.string().describe('Search query (e.g. "web scraping", "email", "database")')}),ie=zod.z.object({tool_name:zod.z.string().describe('Tool name in "merchant/tool" format'),arguments:zod.z.record(zod.z.unknown()).optional().describe("Arguments to pass to the tool")}),oe=zod.z.object({url:zod.z.string().url().describe("The merchant API URL to call"),merchant_public_key:zod.z.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:zod.z.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:zod.z.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:zod.z.number().optional().describe("Expected price in USD for client-side validation")}),le=zod.z.object({skill_id:zod.z.string().describe("The skill ID to execute"),input:zod.z.record(zod.z.unknown()).optional().describe("Input parameters for the skill")}),ce=zod.z.object({skill_id:zod.z.string().describe("The skill ID to check")}),de=zod.z.object({glama_id:zod.z.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:zod.z.string().describe('Glama namespace (e.g. "notion")'),glama_slug:zod.z.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:zod.z.string().describe("Human-readable name for the tool"),tool_description:zod.z.string().optional().describe("Optional description"),env_vars:zod.z.record(zod.z.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:zod.z.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),ue=zod.z.object({status:zod.z.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),ge=zod.z.object({instance_id:zod.z.string().describe("The instance ID to stop")}),pe=zod.z.object({to:zod.z.string().describe("Recipient address (0x...)"),amount_usdc:zod.z.number().positive().describe("Amount in USDC (e.g. 10.5)")}),me=zod.z.object({name:zod.z.string().describe("Name for the child agent"),budget_usd:zod.z.number().positive().describe("Budget to delegate in USD"),budget_period:zod.z.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:zod.z.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:zod.z.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),he=zod.z.object({title:zod.z.string().describe("Task title"),description:zod.z.string().describe("Detailed task description"),budget_usd:zod.z.number().positive().describe("Budget for the task in USD"),skills_required:zod.z.array(zod.z.string()).optional().describe("Required skill IDs")}),ye=zod.z.object({status:zod.z.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:zod.z.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function fe(o){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await o.getBalance(),network:o.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>o.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>o.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:re,handler:async s=>{let{query:n}=re.parse(s);return o.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ie,handler:async s=>{let{tool_name:n,arguments:a}=ie.parse(s);return o.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:oe,handler:async s=>{let{url:n,merchant_public_key:a,method:r,body:i,price_usd:l}=oe.parse(s),d=await o.callMerchantApi({url:n,merchantPublicKey:a,method:r,body:i,priceUsd:l}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>o.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:le,handler:async s=>{let{skill_id:n,input:a}=le.parse(s);return o.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ce,handler:async s=>{let{skill_id:n}=ce.parse(s);return o.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:de,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:r,tool_name:i,tool_description:l,env_vars:d,ttl_hours:g}=de.parse(s);return o.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:r,toolName:i,toolDescription:l,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ue,handler:async s=>{let{status:n}=ue.parse(s);return o.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:ge,handler:async s=>{let{instance_id:n}=ge.parse(s);return await o.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:pe,handler:async s=>{let{to:n,amount_usdc:a}=pe.parse(s);if(!await o.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await o.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:me,handler:async s=>{let{name:n,budget_usd:a,budget_period:r,max_per_tx_usd:i,expires_in_days:l}=me.parse(s);return o.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:r,maxPerTxUsd:i,expiresInDays:l})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:he,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=he.parse(s);return o.createTask({title:n,description:a,budgetUsd:r,skillsRequired:i})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:ye,handler:async s=>{let{status:n,limit:a}=ye.parse(s);return o.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(r=>r.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let r=await a.handler(n);return JSON.stringify(r,null,2)}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(i)}}}}function we(o){if(o instanceof zod.z.ZodObject){let e=o._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let r=a;t[n]=F(r),!(r instanceof zod.z.ZodOptional)&&!(r instanceof zod.z.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function F(o){let e=o;e instanceof zod.z.ZodOptional&&(e=e._def.innerType),e instanceof zod.z.ZodDefault&&(e=e._def.innerType);let t=o._def.description;if(e instanceof zod.z.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof zod.z.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof zod.z.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof zod.z.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof zod.z.ZodArray)return {type:"array",items:F(e._def.type),...t&&{description:t}};if(e instanceof zod.z.ZodRecord)return {type:"object",additionalProperties:F(e._def.valueType),...t&&{description:t}};if(e instanceof zod.z.ZodObject){let s=e._def.shape(),n={};for(let[a,r]of Object.entries(s))n[a]=F(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof zod.z.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ze="0.9.5",be=".config/mixrpay",Qe="wallet.json";function Se(){let o=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return o?D.join(o,be):D.join(M.homedir(),be)}function $(){return D.join(Se(),Qe)}async function Z(o,e){let t=Se(),s=$();b.existsSync(t)||b.mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:o,createdAt:new Date().toISOString(),sdkVersion:Ze};b.writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{b.chmodSync(s,384);}catch{}}async function W(){let o=process.env.MIXRPAY_WALLET_KEY;if(o){if(o.startsWith("0x")&&o.length===66)return o;if(o.length===64)return `0x${o}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=$();if(!b.existsSync(e))return null;try{let t=b.readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function et(){let o=$();if(!b.existsSync(o)){let e=process.env.MIXRPAY_WALLET_KEY;return e&&(e.startsWith("0x")?e:`0x${e}`).length===66,null}try{let e=b.readFileSync(o,"utf-8");return JSON.parse(e)}catch{return null}}async function Q(){let o=process.env.MIXRPAY_WALLET_KEY;return o&&(o.length===64||o.startsWith("0x")&&o.length===66)?true:b.existsSync($())}function tt(){return $()}async function st(){let o=$();if(!b.existsSync(o))return false;try{let{unlinkSync:e}=await import('fs');return e(o),!0}catch{return false}}async function xe(o){let e=null,t=o.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=o.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await o.json();}catch{}if(!e)throw new P("Could not parse payment requirements from 402 response");if(!e.recipient)throw new P("Missing recipient in payment requirements");if(!e.amount)throw new P("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||Y().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function Ae(o,e,t){let s=o.nonce.length===64?`0x${o.nonce}`:Y(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(o.expiresAt),{domain:i,message:l}=ne({fromAddress:t,toAddress:o.recipient,value:o.amount,validAfter:a,validBefore:r,nonce:s,chainId:o.chainId}),d=await e.signTransferAuthorization(i,l),g={x402Version:1,scheme:"exact",network:o.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:o.recipient,value:o.amount.toString(),validAfter:a.toString(),validBefore:r.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function ke(o){return Date.now()/1e3>o.expiresAt}function ee(o){return Number(o.amount)/1e6}var Ee="0.11.0",S=process.env.MIXRPAY_BASE_URL||"https://mixr.network";var gt=3e4,$e={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},De={debug:0,info:1,warn:2,error:3,none:4},te=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return De[e]>=De[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},se=class o{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=L.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||S).replace(/\/$/,""),this.timeout=e.timeout||gt,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new te(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new x("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new x(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new x(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new x("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new c("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new K(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let r=a.substring(2);if(s.endsWith(`.${r}`)&&s!==r)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=register`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new c(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:l,external_wallet:r,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),_="";u.status===503?_=" The service may be temporarily unavailable. Please try again later.":u.status===500?_=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(_=" This may indicate an SDK bug. Please update to the latest version.");let N=h?`${f} (request_id: ${h})${_}`:`${f}${_}`;throw new c(N)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||S).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:r}=e,i=(e.baseUrl||S).replace(/\/$/,""),d=accounts.privateKeyToAccount(t).address,g=await fetch(`${i}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new c(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await accounts.signMessage({message:p,privateKey:t}),f=await fetch(`${i}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:r})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new c(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||S).replace(/\/$/,""),a=accounts.privateKeyToAccount(t).address,r=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new c(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:i,message:l}=await r.json(),d=await accounts.signMessage({message:l,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${i}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new c(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=revoke`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new c(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:l,external_wallet:r,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new c(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=withdraw`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new c(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:l,external_wallet:r,signature:g,to_address:r,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new c(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(s).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=claim-invite`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new c(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:l,agent_wallet_address:r,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new c(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||S).replace(/\/$/,""),n=new o({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),r=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!r.ok){let l=await r.json().catch(()=>({}));throw new c(l.error||`Activation failed: ${r.status}`)}let i=await r.json();return {wallet:n,budget:{maxTotalUsd:i.budget.max_total_usd,maxDailyUsd:i.budget.max_daily_usd,maxPerTxUsd:i.budget.max_per_tx_usd,spentUsd:i.budget.spent_usd,remainingUsd:i.budget.remaining_usd},capabilities:{executeTransactions:i.capabilities.execute_transactions,gasSponsored:i.capabilities.gas_sponsored,batchedTx:i.capabilities.batched_tx},skills:i.skills||[],tools:i.tools||[],gatewayProviders:i.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||S).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new o({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new o({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let r=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(r&&(r.startsWith("agt_live_")||r.startsWith("agt_test_")))return o.fromApiKey(r,{baseUrl:t,logLevel:s});let i=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(i)return o.fromAccessCode(i,{baseUrl:t,logLevel:s});let l=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(l&&d)return o.fromMasterKey(l,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await Promise.resolve().then(()=>(H(),J)),u=g();if(u.success&&u.credentials.sessionKey){let p=new o({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return o.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return o.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return o.deviceFlowLogin({baseUrl:t,logLevel:s});throw new c(`No MixrPay credentials found. Options:
|
|
2
|
-
1. Set MIXRPAY_SESSION_KEY environment variable
|
|
3
|
-
2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)
|
|
4
|
-
3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)
|
|
5
|
-
4. Pass sessionKey or accessCode to connect()
|
|
6
|
-
5. Run \`npx mixrpay login\` to cache credentials
|
|
7
|
-
6. Use connect({ interactive: true }) for browser login`)}static async fromApiKey(e,t){let s=(t?.baseUrl||S).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new c(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let l=await n.json().catch(()=>({}));throw new c(l.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),r=a.session_key;if(!r)throw new c("No session_key in API response");let i=new o({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i.setApiKey(e),a.agent_instance_id&&i.setAgentInstanceId(a.agent_instance_id),i}static async fromAccessCode(e,t){let s=(t?.baseUrl||S).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new c(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new c((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),r=a.session_key,i=a.token,l=a.agent_id;if(!r)throw new c("No session_key in access code response");try{let{saveCredentials:g}=await Promise.resolve().then(()=>(H(),J));g({sessionKey:r,apiToken:i,baseUrl:s});}catch{}let d=new o({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i&&(d.apiKey=i),l&&(d.agentInstanceId=l),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||S).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new c("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new c(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new c(g.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key,l=r.session_key_id;if(!i)throw new c("No session_key in master key response");let d=new o({sessionKey:i,sessionKeyId:l,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(d.agentInstanceId=r.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||S).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new c(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:r,verification_uri:i,verification_uri_complete:l,expires_in:d,interval:g}=n;console.log(`
|
|
1
|
+
'use strict';var b=require('fs'),D=require('path'),M=require('os'),url=require('url'),accounts=require('viem/accounts'),zod=require('zod'),viem=require('viem'),chains=require('viem/chains');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var b__namespace=/*#__PURE__*/_interopNamespace(b);var D__namespace=/*#__PURE__*/_interopNamespace(D);var M__namespace=/*#__PURE__*/_interopNamespace(M);var Ke=Object.defineProperty;var je=(o,e)=>()=>(o&&(e=o(o=0)),e);var Me=(o,e)=>{for(var t in e)Ke(o,t,{get:e[t],enumerable:true});};var J={};Me(J,{deleteCredentials:()=>Ue,getCredentialsFilePath:()=>Ce,hasCredentials:()=>Ie,loadCredentials:()=>B,saveCredentials:()=>Pe});function ve(){if(M__namespace.platform()==="win32"){let t=process.env.APPDATA||D__namespace.join(M__namespace.homedir(),"AppData","Roaming");return D__namespace.join(t,"mixrpay")}let e=process.env.XDG_CONFIG_HOME||D__namespace.join(M__namespace.homedir(),".config");return D__namespace.join(e,"mixrpay")}function q(){return D__namespace.join(ve(),"credentials.json")}function nt(){let o=ve();b__namespace.existsSync(o)||b__namespace.mkdirSync(o,{recursive:true,mode:448});}function Te(o){try{b__namespace.chmodSync(o,384);}catch{}}function Pe(o){try{nt();let e=q(),t={};if(b__namespace.existsSync(e))try{let a=b__namespace.readFileSync(e,"utf-8");t=JSON.parse(a);}catch{t={};}let s={...t,...o,updatedAt:new Date().toISOString()},n=Object.fromEntries(Object.entries(s).filter(([a,r])=>r!==void 0));return b__namespace.writeFileSync(e,JSON.stringify(n,null,2),{mode:384}),Te(e),!0}catch(e){return console.error("[MixrPay] Failed to save credentials:",e),false}}function B(){try{let o=q();if(!b__namespace.existsSync(o))return {success:!0,credentials:{}};let e=b__namespace.readFileSync(o,"utf-8");return {success:!0,credentials:JSON.parse(e)}}catch(o){return {success:false,error:o instanceof Error?o.message:"Failed to load credentials"}}}function Ue(o){try{let e=q();if(!b__namespace.existsSync(e))return !0;if(!o)return b__namespace.unlinkSync(e),!0;let t=B();if(!t.success)return !1;let s={...t.credentials};for(let n of o)delete s[n];return Object.keys(s).length===0?b__namespace.unlinkSync(e):(b__namespace.writeFileSync(e,JSON.stringify(s,null,2),{mode:384}),Te(e)),!0}catch(e){return console.error("[MixrPay] Failed to delete credentials:",e),false}}function Ie(){let o=B();if(!o.success)return false;let{credentials:e}=o;return !!(e.sessionKey||e.apiToken||e.masterKey)}function Ce(){return q()}var H=je(()=>{});var c=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},v=class extends c{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},E=class extends c{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},T=class extends c{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,r=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${r}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},k=class extends c{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},x=class extends c{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},P=class extends c{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},O=class extends c{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},I=class extends c{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},C=class extends c{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},R=class extends c{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},K=class extends c{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}},G=class extends c{constructor(e=6e4,t){super(t||`Rate limit exceeded. Please wait ${Math.ceil(e/1e3)} seconds before retrying.`,"RATE_LIMIT_EXCEEDED",e),this.name="RateLimitError";}isRetryable(){return true}},X=class extends c{reason;constructor(e,t){super(`Network error: ${e}. Check your connection and try again.`,"NETWORK_ERROR",5e3),this.name="NetworkError",this.reason=e,t?.stack&&(this.stack=t.stack);}isRetryable(){return true}},z=class extends c{reason;statusCode;constructor(e,t=401){super(`Authentication failed: ${e}`,t===401?"UNAUTHORIZED":"FORBIDDEN"),this.name="AuthenticationError",this.reason=e,this.statusCode=t;}isRetryable(){return false}};function He(o){return o instanceof c}function Ne(o){return o instanceof c||o instanceof Error?o.message:String(o)}var qe={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Be={name:"USD Coin",version:"2"},Je={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},L=class o{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=accounts.privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new x("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let r=`0x${a}`;return new o(r,n==="test")}catch(r){throw new x(`Failed to decode session key: ${r}`)}}async signTransferAuthorization(e,t){return accounts.signTypedData({privateKey:this.privateKey,domain:e,types:Je,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return accounts.signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function ne(o){let e=qe[o.chainId];if(!e)throw new Error(`USDC not supported on chain ${o.chainId}`);let t={...Be,chainId:o.chainId,verifyingContract:e},s={from:o.fromAddress,to:o.toAddress,value:o.value,validAfter:o.validAfter,validBefore:o.validBefore,nonce:o.nonce};return {domain:t,message:s}}function Y(){let o=new Uint8Array(32);return crypto.getRandomValues(o),`0x${Array.from(o).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ge(o,e){return `MixrPay:${o}:${e.toLowerCase()}`}async function ae(o){let e=Date.now(),t=Ge(e,o.address),s=await o.signMessage(t);return {address:o.address,timestamp:e,signature:s}}var re=zod.z.object({query:zod.z.string().describe('Search query (e.g. "web scraping", "email", "database")')}),ie=zod.z.object({tool_name:zod.z.string().describe('Tool name in "merchant/tool" format'),arguments:zod.z.record(zod.z.unknown()).optional().describe("Arguments to pass to the tool")}),oe=zod.z.object({url:zod.z.string().url().describe("The merchant API URL to call"),merchant_public_key:zod.z.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:zod.z.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:zod.z.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:zod.z.number().optional().describe("Expected price in USD for client-side validation")}),le=zod.z.object({skill_id:zod.z.string().describe("The skill ID to execute"),input:zod.z.record(zod.z.unknown()).optional().describe("Input parameters for the skill")}),ce=zod.z.object({skill_id:zod.z.string().describe("The skill ID to check")}),de=zod.z.object({glama_id:zod.z.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:zod.z.string().describe('Glama namespace (e.g. "notion")'),glama_slug:zod.z.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:zod.z.string().describe("Human-readable name for the tool"),tool_description:zod.z.string().optional().describe("Optional description"),env_vars:zod.z.record(zod.z.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:zod.z.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),ue=zod.z.object({status:zod.z.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),ge=zod.z.object({instance_id:zod.z.string().describe("The instance ID to stop")}),pe=zod.z.object({to:zod.z.string().describe("Recipient address (0x...)"),amount_usdc:zod.z.number().positive().describe("Amount in USDC (e.g. 10.5)")}),me=zod.z.object({name:zod.z.string().describe("Name for the child agent"),budget_usd:zod.z.number().positive().describe("Budget to delegate in USD"),budget_period:zod.z.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:zod.z.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:zod.z.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),he=zod.z.object({title:zod.z.string().describe("Task title"),description:zod.z.string().describe("Detailed task description"),budget_usd:zod.z.number().positive().describe("Budget for the task in USD"),skills_required:zod.z.array(zod.z.string()).optional().describe("Required skill IDs")}),ye=zod.z.object({status:zod.z.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:zod.z.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function fe(o){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await o.getBalance(),network:o.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>o.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>o.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:re,handler:async s=>{let{query:n}=re.parse(s);return o.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ie,handler:async s=>{let{tool_name:n,arguments:a}=ie.parse(s);return o.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:oe,handler:async s=>{let{url:n,merchant_public_key:a,method:r,body:i,price_usd:l}=oe.parse(s),d=await o.callMerchantApi({url:n,merchantPublicKey:a,method:r,body:i,priceUsd:l}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>o.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:le,handler:async s=>{let{skill_id:n,input:a}=le.parse(s);return o.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ce,handler:async s=>{let{skill_id:n}=ce.parse(s);return o.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:de,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:r,tool_name:i,tool_description:l,env_vars:d,ttl_hours:g}=de.parse(s);return o.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:r,toolName:i,toolDescription:l,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ue,handler:async s=>{let{status:n}=ue.parse(s);return o.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:ge,handler:async s=>{let{instance_id:n}=ge.parse(s);return await o.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:pe,handler:async s=>{let{to:n,amount_usdc:a}=pe.parse(s);if(!await o.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await o.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:me,handler:async s=>{let{name:n,budget_usd:a,budget_period:r,max_per_tx_usd:i,expires_in_days:l}=me.parse(s);return o.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:r,maxPerTxUsd:i,expiresInDays:l})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>o.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:he,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=he.parse(s);return o.createTask({title:n,description:a,budgetUsd:r,skillsRequired:i})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:ye,handler:async s=>{let{status:n,limit:a}=ye.parse(s);return o.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(r=>r.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let r=await a.handler(n);return JSON.stringify(r,null,2)}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(i)}}}}function we(o){if(o instanceof zod.z.ZodObject){let e=o._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let r=a;t[n]=F(r),!(r instanceof zod.z.ZodOptional)&&!(r instanceof zod.z.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function F(o){let e=o;e instanceof zod.z.ZodOptional&&(e=e._def.innerType),e instanceof zod.z.ZodDefault&&(e=e._def.innerType);let t=o._def.description;if(e instanceof zod.z.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof zod.z.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof zod.z.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof zod.z.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof zod.z.ZodArray)return {type:"array",items:F(e._def.type),...t&&{description:t}};if(e instanceof zod.z.ZodRecord)return {type:"object",additionalProperties:F(e._def.valueType),...t&&{description:t}};if(e instanceof zod.z.ZodObject){let s=e._def.shape(),n={};for(let[a,r]of Object.entries(s))n[a]=F(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof zod.z.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ze="0.9.5",be=".config/mixrpay",Qe="wallet.json";function Se(){let o=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return o?D.join(o,be):D.join(M.homedir(),be)}function $(){return D.join(Se(),Qe)}async function Z(o,e){let t=Se(),s=$();b.existsSync(t)||b.mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:o,createdAt:new Date().toISOString(),sdkVersion:Ze};b.writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{b.chmodSync(s,384);}catch{}}async function W(){let o=process.env.MIXRPAY_WALLET_KEY;if(o){if(o.startsWith("0x")&&o.length===66)return o;if(o.length===64)return `0x${o}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=$();if(!b.existsSync(e))return null;try{let t=b.readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function et(){let o=$();if(!b.existsSync(o)){let e=process.env.MIXRPAY_WALLET_KEY;return e&&(e.startsWith("0x")?e:`0x${e}`).length===66,null}try{let e=b.readFileSync(o,"utf-8");return JSON.parse(e)}catch{return null}}async function Q(){let o=process.env.MIXRPAY_WALLET_KEY;return o&&(o.length===64||o.startsWith("0x")&&o.length===66)?true:b.existsSync($())}function tt(){return $()}async function st(){let o=$();if(!b.existsSync(o))return false;try{let{unlinkSync:e}=await import('fs');return e(o),!0}catch{return false}}async function xe(o){let e=null,t=o.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=o.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await o.json();}catch{}if(!e)throw new P("Could not parse payment requirements from 402 response");if(!e.recipient)throw new P("Missing recipient in payment requirements");if(!e.amount)throw new P("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||Y().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function Ae(o,e,t){let s=o.nonce.length===64?`0x${o.nonce}`:Y(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(o.expiresAt),{domain:i,message:l}=ne({fromAddress:t,toAddress:o.recipient,value:o.amount,validAfter:a,validBefore:r,nonce:s,chainId:o.chainId}),d=await e.signTransferAuthorization(i,l),g={x402Version:1,scheme:"exact",network:o.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:o.recipient,value:o.amount.toString(),validAfter:a.toString(),validBefore:r.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function ke(o){return Date.now()/1e3>o.expiresAt}function ee(o){return Number(o.amount)/1e6}var Ee="0.11.0",S=process.env.MIXRPAY_BASE_URL||"https://mixr.network";var gt=3e4,$e={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},De={debug:0,info:1,warn:2,error:3,none:4},te=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return De[e]>=De[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},se=class o{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=L.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||S).replace(/\/$/,""),this.timeout=e.timeout||gt,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new te(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new x("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new x(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new x(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new x("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new c("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new K(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let r=a.substring(2);if(s.endsWith(`.${r}`)&&s!==r)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=register`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new c(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:l,external_wallet:r,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),_="";u.status===503?_=" The service may be temporarily unavailable. Please try again later.":u.status===500?_=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(_=" This may indicate an SDK bug. Please update to the latest version.");let N=h?`${f} (request_id: ${h})${_}`:`${f}${_}`;throw new c(N)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||S).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:r}=e,i=(e.baseUrl||S).replace(/\/$/,""),d=accounts.privateKeyToAccount(t).address,g=await fetch(`${i}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new c(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await accounts.signMessage({message:p,privateKey:t}),f=await fetch(`${i}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:r})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new c(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||S).replace(/\/$/,""),a=accounts.privateKeyToAccount(t).address,r=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new c(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:i,message:l}=await r.json(),d=await accounts.signMessage({message:l,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${i}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new c(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=revoke`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new c(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:l,external_wallet:r,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new c(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=withdraw`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new c(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:l,external_wallet:r,signature:g,to_address:r,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new c(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||S).replace(/\/$/,""),r=accounts.privateKeyToAccount(s).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=claim-invite`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new c(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:l,message:d}=await i.json(),g=await accounts.signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:l,agent_wallet_address:r,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new c(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||S).replace(/\/$/,""),n=new o({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),r=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!r.ok){let l=await r.json().catch(()=>({}));throw new c(l.error||`Activation failed: ${r.status}`)}let i=await r.json();return {wallet:n,budget:{maxTotalUsd:i.budget.max_total_usd,maxDailyUsd:i.budget.max_daily_usd,maxPerTxUsd:i.budget.max_per_tx_usd,spentUsd:i.budget.spent_usd,remainingUsd:i.budget.remaining_usd},capabilities:{executeTransactions:i.capabilities.execute_transactions,gasSponsored:i.capabilities.gas_sponsored,batchedTx:i.capabilities.batched_tx},skills:i.skills||[],tools:i.tools||[],gatewayProviders:i.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||S).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new o({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new o({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let r=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(r&&(r.startsWith("agt_live_")||r.startsWith("agt_test_")))return o.fromApiKey(r,{baseUrl:t,logLevel:s});let i=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(i)return o.fromAccessCode(i,{baseUrl:t,logLevel:s});let l=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(l&&d)return o.fromMasterKey(l,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await Promise.resolve().then(()=>(H(),J)),u=g();if(u.success&&u.credentials.sessionKey){let p=new o({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return o.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return o.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return o.deviceFlowLogin({baseUrl:t,logLevel:s});throw new c("No MixrPay credentials found. Options:\n 1. Set MIXRPAY_SESSION_KEY environment variable\n 2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)\n 3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)\n 4. Pass sessionKey or accessCode to connect()\n 5. Run `npx --package @mixrpay/agent-sdk mixrpay login` (or `npm i -g @mixrpay/agent-sdk` then `mixrpay login`)\n 6. Use connect({ interactive: true }) for browser login")}static async fromApiKey(e,t){let s=(t?.baseUrl||S).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new c(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let l=await n.json().catch(()=>({}));throw new c(l.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),r=a.session_key;if(!r)throw new c("No session_key in API response");let i=new o({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i.setApiKey(e),a.agent_instance_id&&i.setAgentInstanceId(a.agent_instance_id),i}static async fromAccessCode(e,t){let s=(t?.baseUrl||S).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new c(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new c((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),r=a.session_key,i=a.token,l=a.agent_id;if(!r)throw new c("No session_key in access code response");try{let{saveCredentials:g}=await Promise.resolve().then(()=>(H(),J));g({sessionKey:r,apiToken:i,baseUrl:s});}catch{}let d=new o({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i&&(d.apiKey=i),l&&(d.agentInstanceId=l),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||S).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new c("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new c(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new c(g.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key,l=r.session_key_id;if(!i)throw new c("No session_key in master key response");let d=new o({sessionKey:i,sessionKeyId:l,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(d.agentInstanceId=r.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||S).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new c(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:r,verification_uri:i,verification_uri_complete:l,expires_in:d,interval:g}=n;console.log(`
|
|
8
2
|
\u{1F510} MixrPay Login
|
|
9
3
|
`),console.log(`Visit: ${l||i}`),console.log(`Enter code: ${r}
|
|
10
4
|
`),console.log(`Waiting for authentication...
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
export{c as deleteCredentials,e as getCredentialsFilePath,d as hasCredentials,b as loadCredentials,a as saveCredentials}from'./chunk-EFAKSIRR.js';import {fileURLToPath}from'url';import {join,dirname}from'path';import {privateKeyToAccount,signMessage,generatePrivateKey,signTypedData}from'viem/accounts';import {z as z$1}from'zod';import {createWalletClient,http,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';import {existsSync,mkdirSync,writeFileSync,chmodSync,readFileSync}from'fs';import {homedir}from'os';var l=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},k=class extends l{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},$=class extends l{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},v=class extends l{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,r=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${r}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},A=class extends l{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},S=class extends l{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},T=class extends l{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},D=class extends l{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},U=class extends l{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},I=class extends l{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},R=class extends l{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},E=class extends l{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}},L=class extends l{constructor(e=6e4,t){super(t||`Rate limit exceeded. Please wait ${Math.ceil(e/1e3)} seconds before retrying.`,"RATE_LIMIT_EXCEEDED",e),this.name="RateLimitError";}isRetryable(){return true}},N=class extends l{reason;constructor(e,t){super(`Network error: ${e}. Check your connection and try again.`,"NETWORK_ERROR",5e3),this.name="NetworkError",this.reason=e,t?.stack&&(this.stack=t.stack);}isRetryable(){return true}},F=class extends l{reason;statusCode;constructor(e,t=401){super(`Authentication failed: ${e}`,t===401?"UNAUTHORIZED":"FORBIDDEN"),this.name="AuthenticationError",this.reason=e,this.statusCode=t;}isRetryable(){return false}};function Ue(c){return c instanceof l}function Ie(c){return c instanceof l||c instanceof Error?c.message:String(c)}var De={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Ee={name:"USD Coin",version:"2"},Oe={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},j=class c{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new S("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let r=`0x${a}`;return new c(r,n==="test")}catch(r){throw new S(`Failed to decode session key: ${r}`)}}async signTransferAuthorization(e,t){return signTypedData({privateKey:this.privateKey,domain:e,types:Oe,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function Y(c){let e=De[c.chainId];if(!e)throw new Error(`USDC not supported on chain ${c.chainId}`);let t={...Ee,chainId:c.chainId,verifyingContract:e},s={from:c.fromAddress,to:c.toAddress,value:c.value,validAfter:c.validAfter,validBefore:c.validBefore,nonce:c.nonce};return {domain:t,message:s}}function W(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ke(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function V(c){let e=Date.now(),t=Ke(e,c.address),s=await c.signMessage(t);return {address:c.address,timestamp:e,signature:s}}var Z=z$1.object({query:z$1.string().describe('Search query (e.g. "web scraping", "email", "database")')}),Q=z$1.object({tool_name:z$1.string().describe('Tool name in "merchant/tool" format'),arguments:z$1.record(z$1.unknown()).optional().describe("Arguments to pass to the tool")}),ee=z$1.object({url:z$1.string().url().describe("The merchant API URL to call"),merchant_public_key:z$1.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:z$1.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:z$1.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:z$1.number().optional().describe("Expected price in USD for client-side validation")}),te=z$1.object({skill_id:z$1.string().describe("The skill ID to execute"),input:z$1.record(z$1.unknown()).optional().describe("Input parameters for the skill")}),se=z$1.object({skill_id:z$1.string().describe("The skill ID to check")}),ne=z$1.object({glama_id:z$1.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:z$1.string().describe('Glama namespace (e.g. "notion")'),glama_slug:z$1.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:z$1.string().describe("Human-readable name for the tool"),tool_description:z$1.string().optional().describe("Optional description"),env_vars:z$1.record(z$1.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:z$1.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),ae=z$1.object({status:z$1.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),re=z$1.object({instance_id:z$1.string().describe("The instance ID to stop")}),ie=z$1.object({to:z$1.string().describe("Recipient address (0x...)"),amount_usdc:z$1.number().positive().describe("Amount in USDC (e.g. 10.5)")}),oe=z$1.object({name:z$1.string().describe("Name for the child agent"),budget_usd:z$1.number().positive().describe("Budget to delegate in USD"),budget_period:z$1.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:z$1.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:z$1.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),le=z$1.object({title:z$1.string().describe("Task title"),description:z$1.string().describe("Detailed task description"),budget_usd:z$1.number().positive().describe("Budget for the task in USD"),skills_required:z$1.array(z$1.string()).optional().describe("Required skill IDs")}),ce=z$1.object({status:z$1.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:z$1.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function de(c){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await c.getBalance(),network:c.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:Z,handler:async s=>{let{query:n}=Z.parse(s);return c.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:Q,handler:async s=>{let{tool_name:n,arguments:a}=Q.parse(s);return c.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ee,handler:async s=>{let{url:n,merchant_public_key:a,method:r,body:i,price_usd:o}=ee.parse(s),d=await c.callMerchantApi({url:n,merchantPublicKey:a,method:r,body:i,priceUsd:o}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:te,handler:async s=>{let{skill_id:n,input:a}=te.parse(s);return c.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:se,handler:async s=>{let{skill_id:n}=se.parse(s);return c.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ne,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:r,tool_name:i,tool_description:o,env_vars:d,ttl_hours:g}=ne.parse(s);return c.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:r,toolName:i,toolDescription:o,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ae,handler:async s=>{let{status:n}=ae.parse(s);return c.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:re,handler:async s=>{let{instance_id:n}=re.parse(s);return await c.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:ie,handler:async s=>{let{to:n,amount_usdc:a}=ie.parse(s);if(!await c.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await c.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:oe,handler:async s=>{let{name:n,budget_usd:a,budget_period:r,max_per_tx_usd:i,expires_in_days:o}=oe.parse(s);return c.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:r,maxPerTxUsd:i,expiresInDays:o})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:le,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=le.parse(s);return c.createTask({title:n,description:a,budgetUsd:r,skillsRequired:i})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:ce,handler:async s=>{let{status:n,limit:a}=ce.parse(s);return c.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(r=>r.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let r=await a.handler(n);return JSON.stringify(r,null,2)}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(i)}}}}function ue(c){if(c instanceof z$1.ZodObject){let e=c._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let r=a;t[n]=M(r),!(r instanceof z$1.ZodOptional)&&!(r instanceof z$1.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function M(c){let e=c;e instanceof z$1.ZodOptional&&(e=e._def.innerType),e instanceof z$1.ZodDefault&&(e=e._def.innerType);let t=c._def.description;if(e instanceof z$1.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof z$1.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof z$1.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof z$1.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof z$1.ZodArray)return {type:"array",items:M(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:M(e._def.valueType),...t&&{description:t}};if(e instanceof z$1.ZodObject){let s=e._def.shape(),n={};for(let[a,r]of Object.entries(s))n[a]=M(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ne="0.9.5",ge=".config/mixrpay",Fe="wallet.json";function me(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,ge):join(homedir(),ge)}function C(){return join(me(),Fe)}async function B(c,e){let t=me(),s=C();existsSync(t)||mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:c,createdAt:new Date().toISOString(),sdkVersion:Ne};writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{chmodSync(s,384);}catch{}}async function H(){let c=process.env.MIXRPAY_WALLET_KEY;if(c){if(c.startsWith("0x")&&c.length===66)return c;if(c.length===64)return `0x${c}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=C();if(!existsSync(e))return null;try{let t=readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function We(){let c=C();if(!existsSync(c)){let e=process.env.MIXRPAY_WALLET_KEY;return e&&(e.startsWith("0x")?e:`0x${e}`).length===66,null}try{let e=readFileSync(c,"utf-8");return JSON.parse(e)}catch{return null}}async function J(){let c=process.env.MIXRPAY_WALLET_KEY;return c&&(c.length===64||c.startsWith("0x")&&c.length===66)?true:existsSync(C())}function qe(){return C()}async function Be(){let c=C();if(!existsSync(c))return false;try{let{unlinkSync:e}=await import('fs');return e(c),!0}catch{return false}}async function he(c){let e=null,t=c.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=c.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await c.json();}catch{}if(!e)throw new T("Could not parse payment requirements from 402 response");if(!e.recipient)throw new T("Missing recipient in payment requirements");if(!e.amount)throw new T("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||W().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function ye(c,e,t){let s=c.nonce.length===64?`0x${c.nonce}`:W(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(c.expiresAt),{domain:i,message:o}=Y({fromAddress:t,toAddress:c.recipient,value:c.amount,validAfter:a,validBefore:r,nonce:s,chainId:c.chainId}),d=await e.signTransferAuthorization(i,o),g={x402Version:1,scheme:"exact",network:c.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:c.recipient,value:c.amount.toString(),validAfter:a.toString(),validBefore:r.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function fe(c){return Date.now()/1e3>c.expiresAt}function G(c){return Number(c.amount)/1e6}var Se="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://mixr.network";var et=3e4,be={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},_e={debug:0,info:1,warn:2,error:3,none:4},X=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return _e[e]>=_e[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},z=class c{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=j.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||_).replace(/\/$/,""),this.timeout=e.timeout||et,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new X(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new S("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new S(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new S(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new S("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new l("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new E(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let r=a.substring(2);if(s.endsWith(`.${r}`)&&s!==r)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=register`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),b="";u.status===503?b=" The service may be temporarily unavailable. Please try again later.":u.status===500?b=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(b=" This may indicate an SDK bug. Please update to the latest version.");let K=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l(K)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||_).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:r}=e,i=(e.baseUrl||_).replace(/\/$/,""),d=privateKeyToAccount(t).address,g=await fetch(`${i}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new l(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await signMessage({message:p,privateKey:t}),f=await fetch(`${i}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:r})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new l(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||_).replace(/\/$/,""),a=privateKeyToAccount(t).address,r=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:i,message:o}=await r.json(),d=await signMessage({message:o,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${i}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new l(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=revoke`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new l(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=withdraw`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,to_address:r,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(s).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=claim-invite`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:o,agent_wallet_address:r,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new l(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||_).replace(/\/$/,""),n=new c({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),r=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!r.ok){let o=await r.json().catch(()=>({}));throw new l(o.error||`Activation failed: ${r.status}`)}let i=await r.json();return {wallet:n,budget:{maxTotalUsd:i.budget.max_total_usd,maxDailyUsd:i.budget.max_daily_usd,maxPerTxUsd:i.budget.max_per_tx_usd,spentUsd:i.budget.spent_usd,remainingUsd:i.budget.remaining_usd},capabilities:{executeTransactions:i.capabilities.execute_transactions,gasSponsored:i.capabilities.gas_sponsored,batchedTx:i.capabilities.batched_tx},skills:i.skills||[],tools:i.tools||[],gatewayProviders:i.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||_).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new c({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new c({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let r=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(r&&(r.startsWith("agt_live_")||r.startsWith("agt_test_")))return c.fromApiKey(r,{baseUrl:t,logLevel:s});let i=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(i)return c.fromAccessCode(i,{baseUrl:t,logLevel:s});let o=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(o&&d)return c.fromMasterKey(o,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await import('./credentials-64ZBZ5AS.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return c.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return c.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return c.deviceFlowLogin({baseUrl:t,logLevel:s});throw new l(`No MixrPay credentials found. Options:
|
|
2
|
-
1. Set MIXRPAY_SESSION_KEY environment variable
|
|
3
|
-
2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)
|
|
4
|
-
3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)
|
|
5
|
-
4. Pass sessionKey or accessCode to connect()
|
|
6
|
-
5. Run \`npx mixrpay login\` to cache credentials
|
|
7
|
-
6. Use connect({ interactive: true }) for browser login`)}static async fromApiKey(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new l(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let o=await n.json().catch(()=>({}));throw new l(o.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),r=a.session_key;if(!r)throw new l("No session_key in API response");let i=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i.setApiKey(e),a.agent_instance_id&&i.setAgentInstanceId(a.agent_instance_id),i}static async fromAccessCode(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new l(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new l((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),r=a.session_key,i=a.token,o=a.agent_id;if(!r)throw new l("No session_key in access code response");try{let{saveCredentials:g}=await import('./credentials-64ZBZ5AS.js');g({sessionKey:r,apiToken:i,baseUrl:s});}catch{}let d=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i&&(d.apiKey=i),o&&(d.agentInstanceId=o),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new l("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(g.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key,o=r.session_key_id;if(!i)throw new l("No session_key in master key response");let d=new c({sessionKey:i,sessionKeyId:o,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(d.agentInstanceId=r.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||_).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new l(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:r,verification_uri:i,verification_uri_complete:o,expires_in:d,interval:g}=n;console.log(`
|
|
1
|
+
export{c as deleteCredentials,e as getCredentialsFilePath,d as hasCredentials,b as loadCredentials,a as saveCredentials}from'./chunk-EFAKSIRR.js';import {fileURLToPath}from'url';import {join,dirname}from'path';import {privateKeyToAccount,signMessage,generatePrivateKey,signTypedData}from'viem/accounts';import {z as z$1}from'zod';import {createWalletClient,http,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';import {existsSync,mkdirSync,writeFileSync,chmodSync,readFileSync}from'fs';import {homedir}from'os';var l=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},k=class extends l{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},$=class extends l{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},v=class extends l{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,r=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${r}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},A=class extends l{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},S=class extends l{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},T=class extends l{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},D=class extends l{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},U=class extends l{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},I=class extends l{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},R=class extends l{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},E=class extends l{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}},L=class extends l{constructor(e=6e4,t){super(t||`Rate limit exceeded. Please wait ${Math.ceil(e/1e3)} seconds before retrying.`,"RATE_LIMIT_EXCEEDED",e),this.name="RateLimitError";}isRetryable(){return true}},N=class extends l{reason;constructor(e,t){super(`Network error: ${e}. Check your connection and try again.`,"NETWORK_ERROR",5e3),this.name="NetworkError",this.reason=e,t?.stack&&(this.stack=t.stack);}isRetryable(){return true}},F=class extends l{reason;statusCode;constructor(e,t=401){super(`Authentication failed: ${e}`,t===401?"UNAUTHORIZED":"FORBIDDEN"),this.name="AuthenticationError",this.reason=e,this.statusCode=t;}isRetryable(){return false}};function Ue(c){return c instanceof l}function Ie(c){return c instanceof l||c instanceof Error?c.message:String(c)}var De={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Ee={name:"USD Coin",version:"2"},Oe={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},j=class c{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new S("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let r=`0x${a}`;return new c(r,n==="test")}catch(r){throw new S(`Failed to decode session key: ${r}`)}}async signTransferAuthorization(e,t){return signTypedData({privateKey:this.privateKey,domain:e,types:Oe,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function Y(c){let e=De[c.chainId];if(!e)throw new Error(`USDC not supported on chain ${c.chainId}`);let t={...Ee,chainId:c.chainId,verifyingContract:e},s={from:c.fromAddress,to:c.toAddress,value:c.value,validAfter:c.validAfter,validBefore:c.validBefore,nonce:c.nonce};return {domain:t,message:s}}function W(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ke(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function V(c){let e=Date.now(),t=Ke(e,c.address),s=await c.signMessage(t);return {address:c.address,timestamp:e,signature:s}}var Z=z$1.object({query:z$1.string().describe('Search query (e.g. "web scraping", "email", "database")')}),Q=z$1.object({tool_name:z$1.string().describe('Tool name in "merchant/tool" format'),arguments:z$1.record(z$1.unknown()).optional().describe("Arguments to pass to the tool")}),ee=z$1.object({url:z$1.string().url().describe("The merchant API URL to call"),merchant_public_key:z$1.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:z$1.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:z$1.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:z$1.number().optional().describe("Expected price in USD for client-side validation")}),te=z$1.object({skill_id:z$1.string().describe("The skill ID to execute"),input:z$1.record(z$1.unknown()).optional().describe("Input parameters for the skill")}),se=z$1.object({skill_id:z$1.string().describe("The skill ID to check")}),ne=z$1.object({glama_id:z$1.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:z$1.string().describe('Glama namespace (e.g. "notion")'),glama_slug:z$1.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:z$1.string().describe("Human-readable name for the tool"),tool_description:z$1.string().optional().describe("Optional description"),env_vars:z$1.record(z$1.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:z$1.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),ae=z$1.object({status:z$1.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),re=z$1.object({instance_id:z$1.string().describe("The instance ID to stop")}),ie=z$1.object({to:z$1.string().describe("Recipient address (0x...)"),amount_usdc:z$1.number().positive().describe("Amount in USDC (e.g. 10.5)")}),oe=z$1.object({name:z$1.string().describe("Name for the child agent"),budget_usd:z$1.number().positive().describe("Budget to delegate in USD"),budget_period:z$1.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:z$1.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:z$1.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),le=z$1.object({title:z$1.string().describe("Task title"),description:z$1.string().describe("Detailed task description"),budget_usd:z$1.number().positive().describe("Budget for the task in USD"),skills_required:z$1.array(z$1.string()).optional().describe("Required skill IDs")}),ce=z$1.object({status:z$1.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:z$1.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function de(c){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await c.getBalance(),network:c.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:Z,handler:async s=>{let{query:n}=Z.parse(s);return c.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:Q,handler:async s=>{let{tool_name:n,arguments:a}=Q.parse(s);return c.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ee,handler:async s=>{let{url:n,merchant_public_key:a,method:r,body:i,price_usd:o}=ee.parse(s),d=await c.callMerchantApi({url:n,merchantPublicKey:a,method:r,body:i,priceUsd:o}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:te,handler:async s=>{let{skill_id:n,input:a}=te.parse(s);return c.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:se,handler:async s=>{let{skill_id:n}=se.parse(s);return c.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ne,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:r,tool_name:i,tool_description:o,env_vars:d,ttl_hours:g}=ne.parse(s);return c.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:r,toolName:i,toolDescription:o,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ae,handler:async s=>{let{status:n}=ae.parse(s);return c.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:re,handler:async s=>{let{instance_id:n}=re.parse(s);return await c.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:ie,handler:async s=>{let{to:n,amount_usdc:a}=ie.parse(s);if(!await c.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await c.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:oe,handler:async s=>{let{name:n,budget_usd:a,budget_period:r,max_per_tx_usd:i,expires_in_days:o}=oe.parse(s);return c.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:r,maxPerTxUsd:i,expiresInDays:o})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:le,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=le.parse(s);return c.createTask({title:n,description:a,budgetUsd:r,skillsRequired:i})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:ce,handler:async s=>{let{status:n,limit:a}=ce.parse(s);return c.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(r=>r.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let r=await a.handler(n);return JSON.stringify(r,null,2)}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(i)}}}}function ue(c){if(c instanceof z$1.ZodObject){let e=c._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let r=a;t[n]=M(r),!(r instanceof z$1.ZodOptional)&&!(r instanceof z$1.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function M(c){let e=c;e instanceof z$1.ZodOptional&&(e=e._def.innerType),e instanceof z$1.ZodDefault&&(e=e._def.innerType);let t=c._def.description;if(e instanceof z$1.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof z$1.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof z$1.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof z$1.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof z$1.ZodArray)return {type:"array",items:M(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:M(e._def.valueType),...t&&{description:t}};if(e instanceof z$1.ZodObject){let s=e._def.shape(),n={};for(let[a,r]of Object.entries(s))n[a]=M(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ne="0.9.5",ge=".config/mixrpay",Fe="wallet.json";function me(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,ge):join(homedir(),ge)}function C(){return join(me(),Fe)}async function B(c,e){let t=me(),s=C();existsSync(t)||mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:c,createdAt:new Date().toISOString(),sdkVersion:Ne};writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{chmodSync(s,384);}catch{}}async function H(){let c=process.env.MIXRPAY_WALLET_KEY;if(c){if(c.startsWith("0x")&&c.length===66)return c;if(c.length===64)return `0x${c}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=C();if(!existsSync(e))return null;try{let t=readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function We(){let c=C();if(!existsSync(c)){let e=process.env.MIXRPAY_WALLET_KEY;return e&&(e.startsWith("0x")?e:`0x${e}`).length===66,null}try{let e=readFileSync(c,"utf-8");return JSON.parse(e)}catch{return null}}async function J(){let c=process.env.MIXRPAY_WALLET_KEY;return c&&(c.length===64||c.startsWith("0x")&&c.length===66)?true:existsSync(C())}function qe(){return C()}async function Be(){let c=C();if(!existsSync(c))return false;try{let{unlinkSync:e}=await import('fs');return e(c),!0}catch{return false}}async function he(c){let e=null,t=c.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=c.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await c.json();}catch{}if(!e)throw new T("Could not parse payment requirements from 402 response");if(!e.recipient)throw new T("Missing recipient in payment requirements");if(!e.amount)throw new T("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||W().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function ye(c,e,t){let s=c.nonce.length===64?`0x${c.nonce}`:W(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(c.expiresAt),{domain:i,message:o}=Y({fromAddress:t,toAddress:c.recipient,value:c.amount,validAfter:a,validBefore:r,nonce:s,chainId:c.chainId}),d=await e.signTransferAuthorization(i,o),g={x402Version:1,scheme:"exact",network:c.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:c.recipient,value:c.amount.toString(),validAfter:a.toString(),validBefore:r.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function fe(c){return Date.now()/1e3>c.expiresAt}function G(c){return Number(c.amount)/1e6}var Se="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://mixr.network";var et=3e4,be={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},_e={debug:0,info:1,warn:2,error:3,none:4},X=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return _e[e]>=_e[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},z=class c{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=j.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||_).replace(/\/$/,""),this.timeout=e.timeout||et,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new X(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new S("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new S(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new S(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new S("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new l("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new E(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let r=a.substring(2);if(s.endsWith(`.${r}`)&&s!==r)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=register`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),b="";u.status===503?b=" The service may be temporarily unavailable. Please try again later.":u.status===500?b=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(b=" This may indicate an SDK bug. Please update to the latest version.");let K=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l(K)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||_).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:r}=e,i=(e.baseUrl||_).replace(/\/$/,""),d=privateKeyToAccount(t).address,g=await fetch(`${i}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new l(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await signMessage({message:p,privateKey:t}),f=await fetch(`${i}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:r})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new l(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||_).replace(/\/$/,""),a=privateKeyToAccount(t).address,r=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:i,message:o}=await r.json(),d=await signMessage({message:o,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${i}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new l(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=revoke`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new l(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=withdraw`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,to_address:r,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(s).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=claim-invite`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:o,agent_wallet_address:r,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new l(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||_).replace(/\/$/,""),n=new c({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),r=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!r.ok){let o=await r.json().catch(()=>({}));throw new l(o.error||`Activation failed: ${r.status}`)}let i=await r.json();return {wallet:n,budget:{maxTotalUsd:i.budget.max_total_usd,maxDailyUsd:i.budget.max_daily_usd,maxPerTxUsd:i.budget.max_per_tx_usd,spentUsd:i.budget.spent_usd,remainingUsd:i.budget.remaining_usd},capabilities:{executeTransactions:i.capabilities.execute_transactions,gasSponsored:i.capabilities.gas_sponsored,batchedTx:i.capabilities.batched_tx},skills:i.skills||[],tools:i.tools||[],gatewayProviders:i.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||_).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new c({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new c({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let r=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(r&&(r.startsWith("agt_live_")||r.startsWith("agt_test_")))return c.fromApiKey(r,{baseUrl:t,logLevel:s});let i=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(i)return c.fromAccessCode(i,{baseUrl:t,logLevel:s});let o=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(o&&d)return c.fromMasterKey(o,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await import('./credentials-64ZBZ5AS.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return c.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return c.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return c.deviceFlowLogin({baseUrl:t,logLevel:s});throw new l("No MixrPay credentials found. Options:\n 1. Set MIXRPAY_SESSION_KEY environment variable\n 2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)\n 3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)\n 4. Pass sessionKey or accessCode to connect()\n 5. Run `npx --package @mixrpay/agent-sdk mixrpay login` (or `npm i -g @mixrpay/agent-sdk` then `mixrpay login`)\n 6. Use connect({ interactive: true }) for browser login")}static async fromApiKey(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new l(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let o=await n.json().catch(()=>({}));throw new l(o.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),r=a.session_key;if(!r)throw new l("No session_key in API response");let i=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i.setApiKey(e),a.agent_instance_id&&i.setAgentInstanceId(a.agent_instance_id),i}static async fromAccessCode(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new l(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new l((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),r=a.session_key,i=a.token,o=a.agent_id;if(!r)throw new l("No session_key in access code response");try{let{saveCredentials:g}=await import('./credentials-64ZBZ5AS.js');g({sessionKey:r,apiToken:i,baseUrl:s});}catch{}let d=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i&&(d.apiKey=i),o&&(d.agentInstanceId=o),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new l("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(g.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key,o=r.session_key_id;if(!i)throw new l("No session_key in master key response");let d=new c({sessionKey:i,sessionKeyId:o,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(d.agentInstanceId=r.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||_).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new l(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:r,verification_uri:i,verification_uri_complete:o,expires_in:d,interval:g}=n;console.log(`
|
|
8
2
|
\u{1F510} MixrPay Login
|
|
9
3
|
`),console.log(`Visit: ${o||i}`),console.log(`Enter code: ${r}
|
|
10
4
|
`),console.log(`Waiting for authentication...
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {fileURLToPath}from'url';import {join,dirname}from'path';import {privateKeyToAccount,signMessage,generatePrivateKey,signTypedData}from'viem/accounts';import {z as z$1}from'zod';import {createWalletClient,http,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';import {existsSync,readFileSync,mkdirSync,writeFileSync,chmodSync}from'fs';import {homedir}from'os';var l=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},k=class extends l{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},$=class extends l{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},T=class extends l{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,r=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${r}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},x=class extends l{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},A=class extends l{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},P=class extends l{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},D=class extends l{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},U=class extends l{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},I=class extends l{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},R=class extends l{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},E=class extends l{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}};var ke={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Te={name:"USD Coin",version:"2"},Pe={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},O=class c{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new A("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let r=`0x${a}`;return new c(r,n==="test")}catch(r){throw new A(`Failed to decode session key: ${r}`)}}async signTransferAuthorization(e,t){return signTypedData({privateKey:this.privateKey,domain:e,types:Pe,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function X(c){let e=ke[c.chainId];if(!e)throw new Error(`USDC not supported on chain ${c.chainId}`);let t={...Te,chainId:c.chainId,verifyingContract:e},s={from:c.fromAddress,to:c.toAddress,value:c.value,validAfter:c.validAfter,validBefore:c.validBefore,nonce:c.nonce};return {domain:t,message:s}}function N(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ue(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function Y(c){let e=Date.now(),t=Ue(e,c.address),s=await c.signMessage(t);return {address:c.address,timestamp:e,signature:s}}var z=z$1.object({query:z$1.string().describe('Search query (e.g. "web scraping", "email", "database")')}),V=z$1.object({tool_name:z$1.string().describe('Tool name in "merchant/tool" format'),arguments:z$1.record(z$1.unknown()).optional().describe("Arguments to pass to the tool")}),Z=z$1.object({url:z$1.string().url().describe("The merchant API URL to call"),merchant_public_key:z$1.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:z$1.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:z$1.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:z$1.number().optional().describe("Expected price in USD for client-side validation")}),Q=z$1.object({skill_id:z$1.string().describe("The skill ID to execute"),input:z$1.record(z$1.unknown()).optional().describe("Input parameters for the skill")}),ee=z$1.object({skill_id:z$1.string().describe("The skill ID to check")}),te=z$1.object({glama_id:z$1.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:z$1.string().describe('Glama namespace (e.g. "notion")'),glama_slug:z$1.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:z$1.string().describe("Human-readable name for the tool"),tool_description:z$1.string().optional().describe("Optional description"),env_vars:z$1.record(z$1.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:z$1.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),se=z$1.object({status:z$1.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),ne=z$1.object({instance_id:z$1.string().describe("The instance ID to stop")}),ae=z$1.object({to:z$1.string().describe("Recipient address (0x...)"),amount_usdc:z$1.number().positive().describe("Amount in USDC (e.g. 10.5)")}),re=z$1.object({name:z$1.string().describe("Name for the child agent"),budget_usd:z$1.number().positive().describe("Budget to delegate in USD"),budget_period:z$1.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:z$1.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:z$1.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),ie=z$1.object({title:z$1.string().describe("Task title"),description:z$1.string().describe("Detailed task description"),budget_usd:z$1.number().positive().describe("Budget for the task in USD"),skills_required:z$1.array(z$1.string()).optional().describe("Required skill IDs")}),oe=z$1.object({status:z$1.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:z$1.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function j(c){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await c.getBalance(),network:c.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:z,handler:async s=>{let{query:n}=z.parse(s);return c.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:V,handler:async s=>{let{tool_name:n,arguments:a}=V.parse(s);return c.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:Z,handler:async s=>{let{url:n,merchant_public_key:a,method:r,body:i,price_usd:o}=Z.parse(s),d=await c.callMerchantApi({url:n,merchantPublicKey:a,method:r,body:i,priceUsd:o}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:Q,handler:async s=>{let{skill_id:n,input:a}=Q.parse(s);return c.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ee,handler:async s=>{let{skill_id:n}=ee.parse(s);return c.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:te,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:r,tool_name:i,tool_description:o,env_vars:d,ttl_hours:g}=te.parse(s);return c.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:r,toolName:i,toolDescription:o,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:se,handler:async s=>{let{status:n}=se.parse(s);return c.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:ne,handler:async s=>{let{instance_id:n}=ne.parse(s);return await c.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:ae,handler:async s=>{let{to:n,amount_usdc:a}=ae.parse(s);if(!await c.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await c.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:re,handler:async s=>{let{name:n,budget_usd:a,budget_period:r,max_per_tx_usd:i,expires_in_days:o}=re.parse(s);return c.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:r,maxPerTxUsd:i,expiresInDays:o})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ie,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=ie.parse(s);return c.createTask({title:n,description:a,budgetUsd:r,skillsRequired:i})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:oe,handler:async s=>{let{status:n,limit:a}=oe.parse(s);return c.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(r=>r.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let r=await a.handler(n);return JSON.stringify(r,null,2)}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(i)}}}}function le(c){if(c instanceof z$1.ZodObject){let e=c._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let r=a;t[n]=K(r),!(r instanceof z$1.ZodOptional)&&!(r instanceof z$1.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function K(c){let e=c;e instanceof z$1.ZodOptional&&(e=e._def.innerType),e instanceof z$1.ZodDefault&&(e=e._def.innerType);let t=c._def.description;if(e instanceof z$1.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof z$1.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof z$1.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof z$1.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof z$1.ZodArray)return {type:"array",items:K(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:K(e._def.valueType),...t&&{description:t}};if(e instanceof z$1.ZodObject){let s=e._def.shape(),n={};for(let[a,r]of Object.entries(s))n[a]=K(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ee="0.9.5",ce=".config/mixrpay",Oe="wallet.json";function de(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,ce):join(homedir(),ce)}function W(){return join(de(),Oe)}async function ue(c,e){let t=de(),s=W();existsSync(t)||mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:c,createdAt:new Date().toISOString(),sdkVersion:Ee};writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{chmodSync(s,384);}catch{}}async function q(){let c=process.env.MIXRPAY_WALLET_KEY;if(c){if(c.startsWith("0x")&&c.length===66)return c;if(c.length===64)return `0x${c}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=W();if(!existsSync(e))return null;try{let t=readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function ge(){let c=process.env.MIXRPAY_WALLET_KEY;return c&&(c.length===64||c.startsWith("0x")&&c.length===66)?true:existsSync(W())}async function pe(c){let e=null,t=c.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=c.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await c.json();}catch{}if(!e)throw new P("Could not parse payment requirements from 402 response");if(!e.recipient)throw new P("Missing recipient in payment requirements");if(!e.amount)throw new P("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||N().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function me(c,e,t){let s=c.nonce.length===64?`0x${c.nonce}`:N(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(c.expiresAt),{domain:i,message:o}=X({fromAddress:t,toAddress:c.recipient,value:c.amount,validAfter:a,validBefore:r,nonce:s,chainId:c.chainId}),d=await e.signTransferAuthorization(i,o),g={x402Version:1,scheme:"exact",network:c.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:c.recipient,value:c.amount.toString(),validAfter:a.toString(),validBefore:r.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function he(c){return Date.now()/1e3>c.expiresAt}function B(c){return Number(c.amount)/1e6}var H="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://mixr.network";var qe=3e4,fe={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},we={debug:0,info:1,warn:2,error:3,none:4},J=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return we[e]>=we[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},M=class c{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=O.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||_).replace(/\/$/,""),this.timeout=e.timeout||qe,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new J(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new A("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new A(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new A(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new A("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new l("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new E(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let r=a.substring(2);if(s.endsWith(`.${r}`)&&s!==r)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=register`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),b="";u.status===503?b=" The service may be temporarily unavailable. Please try again later.":u.status===500?b=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(b=" This may indicate an SDK bug. Please update to the latest version.");let C=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l(C)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||_).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:r}=e,i=(e.baseUrl||_).replace(/\/$/,""),d=privateKeyToAccount(t).address,g=await fetch(`${i}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new l(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await signMessage({message:p,privateKey:t}),f=await fetch(`${i}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:r})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new l(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||_).replace(/\/$/,""),a=privateKeyToAccount(t).address,r=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:i,message:o}=await r.json(),d=await signMessage({message:o,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${i}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new l(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=revoke`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new l(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=withdraw`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,to_address:r,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(s).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=claim-invite`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:o,agent_wallet_address:r,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new l(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||_).replace(/\/$/,""),n=new c({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),r=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!r.ok){let o=await r.json().catch(()=>({}));throw new l(o.error||`Activation failed: ${r.status}`)}let i=await r.json();return {wallet:n,budget:{maxTotalUsd:i.budget.max_total_usd,maxDailyUsd:i.budget.max_daily_usd,maxPerTxUsd:i.budget.max_per_tx_usd,spentUsd:i.budget.spent_usd,remainingUsd:i.budget.remaining_usd},capabilities:{executeTransactions:i.capabilities.execute_transactions,gasSponsored:i.capabilities.gas_sponsored,batchedTx:i.capabilities.batched_tx},skills:i.skills||[],tools:i.tools||[],gatewayProviders:i.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||_).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new c({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new c({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let r=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(r&&(r.startsWith("agt_live_")||r.startsWith("agt_test_")))return c.fromApiKey(r,{baseUrl:t,logLevel:s});let i=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(i)return c.fromAccessCode(i,{baseUrl:t,logLevel:s});let o=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(o&&d)return c.fromMasterKey(o,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await import('./credentials-2PX5YXGV.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return c.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return c.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return c.deviceFlowLogin({baseUrl:t,logLevel:s});throw new l(`No MixrPay credentials found. Options:
|
|
3
|
-
1. Set MIXRPAY_SESSION_KEY environment variable
|
|
4
|
-
2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)
|
|
5
|
-
3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)
|
|
6
|
-
4. Pass sessionKey or accessCode to connect()
|
|
7
|
-
5. Run \`npx mixrpay login\` to cache credentials
|
|
8
|
-
6. Use connect({ interactive: true }) for browser login`)}static async fromApiKey(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new l(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let o=await n.json().catch(()=>({}));throw new l(o.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),r=a.session_key;if(!r)throw new l("No session_key in API response");let i=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i.setApiKey(e),a.agent_instance_id&&i.setAgentInstanceId(a.agent_instance_id),i}static async fromAccessCode(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new l(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new l((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),r=a.session_key,i=a.token,o=a.agent_id;if(!r)throw new l("No session_key in access code response");try{let{saveCredentials:g}=await import('./credentials-2PX5YXGV.js');g({sessionKey:r,apiToken:i,baseUrl:s});}catch{}let d=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i&&(d.apiKey=i),o&&(d.agentInstanceId=o),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new l("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(g.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key,o=r.session_key_id;if(!i)throw new l("No session_key in master key response");let d=new c({sessionKey:i,sessionKeyId:o,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(d.agentInstanceId=r.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||_).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new l(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:r,verification_uri:i,verification_uri_complete:o,expires_in:d,interval:g}=n;console.log(`
|
|
2
|
+
import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {fileURLToPath}from'url';import {join,dirname}from'path';import {privateKeyToAccount,signMessage,generatePrivateKey,signTypedData}from'viem/accounts';import {z as z$1}from'zod';import {createWalletClient,http,parseUnits,encodeFunctionData}from'viem';import {base}from'viem/chains';import {existsSync,readFileSync,mkdirSync,writeFileSync,chmodSync}from'fs';import {homedir}from'os';var l=class extends Error{code;retryAfterMs;constructor(e,t="MIXRPAY_ERROR",s){super(e),this.name="MixrPayError",this.code=t,this.retryAfterMs=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}isRetryable(){return false}},k=class extends l{required;available;topUpUrl;constructor(e,t){let s=e-t;super(`Insufficient balance: need $${e.toFixed(2)}, have $${t.toFixed(2)} (short $${s.toFixed(2)}). Top up your wallet to continue.`,"INSUFFICIENT_BALANCE"),this.name="InsufficientBalanceError",this.required=e,this.available=t,this.topUpUrl="https://mixr.network/manage/wallet";}},$=class extends l{expiredAt;constructor(e){super(`Session key expired at ${e}. Request a new session key from the wallet owner at https://mixrpay.com/manage/invites`,"SESSION_KEY_EXPIRED"),this.name="SessionKeyExpiredError",this.expiredAt=e;}},T=class extends l{limitType;limit;attempted;constructor(e,t,s){let a={per_tx:"Per-transaction",daily:"Daily",total:"Total",client_max:"Client-side"}[e]||e,r=e==="daily"?"Wait until tomorrow or request a higher limit.":e==="client_max"?"Increase maxPaymentUsd in your AgentWallet configuration.":"Request a new session key with a higher limit.";super(`${a} spending limit exceeded: limit is $${t.toFixed(2)}, attempted $${s.toFixed(2)}. ${r}`,"SPENDING_LIMIT_EXCEEDED"),this.name="SpendingLimitExceededError",this.limitType=e,this.limit=t,this.attempted=s;}isRetryable(){return this.limitType==="daily"}},A=class extends l{reason;txHash;constructor(e,t){let s=`Payment failed: ${e}`;t&&(s+=` (tx: ${t} - check on basescan.org)`),super(s,"PAYMENT_FAILED"),this.name="PaymentFailedError",this.reason=e,this.txHash=t;}isRetryable(){return true}},x=class extends l{reason;constructor(e="Invalid session key format"){super(`${e}. Session keys should be in format: sk_live_<64 hex chars> or sk_test_<64 hex chars>. Get one from https://mixrpay.com/manage/invites`,"INVALID_SESSION_KEY"),this.name="InvalidSessionKeyError",this.reason=e;}},P=class extends l{reason;constructor(e){super(`x402 protocol error: ${e}. This may indicate a server configuration issue. If the problem persists, contact the API provider.`,"X402_PROTOCOL_ERROR"),this.name="X402ProtocolError",this.reason=e;}isRetryable(){return true}},D=class extends l{sessionId;expiredAt;constructor(e,t){super(`Session ${e} has expired${t?` at ${t}`:""}. A new session will be created automatically on your next request.`,"SESSION_EXPIRED"),this.name="SessionExpiredError",this.sessionId=e,this.expiredAt=t;}},U=class extends l{sessionId;limit;requested;remaining;constructor(e,t,s,n){super(`Session spending limit exceeded: limit is $${e.toFixed(2)}, requested $${t.toFixed(2)}, remaining $${s.toFixed(2)}. Create a new session with a higher limit to continue.`,"SESSION_LIMIT_EXCEEDED"),this.name="SessionLimitExceededError",this.sessionId=n,this.limit=e,this.requested=t,this.remaining=s;}},I=class extends l{sessionId;constructor(e){super(`Session ${e} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError",this.sessionId=e;}},R=class extends l{sessionId;reason;constructor(e,t){super(`Session ${e} has been revoked${t?`: ${t}`:""}. Create a new session with getOrCreateSession().`,"SESSION_REVOKED"),this.name="SessionRevokedError",this.sessionId=e,this.reason=t;}},E=class extends l{attempted;allowedPatterns;constructor(e,t){let s=t.slice(0,3).join(", "),n=t.length>3?"...":"";super(`Payment to "${e}" not allowed. Session allowlist: ${s}${n}. Update the session allowlist or create a new session.`,"MERCHANT_NOT_ALLOWED"),this.name="MerchantNotAllowedError",this.attempted=e,this.allowedPatterns=t;}};var ke={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},Te={name:"USD Coin",version:"2"},Pe={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},O=class c{privateKey;account;address;isTest;constructor(e,t){this.privateKey=e,this.account=privateKeyToAccount(e),this.address=this.account.address,this.isTest=t;}toString(){return `${this.isTest?"sk_test_":"sk_live_"}${this.privateKey.slice(2)}`}get privateKeyHex(){return this.privateKey.slice(2)}get rawPrivateKey(){return this.privateKey}static fromString(e){let t=/^sk_(live|test)_([a-fA-F0-9]{64})$/,s=e.match(t);if(!s)throw new x("Session key must be in format sk_live_{64_hex} or sk_test_{64_hex}");let n=s[1],a=s[2];try{let r=`0x${a}`;return new c(r,n==="test")}catch(r){throw new x(`Failed to decode session key: ${r}`)}}async signTransferAuthorization(e,t){return signTypedData({privateKey:this.privateKey,domain:e,types:Pe,primaryType:"TransferWithAuthorization",message:t})}async signMessage(e){return signMessage({privateKey:this.privateKey,message:e})}getDefaultChainId(){return this.isTest?84532:8453}};function X(c){let e=ke[c.chainId];if(!e)throw new Error(`USDC not supported on chain ${c.chainId}`);let t={...Te,chainId:c.chainId,verifyingContract:e},s={from:c.fromAddress,to:c.toAddress,value:c.value,validAfter:c.validAfter,validBefore:c.validBefore,nonce:c.nonce};return {domain:t,message:s}}function N(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ue(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function Y(c){let e=Date.now(),t=Ue(e,c.address),s=await c.signMessage(t);return {address:c.address,timestamp:e,signature:s}}var z=z$1.object({query:z$1.string().describe('Search query (e.g. "web scraping", "email", "database")')}),V=z$1.object({tool_name:z$1.string().describe('Tool name in "merchant/tool" format'),arguments:z$1.record(z$1.unknown()).optional().describe("Arguments to pass to the tool")}),Z=z$1.object({url:z$1.string().url().describe("The merchant API URL to call"),merchant_public_key:z$1.string().describe("The merchant's MixrPay public key (pk_live_... or pk_test_...)"),method:z$1.enum(["GET","POST","PUT","PATCH","DELETE"]).default("POST").describe("HTTP method"),body:z$1.unknown().optional().describe("Request body (will be JSON-serialized)"),price_usd:z$1.number().optional().describe("Expected price in USD for client-side validation")}),Q=z$1.object({skill_id:z$1.string().describe("The skill ID to execute"),input:z$1.record(z$1.unknown()).optional().describe("Input parameters for the skill")}),ee=z$1.object({skill_id:z$1.string().describe("The skill ID to check")}),te=z$1.object({glama_id:z$1.string().describe('Glama server ID (e.g. "notion-mcp")'),glama_namespace:z$1.string().describe('Glama namespace (e.g. "notion")'),glama_slug:z$1.string().describe('Glama slug (e.g. "notion-mcp")'),tool_name:z$1.string().describe("Human-readable name for the tool"),tool_description:z$1.string().optional().describe("Optional description"),env_vars:z$1.record(z$1.string()).optional().describe("Environment variables for the MCP server (e.g. API keys)"),ttl_hours:z$1.number().min(1).max(168).optional().describe("Time-to-live in hours (default: 24, max: 168)")}),se=z$1.object({status:z$1.enum(["provisioning","active","stopped","expired"]).optional().describe("Filter by status")}),ne=z$1.object({instance_id:z$1.string().describe("The instance ID to stop")}),ae=z$1.object({to:z$1.string().describe("Recipient address (0x...)"),amount_usdc:z$1.number().positive().describe("Amount in USDC (e.g. 10.5)")}),re=z$1.object({name:z$1.string().describe("Name for the child agent"),budget_usd:z$1.number().positive().describe("Budget to delegate in USD"),budget_period:z$1.enum(["daily","monthly","total"]).default("total").describe("Budget period"),max_per_tx_usd:z$1.number().positive().optional().describe("Max per-transaction limit in USD"),expires_in_days:z$1.number().min(1).max(365).optional().describe("Expiry in days (default: 30)")}),ie=z$1.object({title:z$1.string().describe("Task title"),description:z$1.string().describe("Detailed task description"),budget_usd:z$1.number().positive().describe("Budget for the task in USD"),skills_required:z$1.array(z$1.string()).optional().describe("Required skill IDs")}),oe=z$1.object({status:z$1.string().optional().describe('Filter by status (e.g. "open", "in_progress")'),limit:z$1.number().min(1).max(100).optional().describe("Number of results (default: 20)")});function j(c){let e=[{name:"check_balance",title:"Check Balance",description:"Get the USDC balance of the wallet on Base.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>({balanceUsd:await c.getBalance(),network:c.isTestnet()?"base-sepolia":"base"})},{name:"get_spending_stats",title:"Get Spending Stats",description:"Get session key spending limits and current usage (total spent, remaining daily/total limits, expiry).",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSpendingStats()},{name:"get_session_info",title:"Get Session Info",description:"Get detailed session key information including limits, usage, expiry, and allowed merchants.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getSessionKeyInfo(true)},{name:"run_diagnostics",title:"Run Diagnostics",description:"Run a full health check on the wallet: API connectivity, session key validity, balance, and latency.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.runDiagnostics()},{name:"list_tools",title:"List Marketplace Tools",description:"Browse all available paid API tools on the MixrPay marketplace. Each tool includes pricing and description.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listTools()},{name:"search_tools",title:"Search Tools",description:"Search the Glama MCP server directory for tools by keyword.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:z,handler:async s=>{let{query:n}=z.parse(s);return c.searchGlamaDirectory(n)}},{name:"call_tool",title:"Call Marketplace Tool",description:'Call a paid API tool on the MixrPay marketplace. Payment is automatic from the wallet. Tool names are in "merchant/tool" format (e.g. "firecrawl/scrape").',annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:V,handler:async s=>{let{tool_name:n,arguments:a}=V.parse(s);return c.callTool(n,a||{})}},{name:"call_merchant_api",title:"Call Merchant API",description:"Call any merchant API endpoint with x402 payment. The wallet handles authentication and payment automatically.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:Z,handler:async s=>{let{url:n,merchant_public_key:a,method:r,body:i,price_usd:o}=Z.parse(s),d=await c.callMerchantApi({url:n,merchantPublicKey:a,method:r,body:i,priceUsd:o}),g=await d.json().catch(()=>d.text());return {status:d.status,data:g}}},{name:"list_skills",title:"List Skills",description:"List all available skills (pre-built integrations) that the wallet can use.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:null,handler:async()=>c.listSkills()},{name:"use_skill",title:"Use Skill",description:"Execute a skill by ID. Skills are pre-built integrations (e.g. web scraping, email sending).",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:Q,handler:async s=>{let{skill_id:n,input:a}=Q.parse(s);return c.useSkill(n,{input:a})}},{name:"get_skill_status",title:"Get Skill Status",description:"Check the status and configuration of a specific skill.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:ee,handler:async s=>{let{skill_id:n}=ee.parse(s);return c.getSkillStatus(n)}},{name:"deploy_jit_mcp",title:"Deploy JIT MCP Server",description:"Deploy a just-in-time MCP server from the Glama directory. Creates a temporary hosted MCP server instance.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:te,handler:async s=>{let{glama_id:n,glama_namespace:a,glama_slug:r,tool_name:i,tool_description:o,env_vars:d,ttl_hours:g}=te.parse(s);return c.deployJitMcp({glamaId:n,glamaNamespace:a,glamaSlug:r,toolName:i,toolDescription:o,envVars:d,ttlHours:g})}},{name:"list_jit_instances",title:"List JIT Instances",description:"List all deployed JIT MCP server instances.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:se,handler:async s=>{let{status:n}=se.parse(s);return c.listJitInstances(n?{status:n}:void 0)}},{name:"stop_jit_instance",title:"Stop JIT Instance",description:"Stop a running JIT MCP server instance.",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:false},inputSchema:ne,handler:async s=>{let{instance_id:n}=ne.parse(s);return await c.stopJitInstance(n),{success:true,instance_id:n}}},{name:"transfer_usdc",title:"Transfer USDC",description:"Transfer USDC from the self-custody wallet to another address on Base. Only available when the wallet has a self-custody wallet (AGENT_WALLET_KEY set).",annotations:{readOnlyHint:false,destructiveHint:true,openWorldHint:true},inputSchema:ae,handler:async s=>{let{to:n,amount_usdc:a}=ae.parse(s);if(!await c.hasSelfCustodyWallet())throw new Error("No self-custody wallet configured. Set AGENT_WALLET_KEY to enable transfers.");return {success:true,txHash:await c.transferUSDC({to:n,amountUsdc:a}),to:n,amountUsdc:a}}},{name:"get_budget",title:"Get Available Budget",description:"Get the available delegation budget including remaining amount, whether spawning children is possible, and budget limits.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.getAvailableBudget()},{name:"spawn_child",title:"Spawn Child Session",description:"Create a child invite with a delegated budget from this wallet. Returns an invite code that another agent can claim.",annotations:{readOnlyHint:false,openWorldHint:false},inputSchema:re,handler:async s=>{let{name:n,budget_usd:a,budget_period:r,max_per_tx_usd:i,expires_in_days:o}=re.parse(s);return c.spawnChildInvite({name:n,budgetUsd:a,budgetPeriod:r,maxPerTxUsd:i,expiresInDays:o})}},{name:"list_children",title:"List Child Sessions",description:"List all child sessions (agents) spawned from this wallet.",annotations:{readOnlyHint:true,openWorldHint:false},inputSchema:null,handler:async()=>c.listChildSessions()},{name:"create_task",title:"Create Task",description:"Create a new task on the MixrPay marketplace for other agents to complete.",annotations:{readOnlyHint:false,openWorldHint:true},inputSchema:ie,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=ie.parse(s);return c.createTask({title:n,description:a,budgetUsd:r,skillsRequired:i})}},{name:"list_tasks",title:"List Tasks",description:"Browse available tasks on the MixrPay marketplace.",annotations:{readOnlyHint:true,openWorldHint:true},inputSchema:oe,handler:async s=>{let{status:n,limit:a}=oe.parse(s);return c.listTasks({status:n,limit:a})}}];return {definitions:e,execute:async(s,n)=>{let a=e.find(r=>r.name===s);if(!a)throw new Error(`Unknown tool: ${s}`);try{let r=await a.handler(n);return JSON.stringify(r,null,2)}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(i)}}}}function le(c){if(c instanceof z$1.ZodObject){let e=c._def.shape(),t={},s=[];for(let[n,a]of Object.entries(e)){let r=a;t[n]=K(r),!(r instanceof z$1.ZodOptional)&&!(r instanceof z$1.ZodDefault)&&s.push(n);}return {type:"object",properties:t,...s.length>0?{required:s}:{}}}return {type:"object",properties:{}}}function K(c){let e=c;e instanceof z$1.ZodOptional&&(e=e._def.innerType),e instanceof z$1.ZodDefault&&(e=e._def.innerType);let t=c._def.description;if(e instanceof z$1.ZodString)return {type:"string",...t&&{description:t}};if(e instanceof z$1.ZodNumber)return {type:"number",...t&&{description:t}};if(e instanceof z$1.ZodBoolean)return {type:"boolean",...t&&{description:t}};if(e instanceof z$1.ZodEnum)return {type:"string",enum:e._def.values,...t&&{description:t}};if(e instanceof z$1.ZodArray)return {type:"array",items:K(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:K(e._def.valueType),...t&&{description:t}};if(e instanceof z$1.ZodObject){let s=e._def.shape(),n={};for(let[a,r]of Object.entries(s))n[a]=K(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ee="0.9.5",ce=".config/mixrpay",Oe="wallet.json";function de(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,ce):join(homedir(),ce)}function W(){return join(de(),Oe)}async function ue(c,e){let t=de(),s=W();existsSync(t)||mkdirSync(t,{recursive:true,mode:448});let n={address:e.toLowerCase(),privateKey:c,createdAt:new Date().toISOString(),sdkVersion:Ee};writeFileSync(s,JSON.stringify(n,null,2),{encoding:"utf-8",mode:384});try{chmodSync(s,384);}catch{}}async function q(){let c=process.env.MIXRPAY_WALLET_KEY;if(c){if(c.startsWith("0x")&&c.length===66)return c;if(c.length===64)return `0x${c}`;console.warn("[MixrPay] MIXRPAY_WALLET_KEY has invalid format, ignoring");}let e=W();if(!existsSync(e))return null;try{let t=readFileSync(e,"utf-8"),s=JSON.parse(t);return !s.privateKey||!s.privateKey.startsWith("0x")?(console.warn("[MixrPay] Wallet file has invalid format"),null):s.privateKey}catch(t){return console.warn("[MixrPay] Failed to read wallet file:",t),null}}async function ge(){let c=process.env.MIXRPAY_WALLET_KEY;return c&&(c.length===64||c.startsWith("0x")&&c.length===66)?true:existsSync(W())}async function pe(c){let e=null,t=c.headers.get("X-Payment-Required");if(t)try{e=JSON.parse(t);}catch{}if(!e){let n=c.headers.get("WWW-Authenticate");if(n?.startsWith("X-402 "))try{let a=n.slice(6);e=JSON.parse(atob(a));}catch{}}if(!e)try{e=await c.json();}catch{}if(!e)throw new P("Could not parse payment requirements from 402 response");if(!e.recipient)throw new P("Missing recipient in payment requirements");if(!e.amount)throw new P("Missing amount in payment requirements");let s=Math.floor(Date.now()/1e3);return {recipient:e.recipient,amount:BigInt(e.amount),currency:e.currency||"USDC",chainId:e.chainId||e.chain_id||8453,facilitatorUrl:e.facilitatorUrl||e.facilitator_url||"https://x402.org/facilitator",nonce:e.nonce||N().slice(2),expiresAt:e.expiresAt||e.expires_at||s+300,description:e.description}}async function me(c,e,t){let s=c.nonce.length===64?`0x${c.nonce}`:N(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(c.expiresAt),{domain:i,message:o}=X({fromAddress:t,toAddress:c.recipient,value:c.amount,validAfter:a,validBefore:r,nonce:s,chainId:c.chainId}),d=await e.signTransferAuthorization(i,o),g={x402Version:1,scheme:"exact",network:c.chainId===8453?"base":"base-sepolia",payload:{signature:d,authorization:{from:t,to:c.recipient,value:c.amount.toString(),validAfter:a.toString(),validBefore:r.toString(),nonce:s}}};return btoa(JSON.stringify(g))}function he(c){return Date.now()/1e3>c.expiresAt}function B(c){return Number(c.amount)/1e6}var H="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://mixr.network";var qe=3e4,fe={BASE_MAINNET:{chainId:8453,name:"Base",isTestnet:false},BASE_SEPOLIA:{chainId:84532,name:"Base Sepolia",isTestnet:true}},we={debug:0,info:1,warn:2,error:3,none:4},J=class{level;prefix;constructor(e="none",t="[MixrPay]"){this.level=e,this.prefix=t;}setLevel(e){this.level=e;}shouldLog(e){return we[e]>=we[this.level]}debug(...e){this.shouldLog("debug")&&console.log(`${this.prefix} \u{1F50D}`,...e);}info(...e){this.shouldLog("info")&&console.log(`${this.prefix} \u2139\uFE0F`,...e);}warn(...e){this.shouldLog("warn")&&console.warn(`${this.prefix} \u26A0\uFE0F`,...e);}error(...e){this.shouldLog("error")&&console.error(`${this.prefix} \u274C`,...e);}payment(e,t,s){if(this.shouldLog("info")){let n=s?` for "${s}"`:"";console.log(`${this.prefix} \u{1F4B8} Paid $${e.toFixed(4)} to ${t.slice(0,10)}...${n}`);}}},M=class c{sessionKey;walletAddress;maxPaymentUsd;onPayment;baseUrl;timeout;logger;payments=[];totalSpentUsd=0;sessionKeyInfo;sessionKeyInfoFetchedAt;allowlist;allowlistFetchedAt;selfCustodyAddress;selfCustodyKey;agentInstanceId;apiKey;sessionKeyId;constructor(e){this.validateConfig(e),this.sessionKey=O.fromString(e.sessionKey),this.walletAddress=e.walletAddress||this.sessionKey.address,this.maxPaymentUsd=e.maxPaymentUsd,this.onPayment=e.onPayment,this.baseUrl=(e.baseUrl||_).replace(/\/$/,""),this.timeout=e.timeout||qe,e.apiKey&&(this.apiKey=e.apiKey),e.sessionKeyId&&(this.sessionKeyId=e.sessionKeyId),this.logger=new J(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey,hasSessionKeyId:!!this.sessionKeyId});}validateConfig(e){if(!e.sessionKey)throw new x("Session key is required. Get one from the wallet owner at https://mixrpay.com/manage/invites");let t=e.sessionKey.trim();if(!t.startsWith("sk_live_")&&!t.startsWith("sk_test_")){let a=t.slice(0,8);throw new x(`Invalid session key prefix. Expected 'sk_live_' (mainnet) or 'sk_test_' (testnet), got '${a}'`)}let s=72;if(t.length!==s)throw new x(`Invalid session key length. Expected ${s} characters, got ${t.length}. Make sure you copied the complete key.`);let n=t.slice(8);if(!/^[0-9a-fA-F]+$/.test(n))throw new x("Invalid session key format. The key should contain only hexadecimal characters after the prefix.");if(e.maxPaymentUsd!==void 0){if(e.maxPaymentUsd<=0)throw new l("maxPaymentUsd must be a positive number");e.maxPaymentUsd>1e4&&this.logger?.warn("maxPaymentUsd is very high ($"+e.maxPaymentUsd+"). Consider using a lower limit for safety.");}}async fetchAllowlist(){if(this.allowlist!==void 0&&this.allowlistFetchedAt&&Date.now()-this.allowlistFetchedAt<3e5)return this.allowlist;try{let t=await this.getSessionKeyInfo();return this.allowlist=t.allowedMerchants||[],this.allowlistFetchedAt=Date.now(),this.logger.debug("Fetched allowlist",{patterns:this.allowlist.length,allowAll:this.allowlist.length===0}),this.allowlist}catch(t){return this.logger.warn("Failed to fetch allowlist, allowing all merchants",{error:t}),this.allowlist=[],this.allowlistFetchedAt=Date.now(),this.allowlist}}async validateMerchantAllowed(e,t){let s=await this.fetchAllowlist();if(s.length===0)return;if(!this.matchesAllowlist(e,s,t))throw new E(e,s)}matchesAllowlist(e,t,s){for(let n of t)if(this.matchPattern(e,n,s))return true;return false}matchPattern(e,t,s){return s==="url"?this.matchUrlPattern(e,t):this.matchToolPattern(e,t)}matchUrlPattern(e,t){let s;try{e.includes("://")?s=new URL(e).hostname.toLowerCase():s=e.toLowerCase();}catch{return false}let a=t.toLowerCase().trim();if(a.includes("://"))try{a=new URL(a).hostname;}catch{}if(s===a)return true;if(a.startsWith("*.")){let r=a.substring(2);if(s.endsWith(`.${r}`)&&s!==r)return true}return false}matchToolPattern(e,t){let s=e.toLowerCase().trim(),n=t.toLowerCase().trim();if(s===n)return true;if(n.endsWith("/*")){let a=n.substring(0,n.length-2);if(s.startsWith(`${a}/`))return true}return false}static async register(e){let{privateKey:t,name:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=register`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,name:s})});if(!u.ok){let y=await u.json().catch(()=>({})),f=y.error||`Registration failed with status ${u.status}`,h=y.request_id,w=(y.code||"").toLowerCase(),b="";u.status===503?b=" The service may be temporarily unavailable. Please try again later.":u.status===500?b=" This is a server error. Please contact support with the request ID.":(w==="missing_challenge"||w==="missing_signature")&&(b=" This may indicate an SDK bug. Please update to the latest version.");let C=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l(C)}let p=await u.json();return {userId:p.user_id,depositAddress:p.deposit_address}}static async checkServerHealth(e){let t=(e||_).replace(/\/$/,"");try{let s=await fetch(`${t}/api/health/ready?details=true`);if(!s.ok)return {healthy:!1,database:"unknown",agentRegistrationAvailable:!1,walletServiceConfigured:!1,error:`Health check failed with status ${s.status}`};let n=await s.json();return {healthy:n.status==="ready",database:n.database||"unknown",agentRegistrationAvailable:n.services?.agentRegistration?.available??!1,walletServiceConfigured:n.services?.wallet?.configured??!1}}catch(s){return {healthy:false,database:"unreachable",agentRegistrationAvailable:false,walletServiceConfigured:false,error:s instanceof Error?s.message:"Failed to reach server"}}}static async getSessionKey(e){let{privateKey:t,spendingLimitUsd:s,maxPerTxUsd:n,maxDailyUsd:a,durationDays:r}=e,i=(e.baseUrl||_).replace(/\/$/,""),d=privateKeyToAccount(t).address,g=await fetch(`${i}/api/v1/agent/challenge?wallet=${d}&action=session-key`);if(!g.ok){let w=await g.json().catch(()=>({}));throw new l(w.error||`Failed to get challenge: ${g.status}`)}let{challenge:u,message:p}=await g.json(),y=await signMessage({message:p,privateKey:t}),f=await fetch(`${i}/api/v1/agent/session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:u,external_wallet:d,signature:y,spending_limit_usd:s,max_per_tx_usd:n,max_daily_usd:a,duration_days:r})});if(!f.ok){let w=await f.json().catch(()=>({}));throw new l(w.error||`Session key creation failed: ${f.status}`)}let h=await f.json();return {sessionKey:h.session_key,address:h.address,sessionKeyId:h.session_key_id,expiresAt:new Date(h.expires_at),limits:{maxTotalUsd:h.limits.max_total_usd,maxPerTxUsd:h.limits.max_per_tx_usd,maxDailyUsd:h.limits.max_daily_usd}}}static async getStatus(e){let{privateKey:t}=e,s=(e.baseUrl||_).replace(/\/$/,""),a=privateKeyToAccount(t).address,r=await fetch(`${s}/api/v1/agent/challenge?wallet=${a}&action=status`);if(!r.ok){let p=await r.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${r.status}`)}let{challenge:i,message:o}=await r.json(),d=await signMessage({message:o,privateKey:t}),g=await fetch(`${s}/api/v1/agent/status?challenge=${i}&external_wallet=${a}&signature=${encodeURIComponent(d)}`);if(!g.ok){let p=await g.json().catch(()=>({}));throw new l(p.error||`Failed to get status: ${g.status}`)}let u=await g.json();return {depositAddress:u.deposit_address,balanceUsd:u.balance_usd,activeSessions:u.active_sessions.map(p=>({id:p.id,expiresAt:new Date(p.expires_at),totalSpentUsd:p.total_spent_usd,remainingUsd:p.remaining_usd,maxTotalUsd:p.max_total_usd})),totalSpentUsd:u.total_spent_usd}}static async revokeSessionKey(e){let{privateKey:t,sessionKeyId:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=revoke`);if(!i.ok){let p=await i.json().catch(()=>({}));throw new l(p.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/session-key/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,session_key_id:s})});if(!u.ok){let p=await u.json().catch(()=>({}));throw new l(p.error||`Revocation failed: ${u.status}`)}return true}static async withdraw(e){let{privateKey:t,amountUsd:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(t).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=withdraw`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:t}),u=await fetch(`${n}/api/v1/agent/withdraw`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({challenge:o,external_wallet:r,signature:g,to_address:r,amount_usd:s})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Withdrawal failed: ${u.status}`)}let p=await u.json();return {txHash:p.tx_hash,amountUsd:p.amount_usd,remainingBalanceUsd:p.remaining_balance_usd}}static async claimInvite(e){let{inviteCode:t,privateKey:s}=e,n=(e.baseUrl||_).replace(/\/$/,""),r=privateKeyToAccount(s).address,i=await fetch(`${n}/api/v1/agent/challenge?wallet=${r}&action=claim-invite`);if(!i.ok){let y=await i.json().catch(()=>({}));throw new l(y.error||`Failed to get challenge: ${i.status}`)}let{challenge:o,message:d}=await i.json(),g=await signMessage({message:d,privateKey:s}),u=await fetch(`${n}/api/v1/agent/claim-invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({invite_code:t,challenge:o,agent_wallet_address:r,signature:g})});if(!u.ok){let f=(await u.json().catch(()=>({}))).error||`Failed to claim invite: ${u.status}`,h="";throw u.status===404?h=" The invite code may be invalid or misspelled.":u.status===400&&(f.includes("already claimed")?h=" This invite has already been used by another agent.":f.includes("expired")?h=" Ask the wallet owner to create a new invite.":f.includes("revoked")&&(h=" The wallet owner has revoked this invite.")),new l(`${f}${h}`)}let p=await u.json();return {sessionKey:p.session_key,address:p.address,sessionKeyId:p.session_key_id,expiresAt:new Date(p.expires_at),limits:{budgetUsd:p.limits.budget_usd,budgetPeriod:p.limits.budget_period,maxPerTxUsd:p.limits.max_per_tx_usd},allowedMerchants:p.allowed_merchants||[],inviterName:p.inviter_name||"Anonymous"}}static async activate(e,t){let s=(t?.baseUrl||_).replace(/\/$/,""),n=new c({sessionKey:e,baseUrl:s}),a=await n.getSessionAuthHeaders(),r=await fetch(`${s}/api/v2/agent/activate`,{method:"POST",headers:{"Content-Type":"application/json",...a}});if(!r.ok){let o=await r.json().catch(()=>({}));throw new l(o.error||`Activation failed: ${r.status}`)}let i=await r.json();return {wallet:n,budget:{maxTotalUsd:i.budget.max_total_usd,maxDailyUsd:i.budget.max_daily_usd,maxPerTxUsd:i.budget.max_per_tx_usd,spentUsd:i.budget.spent_usd,remainingUsd:i.budget.remaining_usd},capabilities:{executeTransactions:i.capabilities.execute_transactions,gasSponsored:i.capabilities.gas_sponsored,batchedTx:i.capabilities.batched_tx},skills:i.skills||[],tools:i.tools||[],gatewayProviders:i.gateway_providers||[]}}static async connect(e){let t=(e?.baseUrl||process.env.MIXRPAY_BASE_URL||_).replace(/\/$/,""),s=e?.logLevel||"none",n=process.env.MIXRPAY_INSTANCE_ID;if(e?.sessionKey){let g=new c({sessionKey:e.sessionKey,sessionKeyId:e.sessionKeyId,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}let a=process.env.MIXRPAY_SESSION_KEY;if(a){let g=process.env.MIXRPAY_SESSION_KEY_ID,u=new c({sessionKey:a,sessionKeyId:g,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&u.setAgentInstanceId(n),u}let r=process.env.MIXRPAY_API_KEY||process.env.MIXRPAY_AGENT_TOKEN;if(r&&(r.startsWith("agt_live_")||r.startsWith("agt_test_")))return c.fromApiKey(r,{baseUrl:t,logLevel:s});let i=e?.accessCode||process.env.MIXRPAY_ACCESS_CODE;if(i)return c.fromAccessCode(i,{baseUrl:t,logLevel:s});let o=e?.masterKey||process.env.MIXRPAY_MASTER_KEY,d=e?.agentName||process.env.MIXRPAY_AGENT_NAME;if(o&&d)return c.fromMasterKey(o,d,{baseUrl:t,logLevel:s});try{let{loadCredentials:g}=await import('./credentials-2PX5YXGV.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,sessionKeyId:u.credentials.sessionKeyId,baseUrl:u.credentials.baseUrl||t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment,apiKey:u.credentials.apiToken});return n&&p.setAgentInstanceId(n),p}if(u.success&&u.credentials.apiToken)return c.fromApiKey(u.credentials.apiToken,{baseUrl:t,logLevel:s});if(u.success&&u.credentials.masterKey&&u.credentials.defaultAgentName)return c.fromMasterKey(u.credentials.masterKey,u.credentials.defaultAgentName,{baseUrl:t,logLevel:s})}catch{}if(e?.interactive)return c.deviceFlowLogin({baseUrl:t,logLevel:s});throw new l("No MixrPay credentials found. Options:\n 1. Set MIXRPAY_SESSION_KEY environment variable\n 2. Set MIXRPAY_API_KEY or MIXRPAY_AGENT_TOKEN environment variable (agt_live_xxx)\n 3. Set MIXRPAY_ACCESS_CODE environment variable (mixr-xxx)\n 4. Pass sessionKey or accessCode to connect()\n 5. Run `npx --package @mixrpay/agent-sdk mixrpay login` (or `npm i -g @mixrpay/agent-sdk` then `mixrpay login`)\n 6. Use connect({ interactive: true }) for browser login")}static async fromApiKey(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("agt_live_")&&!e.startsWith("agt_test_"))throw new l(`Invalid API key format. Expected 'agt_live_' or 'agt_test_' prefix, got '${e.slice(0,9)}...'`);let n=await fetch(`${s}/api/v2/agent/session-from-token`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});if(!n.ok){let o=await n.json().catch(()=>({}));throw new l(o.error||`Failed to exchange API key for session: ${n.status}`)}let a=await n.json(),r=a.session_key;if(!r)throw new l("No session_key in API response");let i=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i.setApiKey(e),a.agent_instance_id&&i.setAgentInstanceId(a.agent_instance_id),i}static async fromAccessCode(e,t){let s=(t?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mixr-"))throw new l(`Invalid access code format. Expected 'mixr-' prefix, got '${e.slice(0,5)}...'`);let n=await fetch(`${s}/api/v2/agent/connect`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e})});if(!n.ok){let g=await n.json().catch(()=>({})),u=(g.code||"").toLowerCase(),p="";throw n.status===404||u==="invalid_code"?p=" Check the code for typos or get a new one from the MixrPay dashboard.":n.status===400&&(u==="code_claimed"?p=" This code has already been used. Get a new code from the dashboard.":u==="code_expired"?p=" This code has expired. Get a new code from the dashboard.":u==="code_revoked"&&(p=" This code has been revoked by the owner.")),new l((g.error||`Failed to activate access code: ${n.status}`)+p)}let a=await n.json(),r=a.session_key,i=a.token,o=a.agent_id;if(!r)throw new l("No session_key in access code response");try{let{saveCredentials:g}=await import('./credentials-2PX5YXGV.js');g({sessionKey:r,apiToken:i,baseUrl:s});}catch{}let d=new c({sessionKey:r,baseUrl:s,logLevel:t?.logLevel});return i&&(d.apiKey=i),o&&(d.agentInstanceId=o),d}static async fromMasterKey(e,t,s){let n=(s?.baseUrl||_).replace(/\/$/,"");if(!e.startsWith("mk_live_")&&!e.startsWith("mk_test_"))throw new l("Invalid master key format. Expected 'mk_live_' or 'mk_test_' prefix.");let a=await fetch(`${n}/api/v2/master-keys/session`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({agent_name:t})});if(!a.ok){let g=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(g.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key,o=r.session_key_id;if(!i)throw new l("No session_key in master key response");let d=new c({sessionKey:i,sessionKeyId:o,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(d.agentInstanceId=r.agent.id),d}static async deviceFlowLogin(e){let t=(e?.baseUrl||_).replace(/\/$/,""),s=await fetch(`${t}/api/v2/auth/device/authorize`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){let y=await s.json().catch(()=>({}));throw new l(y.error||`Device flow initiation failed: ${s.status}`)}let n=await s.json(),{device_code:a,user_code:r,verification_uri:i,verification_uri_complete:o,expires_in:d,interval:g}=n;console.log(`
|
|
9
3
|
\u{1F510} MixrPay Login
|
|
10
4
|
`),console.log(`Visit: ${o||i}`),console.log(`Enter code: ${r}
|
|
11
5
|
`),console.log(`Waiting for authentication...
|
|
12
6
|
`);let u=(g||5)*1e3,p=Date.now()+(d||300)*1e3;for(;Date.now()<p;){await new Promise(w=>setTimeout(w,u));let y=await fetch(`${t}/api/v2/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:a})});if(y.ok){let w=await y.json(),b=w.session_key,C=w.session_key_id;if(b){console.log(`\u2705 Authenticated successfully!
|
|
13
|
-
`);try{let{saveCredentials:Se}=await import('./credentials-2PX5YXGV.js');Se({sessionKey:b,sessionKeyId:C,baseUrl:t});}catch{}return new c({sessionKey:b,sessionKeyId:C,baseUrl:t,logLevel:e?.logLevel})}}let h=(await y.json().catch(()=>({}))).error;if(h!=="authorization_pending")if(h==="slow_down"){await new Promise(w=>setTimeout(w,u));continue}else {if(h==="expired_token")throw new l("Device code expired. Please try again.");if(h==="access_denied")throw new l("Authentication was denied by the user.");if(h)throw new l(`Device flow error: ${h}`)}}throw new l("Device flow timed out. Please try again.")}async spawnChildInvite(e){let{budgetUsd:t,name:s,allowedMerchants:n,expiresInDays:a}=e,r=await this.getSessionAuthHeaders(),i=await fetch(`${this.baseUrl}/api/v1/agent/spawn`,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify({budget_usd:t,name:s,allowed_merchants:n,expires_in_days:a})});if(!i.ok){let d=await i.json().catch(()=>({}));throw i.status===409?new l("Concurrent modification - please retry"):i.status===429?new l("Rate limited - too many spawn attempts"):new l(d.error||`Failed to spawn child: ${i.status}`)}let o=await i.json();return {inviteCode:o.invite_code,inviteId:o.invite_id,budgetUsd:o.budget_usd,expiresAt:new Date(o.expires_at),depth:o.depth,maxSpawnBudget:o.max_spawn_budget,allowedMerchants:o.allowed_merchants||[]}}async getAvailableBudget(){let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v1/agent/descendants`,{method:"GET",headers:e});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Failed to get budget: ${t.status}`)}let s=await t.json();return {totalBudget:s.budget.total_usd,spent:s.budget.spent_usd,allocatedToChildren:s.budget.allocated_to_children_usd,available:s.budget.available_usd,maxSpawnBudget:s.max_spawn_budget,canSpawn:s.can_spawn}}async getChildSessions(){let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v1/agent/descendants`,{method:"GET",headers:e});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Failed to get children: ${t.status}`)}return (await t.json()).children||[]}async listChildSessions(){return this.getChildSessions()}async fetch(e,t){this.logger.debug(`Fetching ${t?.method||"GET"} ${e}`),await this.validateMerchantAllowed(e,"url");let s=crypto.randomUUID(),n=this.extractCorrelationId(t?.headers),a=new AbortController,r=setTimeout(()=>a.abort(),this.timeout);try{let i=await fetch(e,{...t,signal:a.signal});return this.logger.debug(`Initial response: ${i.status}`),i.status===402&&(this.logger.info(`Payment required for ${e}`),i=await this.handlePaymentRequired(e,t,i,s,n)),i}catch(i){throw i instanceof Error&&i.name==="AbortError"?new l(`Request timeout after ${this.timeout}ms`):i}finally{clearTimeout(r);}}extractCorrelationId(e){if(!e)return;if(e instanceof Headers)return e.get("X-Correlation-Id")||e.get("x-correlation-id")||void 0;if(Array.isArray(e)){let s=e.find(([n])=>n.toLowerCase()==="x-correlation-id");return s?s[1]:void 0}let t=e;return t["X-Correlation-Id"]||t["x-correlation-id"]||void 0}async handlePaymentRequired(e,t,s,n,a){let r;try{r=await pe(s),this.logger.debug("Payment requirements:",{amount:`$${B(r).toFixed(4)}`,recipient:r.recipient,description:r.description});}catch(u){throw this.logger.error("Failed to parse payment requirements:",u),new
|
|
7
|
+
`);try{let{saveCredentials:Se}=await import('./credentials-2PX5YXGV.js');Se({sessionKey:b,sessionKeyId:C,baseUrl:t});}catch{}return new c({sessionKey:b,sessionKeyId:C,baseUrl:t,logLevel:e?.logLevel})}}let h=(await y.json().catch(()=>({}))).error;if(h!=="authorization_pending")if(h==="slow_down"){await new Promise(w=>setTimeout(w,u));continue}else {if(h==="expired_token")throw new l("Device code expired. Please try again.");if(h==="access_denied")throw new l("Authentication was denied by the user.");if(h)throw new l(`Device flow error: ${h}`)}}throw new l("Device flow timed out. Please try again.")}async spawnChildInvite(e){let{budgetUsd:t,name:s,allowedMerchants:n,expiresInDays:a}=e,r=await this.getSessionAuthHeaders(),i=await fetch(`${this.baseUrl}/api/v1/agent/spawn`,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify({budget_usd:t,name:s,allowed_merchants:n,expires_in_days:a})});if(!i.ok){let d=await i.json().catch(()=>({}));throw i.status===409?new l("Concurrent modification - please retry"):i.status===429?new l("Rate limited - too many spawn attempts"):new l(d.error||`Failed to spawn child: ${i.status}`)}let o=await i.json();return {inviteCode:o.invite_code,inviteId:o.invite_id,budgetUsd:o.budget_usd,expiresAt:new Date(o.expires_at),depth:o.depth,maxSpawnBudget:o.max_spawn_budget,allowedMerchants:o.allowed_merchants||[]}}async getAvailableBudget(){let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v1/agent/descendants`,{method:"GET",headers:e});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Failed to get budget: ${t.status}`)}let s=await t.json();return {totalBudget:s.budget.total_usd,spent:s.budget.spent_usd,allocatedToChildren:s.budget.allocated_to_children_usd,available:s.budget.available_usd,maxSpawnBudget:s.max_spawn_budget,canSpawn:s.can_spawn}}async getChildSessions(){let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v1/agent/descendants`,{method:"GET",headers:e});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Failed to get children: ${t.status}`)}return (await t.json()).children||[]}async listChildSessions(){return this.getChildSessions()}async fetch(e,t){this.logger.debug(`Fetching ${t?.method||"GET"} ${e}`),await this.validateMerchantAllowed(e,"url");let s=crypto.randomUUID(),n=this.extractCorrelationId(t?.headers),a=new AbortController,r=setTimeout(()=>a.abort(),this.timeout);try{let i=await fetch(e,{...t,signal:a.signal});return this.logger.debug(`Initial response: ${i.status}`),i.status===402&&(this.logger.info(`Payment required for ${e}`),i=await this.handlePaymentRequired(e,t,i,s,n)),i}catch(i){throw i instanceof Error&&i.name==="AbortError"?new l(`Request timeout after ${this.timeout}ms`):i}finally{clearTimeout(r);}}extractCorrelationId(e){if(!e)return;if(e instanceof Headers)return e.get("X-Correlation-Id")||e.get("x-correlation-id")||void 0;if(Array.isArray(e)){let s=e.find(([n])=>n.toLowerCase()==="x-correlation-id");return s?s[1]:void 0}let t=e;return t["X-Correlation-Id"]||t["x-correlation-id"]||void 0}async handlePaymentRequired(e,t,s,n,a){let r;try{r=await pe(s),this.logger.debug("Payment requirements:",{amount:`$${B(r).toFixed(4)}`,recipient:r.recipient,description:r.description});}catch(u){throw this.logger.error("Failed to parse payment requirements:",u),new A(`Failed to parse payment requirements: ${u}. The server may not be properly configured for x402 payments.`)}if(he(r))throw new A("Payment requirements have expired. This usually means the request took too long. Try again.");let i=B(r);if(this.maxPaymentUsd!==void 0&&i>this.maxPaymentUsd)throw new T("client_max",this.maxPaymentUsd,i);let o;try{this.logger.debug("Signing payment authorization..."),o=await me(r,this.sessionKey,this.walletAddress);}catch(u){throw this.logger.error("Failed to sign payment:",u),new A(`Failed to sign payment: ${u}. This may indicate an issue with the session key.`)}this.logger.debug("Retrying request with payment...");let d=new Headers(t?.headers);d.set("X-PAYMENT",o);let g=await fetch(e,{...t,headers:d});if(g.status!==402){let u={amountUsd:i,recipient:r.recipient,txHash:g.headers.get("X-Payment-TxHash"),timestamp:new Date,description:r.description,url:e,requestId:n,correlationId:a};this.payments.push(u),this.totalSpentUsd+=i,this.logger.payment(i,r.recipient,r.description),this.onPayment&&this.onPayment(u);}else await this.handlePaymentError(g);return g}async handlePaymentError(e){let t={};try{t=await e.json();}catch{}let s=(t.error_code||"").toLowerCase(),n=t.error||t.message||"Payment required";if(this.logger.error("Payment failed:",{errorCode:s,errorMessage:n,errorData:t}),s==="insufficient_balance"){let a=t.required||0,r=t.available||0;throw new k(a,r)}else throw s==="session_key_expired"?new $(t.expired_at||"unknown"):s==="spending_limit_exceeded"?new T(t.limit_type||"unknown",t.limit||0,t.attempted||0):new A(n)}getWalletAddress(){return this.walletAddress}getSessionKeyId(){return this.sessionKeyId}isTestnet(){return this.sessionKey.isTest}getNetwork(){return this.isTestnet()?fe.BASE_SEPOLIA:fe.BASE_MAINNET}async getBalance(){this.logger.debug("Fetching wallet balance...");try{let e=await fetch(`${this.baseUrl}/api/v1/session-key/info`,{headers:{"X-Session-Key":this.sessionKey.address.toLowerCase()}});if(!e.ok)throw new Error("Failed to get session key info");let t=await e.json(),s=t.wallet_address||t.walletAddress;if(!s)throw new Error("No wallet address in session key info");let n=await fetch(`${this.baseUrl}/api/wallet/balance?address=${s}&chain=base`);if(n.ok){let a=await n.json(),r=a.balance_usdc||a.balance_usd||0;return this.logger.debug(`Balance: $${r}`),r}}catch(e){this.logger.warn("Failed to fetch balance:",e);}return this.logger.debug("Using estimated balance based on tracking"),Math.max(0,100-this.totalSpentUsd)}async canAfford(e){let t=await this.getBalance(),s=t>=e;return {canAfford:s,balance:t,shortfall:s?0:e-t,remainingAfter:s?t-e:0}}async getSessionKeyInfo(e=false){let t=this.sessionKeyInfoFetchedAt?Date.now()-this.sessionKeyInfoFetchedAt:1/0;if(!e&&this.sessionKeyInfo&&t<6e4)return this.sessionKeyInfo;this.logger.debug("Fetching session key info...");try{let s=await fetch(`${this.baseUrl}/api/v1/session-key/info`,{headers:{"X-Session-Key":this.sessionKey.address.toLowerCase()}});if(s.ok){let n=await s.json();return this.sessionKeyInfo={address:this.sessionKey.address,walletAddress:n.wallet_address??n.walletAddress??null,isValid:n.is_valid??n.isValid??!0,limits:{perTxUsd:n.per_tx_limit_usd??n.perTxLimitUsd??null,dailyUsd:n.daily_limit_usd??n.dailyLimitUsd??null,totalUsd:n.total_limit_usd??n.totalLimitUsd??null},usage:{todayUsd:n.today_spent_usd??n.todaySpentUsd??0,totalUsd:n.total_spent_usd??n.totalSpentUsd??0,txCount:n.tx_count??n.txCount??0},expiresAt:n.expires_at?new Date(n.expires_at):null,createdAt:n.created_at?new Date(n.created_at):null,name:n.name,allowedMerchants:n.allowed_merchants??n.allowedMerchants??[]},this.sessionKeyInfoFetchedAt=Date.now(),this.sessionKeyInfo}}catch(s){this.logger.warn("Failed to fetch session key info:",s);}return {address:this.sessionKey.address,walletAddress:null,isValid:true,limits:{perTxUsd:null,dailyUsd:null,totalUsd:null},usage:{todayUsd:this.totalSpentUsd,totalUsd:this.totalSpentUsd,txCount:this.payments.length},expiresAt:null,createdAt:null}}async getSpendingStats(){this.logger.debug("Fetching spending stats...");try{let e=await fetch(`${this.baseUrl}/api/v1/session-key/stats`,{headers:{"X-Session-Key":this.sessionKey.address.toLowerCase()}});if(e.ok){let t=await e.json();return {totalSpentUsd:t.total_spent_usd||t.totalSpentUsd||this.totalSpentUsd,txCount:t.tx_count||t.txCount||this.payments.length,remainingDailyUsd:t.remaining_daily_usd||t.remainingDailyUsd||null,remainingTotalUsd:t.remaining_total_usd||t.remainingTotalUsd||null,expiresAt:t.expires_at?new Date(t.expires_at):null}}}catch(e){this.logger.warn("Failed to fetch spending stats:",e);}return {totalSpentUsd:this.totalSpentUsd,txCount:this.payments.length,remainingDailyUsd:null,remainingTotalUsd:null,expiresAt:null}}getPaymentHistory(){return [...this.payments]}getTotalSpent(){return this.totalSpentUsd}async createSelfCustodyWallet(){if(!this.agentInstanceId)throw new l("Agent instance ID is required for self-custody wallet. Use AgentWallet.fromApiKey() or set MIXRPAY_INSTANCE_ID environment variable.","NO_AGENT_INSTANCE_ID");let e=await q();if(e){let i=privateKeyToAccount(e);return this.selfCustodyAddress=i.address,this.selfCustodyKey=e,this.logger.info("Loaded existing self-custody wallet",{address:i.address}),{address:i.address,privateKey:e}}let t=generatePrivateKey(),s=privateKeyToAccount(t),n=Date.now(),a=`MixrPay Wallet Registration
|
|
14
8
|
Address: ${s.address}
|
|
15
9
|
Timestamp: ${n}`,r=await s.signMessage({message:a});return await this.registerWalletAddress(s.address,r,n),await ue(t,s.address),this.selfCustodyAddress=s.address,this.selfCustodyKey=t,this.logger.info("Created self-custody wallet",{address:s.address}),{address:s.address,privateKey:t}}async registerWalletAddress(e,t,s){if(!this.apiKey)throw new l("API key is required for wallet registration. Use AgentWallet.fromApiKey() to initialize.","NO_API_KEY");let n=await fetch(`${this.baseUrl}/api/v2/agent/wallet/register`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({address:e,signature:t,timestamp:s})});if(!n.ok){let a=await n.json().catch(()=>({}));throw new l(a.error||`Failed to register wallet: ${n.status}`,"WALLET_REGISTRATION_FAILED")}}async loadSelfCustodyWallet(){let e=await q();if(!e)return false;let t=privateKeyToAccount(e);return this.selfCustodyAddress=t.address,this.selfCustodyKey=e,this.logger.debug("Loaded self-custody wallet",{address:t.address}),true}async hasSelfCustodyWallet(){return await ge()}getSelfCustodyAddress(){return this.selfCustodyAddress||null}async executeFromOwnWallet(e){if(!this.selfCustodyKey||!this.selfCustodyAddress)throw new l("Self-custody wallet not loaded. Call loadSelfCustodyWallet() or createSelfCustodyWallet() first.","WALLET_NOT_LOADED");let{to:t,value:s,data:n,gasLimit:a}=e,r=privateKeyToAccount(this.selfCustodyKey),i=createWalletClient({account:r,chain:base,transport:http()});this.logger.debug("Executing transaction from self-custody wallet",{from:this.selfCustodyAddress,to:t,value:s?.toString()});try{let o=await i.sendTransaction({to:t,value:s??BigInt(0),data:n,gas:a});this.logger.info("Transaction submitted",{txHash:o});let d=!1;try{await this.reportTransaction(o,t,s??BigInt(0)),d=!0;}catch(g){this.logger.warn("Failed to report transaction to MixrPay",{txHash:o,error:g instanceof Error?g.message:g});}return {txHash:o,reportedToMixrPay:d}}catch(o){throw this.logger.error("Transaction failed",{error:o instanceof Error?o.message:o}),new l(`Transaction failed: ${o instanceof Error?o.message:"Unknown error"}`,"TRANSACTION_FAILED")}}async transferUSDC(e){if(!this.selfCustodyKey||!this.selfCustodyAddress)throw new l("Self-custody wallet not loaded. Call loadSelfCustodyWallet() or createSelfCustodyWallet() first.","WALLET_NOT_LOADED");let{to:t,amountUsdc:s}=e,n="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",a=6,r=parseUnits(s.toFixed(a),a),i=encodeFunctionData({abi:[{name:"transfer",type:"function",inputs:[{name:"to",type:"address"},{name:"amount",type:"uint256"}],outputs:[{type:"bool"}]}],functionName:"transfer",args:[t,r]});return this.logger.debug("Transferring USDC",{from:this.selfCustodyAddress,to:t,amountUsdc:s,amountMinorUnits:r.toString()}),(await this.executeFromOwnWallet({to:n,data:i})).txHash}async reportTransaction(e,t,s){if(!this.apiKey){this.logger.warn("Cannot report transaction - no API key set");return}let n=await fetch(`${this.baseUrl}/api/v2/agent/tx/report`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({tx_hash:e,to_address:t,value:s.toString(),chain_id:base.id})});if(!n.ok){let a=await n.json().catch(()=>({}));throw new l(a.error||`Failed to report transaction: ${n.status}`,"TX_REPORT_FAILED")}}getAgentInstanceId(){return this.agentInstanceId}setAgentInstanceId(e){this.agentInstanceId=e;}setApiKey(e){this.apiKey=e;}mcp(){let e=join(dirname(fileURLToPath(import.meta.url)),"mcp-server.js"),t={MIXRPAY_SESSION_KEY:this.sessionKey.toString(),MIXRPAY_BASE_URL:this.baseUrl};return this.apiKey&&(t.MIXRPAY_API_KEY=this.apiKey),this.agentInstanceId&&(t.MIXRPAY_INSTANCE_ID=this.agentInstanceId),this.selfCustodyKey&&(t.AGENT_WALLET_KEY=this.selfCustodyKey),this.maxPaymentUsd&&(t.MIXRPAY_MAX_PAYMENT_USD=String(this.maxPaymentUsd)),{command:"node",args:[e],env:t}}tools(){let{definitions:e,execute:t}=j(this);return {definitions:e.map(n=>({name:n.name,description:n.description,input_schema:n.inputSchema?le(n.inputSchema):{type:"object",properties:{}}})),execute:t}}async runDiagnostics(){this.logger.info("Running diagnostics...");let e=[],t=[],s={},n,a;s.sessionKeyFormat=true;try{let o=Date.now(),d=await fetch(`${this.baseUrl}/health`,{method:"GET",signal:AbortSignal.timeout(5e3)});n=Date.now()-o,s.apiConnectivity=d.ok,d.ok||(e.push(`API server returned ${d.status}. Check baseUrl configuration.`),t.push("Verify the baseUrl configuration points to a valid MixrPay server.")),n>2e3&&(e.push(`High API latency: ${n}ms. This may cause timeouts.`),t.push("Consider using a server closer to your region or check network connectivity."));}catch{s.apiConnectivity=false,e.push("Cannot connect to MixrPay API. Check your network connection and baseUrl."),t.push("Verify network connectivity and that the MixrPay server is running.");}try{let o=await this.getSessionKeyInfo(!0);s.sessionKeyValid=o.isValid,o.isValid||(e.push("Session key is invalid or has been revoked."),t.push("Request a new session key from the wallet owner at https://mixrpay.com/manage/invites"));let d=new Date,g=null;o.expiresAt&&(g=(o.expiresAt.getTime()-d.getTime())/(1e3*60*60),o.expiresAt<d?(s.sessionKeyValid=!1,e.push(`Session key expired on ${o.expiresAt.toISOString()}`),t.push("Create a new session key to continue making payments.")):g<24&&(e.push(`Session key expires in ${g.toFixed(1)} hours.`),t.push("Consider creating a new session key before the current one expires.")));let u=await this.getSpendingStats();a={remainingDailyUsd:u.remainingDailyUsd,remainingTotalUsd:u.remainingTotalUsd,expiresAt:o.expiresAt,expiresInHours:g},u.remainingDailyUsd!==null&&u.remainingDailyUsd<1&&(e.push(`Daily limit nearly exhausted: $${u.remainingDailyUsd.toFixed(2)} remaining.`),t.push("Wait until tomorrow for daily limit to reset, or request a higher daily limit.")),u.remainingTotalUsd!==null&&u.remainingTotalUsd<1&&(e.push(`Total limit nearly exhausted: $${u.remainingTotalUsd.toFixed(2)} remaining.`),t.push("Request a new session key with a higher total limit."));}catch{s.sessionKeyValid=false,e.push("Could not verify session key validity."),t.push("Check network connectivity and try again.");}let r=0;try{r=await this.getBalance(),s.hasBalance=r>0,r<=0?(e.push("Wallet has no USDC balance. Top up at https://mixrpay.com/manage/wallet"),t.push("Deposit USDC to your wallet address to enable payments.")):r<1&&(e.push(`Low balance: $${r.toFixed(2)}. Consider topping up.`),t.push("Top up your wallet balance to avoid payment failures."));}catch{s.hasBalance=false,e.push("Could not fetch wallet balance."),t.push("Check network connectivity and try again.");}let i=e.length===0;return this.logger.info("Diagnostics complete:",{healthy:i,issues:e,latencyMs:n}),{healthy:i,issues:e,checks:s,sdkVersion:H,network:this.getNetwork().name,walletAddress:this.walletAddress,sessionLimits:a,latencyMs:n,recommendations:t}}async generateSiwe(e){let{domain:t,uri:s,statement:n,nonce:a=crypto.randomUUID(),issuedAt:r=new Date,expirationTime:i,notBefore:o,requestId:d,resources:g}=e,u=this.sessionKey.address,p=this.getNetwork().chainId,y="1",f=`${t} wants you to sign in with your Ethereum account:
|
|
16
10
|
`;if(f+=`${u}
|