@mixrpay/agent-sdk 0.1.1 → 0.3.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/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/session-key.ts
2
2
  import {
3
3
  privateKeyToAccount,
4
- signTypedData
4
+ signTypedData,
5
+ signMessage as viemSignMessage
5
6
  } from "viem/accounts";
6
7
 
7
8
  // src/errors.ts
@@ -114,17 +115,71 @@ var X402ProtocolError = class extends MixrPayError {
114
115
  this.reason = reason;
115
116
  }
116
117
  };
117
- function isMixrPayError(error) {
118
- return error instanceof MixrPayError;
119
- }
120
- function getErrorMessage(error) {
121
- if (error instanceof MixrPayError) {
122
- return error.message;
118
+ var SessionExpiredError = class extends MixrPayError {
119
+ /** ID of the expired session */
120
+ sessionId;
121
+ /** When the session expired (ISO string or Date) */
122
+ expiredAt;
123
+ constructor(sessionId, expiredAt) {
124
+ super(
125
+ `Session ${sessionId} has expired${expiredAt ? ` at ${expiredAt}` : ""}. A new session will be created automatically on your next request.`,
126
+ "SESSION_EXPIRED"
127
+ );
128
+ this.name = "SessionExpiredError";
129
+ this.sessionId = sessionId;
130
+ this.expiredAt = expiredAt;
131
+ }
132
+ };
133
+ var SessionLimitExceededError = class extends MixrPayError {
134
+ /** ID of the session */
135
+ sessionId;
136
+ /** The session's spending limit in USD */
137
+ limit;
138
+ /** The amount requested in USD */
139
+ requested;
140
+ /** Remaining balance in the session (limit - used) */
141
+ remaining;
142
+ constructor(limit, requested, remaining, sessionId) {
143
+ super(
144
+ `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.`,
145
+ "SESSION_LIMIT_EXCEEDED"
146
+ );
147
+ this.name = "SessionLimitExceededError";
148
+ this.sessionId = sessionId;
149
+ this.limit = limit;
150
+ this.requested = requested;
151
+ this.remaining = remaining;
152
+ }
153
+ };
154
+ var SessionNotFoundError = class extends MixrPayError {
155
+ /** The session ID that was not found */
156
+ sessionId;
157
+ constructor(sessionId) {
158
+ super(
159
+ `Session ${sessionId} not found. It may have been deleted or never existed. Create a new session with getOrCreateSession().`,
160
+ "SESSION_NOT_FOUND"
161
+ );
162
+ this.name = "SessionNotFoundError";
163
+ this.sessionId = sessionId;
123
164
  }
124
- if (error instanceof Error) {
125
- return error.message;
165
+ };
166
+ var SessionRevokedError = class extends MixrPayError {
167
+ /** The session ID that was revoked */
168
+ sessionId;
169
+ /** Optional reason for revocation */
170
+ reason;
171
+ constructor(sessionId, reason) {
172
+ super(
173
+ `Session ${sessionId} has been revoked${reason ? `: ${reason}` : ""}. Create a new session with getOrCreateSession().`,
174
+ "SESSION_REVOKED"
175
+ );
176
+ this.name = "SessionRevokedError";
177
+ this.sessionId = sessionId;
178
+ this.reason = reason;
126
179
  }
127
- return String(error);
180
+ };
181
+ function isMixrPayError(error) {
182
+ return error instanceof MixrPayError;
128
183
  }
129
184
 
130
185
  // src/session-key.ts
@@ -159,6 +214,13 @@ var SessionKey = class _SessionKey {
159
214
  this.address = this.account.address;
160
215
  this.isTest = isTest;
161
216
  }
217
+ /**
218
+ * Get the private key as hex string (without 0x prefix).
219
+ * Used for API authentication headers.
220
+ */
221
+ get privateKeyHex() {
222
+ return this.privateKey.slice(2);
223
+ }
162
224
  /**
163
225
  * Parse a session key string into a SessionKey object.
164
226
  *
@@ -199,6 +261,18 @@ var SessionKey = class _SessionKey {
199
261
  message
200
262
  });
201
263
  }
264
+ /**
265
+ * Sign a plain message (EIP-191 personal sign).
266
+ *
267
+ * @param message - Message to sign
268
+ * @returns Hex-encoded signature
269
+ */
270
+ async signMessage(message) {
271
+ return viemSignMessage({
272
+ privateKey: this.privateKey,
273
+ message
274
+ });
275
+ }
202
276
  /**
203
277
  * Get the chain ID based on whether this is a test key.
204
278
  */
@@ -231,6 +305,19 @@ function generateNonce() {
231
305
  crypto.getRandomValues(bytes);
232
306
  return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
233
307
  }
308
+ function buildSessionAuthMessage(timestamp, address) {
309
+ return `MixrPay:${timestamp}:${address.toLowerCase()}`;
310
+ }
311
+ async function createSessionAuthPayload(sessionKey) {
312
+ const timestamp = Date.now();
313
+ const message = buildSessionAuthMessage(timestamp, sessionKey.address);
314
+ const signature = await sessionKey.signMessage(message);
315
+ return {
316
+ address: sessionKey.address,
317
+ timestamp,
318
+ signature
319
+ };
320
+ }
234
321
 
235
322
  // src/x402.ts
236
323
  async function parse402Response(response) {
@@ -319,21 +406,10 @@ function isPaymentExpired(requirements) {
319
406
  function getAmountUsd(requirements) {
320
407
  return Number(requirements.amount) / 1e6;
321
408
  }
322
- function validatePaymentAmount(amountUsd, maxPaymentUsd) {
323
- if (amountUsd <= 0) {
324
- throw new X402ProtocolError(`Invalid payment amount: $${amountUsd.toFixed(2)}`);
325
- }
326
- if (maxPaymentUsd !== void 0 && amountUsd > maxPaymentUsd) {
327
- throw new X402ProtocolError(
328
- `Payment amount $${amountUsd.toFixed(2)} exceeds client limit $${maxPaymentUsd.toFixed(2)}`
329
- );
330
- }
331
- }
332
409
 
333
410
  // src/agent-wallet.ts
334
- var SDK_VERSION = "0.1.0";
411
+ var SDK_VERSION = "0.3.0";
335
412
  var DEFAULT_BASE_URL = process.env.MIXRPAY_BASE_URL || "https://mixrpay.com";
336
- var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
337
413
  var DEFAULT_TIMEOUT = 3e4;
338
414
  var NETWORKS = {
339
415
  BASE_MAINNET: { chainId: 8453, name: "Base", isTestnet: false },
@@ -908,29 +984,468 @@ var AgentWallet = class {
908
984
  setLogLevel(level) {
909
985
  this.logger.setLevel(level);
910
986
  }
987
+ // ===========================================================================
988
+ // Session Authorization Methods (for MixrPay Merchants)
989
+ // ===========================================================================
990
+ /**
991
+ * Create the X-Session-Auth header for secure API authentication.
992
+ * Uses signature-based authentication - private key is NEVER transmitted.
993
+ *
994
+ * @returns Headers object with X-Session-Auth
995
+ */
996
+ async getSessionAuthHeaders() {
997
+ const payload = await createSessionAuthPayload(this.sessionKey);
998
+ return {
999
+ "X-Session-Auth": JSON.stringify(payload)
1000
+ };
1001
+ }
1002
+ /**
1003
+ * Get an existing session or create a new one with a MixrPay merchant.
1004
+ *
1005
+ * This is the recommended way to interact with MixrPay-enabled APIs.
1006
+ * If an active session exists, it will be returned. Otherwise, a new
1007
+ * session authorization request will be created and confirmed.
1008
+ *
1009
+ * @param options - Session creation options
1010
+ * @returns Active session authorization
1011
+ *
1012
+ * @throws {MixrPayError} If merchant is not found or session creation fails
1013
+ *
1014
+ * @example
1015
+ * ```typescript
1016
+ * const session = await wallet.getOrCreateSession({
1017
+ * merchantPublicKey: 'pk_live_abc123...',
1018
+ * spendingLimitUsd: 25.00,
1019
+ * durationDays: 7,
1020
+ * });
1021
+ *
1022
+ * console.log(`Session active: $${session.remainingLimitUsd} remaining`);
1023
+ * ```
1024
+ */
1025
+ async getOrCreateSession(options) {
1026
+ this.logger.debug("getOrCreateSession called", options);
1027
+ const { merchantPublicKey, spendingLimitUsd = 25, durationDays = 7 } = options;
1028
+ try {
1029
+ const existingSession = await this.getSessionByMerchant(merchantPublicKey);
1030
+ if (existingSession && existingSession.status === "active") {
1031
+ this.logger.debug("Found existing active session", existingSession.id);
1032
+ return existingSession;
1033
+ }
1034
+ } catch {
1035
+ }
1036
+ this.logger.info(`Creating new session with merchant ${merchantPublicKey.slice(0, 20)}...`);
1037
+ const authHeaders = await this.getSessionAuthHeaders();
1038
+ const authorizeResponse = await fetch(`${this.baseUrl}/api/v2/session/authorize`, {
1039
+ method: "POST",
1040
+ headers: {
1041
+ "Content-Type": "application/json",
1042
+ ...authHeaders
1043
+ },
1044
+ body: JSON.stringify({
1045
+ merchant_public_key: merchantPublicKey,
1046
+ spending_limit_usd: spendingLimitUsd,
1047
+ duration_days: durationDays
1048
+ })
1049
+ });
1050
+ if (!authorizeResponse.ok) {
1051
+ const error = await authorizeResponse.json().catch(() => ({}));
1052
+ throw new MixrPayError(
1053
+ error.message || error.error || `Failed to create session: ${authorizeResponse.status}`
1054
+ );
1055
+ }
1056
+ const authorizeData = await authorizeResponse.json();
1057
+ const sessionId = authorizeData.session_id;
1058
+ const messageToSign = authorizeData.message_to_sign;
1059
+ if (!sessionId || !messageToSign) {
1060
+ throw new MixrPayError("Invalid authorize response: missing session_id or message_to_sign");
1061
+ }
1062
+ this.logger.debug("Signing session authorization message...");
1063
+ const signature = await this.sessionKey.signMessage(messageToSign);
1064
+ const confirmResponse = await fetch(`${this.baseUrl}/api/v2/session/confirm`, {
1065
+ method: "POST",
1066
+ headers: {
1067
+ "Content-Type": "application/json"
1068
+ },
1069
+ body: JSON.stringify({
1070
+ session_id: sessionId,
1071
+ signature,
1072
+ wallet_address: this.walletAddress
1073
+ })
1074
+ });
1075
+ if (!confirmResponse.ok) {
1076
+ const error = await confirmResponse.json().catch(() => ({}));
1077
+ throw new MixrPayError(
1078
+ error.message || `Failed to confirm session: ${confirmResponse.status}`
1079
+ );
1080
+ }
1081
+ const confirmData = await confirmResponse.json();
1082
+ this.logger.info(`Session created: ${confirmData.session?.id || sessionId}`);
1083
+ return this.parseSessionResponse(confirmData.session || confirmData);
1084
+ }
1085
+ /**
1086
+ * Get session status for a specific merchant.
1087
+ *
1088
+ * @param merchantPublicKey - The merchant's public key
1089
+ * @returns Session authorization or null if not found
1090
+ */
1091
+ async getSessionByMerchant(merchantPublicKey) {
1092
+ this.logger.debug("getSessionByMerchant", merchantPublicKey);
1093
+ const authHeaders = await this.getSessionAuthHeaders();
1094
+ const response = await fetch(`${this.baseUrl}/api/v2/session/status?merchant_public_key=${encodeURIComponent(merchantPublicKey)}`, {
1095
+ headers: authHeaders
1096
+ });
1097
+ if (response.status === 404) {
1098
+ return null;
1099
+ }
1100
+ if (!response.ok) {
1101
+ const error = await response.json().catch(() => ({}));
1102
+ throw new MixrPayError(error.message || `Failed to get session: ${response.status}`);
1103
+ }
1104
+ const data = await response.json();
1105
+ return data.session ? this.parseSessionResponse(data.session) : null;
1106
+ }
1107
+ /**
1108
+ * List all session authorizations for this wallet.
1109
+ *
1110
+ * @returns Array of session authorizations
1111
+ *
1112
+ * @example
1113
+ * ```typescript
1114
+ * const sessions = await wallet.listSessions();
1115
+ * for (const session of sessions) {
1116
+ * console.log(`${session.merchantName}: $${session.remainingLimitUsd} remaining`);
1117
+ * }
1118
+ * ```
1119
+ */
1120
+ async listSessions() {
1121
+ this.logger.debug("listSessions");
1122
+ const authHeaders = await this.getSessionAuthHeaders();
1123
+ const response = await fetch(`${this.baseUrl}/api/v2/session/list`, {
1124
+ headers: authHeaders
1125
+ });
1126
+ if (!response.ok) {
1127
+ const error = await response.json().catch(() => ({}));
1128
+ throw new MixrPayError(error.message || `Failed to list sessions: ${response.status}`);
1129
+ }
1130
+ const data = await response.json();
1131
+ return (data.sessions || []).map((s) => this.parseSessionResponse(s));
1132
+ }
1133
+ /**
1134
+ * Revoke a session authorization.
1135
+ *
1136
+ * After revocation, no further charges can be made against this session.
1137
+ *
1138
+ * @param sessionId - The session ID to revoke
1139
+ * @returns true if revoked successfully
1140
+ *
1141
+ * @example
1142
+ * ```typescript
1143
+ * const revoked = await wallet.revokeSession('sess_abc123');
1144
+ * if (revoked) {
1145
+ * console.log('Session revoked successfully');
1146
+ * }
1147
+ * ```
1148
+ */
1149
+ async revokeSession(sessionId) {
1150
+ this.logger.debug("revokeSession", sessionId);
1151
+ const authHeaders = await this.getSessionAuthHeaders();
1152
+ const response = await fetch(`${this.baseUrl}/api/v2/session/revoke`, {
1153
+ method: "POST",
1154
+ headers: {
1155
+ "Content-Type": "application/json",
1156
+ ...authHeaders
1157
+ },
1158
+ body: JSON.stringify({ session_id: sessionId })
1159
+ });
1160
+ if (!response.ok) {
1161
+ const error = await response.json().catch(() => ({}));
1162
+ this.logger.error("Failed to revoke session:", error);
1163
+ return false;
1164
+ }
1165
+ this.logger.info(`Session ${sessionId} revoked`);
1166
+ return true;
1167
+ }
1168
+ /**
1169
+ * Get statistics about all session authorizations.
1170
+ *
1171
+ * This provides an overview of active, expired, and revoked sessions,
1172
+ * along with aggregate spending information.
1173
+ *
1174
+ * @returns Session statistics
1175
+ *
1176
+ * @example
1177
+ * ```typescript
1178
+ * const stats = await wallet.getSessionStats();
1179
+ * console.log(`Active sessions: ${stats.activeCount}`);
1180
+ * console.log(`Total authorized: $${stats.totalAuthorizedUsd.toFixed(2)}`);
1181
+ * console.log(`Total remaining: $${stats.totalRemainingUsd.toFixed(2)}`);
1182
+ *
1183
+ * for (const session of stats.activeSessions) {
1184
+ * console.log(`${session.merchantName}: $${session.remainingUsd} remaining`);
1185
+ * }
1186
+ * ```
1187
+ */
1188
+ async getSessionStats() {
1189
+ this.logger.debug("getSessionStats");
1190
+ const sessions = await this.listSessions();
1191
+ const now = /* @__PURE__ */ new Date();
1192
+ const active = [];
1193
+ const expired = [];
1194
+ const revoked = [];
1195
+ for (const session of sessions) {
1196
+ if (session.status === "revoked") {
1197
+ revoked.push(session);
1198
+ } else if (session.status === "expired" || session.expiresAt && session.expiresAt < now) {
1199
+ expired.push(session);
1200
+ } else if (session.status === "active") {
1201
+ active.push(session);
1202
+ }
1203
+ }
1204
+ const totalAuthorizedUsd = active.reduce((sum, s) => sum + s.spendingLimitUsd, 0);
1205
+ const totalSpentUsd = sessions.reduce((sum, s) => sum + s.amountUsedUsd, 0);
1206
+ const totalRemainingUsd = active.reduce((sum, s) => sum + s.remainingLimitUsd, 0);
1207
+ return {
1208
+ activeCount: active.length,
1209
+ expiredCount: expired.length,
1210
+ revokedCount: revoked.length,
1211
+ totalAuthorizedUsd,
1212
+ totalSpentUsd,
1213
+ totalRemainingUsd,
1214
+ activeSessions: active.map((s) => ({
1215
+ id: s.id,
1216
+ merchantName: s.merchantName,
1217
+ merchantPublicKey: s.merchantId,
1218
+ // merchantId is the public key in this context
1219
+ spendingLimitUsd: s.spendingLimitUsd,
1220
+ remainingUsd: s.remainingLimitUsd,
1221
+ expiresAt: s.expiresAt
1222
+ }))
1223
+ };
1224
+ }
1225
+ /**
1226
+ * Charge against an active session authorization.
1227
+ *
1228
+ * This is useful when you need to manually charge a session outside of
1229
+ * the `callMerchantApi()` flow.
1230
+ *
1231
+ * @param sessionId - The session ID to charge
1232
+ * @param amountUsd - Amount to charge in USD
1233
+ * @param options - Additional charge options
1234
+ * @returns Charge result
1235
+ *
1236
+ * @example
1237
+ * ```typescript
1238
+ * const result = await wallet.chargeSession('sess_abc123', 0.05, {
1239
+ * feature: 'ai-generation',
1240
+ * idempotencyKey: 'unique-key-123',
1241
+ * });
1242
+ *
1243
+ * console.log(`Charged $${result.amountUsd}, remaining: $${result.remainingSessionBalanceUsd}`);
1244
+ * ```
1245
+ */
1246
+ async chargeSession(sessionId, amountUsd, options = {}) {
1247
+ this.logger.debug("chargeSession", { sessionId, amountUsd, options });
1248
+ const authHeaders = await this.getSessionAuthHeaders();
1249
+ const response = await fetch(`${this.baseUrl}/api/v2/charge`, {
1250
+ method: "POST",
1251
+ headers: {
1252
+ "Content-Type": "application/json",
1253
+ ...authHeaders
1254
+ },
1255
+ body: JSON.stringify({
1256
+ session_id: sessionId,
1257
+ price_usd: amountUsd,
1258
+ feature: options.feature,
1259
+ idempotency_key: options.idempotencyKey,
1260
+ metadata: options.metadata
1261
+ })
1262
+ });
1263
+ if (!response.ok) {
1264
+ const error = await response.json().catch(() => ({}));
1265
+ const errorCode = error.error || error.error_code || "";
1266
+ if (response.status === 402) {
1267
+ if (errorCode === "session_limit_exceeded") {
1268
+ const limit = error.sessionLimitUsd || error.session_limit_usd || 0;
1269
+ const remaining = error.remainingUsd || error.remaining_usd || 0;
1270
+ throw new SessionLimitExceededError(limit, amountUsd, remaining, sessionId);
1271
+ }
1272
+ if (errorCode === "insufficient_balance") {
1273
+ throw new InsufficientBalanceError(
1274
+ amountUsd,
1275
+ error.availableUsd || error.available_usd || 0
1276
+ );
1277
+ }
1278
+ }
1279
+ if (response.status === 404 || errorCode === "session_not_found") {
1280
+ throw new SessionNotFoundError(sessionId);
1281
+ }
1282
+ if (errorCode === "session_expired") {
1283
+ throw new SessionExpiredError(sessionId, error.expiredAt || error.expires_at);
1284
+ }
1285
+ if (errorCode === "session_revoked") {
1286
+ throw new SessionRevokedError(sessionId, error.reason);
1287
+ }
1288
+ throw new MixrPayError(error.message || `Charge failed: ${response.status}`);
1289
+ }
1290
+ const data = await response.json();
1291
+ this.logger.payment(amountUsd, sessionId, options.feature);
1292
+ return {
1293
+ success: true,
1294
+ chargeId: data.chargeId || data.charge_id,
1295
+ amountUsd: data.amountUsd || data.amount_usd || amountUsd,
1296
+ txHash: data.txHash || data.tx_hash,
1297
+ remainingSessionBalanceUsd: data.remainingSessionBalanceUsd || data.remaining_session_balance_usd || 0
1298
+ };
1299
+ }
1300
+ /**
1301
+ * Call a MixrPay merchant's API with automatic session management.
1302
+ *
1303
+ * This is the recommended way to interact with MixrPay-enabled APIs.
1304
+ * It automatically:
1305
+ * 1. Gets or creates a session authorization
1306
+ * 2. Adds the `X-Mixr-Session` header to the request
1307
+ * 3. Handles payment errors and session expiration
1308
+ *
1309
+ * @param options - API call options
1310
+ * @returns Response from the merchant API
1311
+ *
1312
+ * @example
1313
+ * ```typescript
1314
+ * const response = await wallet.callMerchantApi({
1315
+ * url: 'https://api.merchant.com/generate',
1316
+ * merchantPublicKey: 'pk_live_abc123...',
1317
+ * method: 'POST',
1318
+ * body: { prompt: 'Hello world' },
1319
+ * priceUsd: 0.05,
1320
+ * });
1321
+ *
1322
+ * const data = await response.json();
1323
+ * ```
1324
+ */
1325
+ async callMerchantApi(options) {
1326
+ const {
1327
+ url,
1328
+ method = "POST",
1329
+ body,
1330
+ headers: customHeaders = {},
1331
+ merchantPublicKey,
1332
+ priceUsd,
1333
+ feature
1334
+ } = options;
1335
+ this.logger.debug("callMerchantApi", { url, method, merchantPublicKey, priceUsd });
1336
+ if (priceUsd !== void 0 && this.maxPaymentUsd !== void 0 && priceUsd > this.maxPaymentUsd) {
1337
+ throw new SpendingLimitExceededError("client_max", this.maxPaymentUsd, priceUsd);
1338
+ }
1339
+ const session = await this.getOrCreateSession({
1340
+ merchantPublicKey,
1341
+ spendingLimitUsd: 25,
1342
+ // Default limit
1343
+ durationDays: 7
1344
+ });
1345
+ const headers = {
1346
+ "Content-Type": "application/json",
1347
+ "X-Mixr-Session": session.id,
1348
+ ...customHeaders
1349
+ };
1350
+ if (feature) {
1351
+ headers["X-Mixr-Feature"] = feature;
1352
+ }
1353
+ const requestBody = body !== void 0 ? typeof body === "string" ? body : JSON.stringify(body) : void 0;
1354
+ const response = await fetch(url, {
1355
+ method,
1356
+ headers,
1357
+ body: requestBody,
1358
+ signal: AbortSignal.timeout(this.timeout)
1359
+ });
1360
+ const chargedAmount = response.headers.get("X-Mixr-Charged");
1361
+ if (chargedAmount) {
1362
+ const amountUsd = parseFloat(chargedAmount);
1363
+ if (!isNaN(amountUsd)) {
1364
+ const payment = {
1365
+ amountUsd,
1366
+ recipient: merchantPublicKey,
1367
+ txHash: response.headers.get("X-Payment-TxHash"),
1368
+ timestamp: /* @__PURE__ */ new Date(),
1369
+ description: feature || "API call",
1370
+ url
1371
+ };
1372
+ this.payments.push(payment);
1373
+ this.totalSpentUsd += amountUsd;
1374
+ this.logger.payment(amountUsd, merchantPublicKey, feature);
1375
+ if (this.onPayment) {
1376
+ this.onPayment(payment);
1377
+ }
1378
+ }
1379
+ }
1380
+ if (response.status === 402) {
1381
+ const errorData = await response.json().catch(() => ({}));
1382
+ const errorCode = errorData.error || errorData.error_code || "";
1383
+ if (errorCode === "session_expired") {
1384
+ this.logger.info("Session expired, creating new one...");
1385
+ const newSession = await this.getOrCreateSession({
1386
+ merchantPublicKey,
1387
+ spendingLimitUsd: 25,
1388
+ durationDays: 7
1389
+ });
1390
+ headers["X-Mixr-Session"] = newSession.id;
1391
+ return fetch(url, {
1392
+ method,
1393
+ headers,
1394
+ body: requestBody,
1395
+ signal: AbortSignal.timeout(this.timeout)
1396
+ });
1397
+ }
1398
+ if (errorCode === "session_limit_exceeded") {
1399
+ const limit = errorData.sessionLimitUsd || errorData.session_limit_usd || 0;
1400
+ const remaining = errorData.remainingUsd || errorData.remaining_usd || 0;
1401
+ throw new SessionLimitExceededError(limit, priceUsd || 0, remaining, session.id);
1402
+ }
1403
+ if (errorCode === "session_revoked") {
1404
+ throw new SessionRevokedError(session.id, errorData.reason);
1405
+ }
1406
+ if (errorCode === "session_not_found") {
1407
+ throw new SessionNotFoundError(session.id);
1408
+ }
1409
+ if (errorCode === "insufficient_balance") {
1410
+ throw new InsufficientBalanceError(
1411
+ priceUsd || 0,
1412
+ errorData.availableUsd || errorData.available_usd || 0
1413
+ );
1414
+ }
1415
+ }
1416
+ return response;
1417
+ }
1418
+ /**
1419
+ * Parse session response data into SessionAuthorization object.
1420
+ */
1421
+ parseSessionResponse(data) {
1422
+ return {
1423
+ id: data.id || data.session_id || data.sessionId,
1424
+ merchantId: data.merchantId || data.merchant_id,
1425
+ merchantName: data.merchantName || data.merchant_name || "Unknown",
1426
+ status: data.status || "active",
1427
+ spendingLimitUsd: Number(data.spendingLimitUsd || data.spending_limit_usd || data.spendingLimit || 0),
1428
+ amountUsedUsd: Number(data.amountUsedUsd || data.amount_used_usd || data.amountUsed || 0),
1429
+ remainingLimitUsd: Number(
1430
+ data.remainingLimitUsd || data.remaining_limit_usd || data.remainingLimit || Number(data.spendingLimitUsd || data.spending_limit_usd || 0) - Number(data.amountUsedUsd || data.amount_used_usd || 0)
1431
+ ),
1432
+ expiresAt: new Date(data.expiresAt || data.expires_at),
1433
+ createdAt: new Date(data.createdAt || data.created_at)
1434
+ };
1435
+ }
911
1436
  };
912
1437
  export {
913
1438
  AgentWallet,
914
- DEFAULT_BASE_URL,
915
- DEFAULT_FACILITATOR_URL,
916
- DEFAULT_TIMEOUT,
917
1439
  InsufficientBalanceError,
918
1440
  InvalidSessionKeyError,
919
1441
  MixrPayError,
920
- NETWORKS,
921
1442
  PaymentFailedError,
922
1443
  SDK_VERSION,
923
- SessionKey,
1444
+ SessionExpiredError,
924
1445
  SessionKeyExpiredError,
1446
+ SessionLimitExceededError,
1447
+ SessionNotFoundError,
1448
+ SessionRevokedError,
925
1449
  SpendingLimitExceededError,
926
- X402ProtocolError,
927
- buildTransferAuthorizationData,
928
- buildXPaymentHeader,
929
- generateNonce,
930
- getAmountUsd,
931
- getErrorMessage,
932
- isMixrPayError,
933
- isPaymentExpired,
934
- parse402Response,
935
- validatePaymentAmount
1450
+ isMixrPayError
936
1451
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mixrpay/agent-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "MixrPay Agent SDK - Enable AI agents to make x402 payments with session keys",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",