@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 +36 -12
- package/dist/index.cjs +160 -67
- package/dist/index.d.cts +142 -268
- package/dist/index.d.ts +142 -268
- package/dist/index.js +155 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -115,17 +115,71 @@ var X402ProtocolError = class extends MixrPayError {
|
|
|
115
115
|
this.reason = reason;
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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;
|
|
124
152
|
}
|
|
125
|
-
|
|
126
|
-
|
|
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;
|
|
127
164
|
}
|
|
128
|
-
|
|
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;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
function isMixrPayError(error) {
|
|
182
|
+
return error instanceof MixrPayError;
|
|
129
183
|
}
|
|
130
184
|
|
|
131
185
|
// src/session-key.ts
|
|
@@ -352,21 +406,10 @@ function isPaymentExpired(requirements) {
|
|
|
352
406
|
function getAmountUsd(requirements) {
|
|
353
407
|
return Number(requirements.amount) / 1e6;
|
|
354
408
|
}
|
|
355
|
-
function validatePaymentAmount(amountUsd, maxPaymentUsd) {
|
|
356
|
-
if (amountUsd <= 0) {
|
|
357
|
-
throw new X402ProtocolError(`Invalid payment amount: $${amountUsd.toFixed(2)}`);
|
|
358
|
-
}
|
|
359
|
-
if (maxPaymentUsd !== void 0 && amountUsd > maxPaymentUsd) {
|
|
360
|
-
throw new X402ProtocolError(
|
|
361
|
-
`Payment amount $${amountUsd.toFixed(2)} exceeds client limit $${maxPaymentUsd.toFixed(2)}`
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
409
|
|
|
366
410
|
// src/agent-wallet.ts
|
|
367
|
-
var SDK_VERSION = "0.1
|
|
411
|
+
var SDK_VERSION = "0.3.1";
|
|
368
412
|
var DEFAULT_BASE_URL = process.env.MIXRPAY_BASE_URL || "https://mixrpay.com";
|
|
369
|
-
var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
|
|
370
413
|
var DEFAULT_TIMEOUT = 3e4;
|
|
371
414
|
var NETWORKS = {
|
|
372
415
|
BASE_MAINNET: { chainId: 8453, name: "Base", isTestnet: false },
|
|
@@ -1122,6 +1165,63 @@ var AgentWallet = class {
|
|
|
1122
1165
|
this.logger.info(`Session ${sessionId} revoked`);
|
|
1123
1166
|
return true;
|
|
1124
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
|
+
}
|
|
1125
1225
|
/**
|
|
1126
1226
|
* Charge against an active session authorization.
|
|
1127
1227
|
*
|
|
@@ -1162,21 +1262,29 @@ var AgentWallet = class {
|
|
|
1162
1262
|
});
|
|
1163
1263
|
if (!response.ok) {
|
|
1164
1264
|
const error = await response.json().catch(() => ({}));
|
|
1265
|
+
const errorCode = error.error || error.error_code || "";
|
|
1165
1266
|
if (response.status === 402) {
|
|
1166
|
-
if (
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
amountUsd
|
|
1171
|
-
);
|
|
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);
|
|
1172
1271
|
}
|
|
1173
|
-
if (
|
|
1272
|
+
if (errorCode === "insufficient_balance") {
|
|
1174
1273
|
throw new InsufficientBalanceError(
|
|
1175
1274
|
amountUsd,
|
|
1176
1275
|
error.availableUsd || error.available_usd || 0
|
|
1177
1276
|
);
|
|
1178
1277
|
}
|
|
1179
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
|
+
}
|
|
1180
1288
|
throw new MixrPayError(error.message || `Charge failed: ${response.status}`);
|
|
1181
1289
|
}
|
|
1182
1290
|
const data = await response.json();
|
|
@@ -1271,7 +1379,8 @@ var AgentWallet = class {
|
|
|
1271
1379
|
}
|
|
1272
1380
|
if (response.status === 402) {
|
|
1273
1381
|
const errorData = await response.json().catch(() => ({}));
|
|
1274
|
-
|
|
1382
|
+
const errorCode = errorData.error || errorData.error_code || "";
|
|
1383
|
+
if (errorCode === "session_expired") {
|
|
1275
1384
|
this.logger.info("Session expired, creating new one...");
|
|
1276
1385
|
const newSession = await this.getOrCreateSession({
|
|
1277
1386
|
merchantPublicKey,
|
|
@@ -1286,17 +1395,21 @@ var AgentWallet = class {
|
|
|
1286
1395
|
signal: AbortSignal.timeout(this.timeout)
|
|
1287
1396
|
});
|
|
1288
1397
|
}
|
|
1289
|
-
if (
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
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);
|
|
1295
1408
|
}
|
|
1296
|
-
if (
|
|
1409
|
+
if (errorCode === "insufficient_balance") {
|
|
1297
1410
|
throw new InsufficientBalanceError(
|
|
1298
1411
|
priceUsd || 0,
|
|
1299
|
-
errorData.availableUsd || 0
|
|
1412
|
+
errorData.availableUsd || errorData.available_usd || 0
|
|
1300
1413
|
);
|
|
1301
1414
|
}
|
|
1302
1415
|
}
|
|
@@ -1323,26 +1436,16 @@ var AgentWallet = class {
|
|
|
1323
1436
|
};
|
|
1324
1437
|
export {
|
|
1325
1438
|
AgentWallet,
|
|
1326
|
-
DEFAULT_BASE_URL,
|
|
1327
|
-
DEFAULT_FACILITATOR_URL,
|
|
1328
|
-
DEFAULT_TIMEOUT,
|
|
1329
1439
|
InsufficientBalanceError,
|
|
1330
1440
|
InvalidSessionKeyError,
|
|
1331
1441
|
MixrPayError,
|
|
1332
|
-
NETWORKS,
|
|
1333
1442
|
PaymentFailedError,
|
|
1334
1443
|
SDK_VERSION,
|
|
1335
|
-
|
|
1444
|
+
SessionExpiredError,
|
|
1336
1445
|
SessionKeyExpiredError,
|
|
1446
|
+
SessionLimitExceededError,
|
|
1447
|
+
SessionNotFoundError,
|
|
1448
|
+
SessionRevokedError,
|
|
1337
1449
|
SpendingLimitExceededError,
|
|
1338
|
-
|
|
1339
|
-
buildTransferAuthorizationData,
|
|
1340
|
-
buildXPaymentHeader,
|
|
1341
|
-
generateNonce,
|
|
1342
|
-
getAmountUsd,
|
|
1343
|
-
getErrorMessage,
|
|
1344
|
-
isMixrPayError,
|
|
1345
|
-
isPaymentExpired,
|
|
1346
|
-
parse402Response,
|
|
1347
|
-
validatePaymentAmount
|
|
1450
|
+
isMixrPayError
|
|
1348
1451
|
};
|