@mixrpay/agent-sdk 0.9.5 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -30
- package/dist/{agent-wallet-PG5YUSUR.js → agent-wallet-QEL6J4X2.js} +1 -1
- package/dist/chunk-UED36HQN.js +32 -0
- package/dist/cli.js +2 -2
- package/dist/index.cjs +20 -20
- package/dist/index.d.cts +500 -15
- package/dist/index.d.ts +500 -15
- package/dist/index.js +19 -19
- package/dist/mcp-server.js +18 -18
- package/package.json +7 -18
- package/dist/chunk-IUGFHZWI.js +0 -32
package/README.md
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# @mixrpay/agent-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Non-custodial wallet, DeFi, and payments SDK for AI agents. Includes MCP server, Anthropic tool definitions, and 20+ gateway tools.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @mixrpay/agent-sdk
|
|
9
|
+
# or
|
|
10
|
+
yarn add @mixrpay/agent-sdk
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @mixrpay/agent-sdk
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
## Quick Start
|
|
@@ -13,70 +17,175 @@ npm install @mixrpay/agent-sdk
|
|
|
13
17
|
```typescript
|
|
14
18
|
import { AgentWallet } from '@mixrpay/agent-sdk';
|
|
15
19
|
|
|
16
|
-
// Connect (auto-detects credentials from env)
|
|
17
20
|
const wallet = await AgentWallet.connect();
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
const balances = await wallet.getBalances();
|
|
23
|
+
console.log(balances);
|
|
24
|
+
|
|
25
|
+
await wallet.transfer('0x...', '10.00');
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Authentication
|
|
29
|
+
|
|
30
|
+
### Device Flow (Browser)
|
|
31
|
+
|
|
32
|
+
On first run, `connect()` opens your browser for login. After approval, credentials are cached locally.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
const wallet = await AgentWallet.connect();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### API Key
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const wallet = await AgentWallet.connect({
|
|
42
|
+
apiKey: 'agt_live_...',
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or via environment variable:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
MIXRPAY_API_KEY=agt_live_xxx node my-agent.js
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Access Code
|
|
53
|
+
|
|
54
|
+
For agents connecting to an existing human-managed wallet with budget limits:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
20
57
|
const wallet = await AgentWallet.connect({
|
|
21
58
|
accessCode: 'mixr-abc123',
|
|
22
59
|
});
|
|
23
60
|
```
|
|
24
61
|
|
|
25
|
-
##
|
|
62
|
+
## Wallet & DeFi
|
|
26
63
|
|
|
27
64
|
```typescript
|
|
28
|
-
// Check balances
|
|
65
|
+
// Check balances (tokens + delegation budget)
|
|
29
66
|
const balances = await wallet.getBalances();
|
|
30
67
|
|
|
31
68
|
// Transfer USDC
|
|
32
|
-
|
|
69
|
+
await wallet.transfer('0x...', '10.00');
|
|
33
70
|
|
|
34
|
-
// Swap tokens
|
|
35
|
-
|
|
71
|
+
// Swap tokens via 0x
|
|
72
|
+
await wallet.swap('ETH', 'USDC', '0.1');
|
|
36
73
|
|
|
37
|
-
// Bridge cross-chain
|
|
74
|
+
// Bridge cross-chain via deBridge
|
|
38
75
|
const bridge = await wallet.bridge('USDC', '100', 'ethereum');
|
|
76
|
+
await wallet.waitForBridgeCompletion(bridge.order_id);
|
|
77
|
+
|
|
78
|
+
// Execute arbitrary on-chain transactions
|
|
79
|
+
await wallet.executeTransaction({
|
|
80
|
+
to: '0x...contractAddress',
|
|
81
|
+
data: '0x...calldata',
|
|
82
|
+
estimatedCostUsd: 5.0,
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Paid APIs (x402)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const response = await wallet.fetchPaid('https://api.example.com/endpoint');
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Gateway Tools
|
|
39
93
|
|
|
40
|
-
|
|
41
|
-
const
|
|
94
|
+
```typescript
|
|
95
|
+
const tools = await wallet.listTools();
|
|
42
96
|
|
|
43
|
-
// Call gateway tools
|
|
44
97
|
const result = await wallet.callTool('firecrawl', {
|
|
45
98
|
action: 'scrape',
|
|
46
99
|
url: 'https://example.com',
|
|
47
100
|
});
|
|
101
|
+
```
|
|
48
102
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
103
|
+
## Transaction History
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const history = await wallet.getTransactions({ limit: 50 });
|
|
107
|
+
|
|
108
|
+
for (const tx of history.transactions) {
|
|
109
|
+
console.log(`${tx.chargeType}: $${tx.amount} - ${tx.status}`);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Multi-Step Plans
|
|
114
|
+
|
|
115
|
+
Submit, approve, and execute multi-step plans with idempotent resumption:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const plan = await wallet.submitPlan({
|
|
119
|
+
title: 'Rebalance portfolio',
|
|
120
|
+
steps: [
|
|
121
|
+
{ action: 'swap', params: { sellToken: 'ETH', buyToken: 'USDC', sellAmount: '0.5' }, description: 'Sell ETH' },
|
|
122
|
+
{ action: 'bridge', params: { token: 'USDC', amount: '500', destChain: 'ethereum' }, description: 'Bridge to Ethereum' },
|
|
123
|
+
],
|
|
124
|
+
totalEstimatedCostUsd: 510,
|
|
54
125
|
});
|
|
126
|
+
|
|
127
|
+
if (plan.status === 'auto_approved') {
|
|
128
|
+
const result = await wallet.executePlan(plan.planId);
|
|
129
|
+
console.log(result.status);
|
|
130
|
+
}
|
|
55
131
|
```
|
|
56
132
|
|
|
57
|
-
##
|
|
133
|
+
## Claude Agent SDK
|
|
58
134
|
|
|
59
|
-
Use as an MCP server
|
|
135
|
+
Use as an MCP server with the Claude Agent SDK:
|
|
60
136
|
|
|
61
|
-
```
|
|
62
|
-
|
|
137
|
+
```typescript
|
|
138
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
139
|
+
import { AgentWallet } from '@mixrpay/agent-sdk';
|
|
140
|
+
|
|
141
|
+
const wallet = await AgentWallet.connect();
|
|
142
|
+
|
|
143
|
+
for await (const msg of query({
|
|
144
|
+
prompt: 'Check my balance and swap 0.1 ETH for USDC',
|
|
145
|
+
options: {
|
|
146
|
+
mcpServers: {
|
|
147
|
+
wallet: wallet.mcp(),
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
})) {
|
|
151
|
+
console.log(msg);
|
|
152
|
+
}
|
|
63
153
|
```
|
|
64
154
|
|
|
65
|
-
Or
|
|
155
|
+
Or use `wallet.tools()` for direct Anthropic SDK integration:
|
|
66
156
|
|
|
67
157
|
```typescript
|
|
68
|
-
|
|
158
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
159
|
+
|
|
160
|
+
const toolkit = wallet.tools();
|
|
161
|
+
|
|
162
|
+
const response = await anthropic.messages.create({
|
|
163
|
+
model: 'claude-sonnet-4-20250514',
|
|
164
|
+
tools: toolkit.definitions,
|
|
165
|
+
messages: [{ role: 'user', content: 'Transfer 5 USDC to 0x...' }],
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Execute tool calls returned by Claude
|
|
169
|
+
for (const block of response.content) {
|
|
170
|
+
if (block.type === 'tool_use') {
|
|
171
|
+
const result = await toolkit.execute(block.name, block.input);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
69
174
|
```
|
|
70
175
|
|
|
71
|
-
##
|
|
176
|
+
## MCP Server (Standalone)
|
|
72
177
|
|
|
73
178
|
```bash
|
|
74
|
-
|
|
179
|
+
MIXRPAY_API_KEY=agt_live_... npx mixrpay-mcp
|
|
180
|
+
```
|
|
75
181
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
mixrpay
|
|
182
|
+
## CLI
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npx mixrpay login
|
|
186
|
+
npx mixrpay whoami
|
|
187
|
+
npx mixrpay status
|
|
188
|
+
npx mixrpay logout
|
|
80
189
|
```
|
|
81
190
|
|
|
82
191
|
## Error Handling
|
|
@@ -91,11 +200,32 @@ try {
|
|
|
91
200
|
console.log(`Need $${error.required}, have $${error.available}`);
|
|
92
201
|
}
|
|
93
202
|
if (error instanceof MixrPayError && error.isRetryable()) {
|
|
94
|
-
await
|
|
203
|
+
await new Promise((r) => setTimeout(r, error.retryAfterMs || 1000));
|
|
95
204
|
}
|
|
96
205
|
}
|
|
97
206
|
```
|
|
98
207
|
|
|
208
|
+
## Environment Variables
|
|
209
|
+
|
|
210
|
+
| Variable | Description |
|
|
211
|
+
| --- | --- |
|
|
212
|
+
| `MIXRPAY_API_KEY` | Agent API key (`agt_live_...`), skips device flow |
|
|
213
|
+
| `MIXRPAY_SESSION_KEY` | Session key for delegation signing |
|
|
214
|
+
| `MIXRPAY_BASE_URL` | Custom API URL (default: `https://www.mixrpay.com`) |
|
|
215
|
+
|
|
216
|
+
## Features
|
|
217
|
+
|
|
218
|
+
- Non-custodial agent wallets (keys stay local)
|
|
219
|
+
- DeFi primitives: swap (0x), bridge (deBridge), transfer
|
|
220
|
+
- 20+ gateway tools (Firecrawl, Exa, Tavily, and more)
|
|
221
|
+
- x402 auto-pay proxy for paid APIs
|
|
222
|
+
- MCP server for Claude Agent SDK
|
|
223
|
+
- Anthropic tool definitions for `messages.create()`
|
|
224
|
+
- Multi-step plan submission with human approval
|
|
225
|
+
- Idempotent execution with resume support
|
|
226
|
+
- Transaction history and spending stats
|
|
227
|
+
- Budget governance (per-tx limits, daily/total caps)
|
|
228
|
+
|
|
99
229
|
## Documentation
|
|
100
230
|
|
|
101
231
|
[mixrpay.com/docs](https://www.mixrpay.com/docs)
|
|
@@ -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-UED36HQN.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
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://mixrpay.com/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}},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}},C=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;}},D=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 _e={8453:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",84532:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"},xe={name:"USD Coin",version:"2"},Se={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"}]},E=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:Se,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=_e[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 K(){let c=new Uint8Array(32);return crypto.getRandomValues(c),`0x${Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function Ae(c,e){return `MixrPay:${c}:${e.toLowerCase()}`}async function B(c){let e=Date.now(),t=Ae(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:r,body:i,price_usd:o}=X.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: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:r,tool_name:i,tool_description:o,env_vars:d,ttl_hours:g}=V.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: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:r,max_per_tx_usd:i,expires_in_days:o}=te.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:se,handler:async s=>{let{title:n,description:a,budget_usd:r,skills_required:i}=se.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: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(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 re(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]=O(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 O(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:O(e._def.type),...t&&{description:t}};if(e instanceof z$1.ZodRecord)return {type:"object",additionalProperties:O(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]=O(r);return {type:"object",properties:n,...t&&{description:t}}}return e instanceof z$1.ZodUnknown?{...t&&{description:t}}:{...t&&{description:t}}}var Ie="0.9.5",ie=".config/mixrpay",Re="wallet.json";function oe(){let c=process.env.MIXRPAY_WORKSPACE_DIR||process.env.OPENCLAW_WORKSPACE_DIR;return c?join(c,ie):join(homedir(),ie)}function N(){return join(oe(),Re)}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:Ie};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||K().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}`:K(),a=BigInt(Math.floor(Date.now()/1e3))-60n,r=BigInt(c.expiresAt),{domain:i,message:o}=q({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 ge(c){return Date.now()/1e3>c.expiresAt}function F(c){return Number(c.amount)/1e6}var He="0.11.0",_=process.env.MIXRPAY_BASE_URL||"https://www.mixrpay.com",ut="https://x402.org/facilitator",Ne=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;constructor(e){this.validateConfig(e),this.sessionKey=E.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||Ne,e.apiKey&&(this.apiKey=e.apiKey),this.logger=new W(e.logLevel||"none"),this.logger.debug("AgentWallet initialized",{walletAddress:this.walletAddress,isTestnet:this.isTestnet(),maxPaymentUsd:this.maxPaymentUsd,hasApiKey:!!this.apiKey});}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 D(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 j=h?`${f} (request_id: ${h})${b}`:`${f}${b}`;throw new l(j)}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,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=new c({sessionKey:a,baseUrl:t,logLevel:s,maxPaymentUsd:e?.maxPaymentUsd,onPayment:e?.onPayment});return n&&g.setAgentInstanceId(n),g}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-XJV2ESBQ.js'),u=g();if(u.success&&u.credentials.sessionKey){let p=new c({sessionKey:u.credentials.sessionKey,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-XJV2ESBQ.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 d=await a.json().catch(()=>({}));throw a.status===404?new l(`Agent '${t}' not found. Use the MixrPay dashboard to create it.`):new l(d.error||`Failed to get session from master key: ${a.status}`)}let r=await a.json(),i=r.session_key;if(!i)throw new l("No session_key in master key response");let o=new c({sessionKey:i,baseUrl:n,logLevel:s?.logLevel});return r.agent?.id&&(o.agentInstanceId=r.agent.id),o}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
|
+
\u{1F510} MixrPay Login
|
|
10
|
+
`),console.log(`Visit: ${o||i}`),console.log(`Enter code: ${r}
|
|
11
|
+
`),console.log(`Waiting for authentication...
|
|
12
|
+
`);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 b=(await y.json()).session_key;if(b){console.log(`\u2705 Authenticated successfully!
|
|
13
|
+
`);try{let{saveCredentials:j}=await import('./credentials-XJV2ESBQ.js');j({sessionKey:b,baseUrl:t});}catch{}return new c({sessionKey:b,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 de(s),this.logger.debug("Payment requirements:",{amount:`$${F(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(ge(r))throw new A("Payment requirements have expired. This usually means the request took too long. Try again.");let i=F(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 ue(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 v(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}isTestnet(){return this.sessionKey.isTest}getNetwork(){return this.isTestnet()?me.BASE_SEPOLIA:me.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 L();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
|
+
Address: ${s.address}
|
|
15
|
+
Timestamp: ${n}`,r=await s.signMessage({message:a});return await this.registerWalletAddress(s.address,r,n),await le(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 L();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 ce()}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}=ae(this);return {definitions:e.map(n=>({name:n.name,description:n.description,input_schema:n.inputSchema?re(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:He,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
|
+
`;if(f+=`${u}
|
|
17
|
+
|
|
18
|
+
`,n&&(f+=`${n}
|
|
19
|
+
|
|
20
|
+
`),f+=`URI: ${s}
|
|
21
|
+
`,f+=`Version: ${y}
|
|
22
|
+
`,f+=`Chain ID: ${p}
|
|
23
|
+
`,f+=`Nonce: ${a}
|
|
24
|
+
`,f+=`Issued At: ${r.toISOString()}`,i&&(f+=`
|
|
25
|
+
Expiration Time: ${i.toISOString()}`),o&&(f+=`
|
|
26
|
+
Not Before: ${o.toISOString()}`),d&&(f+=`
|
|
27
|
+
Request ID: ${d}`),g&&g.length>0){f+=`
|
|
28
|
+
Resources:`;for(let w of g)f+=`
|
|
29
|
+
- ${w}`;}let h=await this.sessionKey.signMessage(f);return {message:f,signature:h,address:u,chainId:p,nonce:a,issuedAt:r,expirationTime:i}}setDebug(e){this.logger.setLevel(e?"debug":"none");}setLogLevel(e){this.logger.setLevel(e);}async getSessionAuthHeaders(){let e=await B(this.sessionKey);return {"X-Session-Auth":JSON.stringify(e)}}async getOrCreateSession(e){this.logger.debug("getOrCreateSession called",e);let{merchantPublicKey:t,spendingLimitUsd:s,durationDays:n}=e;try{let y=await this.getSessionByMerchant(t);if(y&&y.status==="active")return this.logger.debug("Found existing active session",y.id),y}catch{}this.logger.info(`Creating new session with merchant ${t.slice(0,20)}...`);let a=await this.getSessionAuthHeaders(),r=await fetch(`${this.baseUrl}/api/v2/session/authorize`,{method:"POST",headers:{"Content-Type":"application/json",...a},body:JSON.stringify({merchant_public_key:t,spending_limit_usd:s,duration_days:n})});if(!r.ok){let y=await r.json().catch(()=>({}));throw new l(y.message||y.error||`Failed to create session: ${r.status}`)}let i=await r.json(),o=i.session_id,d=i.message_to_sign;if(!o||!d)throw new l("Invalid authorize response: missing session_id or message_to_sign");this.logger.debug("Signing session authorization message...");let g=await this.sessionKey.signMessage(d),u=await fetch(`${this.baseUrl}/api/v2/session/confirm`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({session_id:o,signature:g,wallet_address:this.walletAddress})});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.message||`Failed to confirm session: ${u.status}`)}let p=await u.json();return this.logger.info(`Session created: ${p.session?.id||o}`),this.parseSessionResponse(p.session||p)}async getSessionByMerchant(e){this.logger.debug("getSessionByMerchant",e);let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/session/status?merchant_public_key=${encodeURIComponent(e)}`,{headers:t});if(s.status===404)return null;if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.message||`Failed to get session: ${s.status}`)}let n=await s.json();return n.session?this.parseSessionResponse(n.session):null}async listSessions(){this.logger.debug("listSessions");let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v2/session/list`,{headers:e});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.message||`Failed to list sessions: ${t.status}`)}return ((await t.json()).sessions||[]).map(n=>this.parseSessionResponse(n))}async revokeSession(e){this.logger.debug("revokeSession",e);let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/session/revoke`,{method:"POST",headers:{"Content-Type":"application/json",...t},body:JSON.stringify({session_id:e})});if(!s.ok){let n=await s.json().catch(()=>({}));return this.logger.error("Failed to revoke session:",n),false}return this.logger.info(`Session ${e} revoked`),true}async getSessionStats(){this.logger.debug("getSessionStats");let e=await this.listSessions(),t=new Date,s=[],n=[],a=[];for(let d of e)d.status==="revoked"?a.push(d):d.status==="expired"||d.expiresAt&&d.expiresAt<t?n.push(d):d.status==="active"&&s.push(d);let r=s.reduce((d,g)=>d+g.spendingLimitUsd,0),i=e.reduce((d,g)=>d+g.amountUsedUsd,0),o=s.reduce((d,g)=>d+g.remainingLimitUsd,0);return {activeCount:s.length,expiredCount:n.length,revokedCount:a.length,totalAuthorizedUsd:r,totalSpentUsd:i,totalRemainingUsd:o,activeSessions:s.map(d=>({id:d.id,merchantName:d.merchantName,merchantPublicKey:d.merchantId,spendingLimitUsd:d.spendingLimitUsd,remainingUsd:d.remainingLimitUsd,expiresAt:d.expiresAt}))}}async chargeSession(e,t,s={}){this.logger.debug("chargeSession",{sessionId:e,amountUsd:t,options:s});let n=await this.getSessionAuthHeaders(),a=await fetch(`${this.baseUrl}/api/v2/charge`,{method:"POST",headers:{"Content-Type":"application/json",...n},body:JSON.stringify({session_id:e,price_usd:t,feature:s.feature,idempotency_key:s.idempotencyKey,metadata:s.metadata})});if(!a.ok){let i=await a.json().catch(()=>({})),o=(i.error||i.error_code||"").toLowerCase();if(a.status===402){if(o==="session_limit_exceeded"){let d=i.sessionLimitUsd||i.session_limit_usd||0,g=i.remainingUsd||i.remaining_usd||0;throw new U(d,t,g,e)}if(o==="insufficient_balance")throw new v(t,i.availableUsd||i.available_usd||0)}throw a.status===404||o==="session_not_found"?new I(e):o==="session_expired"?new C(e,i.expiredAt||i.expires_at):o==="session_revoked"?new R(e,i.reason):new l(i.message||`Charge failed: ${a.status}`)}let r=await a.json();return this.logger.payment(t,e,s.feature),{success:true,chargeId:r.chargeId||r.charge_id,amountUsd:r.amountUsd||r.amount_usd||t,txHash:r.txHash||r.tx_hash,remainingSessionBalanceUsd:r.remainingSessionBalanceUsd||r.remaining_session_balance_usd||0}}async callMerchantApi(e){let{url:t,method:s="POST",body:n,headers:a={},merchantPublicKey:r,priceUsd:i,feature:o}=e;if(this.logger.debug("callMerchantApi",{url:t,method:s,merchantPublicKey:r,priceUsd:i}),await this.validateMerchantAllowed(t,"url"),i!==void 0&&this.maxPaymentUsd!==void 0&&i>this.maxPaymentUsd)throw new T("client_max",this.maxPaymentUsd,i);let d=await this.getOrCreateSession({merchantPublicKey:r}),g={"Content-Type":"application/json","X-Mixr-Session":d.id,...a};o&&(g["X-Mixr-Feature"]=o);let u=n!==void 0?typeof n=="string"?n:JSON.stringify(n):void 0,p=await fetch(t,{method:s,headers:g,body:u,signal:AbortSignal.timeout(this.timeout)}),y=p.headers.get("X-Mixr-Charged");if(y){let f=parseFloat(y);if(!isNaN(f)){let h={amountUsd:f,recipient:r,txHash:p.headers.get("X-Payment-TxHash"),timestamp:new Date,description:o||"API call",url:t,requestId:crypto.randomUUID(),correlationId:this.extractCorrelationId(a)};this.payments.push(h),this.totalSpentUsd+=f,this.logger.payment(f,r,o),this.onPayment&&this.onPayment(h);}}if(p.status===402){let f=await p.json().catch(()=>({})),h=(f.error||f.error_code||"").toLowerCase();if(h==="session_expired"){this.logger.info("Session expired, creating new one...");let w=await this.getOrCreateSession({merchantPublicKey:r});return g["X-Mixr-Session"]=w.id,fetch(t,{method:s,headers:g,body:u,signal:AbortSignal.timeout(this.timeout)})}if(h==="session_limit_exceeded"){let w=f.sessionLimitUsd||f.session_limit_usd||0,b=f.remainingUsd||f.remaining_usd||0;throw new U(w,i||0,b,d.id)}if(h==="session_revoked")throw new R(d.id,f.reason);if(h==="session_not_found")throw new I(d.id);if(h==="insufficient_balance")throw new v(i||0,f.availableUsd||f.available_usd||0)}return p}parseSessionResponse(e){return {id:e.id||e.session_id||e.sessionId,merchantId:e.merchantId||e.merchant_id,merchantName:e.merchantName||e.merchant_name||"Unknown",status:e.status||"active",spendingLimitUsd:Number(e.spendingLimitUsd||e.spending_limit_usd||e.spendingLimit||0),amountUsedUsd:Number(e.amountUsedUsd||e.amount_used_usd||e.amountUsed||0),remainingLimitUsd:Number(e.remainingLimitUsd||e.remaining_limit_usd||e.remainingLimit||Number(e.spendingLimitUsd||e.spending_limit_usd||0)-Number(e.amountUsedUsd||e.amount_used_usd||0)),expiresAt:new Date(e.expiresAt||e.expires_at),createdAt:new Date(e.createdAt||e.created_at)}}async getMCPAuthHeaders(){let e=Date.now().toString(),t=`MixrPay MCP Auth
|
|
30
|
+
Wallet: ${this.walletAddress}
|
|
31
|
+
Timestamp: ${e}`,s=await this.sessionKey.signMessage(t);return {"X-Mixr-Wallet":this.walletAddress,"X-Mixr-Signature":s,"X-Mixr-Timestamp":e}}async listTools(){this.logger.debug("listTools");let e=await fetch(`${this.baseUrl}/api/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",method:"tools/list",id:Date.now()})});if(!e.ok)throw new l(`Failed to list MCP tools: ${e.status}`);let t=await e.json();if(t.error)throw new l(t.error.message||"Failed to list MCP tools");return (t.result?.tools||[]).map(s=>({name:s.name,description:s.description,inputSchema:s.inputSchema,priceUsd:s["x-mixrpay"]?.priceUsd||0,merchantName:s["x-mixrpay"]?.merchantName,merchantSlug:s["x-mixrpay"]?.merchantSlug,verified:s["x-mixrpay"]?.verified||false}))}async listMCPTools(){return this.listTools()}async callTool(e,t={}){this.logger.debug("callTool",{toolName:e,args:t}),await this.validateMerchantAllowed(e,"tool");let s=await this.getMCPAuthHeaders(),a=await(await fetch(`${this.baseUrl}/api/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...s},body:JSON.stringify({jsonrpc:"2.0",method:"tools/call",params:{name:e,arguments:t},id:Date.now()})})).json();if(a.error)throw new l(a.error.message||"MCP tool call failed");let r=a.result?.content?.[0],i=r?.text?JSON.parse(r.text):null,o=a.result?._mixrpay||{};if(o.chargedUsd){let d={amountUsd:o.chargedUsd,recipient:e.split("/")[0]||e,txHash:o.txHash,timestamp:new Date,description:`MCP: ${e}`,url:`${this.baseUrl}/api/mcp`,requestId:crypto.randomUUID()};this.payments.push(d),this.totalSpentUsd+=o.chargedUsd,this.logger.payment(o.chargedUsd,e,"MCP call"),this.onPayment&&this.onPayment(d);}return {data:i,chargedUsd:o.chargedUsd||0,txHash:o.txHash,latencyMs:o.latencyMs}}async callMCPTool(e,t={}){return this.callTool(e,t)}async deployJitMcp(e){this.logger.debug("deployJitMcp",{glamaId:e.glamaId,toolName:e.toolName});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit/deploy`,{method:"POST",headers:{"Content-Type":"application/json",...t},body:JSON.stringify({glama_id:e.glamaId,glama_namespace:e.glamaNamespace,glama_slug:e.glamaSlug,tool_name:e.toolName,tool_description:e.toolDescription,env_vars:e.envVars,ttl_hours:e.ttlHours||24})});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`JIT deploy failed: ${s.status}`)}let n=await s.json();if(n.payment?.amount_usd>0){let a={amountUsd:n.payment.amount_usd,recipient:"mixrpay-jit-deploy",txHash:n.payment.tx_hash,timestamp:new Date,description:`JIT Deploy: ${e.toolName}`,url:`${this.baseUrl}/api/v2/jit/deploy`,requestId:n.request_id||crypto.randomUUID()};this.payments.push(a),this.totalSpentUsd+=n.payment.amount_usd,this.logger.payment(n.payment.amount_usd,"jit-deploy",e.toolName),this.onPayment&&this.onPayment(a);}return {instance:this.parseJitInstance(n.instance),payment:{method:n.payment.method,amountUsd:n.payment.amount_usd,txHash:n.payment.tx_hash}}}async listJitInstances(e){this.logger.debug("listJitInstances",e);let t=await this.getSessionAuthHeaders(),s=new URLSearchParams;e?.status&&s.set("status",e.status);let n=await fetch(`${this.baseUrl}/api/v2/jit/instances?${s}`,{headers:t});if(!n.ok){let r=await n.json().catch(()=>({}));throw new l(r.error||`Failed to list JIT instances: ${n.status}`)}return ((await n.json()).instances||[]).map(r=>this.parseJitInstance(r))}async stopJitInstance(e){this.logger.debug("stopJitInstance",{instanceId:e});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit/instances/${e}`,{method:"DELETE",headers:t});if(!s.ok){let n=await s.json().catch(()=>({}));throw new l(n.error||`Failed to stop JIT instance: ${s.status}`)}}parseJitInstance(e){return {id:e.id,endpointUrl:e.endpoint_url,toolName:e.tool_name,glamaId:e.glama_id,glamaNamespace:e.glama_namespace,glamaSlug:e.glama_slug,status:e.status,mode:e.mode,ttlHours:e.ttl_hours,expiresAt:new Date(e.expires_at),createdAt:new Date(e.created_at)}}async getJitInstance(e){this.logger.debug("getJitInstance",{instanceId:e});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit/instances/${e}`,{headers:t});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Failed to get JIT instance: ${s.status}`)}let n=await s.json();return this.parseJitInstance(n.instance)}async executeTransaction(e){this.logger.debug("executeTransaction",{to:e.to,estimatedCostUsd:e.estimatedCostUsd});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/tx/execute`,{method:"POST",headers:{"Content-Type":"application/json",...t},body:JSON.stringify({to:e.to,data:e.data,value:e.value?.toString()??"0",chain_id:e.chainId,estimated_cost_usd:e.estimatedCostUsd,description:e.description,idempotency_key:e.idempotencyKey})}),n=await s.json().catch(()=>({}));if(!s.ok){let a=(n.error_code||"tx_failed").toLowerCase(),r=n.error||`Transaction execution failed: ${s.status}`;throw a==="budget_exceeded"?new l(r,"SPENDING_LIMIT_EXCEEDED"):new l(r,a)}return this.logger.info("Transaction executed",{txHash:n.tx_hash,estimatedCostUsd:e.estimatedCostUsd,remainingBudgetUsd:n.remaining_budget_usd}),{success:true,txHash:n.tx_hash,chargeId:n.charge_id,estimatedCostUsd:n.estimated_cost_usd,remainingBudgetUsd:n.remaining_budget_usd}}async useSkill(e,t){this.logger.debug("useSkill",{skillId:e,options:t});let s=await this.getSessionAuthHeaders(),n=await fetch(`${this.baseUrl}/api/v2/skills/${e}/use`,{method:"POST",headers:{"Content-Type":"application/json",...s},body:JSON.stringify({ttl_hours:t?.ttlHours||24})});if(!n.ok){let r=await n.json().catch(()=>({}));throw r.configure_url?new l(`${r.error||"Skill not configured"}. Configure at: ${this.baseUrl}${r.configure_url}`,"SKILL_NOT_CONFIGURED"):new l(r.error||`Failed to use skill: ${n.status}`)}let a=await n.json();return {skillId:a.skill_id,endpoint:a.endpoint,tools:a.tools||[],expiresAt:new Date(a.expires_at),instanceId:a.instance_id}}async listSkills(){this.logger.debug("listSkills");let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v2/skills`,{headers:e});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Failed to list skills: ${t.status}`)}return (await t.json()).skills||[]}async getConnectedApps(){this.logger.debug("getConnectedApps");let e=await this.getSessionAuthHeaders(),t=await fetch(`${this.baseUrl}/api/v2/skills/composio/connections`,{headers:e});if(!t.ok){let a=await t.json().catch(()=>({}));throw new l(a.error||`Failed to get connected apps: ${t.status}`,"CONNECTED_APPS_FAILED")}let s=await t.json();return {connected:(s.connections||[]).filter(a=>a.status==="connected").map(a=>a.app.toLowerCase()),connections:s.connections||[],oauthConnections:s.oauth_connections||[],apiKeyConnections:s.api_key_connections||[]}}async getSkillStatus(e){this.logger.debug("getSkillStatus",{skillId:e});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/skills/${e}/configure`,{headers:t});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Failed to get skill status: ${s.status}`)}let n=await s.json();return {skillId:n.skill_id,status:n.status,configuredVars:n.configured_vars||[],lastUsedAt:n.last_used_at?new Date(n.last_used_at):void 0,errorMessage:n.error_message}}async configureSkill(e,t){this.logger.debug("configureSkill",{skillId:e,varNames:Object.keys(t)});let s=await this.getSessionAuthHeaders(),n=await fetch(`${this.baseUrl}/api/v2/skills/${e}/configure`,{method:"POST",headers:{"Content-Type":"application/json",...s},body:JSON.stringify({env_vars:t})});if(!n.ok){let r=await n.json().catch(()=>({}));throw new l(r.error||`Failed to configure skill: ${n.status}`,r.error_code)}let a=await n.json();return {success:true,skillId:a.skill_id,configuredVars:a.configured_vars||[]}}async searchGlamaDirectory(e){this.logger.debug("searchGlamaDirectory",{query:e});let t=new URLSearchParams({q:e}),s=await fetch(`${this.baseUrl}/api/mcp/glama?${t}`);if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Glama search failed: ${s.status}`)}let n=await s.json();return {servers:(n.servers||[]).map(a=>this.parseGlamaServer(a)),pageInfo:n.pageInfo,query:n.query}}async getFeaturedGlamaServers(){this.logger.debug("getFeaturedGlamaServers");let e=await fetch(`${this.baseUrl}/api/mcp/glama`);if(!e.ok){let s=await e.json().catch(()=>({}));throw new l(s.error||`Failed to get featured servers: ${e.status}`)}let t=await e.json();return {servers:(t.servers||[]).map(s=>this.parseGlamaServer(s)),featured:t.featured}}parseGlamaServer(e){let t=e.importData;return {id:e.id,name:e.name,namespace:e.namespace,slug:e.slug,description:e.description,url:e.url,attributes:e.attributes,canHost:e.canHost,tools:e.tools||[],repository:e.repository,license:e.spdxLicense?.name,importData:t?{glamaId:t.glamaId,glamaNamespace:t.glamaNamespace,glamaSlug:t.glamaSlug,suggestedName:t.suggestedName,suggestedDescription:t.suggestedDescription,hostingType:t.hostingType,requiredEnvVars:t.requiredEnvVars,optionalEnvVars:t.optionalEnvVars}:void 0}}async deployTaskAgent(e){this.logger.debug("deployTaskAgent",{name:e.name,budgetUsd:e.budgetUsd});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit-task/deploy`,{method:"POST",headers:{"Content-Type":"application/json",...t},body:JSON.stringify({name:e.name,prompt:e.prompt,system_prompt:e.systemPrompt,model:e.model||"claude-sonnet-4-5",tools:e.tools||[],budget_usd:e.budgetUsd,ttl_hours:e.ttlHours||24,max_iterations:e.maxIterations||10,plan_id:e.planId,task_id:e.taskId,idempotency_key:e.idempotencyKey,auto_run:e.autoRun||false})});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Task agent deploy failed: ${s.status}`)}let n=await s.json();return {instance:this.parseTaskAgentInstance(n.instance),idempotent:n.idempotent||false,requestId:n.request_id}}async getTaskAgentStatus(e){this.logger.debug("getTaskAgentStatus",{instanceId:e});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit-task/${e}`,{method:"GET",headers:t});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Failed to get task status: ${s.status}`)}let n=await s.json();return this.parseTaskAgentStatus(n)}async triggerTaskAgent(e){this.logger.debug("triggerTaskAgent",{instanceId:e});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit-task/${e}`,{method:"POST",headers:{"Content-Type":"application/json",...t}});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Failed to trigger task: ${s.status}`)}let n=await s.json();return {success:n.success,status:n.status}}async cancelTaskAgent(e){this.logger.debug("cancelTaskAgent",{instanceId:e});let t=await this.getSessionAuthHeaders(),s=await fetch(`${this.baseUrl}/api/v2/jit-task/${e}`,{method:"DELETE",headers:t});if(!s.ok){let a=await s.json().catch(()=>({}));throw new l(a.error||`Failed to cancel task: ${s.status}`)}let n=await s.json();return {success:n.success,status:n.status}}async listTaskAgents(e){this.logger.debug("listTaskAgents",{options:e});let t=await this.getSessionAuthHeaders(),s=new URLSearchParams;e?.status&&s.set("status",e.status),e?.planId&&s.set("plan_id",e.planId),e?.taskId&&s.set("task_id",e.taskId),e?.limit!==void 0&&s.set("limit",String(e.limit)),e?.offset!==void 0&&s.set("offset",String(e.offset));let n=s.toString(),a=`${this.baseUrl}/api/v2/jit-task${n?`?${n}`:""}`,r=await fetch(a,{method:"GET",headers:t});if(!r.ok){let o=await r.json().catch(()=>({}));throw new l(o.error||`Failed to list task agents: ${r.status}`)}let i=await r.json();return {taskAgents:(i.task_agents||[]).map(o=>{let d=o.budget,g=o.iterations,u=o.usage,p=o.plan,y=o.task;return {id:o.id,name:o.name,prompt:o.prompt,model:o.model,tools:o.tools,status:o.status,budget:{totalUsd:d.total_usd,spentUsd:d.spent_usd,remainingUsd:d.remaining_usd},iterations:{current:g.current,max:g.max},usage:{toolCalls:u.tool_calls,inputTokens:u.input_tokens,outputTokens:u.output_tokens},result:o.result,error:o.error,depth:o.depth,plan:p?{id:p.id,title:p.title}:null,task:y?{id:y.id,title:y.title}:null,ttlHours:o.ttl_hours,expiresAt:new Date(o.expires_at),createdAt:new Date(o.created_at),startedAt:o.started_at?new Date(o.started_at):void 0,completedAt:o.completed_at?new Date(o.completed_at):void 0}}),pagination:{total:i.pagination.total,limit:i.pagination.limit,offset:i.pagination.offset,hasMore:i.pagination.has_more},stats:{active:i.stats.active??0,completed:i.stats.completed??0,failed:i.stats.failed??0,totalSpentUsd:i.stats.total_spent_usd??0}}}async waitForTaskAgent(e,t){let s=t?.pollIntervalMs||2e3,n=t?.timeoutMs||3e5,a=Date.now();for(this.logger.debug("waitForTaskAgent",{instanceId:e,pollIntervalMs:s,timeoutMs:n});;){let r=await this.getTaskAgentStatus(e);if(["completed","failed","cancelled","budget_exceeded","expired"].includes(r.status))return {id:r.id,status:r.status,result:r.result,error:r.error,spentUsd:r.budget.spentUsd,iterations:r.iterations.current,toolCalls:r.usage.toolCalls,completedAt:r.completedAt};if(Date.now()-a>n)throw new l(`Task agent wait timeout after ${n}ms`);await new Promise(i=>setTimeout(i,s));}}parseTaskAgentInstance(e){return {id:e.id,name:e.name,endpointUrl:e.endpoint_url,statusUrl:e.status_url,triggerUrl:e.trigger_url,cancelUrl:e.cancel_url,resultUrl:e.result_url,status:e.status,budgetUsd:e.budget_usd,expiresAt:new Date(e.expires_at),depth:e.depth,maxIterations:e.max_iterations}}parseTaskAgentStatus(e){let t=e.budget,s=e.iterations,n=e.usage,a=e.endpoints;return {id:e.id,name:e.name,prompt:e.prompt,model:e.model,tools:e.tools,status:e.status,budget:{totalUsd:t?.total_usd??0,spentUsd:t?.spent_usd??0,remainingUsd:t?.remaining_usd??0},iterations:{current:s?.current??0,max:s?.max??0},usage:{toolCalls:n?.tool_calls??0,inputTokens:n?.input_tokens??0,outputTokens:n?.output_tokens??0},result:e.result,error:e.error,depth:e.depth,planId:e.plan_id,taskId:e.task_id,endpoints:{statusUrl:a?.status_url??"",triggerUrl:a?.trigger_url??"",cancelUrl:a?.cancel_url??"",resultUrl:a?.result_url??""},ttlHours:e.ttl_hours,expiresAt:new Date(e.expires_at),createdAt:new Date(e.created_at),startedAt:e.started_at?new Date(e.started_at):void 0,completedAt:e.completed_at?new Date(e.completed_at):void 0}}async complete(e,t){this.logger.debug("complete",{promptLength:e.length,model:t?.model});let s=await this.runAgent({messages:[{role:"user",content:e}],config:{model:t?.model||"gpt-4o-mini",maxIterations:1,tools:[],systemPrompt:t?.systemPrompt}});return {text:s.response,costUsd:s.cost.totalUsd,tokens:s.tokens,model:t?.model||"gpt-4o-mini"}}async runAgent(e){let{sessionId:t,messages:s,config:n={},stream:a=false,idempotencyKey:r,onEvent:i}=e;this.logger.debug("runAgent",{sessionId:t||"(from signature)",messageCount:s.length,config:n,stream:a});let o={messages:s.map(g=>({role:g.role,content:g.content})),config:{model:n.model,max_iterations:n.maxIterations,tools:n.tools,system_prompt:n.systemPrompt},stream:a,idempotency_key:r};t&&(o.session_id=t);let d=18e4;if(!a){let g=await this.getSessionAuthHeaders(),u=await fetch(`${this.baseUrl}/api/v2/agent/run`,{method:"POST",headers:{"Content-Type":"application/json",...g},body:JSON.stringify(o),signal:AbortSignal.timeout(d)});if(!u.ok){let y=await u.json().catch(()=>({}));throw new l(y.error||`Agent run failed: ${u.status}`)}let p=await u.json();if(p.cost?.total_usd>0){let y={amountUsd:p.cost.total_usd,recipient:"mixrpay-agent-run",txHash:p.tx_hash,timestamp:new Date,description:`Agent run: ${p.run_id}`,url:`${this.baseUrl}/api/v2/agent/run`,requestId:r||crypto.randomUUID()};this.payments.push(y),this.totalSpentUsd+=p.cost.total_usd,this.logger.payment(p.cost.total_usd,"agent-run",p.run_id),this.onPayment&&this.onPayment(y);}return {runId:p.run_id,status:p.status,response:p.response,iterations:p.iterations,toolsUsed:p.tools_used,cost:{llmUsd:p.cost.llm_usd,toolsUsd:p.cost.tools_usd,totalUsd:p.cost.total_usd},tokens:p.tokens,sessionRemainingUsd:p.session_remaining_usd,txHash:p.tx_hash}}return this.runAgentStreaming(o,i)}async runAgentStreaming(e,t){let n=await this.getSessionAuthHeaders(),a=await fetch(`${this.baseUrl}/api/v2/agent/run`,{method:"POST",headers:{"Content-Type":"application/json",...n},body:JSON.stringify(e),signal:AbortSignal.timeout(3e5)});if(!a.ok){let g=await a.json().catch(()=>({}));throw new l(g.error||`Agent run failed: ${a.status}`)}let r=a.body?.getReader();if(!r)throw new l("No response body for streaming");let i=new TextDecoder,o="",d=null;for(;;){let{done:g,value:u}=await r.read();if(g)break;o+=i.decode(u,{stream:true});let p=o.split(`
|
|
32
|
+
`);o=p.pop()||"";let y="";for(let f of p)if(f.startsWith("event: "))y=f.slice(7).trim();else if(f.startsWith("data: ")&&y){try{let h=JSON.parse(f.slice(6)),w=this.parseSSEEvent(y,h);if(w){if(t?.(w),y==="complete"&&(d={runId:h.run_id,status:"completed",response:h.response,iterations:h.iterations,toolsUsed:h.tools_used,cost:{llmUsd:0,toolsUsd:0,totalUsd:h.total_cost_usd},tokens:{prompt:0,completion:0},sessionRemainingUsd:0,txHash:h.tx_hash},h.total_cost_usd>0)){let b={amountUsd:h.total_cost_usd,recipient:"mixrpay-agent-run",txHash:h.tx_hash,timestamp:new Date,description:`Agent run: ${h.run_id}`,url:`${this.baseUrl}/api/v2/agent/run`,requestId:e.idempotency_key||crypto.randomUUID()};this.payments.push(b),this.totalSpentUsd+=h.total_cost_usd,this.onPayment&&this.onPayment(b);}if(y==="error")throw new l(h.error||"Agent run failed")}}catch(h){if(h instanceof l)throw h;this.logger.warn("Failed to parse SSE event:",h);}y="";}}if(!d)throw new l("Agent run completed without final result");return d}parseSSEEvent(e,t){switch(e){case "run_start":return {type:"run_start",runId:t.run_id};case "iteration_start":return {type:"iteration_start",iteration:t.iteration};case "llm_chunk":return {type:"llm_chunk",delta:t.delta};case "tool_call":return {type:"tool_call",tool:t.tool,arguments:t.arguments};case "tool_result":return {type:"tool_result",tool:t.tool,success:t.success,costUsd:t.cost_usd,error:t.error};case "iteration_complete":return {type:"iteration_complete",iteration:t.iteration,tokens:t.tokens,costUsd:t.cost_usd};case "complete":return {type:"complete",runId:t.run_id,response:t.response,totalCostUsd:t.total_cost_usd,txHash:t.tx_hash,iterations:t.iterations,toolsUsed:t.tools_used};case "error":return {type:"error",error:t.error,partialCostUsd:t.partial_cost_usd};default:return null}}async getAgentRunStatus(e,t){this.logger.debug("getAgentRunStatus",{runId:e});let s=await this.getSessionAuthHeaders(),n=await fetch(`${this.baseUrl}/api/v2/agent/run/${e}`,{headers:s});if(!n.ok){let r=await n.json().catch(()=>({}));throw new l(r.error||`Failed to get run status: ${n.status}`)}let a=await n.json();return {runId:a.run_id,status:a.status,response:a.response,iterations:a.iterations,toolsUsed:a.tools_used,cost:{llmUsd:a.cost.llm_usd,toolsUsd:a.cost.tools_usd,totalUsd:a.cost.total_usd},tokens:a.tokens,txHash:a.tx_hash,error:a.error,startedAt:new Date(a.started_at),completedAt:a.completed_at?new Date(a.completed_at):void 0}}async callToolWithSession(e,t,s={}){this.logger.debug("callToolWithSession",{sessionId:e,toolName:t,args:s}),await this.validateMerchantAllowed(t,"tool");let a=await(await fetch(`${this.baseUrl}/api/mcp`,{method:"POST",headers:{"Content-Type":"application/json","X-Mixr-Session":e},body:JSON.stringify({jsonrpc:"2.0",method:"tools/call",params:{name:t,arguments:s},id:Date.now()})})).json();if(a.error)throw new l(a.error.message||"MCP tool call failed");let r=a.result?.content?.[0],i=r?.text?JSON.parse(r.text):null,o=a.result?._mixrpay||{};if(o.chargedUsd){let d={amountUsd:o.chargedUsd,recipient:t.split("/")[0]||t,txHash:o.txHash,timestamp:new Date,description:`MCP: ${t}`,url:`${this.baseUrl}/api/mcp`,requestId:crypto.randomUUID()};this.payments.push(d),this.totalSpentUsd+=o.chargedUsd,this.logger.payment(o.chargedUsd,t,"MCP call (session)"),this.onPayment&&this.onPayment(d);}return {data:i,chargedUsd:o.chargedUsd||0,txHash:o.txHash,latencyMs:o.latencyMs}}async callMCPToolWithSession(e,t,s={}){return this.callToolWithSession(e,t,s)}async createTask(e){this.logger.info(`Creating task: ${e.title}`);let t=await this.callApi("/api/v2/tasks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:e.title,description:e.description,budget_usd:e.budgetUsd,deliverables:e.deliverables,category:e.category,expires_in_days:e.expiresInDays})}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to create task");return this.parseTask(s.task)}async listTasks(e){let t=new URLSearchParams;e?.status&&t.set("status",e.status),e?.category&&t.set("category",e.category),e?.minBudget!==void 0&&t.set("min_budget",String(e.minBudget)),e?.maxBudget!==void 0&&t.set("max_budget",String(e.maxBudget)),e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.offset!==void 0&&t.set("offset",String(e.offset));let s=`/api/v2/tasks${t.toString()?`?${t}`:""}`,n=await this.callApi(s,{method:"GET"}),a=await n.json();if(!n.ok)throw new l(a.error||"Failed to list tasks");return {tasks:a.tasks.map(r=>this.parseTask(r)),pagination:a.pagination}}async getTask(e){let t=await this.callApi(`/api/v2/tasks/${e}`,{method:"GET"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to get task");return this.parseTask(s.task)}async getMyTasks(e={}){let t=new URLSearchParams;e.role&&t.set("role",e.role),e.status&&t.set("status",e.status),e.page&&t.set("page",e.page.toString()),e.limit&&t.set("limit",e.limit.toString());let s=t.toString(),n=`/api/v2/tasks/my${s?`?${s}`:""}`,a=await this.callApi(n,{method:"GET"}),r=await a.json();if(!a.ok)throw new l(r.error||"Failed to get tasks");return {tasks:r.tasks.map(i=>({...this.parseTask(i),isCreator:i.is_creator,isAgent:i.is_agent})),pagination:{page:r.pagination.page,limit:r.pagination.limit,total:r.pagination.total,totalPages:r.pagination.total_pages}}}async requestTask(e,t){this.logger.info(`Requesting task: ${e}`);let s=await this.callApi(`/api/v2/tasks/${e}/request`,{method:"POST",headers:{"Content-Type":"application/json"},body:t?JSON.stringify({message:t}):"{}"}),n=await s.json();if(!s.ok)throw new l(n.error||"Failed to request task");return {id:n.request.id,taskId:n.request.task_id,status:n.request.status,message:n.request.message,createdAt:new Date(n.request.created_at)}}async getTaskRequests(e){let t=await this.callApi(`/api/v2/tasks/${e}/requests`,{method:"GET"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to get task requests");return s.requests.map(n=>({id:n.id,status:n.status,message:n.message,createdAt:new Date(n.created_at),reviewedAt:n.reviewed_at?new Date(n.reviewed_at):void 0,agent:n.agent}))}async acceptTaskRequest(e,t){this.logger.info(`Accepting request ${t} for task ${e}`);let s=await this.callApi(`/api/v2/tasks/${e}/requests/${t}/accept`,{method:"POST"}),n=await s.json();if(!s.ok)throw new l(n.error||"Failed to accept request");return {success:n.success,task:{id:n.task.id,status:n.task.status,agentUserId:n.task.agent_user_id},session:{id:n.session.id,sessionKey:n.session.session_key,address:n.session.address,expiresAt:new Date(n.session.expires_at),budgetUsd:n.session.budget_usd,allowedMerchants:n.session.allowed_merchants||[]},invite:{id:n.invite.id,code:n.invite.code},listingFeeTxHash:n.listing_fee_tx_hash}}async rejectTaskRequest(e,t){let s=await this.callApi(`/api/v2/tasks/${e}/requests/${t}/reject`,{method:"POST"}),n=await s.json();if(!s.ok)throw new l(n.error||"Failed to reject request")}async submitTask(e,t){this.logger.info(`Submitting task: ${e}`);let s=await this.callApi(`/api/v2/tasks/${e}/submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({output_text:t.text,output_url:t.url})}),n=await s.json();if(!s.ok)throw new l(n.error||"Failed to submit task")}async approveTask(e){this.logger.info(`Approving task: ${e}`);let t=await this.callApi(`/api/v2/tasks/${e}/approve`,{method:"POST"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to approve task");return {success:s.success,task:{id:s.task.id,status:s.task.status,completedAt:new Date(s.task.completed_at)},payout:{status:s.payout.status,amountUsd:s.payout.amount_usd,txHash:s.payout.tx_hash}}}async rejectTaskSubmission(e,t){let s=await this.callApi(`/api/v2/tasks/${e}/reject`,{method:"POST",headers:{"Content-Type":"application/json"},body:t?JSON.stringify({feedback:t}):"{}"}),n=await s.json();if(!s.ok)throw new l(n.error||"Failed to reject task")}async cancelTask(e){let t=await this.callApi(`/api/v2/tasks/${e}`,{method:"DELETE"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to cancel task")}async createSubtask(e){this.logger.info(`Creating subtask: ${e.title}`);let t=await this.callApi("/api/v2/tasks/create-subtask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parent_task_id:e.parentTaskId,title:e.title,description:e.description,deliverables:e.deliverables,category:e.category,budget_usd:e.budgetUsd,allow_sub_agents:e.allowSubAgents,expires_in_days:e.expiresInDays,idempotency_key:e.idempotencyKey})}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to create subtask");return this.parseTask(s.task)}async updateTaskStatus(e,t,s,n){this.logger.info(`Updating task ${e} status to ${t}`);let a=await this.callApi(`/api/v2/tasks/${e}/status`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:t,note:s,idempotency_key:n})}),r=await a.json();if(!a.ok)throw new l(r.error||"Failed to update task status");return this.parseTask(r.task)}async getSubtasks(e){let t=await this.callApi(`/api/v2/tasks/${e}/subtasks`,{method:"GET"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to get subtasks");return (s.subtasks||[]).map(n=>this.parseTask(n))}async getTaskStatusHistory(e){let t=await this.callApi(`/api/v2/tasks/${e}/status`,{method:"GET"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to get task status history");return {taskId:s.task_id,currentStatus:s.current_status,history:(s.history||[]).map(n=>({id:n.id,oldStatus:n.old_status,newStatus:n.new_status,note:n.note,createdAt:new Date(n.created_at)}))}}async requestApproval(e){this.logger.info(`Requesting approval for: ${e.actionType}`);let t=await this.callApi("/api/v2/approvals/request",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action_type:e.actionType,action_payload:e.actionPayload,context:e.context,expires_in_hours:e.expiresInHours,idempotency_key:e.idempotencyKey})}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to request approval");return s.auto_approved?{autoApproved:true,reason:s.reason}:this.parseApprovalRequest(s.approval_request)}async checkApprovalStatus(e){let t=await this.callApi(`/api/v2/approvals/check?request_id=${e}`,{method:"GET"}),s=await t.json();if(!t.ok)throw new l(s.error||"Failed to check approval status");return {requestId:s.request_id,status:s.status,responseNote:s.response_note,approvalScope:s.approval_scope,respondedAt:s.responded_at?new Date(s.responded_at):void 0}}async checkActionPermission(e,t){let s=`/api/v2/approvals/check?action_type=${encodeURIComponent(e)}`;t!==void 0&&(s+=`&amount_usd=${t}`);let n=await this.callApi(s,{method:"GET"}),a=await n.json();if(!n.ok)throw new l(a.error||"Failed to check action permission");return {actionType:a.action_type,needsApproval:a.needs_approval,reason:a.reason}}async waitForApproval(e,t={}){let s=t.pollIntervalMs||5e3,n=t.timeoutMs||3e5,a=Date.now();for(;Date.now()-a<n;){let r=await this.checkApprovalStatus(e);if(r.status!=="pending")return r;await new Promise(i=>setTimeout(i,s));}return {requestId:e,status:"expired"}}parseApprovalRequest(e){return {id:e.id,actionType:e.action_type,actionPayload:e.action_payload,context:e.context,status:e.status,responseNote:e.response_note,approvalScope:e.approval_scope,createdAt:new Date(e.created_at),expiresAt:new Date(e.expires_at),respondedAt:e.responded_at?new Date(e.responded_at):void 0}}parseTask(e){return {id:e.id,title:e.title,description:e.description,deliverables:e.deliverables||[],category:e.category,budgetUsd:e.budget_usd,listingFeeUsd:e.listing_fee_usd,status:e.status,createdAt:new Date(e.created_at),updatedAt:e.updated_at?new Date(e.updated_at):void 0,expiresAt:e.expires_at?new Date(e.expires_at):void 0,claimedAt:e.claimed_at?new Date(e.claimed_at):void 0,submittedAt:e.submitted_at?new Date(e.submitted_at):void 0,completedAt:e.completed_at?new Date(e.completed_at):void 0,creator:e.creator,assignedAgent:e.assigned_agent,requestCount:e.request_count,output:e.output,payment:e.payment}}async getBalances(){let e=await this.callApiWithAuth("/api/v2/agent/balances",{method:"GET"});if(!e.ok){let t=await e.json().catch(()=>({}));throw new l(t.error||`Failed to get balances: ${e.status}`)}return e.json()}async getTransactions(e){let t=new URLSearchParams;e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.offset!==void 0&&t.set("offset",String(e.offset)),e?.chargeType&&t.set("charge_type",e.chargeType),e?.status&&t.set("status",e.status),e?.since&&t.set("since",e.since.toISOString());let s=t.toString(),n=`/api/v2/agent/transactions${s?`?${s}`:""}`,a=await this.callApiWithAuth(n,{method:"GET"});if(!a.ok){let i=await a.json().catch(()=>({}));throw new l(i.error||`Failed to get transactions: ${a.status}`)}let r=await a.json();return {transactions:r.transactions.map(i=>({id:i.id,chargeType:i.charge_type,amount:i.amount,currency:i.currency,status:i.status,description:i.description,txHash:i.tx_hash,fromAddress:i.from_address,toAddress:i.to_address,planId:i.plan_id,planStepIndex:i.plan_step_index,createdAt:i.created_at,confirmedAt:i.confirmed_at})),total:r.total,hasMore:r.has_more}}async transfer(e,t,s="USDC",n){let a=await this.callApiWithAuth("/api/v2/agent/transfer",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({to:e,amount:t,currency:s,idempotency_key:n?.idempotencyKey})});if(!a.ok){let r=await a.json().catch(()=>({}));throw new l(r.error||`Transfer failed: ${a.status}`)}return a.json()}async swap(e,t,s,n){let a=typeof n=="number"?n:n?.slippageBps??100,r=typeof n=="object"?n?.idempotencyKey:void 0,i=await this.callApiWithAuth("/api/v2/agent/swap",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sell_token:e,buy_token:t,sell_amount:s,slippage_bps:a,idempotency_key:r})});if(!i.ok){let o=await i.json().catch(()=>({}));throw new l(o.error||`Swap failed: ${i.status}`)}return i.json()}async bridge(e,t,s,n){let a=typeof n=="string"?n:n?.destAddress,r=typeof n=="object"?n?.idempotencyKey:void 0,i=await this.callApiWithAuth("/api/v2/agent/bridge",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e,amount:t,dest_chain:s,dest_address:a,idempotency_key:r})});if(!i.ok){let o=await i.json().catch(()=>({}));throw new l(o.error||`Bridge failed: ${i.status}`)}return i.json()}async getBridgeStatus(e){let t=await this.callApiWithAuth(`/api/v2/agent/bridge/status?order_id=${encodeURIComponent(e)}`,{method:"GET"});if(!t.ok){let s=await t.json().catch(()=>({}));throw new l(s.error||`Bridge status check failed: ${t.status}`)}return t.json()}async fetchPaid(e,t){let s=await this.callApiWithAuth("/api/v2/agent/fetch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:e,method:t?.method||"GET",headers:t?.headers,body:t?.body,max_payment_usd:t?.maxPaymentUsd,idempotency_key:t?.idempotencyKey})});if(!s.ok){let n=await s.json().catch(()=>({}));throw new l(n.error||`Fetch failed: ${s.status}`)}return s.json()}async submitPlan(e){let t=await this.callApiWithAuth("/api/v2/agent/plan",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:e.title,description:e.description,steps:e.steps.map(n=>({action:n.action,params:n.params,estimated_cost_usd:n.estimatedCostUsd,description:n.description})),total_estimated_cost_usd:e.totalEstimatedCostUsd,requires_approval:e.requiresApproval,idempotency_key:e.idempotencyKey})});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Plan submission failed: ${t.status}`)}let s=await t.json();return {planId:s.plan_id,status:s.status,approvalUrl:s.approval_url}}async getPlanStatus(e){let t=await this.callApiWithAuth(`/api/v2/agent/plan/${encodeURIComponent(e)}`,{method:"GET"});if(!t.ok){let n=await t.json().catch(()=>({}));throw new l(n.error||`Plan status check failed: ${t.status}`)}let s=await t.json();return {planId:s.plan_id,title:s.title,description:s.description,status:s.status,steps:s.steps.map(n=>({index:n.index,action:n.action,description:n.description,estimatedCostUsd:n.estimated_cost_usd,status:n.status,txHash:n.tx_hash,chargeId:n.charge_id,bridgeOrderId:n.bridge_order_id,error:n.error,submittedAt:n.submitted_at,completedAt:n.completed_at})),totalEstimatedCostUsd:s.total_estimated_cost_usd,approval:s.approval,createdAt:s.created_at,expiresAt:s.expires_at}}async listPlans(e){let t=new URLSearchParams;e?.limit&&t.set("limit",e.limit.toString()),e?.offset&&t.set("offset",e.offset.toString()),e?.status&&t.set("status",e.status);let s=t.toString(),n=s?`/api/v2/agent/plan?${s}`:"/api/v2/agent/plan",a=await this.callApiWithAuth(n,{method:"GET"});if(!a.ok){let i=await a.json().catch(()=>({}));throw new l(i.error||`Plan listing failed: ${a.status}`)}let r=await a.json();return {plans:r.plans.map(i=>({planId:i.plan_id,title:i.title,status:i.status,totalEstimatedCostUsd:i.total_estimated_cost_usd,stepsCompleted:i.steps_completed,stepsTotal:i.steps_total,createdAt:i.created_at})),total:r.total,hasMore:r.has_more}}async reportPlanProgress(e,t,s,n){let a=await this.callApiWithAuth(`/api/v2/agent/plan/${encodeURIComponent(e)}/progress`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step_index:t,status:s,tx_hash:n?.txHash,charge_id:n?.chargeId,bridge_order_id:n?.bridgeOrderId,error:n?.error})});if(!a.ok){let r=await a.json().catch(()=>({}));this.logger.warn("[Plan] Progress report failed",{planId:e,stepIndex:t,status:s,error:r.error});}}async waitForBridgeCompletion(e,t){let s=t?.pollIntervalMs??15e3,n=t?.timeoutMs??18e5,a=Date.now();for(;Date.now()-a<n;){let r=await this.getBridgeStatus(e);if(r.status==="fulfilled")return;if(r.status==="failed"||r.status==="cancelled")throw new l(`Bridge failed: ${r.status}`);await new Promise(i=>setTimeout(i,s));}throw new l("Bridge confirmation timeout")}async waitForPlanCompletion(e,t){let s=t?.pollIntervalMs??15e3,n=t?.timeoutMs??18e5,a=Date.now();for(;Date.now()-a<n;){let r=await this.getPlanStatus(e);if(["completed","partial_failure","failed","rejected","expired"].includes(r.status))return r;await new Promise(i=>setTimeout(i,s));}return this.getPlanStatus(e)}async executePlan(e){let t=await this.getPlanStatus(e);if(!["approved","auto_approved","executing"].includes(t.status))throw new l(`Plan is ${t.status}, cannot execute`);for(let s of t.steps)if(!(s.status==="completed"||s.status==="skipped")&&s.status!=="failed")try{await this.reportPlanProgress(e,s.index,"executing");let n,a=`plan:${e}:step:${s.index}`,r=t.steps[s.index]?.params||{};switch(s.action){case "swap":n=await this.swap(r.sellToken,r.buyToken,r.sellAmount,{slippageBps:r.slippageBps,idempotencyKey:a});break;case "bridge":{n=await this.bridge(r.token,r.amount,r.destChain,{destAddress:r.destAddress,idempotencyKey:a}),n.order_id&&(await this.reportPlanProgress(e,s.index,"awaiting_confirmation",{bridgeOrderId:n.order_id}),await this.waitForBridgeCompletion(n.order_id));break}case "transfer":n=await this.transfer(r.to,r.amount,r.currency||"USDC",{idempotencyKey:a});break;case "fetch":{n={charge_id:(await this.fetchPaid(r.url,{method:r.method,headers:r.headers,body:r.body,idempotencyKey:a})).payment?.charge_id};break}case "tool_call":{"callTool"in this&&typeof this.callTool=="function"&&await this.callTool(r.toolName,r.arguments);break}case "custom":this.logger.warn("[Plan] Custom action not executable directly",{planId:e,stepIndex:s.index});break}await this.reportPlanProgress(e,s.index,"completed",{txHash:n?.tx_hash,chargeId:n?.charge_id,bridgeOrderId:n?.order_id});}catch(n){let a=n instanceof Error?n.message:String(n);await this.reportPlanProgress(e,s.index,"failed",{error:a});for(let r of t.steps.filter(i=>i.index>s.index&&i.status==="pending"))await this.reportPlanProgress(e,r.index,"skipped");return this.getPlanStatus(e)}return this.getPlanStatus(e)}async callApiWithAuth(e,t={}){let s=`${this.baseUrl}${e}`,n={...t.headers};if(this.apiKey)n.Authorization=`Bearer ${this.apiKey}`;else {let a=await this.getSessionAuthHeaders();Object.assign(n,a);}return fetch(s,{...t,headers:n})}async callApi(e,t={}){let s=`${this.baseUrl}${e}`,n={...t.headers};if(this.sessionKey){let r=privateKeyToAccount(this.sessionKey.rawPrivateKey).address.toLowerCase(),i=Date.now(),o=`MixrPay:${i}:${r}`,d=await signMessage({message:o,privateKey:this.sessionKey.rawPrivateKey});n["X-Session-Auth"]=JSON.stringify({address:r,timestamp:i,signature:d});}return fetch(s,{...t,headers:n})}};export{l as a,He as b,_ as c,ut as d,Ne as e,me as f,ye as g};
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {b,a as a$1,e,d,c as c$1}from'./chunk-SWK4Q2A3.js';import {c,g,a}from'./chunk-
|
|
2
|
+
import {b,a as a$1,e,d,c as c$1}from'./chunk-SWK4Q2A3.js';import {c,g,a}from'./chunk-UED36HQN.js';function x(e){let i={command:"",flags:{},positionals:[]},o=0;for(;o<e.length;){let r=e[o];if(r.startsWith("--")){let[n,t]=r.slice(2).split("=");t!==void 0?i.flags[n]=t:o+1<e.length&&!e[o+1].startsWith("-")?i.flags[n]=e[++o]:i.flags[n]=true;}else if(r.startsWith("-")){let n=r.slice(1);o+1<e.length&&!e[o+1].startsWith("-")?i.flags[n]=e[++o]:i.flags[n]=true;}else i.command?i.positionals.push(r):i.command=r;o++;}return i}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
|
|
@@ -144,4 +144,4 @@ ENVIRONMENT VARIABLES
|
|
|
144
144
|
AGENT_WALLET_KEY Agent's wallet private key
|
|
145
145
|
|
|
146
146
|
For more info, visit: https://docs.mixrpay.com/cli
|
|
147
|
-
`);}function k(){import('./agent-wallet-
|
|
147
|
+
`);}function k(){import('./agent-wallet-QEL6J4X2.js').then(({SDK_VERSION:e})=>{console.log(`mixrpay v${e}`);});}async function E(){let e=x(process.argv.slice(2));if(e.flags.help||e.flags.h){h();return}if(e.flags.version||e.flags.v){k();return}switch(e.command){case "login":await v(e.flags);break;case "logout":await A();break;case "whoami":await w(e.flags);break;case "register":await S(e.flags);break;case "status":await $(e.flags);break;case "":case "help":h();break;default:console.error(`Unknown command: ${e.command}`),console.error("\nRun `mixrpay --help` for usage information."),process.exit(1);}}E().catch(e=>{console.error("Fatal error:",e),process.exit(1);});
|