@mixrpay/agent-sdk 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -127,7 +127,7 @@ const session = await wallet.getOrCreateSession({
127
127
  });
128
128
 
129
129
  console.log('Session ID:', session.id);
130
- console.log('Remaining:', session.remainingUsd);
130
+ console.log('Remaining:', session.remainingLimitUsd);
131
131
  console.log('Expires:', session.expiresAt);
132
132
 
133
133
  // Charge manually
@@ -154,7 +154,7 @@ const response = await fetch('https://api.merchant.com/generate', {
154
154
  // List all active sessions
155
155
  const sessions = await wallet.listSessions();
156
156
  for (const session of sessions) {
157
- console.log(`${session.merchantName}: $${session.remainingUsd} remaining`);
157
+ console.log(`${session.merchantName}: $${session.remainingLimitUsd} remaining`);
158
158
  }
159
159
 
160
160
  // Revoke a session (e.g., when done with a merchant)
@@ -197,8 +197,11 @@ import {
197
197
  InsufficientBalanceError,
198
198
  SpendingLimitExceededError,
199
199
  SessionKeyExpiredError,
200
+ // Session Authorization Errors
200
201
  SessionExpiredError,
201
202
  SessionLimitExceededError,
203
+ SessionNotFoundError,
204
+ SessionRevokedError,
202
205
  } from '@mixrpay/agent-sdk';
203
206
 
204
207
  const wallet = new AgentWallet({ sessionKey: 'sk_live_...' });
@@ -210,11 +213,15 @@ try {
210
213
  console.log(`❌ Not enough funds: need $${error.required}, have $${error.available}`);
211
214
  console.log(` Top up at: ${error.topUpUrl}`);
212
215
  } else if (error instanceof SessionExpiredError) {
213
- console.log('❌ Session expired, creating new one...');
216
+ console.log(`❌ Session ${error.sessionId} expired`);
214
217
  // SDK will auto-create on next callMerchantApi()
215
218
  } else if (error instanceof SessionLimitExceededError) {
216
- console.log(`❌ Session limit exceeded: ${error.limitType}`);
217
- console.log(` Limit: $${error.limit}, Requested: $${error.requested}`);
219
+ console.log(`❌ Session limit exceeded`);
220
+ console.log(` Limit: $${error.limit}, Requested: $${error.requested}, Remaining: $${error.remaining}`);
221
+ } else if (error instanceof SessionNotFoundError) {
222
+ console.log(`❌ Session ${error.sessionId} not found`);
223
+ } else if (error instanceof SessionRevokedError) {
224
+ console.log(`❌ Session ${error.sessionId} was revoked: ${error.reason || 'no reason given'}`);
218
225
  } else if (error instanceof SpendingLimitExceededError) {
219
226
  console.log(`❌ Session key limit exceeded: ${error.limitType}`);
220
227
  } else if (error instanceof SessionKeyExpiredError) {
@@ -372,24 +379,41 @@ new AgentWallet({
372
379
  ### Types
373
380
 
374
381
  ```typescript
375
- interface Session {
382
+ interface SessionAuthorization {
376
383
  id: string;
377
- merchantPublicKey: string;
378
- merchantName?: string;
384
+ merchantId: string;
385
+ merchantName: string;
386
+ status: 'pending' | 'active' | 'expired' | 'revoked';
379
387
  spendingLimitUsd: number;
380
- spentUsd: number;
381
- remainingUsd: number;
382
- status: 'active' | 'expired' | 'revoked';
388
+ amountUsedUsd: number;
389
+ remainingLimitUsd: number;
383
390
  expiresAt: Date;
384
391
  createdAt: Date;
385
392
  }
386
393
 
394
+ interface SessionStats {
395
+ activeCount: number;
396
+ expiredCount: number;
397
+ revokedCount: number;
398
+ totalAuthorizedUsd: number;
399
+ totalSpentUsd: number;
400
+ totalRemainingUsd: number;
401
+ activeSessions: Array<{
402
+ id: string;
403
+ merchantName: string;
404
+ merchantPublicKey: string;
405
+ spendingLimitUsd: number;
406
+ remainingUsd: number;
407
+ expiresAt: Date;
408
+ }>;
409
+ }
410
+
387
411
  interface ChargeResult {
388
412
  success: boolean;
389
413
  chargeId: string;
390
414
  amountUsd: number;
391
415
  txHash?: string;
392
- remainingUsd: number;
416
+ remainingSessionBalanceUsd: number;
393
417
  }
394
418
 
395
419
  interface PaymentEvent {
package/dist/index.cjs CHANGED
@@ -21,28 +21,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AgentWallet: () => AgentWallet,
24
- DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
25
- DEFAULT_FACILITATOR_URL: () => DEFAULT_FACILITATOR_URL,
26
- DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
27
24
  InsufficientBalanceError: () => InsufficientBalanceError,
28
25
  InvalidSessionKeyError: () => InvalidSessionKeyError,
29
26
  MixrPayError: () => MixrPayError,
30
- NETWORKS: () => NETWORKS,
31
27
  PaymentFailedError: () => PaymentFailedError,
32
28
  SDK_VERSION: () => SDK_VERSION,
33
- SessionKey: () => SessionKey,
29
+ SessionExpiredError: () => SessionExpiredError,
34
30
  SessionKeyExpiredError: () => SessionKeyExpiredError,
31
+ SessionLimitExceededError: () => SessionLimitExceededError,
32
+ SessionNotFoundError: () => SessionNotFoundError,
33
+ SessionRevokedError: () => SessionRevokedError,
35
34
  SpendingLimitExceededError: () => SpendingLimitExceededError,
36
- X402ProtocolError: () => X402ProtocolError,
37
- buildTransferAuthorizationData: () => buildTransferAuthorizationData,
38
- buildXPaymentHeader: () => buildXPaymentHeader,
39
- generateNonce: () => generateNonce,
40
- getAmountUsd: () => getAmountUsd,
41
- getErrorMessage: () => getErrorMessage,
42
- isMixrPayError: () => isMixrPayError,
43
- isPaymentExpired: () => isPaymentExpired,
44
- parse402Response: () => parse402Response,
45
- validatePaymentAmount: () => validatePaymentAmount
35
+ isMixrPayError: () => isMixrPayError
46
36
  });
47
37
  module.exports = __toCommonJS(index_exports);
48
38
 
@@ -159,17 +149,71 @@ var X402ProtocolError = class extends MixrPayError {
159
149
  this.reason = reason;
160
150
  }
161
151
  };
162
- function isMixrPayError(error) {
163
- return error instanceof MixrPayError;
164
- }
165
- function getErrorMessage(error) {
166
- if (error instanceof MixrPayError) {
167
- return error.message;
152
+ var SessionExpiredError = class extends MixrPayError {
153
+ /** ID of the expired session */
154
+ sessionId;
155
+ /** When the session expired (ISO string or Date) */
156
+ expiredAt;
157
+ constructor(sessionId, expiredAt) {
158
+ super(
159
+ `Session ${sessionId} has expired${expiredAt ? ` at ${expiredAt}` : ""}. A new session will be created automatically on your next request.`,
160
+ "SESSION_EXPIRED"
161
+ );
162
+ this.name = "SessionExpiredError";
163
+ this.sessionId = sessionId;
164
+ this.expiredAt = expiredAt;
165
+ }
166
+ };
167
+ var SessionLimitExceededError = class extends MixrPayError {
168
+ /** ID of the session */
169
+ sessionId;
170
+ /** The session's spending limit in USD */
171
+ limit;
172
+ /** The amount requested in USD */
173
+ requested;
174
+ /** Remaining balance in the session (limit - used) */
175
+ remaining;
176
+ constructor(limit, requested, remaining, sessionId) {
177
+ super(
178
+ `Session spending limit exceeded: limit is $${limit.toFixed(2)}, requested $${requested.toFixed(2)}, remaining $${remaining.toFixed(2)}. Create a new session with a higher limit to continue.`,
179
+ "SESSION_LIMIT_EXCEEDED"
180
+ );
181
+ this.name = "SessionLimitExceededError";
182
+ this.sessionId = sessionId;
183
+ this.limit = limit;
184
+ this.requested = requested;
185
+ this.remaining = remaining;
168
186
  }
169
- if (error instanceof Error) {
170
- return error.message;
187
+ };
188
+ var SessionNotFoundError = class extends MixrPayError {
189
+ /** The session ID that was not found */
190
+ sessionId;
191
+ constructor(sessionId) {
192
+ super(
193
+ `Session ${sessionId} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,
194
+ "SESSION_NOT_FOUND"
195
+ );
196
+ this.name = "SessionNotFoundError";
197
+ this.sessionId = sessionId;
171
198
  }
172
- return String(error);
199
+ };
200
+ var SessionRevokedError = class extends MixrPayError {
201
+ /** The session ID that was revoked */
202
+ sessionId;
203
+ /** Optional reason for revocation */
204
+ reason;
205
+ constructor(sessionId, reason) {
206
+ super(
207
+ `Session ${sessionId} has been revoked${reason ? `: ${reason}` : ""}. Create a new session with getOrCreateSession().`,
208
+ "SESSION_REVOKED"
209
+ );
210
+ this.name = "SessionRevokedError";
211
+ this.sessionId = sessionId;
212
+ this.reason = reason;
213
+ }
214
+ };
215
+ function isMixrPayError(error) {
216
+ return error instanceof MixrPayError;
173
217
  }
174
218
 
175
219
  // src/session-key.ts
@@ -396,21 +440,10 @@ function isPaymentExpired(requirements) {
396
440
  function getAmountUsd(requirements) {
397
441
  return Number(requirements.amount) / 1e6;
398
442
  }
399
- function validatePaymentAmount(amountUsd, maxPaymentUsd) {
400
- if (amountUsd <= 0) {
401
- throw new X402ProtocolError(`Invalid payment amount: $${amountUsd.toFixed(2)}`);
402
- }
403
- if (maxPaymentUsd !== void 0 && amountUsd > maxPaymentUsd) {
404
- throw new X402ProtocolError(
405
- `Payment amount $${amountUsd.toFixed(2)} exceeds client limit $${maxPaymentUsd.toFixed(2)}`
406
- );
407
- }
408
- }
409
443
 
410
444
  // src/agent-wallet.ts
411
- var SDK_VERSION = "0.1.0";
445
+ var SDK_VERSION = "0.3.1";
412
446
  var DEFAULT_BASE_URL = process.env.MIXRPAY_BASE_URL || "https://mixrpay.com";
413
- var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
414
447
  var DEFAULT_TIMEOUT = 3e4;
415
448
  var NETWORKS = {
416
449
  BASE_MAINNET: { chainId: 8453, name: "Base", isTestnet: false },
@@ -1166,6 +1199,63 @@ var AgentWallet = class {
1166
1199
  this.logger.info(`Session ${sessionId} revoked`);
1167
1200
  return true;
1168
1201
  }
1202
+ /**
1203
+ * Get statistics about all session authorizations.
1204
+ *
1205
+ * This provides an overview of active, expired, and revoked sessions,
1206
+ * along with aggregate spending information.
1207
+ *
1208
+ * @returns Session statistics
1209
+ *
1210
+ * @example
1211
+ * ```typescript
1212
+ * const stats = await wallet.getSessionStats();
1213
+ * console.log(`Active sessions: ${stats.activeCount}`);
1214
+ * console.log(`Total authorized: $${stats.totalAuthorizedUsd.toFixed(2)}`);
1215
+ * console.log(`Total remaining: $${stats.totalRemainingUsd.toFixed(2)}`);
1216
+ *
1217
+ * for (const session of stats.activeSessions) {
1218
+ * console.log(`${session.merchantName}: $${session.remainingUsd} remaining`);
1219
+ * }
1220
+ * ```
1221
+ */
1222
+ async getSessionStats() {
1223
+ this.logger.debug("getSessionStats");
1224
+ const sessions = await this.listSessions();
1225
+ const now = /* @__PURE__ */ new Date();
1226
+ const active = [];
1227
+ const expired = [];
1228
+ const revoked = [];
1229
+ for (const session of sessions) {
1230
+ if (session.status === "revoked") {
1231
+ revoked.push(session);
1232
+ } else if (session.status === "expired" || session.expiresAt && session.expiresAt < now) {
1233
+ expired.push(session);
1234
+ } else if (session.status === "active") {
1235
+ active.push(session);
1236
+ }
1237
+ }
1238
+ const totalAuthorizedUsd = active.reduce((sum, s) => sum + s.spendingLimitUsd, 0);
1239
+ const totalSpentUsd = sessions.reduce((sum, s) => sum + s.amountUsedUsd, 0);
1240
+ const totalRemainingUsd = active.reduce((sum, s) => sum + s.remainingLimitUsd, 0);
1241
+ return {
1242
+ activeCount: active.length,
1243
+ expiredCount: expired.length,
1244
+ revokedCount: revoked.length,
1245
+ totalAuthorizedUsd,
1246
+ totalSpentUsd,
1247
+ totalRemainingUsd,
1248
+ activeSessions: active.map((s) => ({
1249
+ id: s.id,
1250
+ merchantName: s.merchantName,
1251
+ merchantPublicKey: s.merchantId,
1252
+ // merchantId is the public key in this context
1253
+ spendingLimitUsd: s.spendingLimitUsd,
1254
+ remainingUsd: s.remainingLimitUsd,
1255
+ expiresAt: s.expiresAt
1256
+ }))
1257
+ };
1258
+ }
1169
1259
  /**
1170
1260
  * Charge against an active session authorization.
1171
1261
  *
@@ -1206,21 +1296,29 @@ var AgentWallet = class {
1206
1296
  });
1207
1297
  if (!response.ok) {
1208
1298
  const error = await response.json().catch(() => ({}));
1299
+ const errorCode = error.error || error.error_code || "";
1209
1300
  if (response.status === 402) {
1210
- if (error.error === "session_limit_exceeded") {
1211
- throw new SpendingLimitExceededError(
1212
- "session",
1213
- error.sessionLimitUsd || error.session_limit_usd || 0,
1214
- amountUsd
1215
- );
1301
+ if (errorCode === "session_limit_exceeded") {
1302
+ const limit = error.sessionLimitUsd || error.session_limit_usd || 0;
1303
+ const remaining = error.remainingUsd || error.remaining_usd || 0;
1304
+ throw new SessionLimitExceededError(limit, amountUsd, remaining, sessionId);
1216
1305
  }
1217
- if (error.error === "insufficient_balance") {
1306
+ if (errorCode === "insufficient_balance") {
1218
1307
  throw new InsufficientBalanceError(
1219
1308
  amountUsd,
1220
1309
  error.availableUsd || error.available_usd || 0
1221
1310
  );
1222
1311
  }
1223
1312
  }
1313
+ if (response.status === 404 || errorCode === "session_not_found") {
1314
+ throw new SessionNotFoundError(sessionId);
1315
+ }
1316
+ if (errorCode === "session_expired") {
1317
+ throw new SessionExpiredError(sessionId, error.expiredAt || error.expires_at);
1318
+ }
1319
+ if (errorCode === "session_revoked") {
1320
+ throw new SessionRevokedError(sessionId, error.reason);
1321
+ }
1224
1322
  throw new MixrPayError(error.message || `Charge failed: ${response.status}`);
1225
1323
  }
1226
1324
  const data = await response.json();
@@ -1315,7 +1413,8 @@ var AgentWallet = class {
1315
1413
  }
1316
1414
  if (response.status === 402) {
1317
1415
  const errorData = await response.json().catch(() => ({}));
1318
- if (errorData.error === "session_expired") {
1416
+ const errorCode = errorData.error || errorData.error_code || "";
1417
+ if (errorCode === "session_expired") {
1319
1418
  this.logger.info("Session expired, creating new one...");
1320
1419
  const newSession = await this.getOrCreateSession({
1321
1420
  merchantPublicKey,
@@ -1330,17 +1429,21 @@ var AgentWallet = class {
1330
1429
  signal: AbortSignal.timeout(this.timeout)
1331
1430
  });
1332
1431
  }
1333
- if (errorData.error === "session_limit_exceeded") {
1334
- throw new SpendingLimitExceededError(
1335
- "session",
1336
- errorData.sessionLimitUsd || 0,
1337
- priceUsd || 0
1338
- );
1432
+ if (errorCode === "session_limit_exceeded") {
1433
+ const limit = errorData.sessionLimitUsd || errorData.session_limit_usd || 0;
1434
+ const remaining = errorData.remainingUsd || errorData.remaining_usd || 0;
1435
+ throw new SessionLimitExceededError(limit, priceUsd || 0, remaining, session.id);
1436
+ }
1437
+ if (errorCode === "session_revoked") {
1438
+ throw new SessionRevokedError(session.id, errorData.reason);
1439
+ }
1440
+ if (errorCode === "session_not_found") {
1441
+ throw new SessionNotFoundError(session.id);
1339
1442
  }
1340
- if (errorData.error === "insufficient_balance") {
1443
+ if (errorCode === "insufficient_balance") {
1341
1444
  throw new InsufficientBalanceError(
1342
1445
  priceUsd || 0,
1343
- errorData.availableUsd || 0
1446
+ errorData.availableUsd || errorData.available_usd || 0
1344
1447
  );
1345
1448
  }
1346
1449
  }
@@ -1368,26 +1471,16 @@ var AgentWallet = class {
1368
1471
  // Annotate the CommonJS export names for ESM import in node:
1369
1472
  0 && (module.exports = {
1370
1473
  AgentWallet,
1371
- DEFAULT_BASE_URL,
1372
- DEFAULT_FACILITATOR_URL,
1373
- DEFAULT_TIMEOUT,
1374
1474
  InsufficientBalanceError,
1375
1475
  InvalidSessionKeyError,
1376
1476
  MixrPayError,
1377
- NETWORKS,
1378
1477
  PaymentFailedError,
1379
1478
  SDK_VERSION,
1380
- SessionKey,
1479
+ SessionExpiredError,
1381
1480
  SessionKeyExpiredError,
1481
+ SessionLimitExceededError,
1482
+ SessionNotFoundError,
1483
+ SessionRevokedError,
1382
1484
  SpendingLimitExceededError,
1383
- X402ProtocolError,
1384
- buildTransferAuthorizationData,
1385
- buildXPaymentHeader,
1386
- generateNonce,
1387
- getAmountUsd,
1388
- getErrorMessage,
1389
- isMixrPayError,
1390
- isPaymentExpired,
1391
- parse402Response,
1392
- validatePaymentAmount
1485
+ isMixrPayError
1393
1486
  });