@mixrpay/agent-sdk 0.4.1 → 0.6.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.cjs CHANGED
@@ -32,6 +32,8 @@ __export(index_exports, {
32
32
  SessionNotFoundError: () => SessionNotFoundError,
33
33
  SessionRevokedError: () => SessionRevokedError,
34
34
  SpendingLimitExceededError: () => SpendingLimitExceededError,
35
+ X402ProtocolError: () => X402ProtocolError,
36
+ getErrorMessage: () => getErrorMessage,
35
37
  isMixrPayError: () => isMixrPayError
36
38
  });
37
39
  module.exports = __toCommonJS(index_exports);
@@ -43,14 +45,43 @@ var import_accounts = require("viem/accounts");
43
45
  var MixrPayError = class extends Error {
44
46
  /** Error code for programmatic handling */
45
47
  code;
46
- constructor(message, code = "MIXRPAY_ERROR") {
48
+ /** Optional hint for how long to wait before retrying (in milliseconds) */
49
+ retryAfterMs;
50
+ constructor(message, code = "MIXRPAY_ERROR", retryAfterMs) {
47
51
  super(message);
48
52
  this.name = "MixrPayError";
49
53
  this.code = code;
54
+ this.retryAfterMs = retryAfterMs;
50
55
  if (Error.captureStackTrace) {
51
56
  Error.captureStackTrace(this, this.constructor);
52
57
  }
53
58
  }
59
+ /**
60
+ * Check if this error is retryable.
61
+ *
62
+ * Returns true if the operation might succeed on retry (e.g., transient network issues).
63
+ * Returns false if the error requires user action to resolve (e.g., insufficient balance).
64
+ *
65
+ * @returns true if the operation should be retried, false otherwise
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * try {
70
+ * await wallet.fetch(...);
71
+ * } catch (error) {
72
+ * if (error instanceof MixrPayError && error.isRetryable()) {
73
+ * // Retry the operation
74
+ * await retry();
75
+ * } else {
76
+ * // Handle permanent failure
77
+ * throw error;
78
+ * }
79
+ * }
80
+ * ```
81
+ */
82
+ isRetryable() {
83
+ return false;
84
+ }
54
85
  };
55
86
  var InsufficientBalanceError = class extends MixrPayError {
56
87
  /** Amount required for the payment in USD */
@@ -108,6 +139,14 @@ var SpendingLimitExceededError = class extends MixrPayError {
108
139
  this.limit = limit;
109
140
  this.attempted = attempted;
110
141
  }
142
+ /**
143
+ * Daily limits reset at midnight, so those are retryable (after waiting).
144
+ * Other limit types require user action (new session key, config change).
145
+ * @returns true only for daily limits
146
+ */
147
+ isRetryable() {
148
+ return this.limitType === "daily";
149
+ }
111
150
  };
112
151
  var PaymentFailedError = class extends MixrPayError {
113
152
  /** Detailed reason for the failure */
@@ -124,6 +163,13 @@ var PaymentFailedError = class extends MixrPayError {
124
163
  this.reason = reason;
125
164
  this.txHash = txHash;
126
165
  }
166
+ /**
167
+ * Payment failures are often transient (network issues, temporary server errors).
168
+ * @returns true - payment failures should generally be retried
169
+ */
170
+ isRetryable() {
171
+ return true;
172
+ }
127
173
  };
128
174
  var InvalidSessionKeyError = class extends MixrPayError {
129
175
  /** Detailed reason why the key is invalid */
@@ -148,6 +194,13 @@ var X402ProtocolError = class extends MixrPayError {
148
194
  this.name = "X402ProtocolError";
149
195
  this.reason = reason;
150
196
  }
197
+ /**
198
+ * Protocol errors may be caused by temporary server issues.
199
+ * @returns true - worth retrying in case server recovers
200
+ */
201
+ isRetryable() {
202
+ return true;
203
+ }
151
204
  };
152
205
  var SessionExpiredError = class extends MixrPayError {
153
206
  /** ID of the expired session */
@@ -215,6 +268,15 @@ var SessionRevokedError = class extends MixrPayError {
215
268
  function isMixrPayError(error) {
216
269
  return error instanceof MixrPayError;
217
270
  }
271
+ function getErrorMessage(error) {
272
+ if (error instanceof MixrPayError) {
273
+ return error.message;
274
+ }
275
+ if (error instanceof Error) {
276
+ return error.message;
277
+ }
278
+ return String(error);
279
+ }
218
280
 
219
281
  // src/session-key.ts
220
282
  var USDC_ADDRESSES = {
@@ -353,6 +415,9 @@ async function createSessionAuthPayload(sessionKey) {
353
415
  };
354
416
  }
355
417
 
418
+ // src/agent-wallet.ts
419
+ var import_accounts2 = require("viem/accounts");
420
+
356
421
  // src/x402.ts
357
422
  async function parse402Response(response) {
358
423
  let paymentData = null;
@@ -442,7 +507,7 @@ function getAmountUsd(requirements) {
442
507
  }
443
508
 
444
509
  // src/agent-wallet.ts
445
- var SDK_VERSION = "0.4.1";
510
+ var SDK_VERSION = "0.6.0";
446
511
  var DEFAULT_BASE_URL = process.env.MIXRPAY_BASE_URL || "https://www.mixrpay.com";
447
512
  var DEFAULT_TIMEOUT = 3e4;
448
513
  var NETWORKS = {
@@ -586,6 +651,237 @@ var AgentWallet = class {
586
651
  }
587
652
  }
588
653
  // ===========================================================================
654
+ // Static Agent Registration Methods
655
+ // ===========================================================================
656
+ /**
657
+ * Register a new agent with MixrPay.
658
+ *
659
+ * This creates a Privy-managed embedded wallet for the agent's payments.
660
+ * The agent proves ownership of their external wallet by signing a challenge.
661
+ *
662
+ * @param options - Registration options including the private key
663
+ * @returns Registration result with deposit address
664
+ * @throws {MixrPayError} If registration fails
665
+ *
666
+ * @example
667
+ * ```typescript
668
+ * const { depositAddress, userId } = await AgentWallet.register({
669
+ * privateKey: process.env.AGENT_WALLET_KEY as `0x${string}`,
670
+ * name: 'My Trading Agent',
671
+ * });
672
+ *
673
+ * console.log(`Fund your agent at: ${depositAddress}`);
674
+ * ```
675
+ */
676
+ static async register(options) {
677
+ const { privateKey, name } = options;
678
+ const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
679
+ const account = (0, import_accounts2.privateKeyToAccount)(privateKey);
680
+ const walletAddress = account.address;
681
+ const challengeResponse = await fetch(
682
+ `${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=register`
683
+ );
684
+ if (!challengeResponse.ok) {
685
+ const error = await challengeResponse.json().catch(() => ({}));
686
+ throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
687
+ }
688
+ const { challenge, message } = await challengeResponse.json();
689
+ const signature = await (0, import_accounts2.signMessage)({ message, privateKey });
690
+ const registerResponse = await fetch(`${baseUrl}/api/v1/agent/register`, {
691
+ method: "POST",
692
+ headers: { "Content-Type": "application/json" },
693
+ body: JSON.stringify({
694
+ challenge,
695
+ external_wallet: walletAddress,
696
+ signature,
697
+ name
698
+ })
699
+ });
700
+ if (!registerResponse.ok) {
701
+ const error = await registerResponse.json().catch(() => ({}));
702
+ throw new MixrPayError(error.error || `Registration failed: ${registerResponse.status}`);
703
+ }
704
+ const data = await registerResponse.json();
705
+ return {
706
+ userId: data.user_id,
707
+ depositAddress: data.deposit_address
708
+ };
709
+ }
710
+ /**
711
+ * Get a session key for an already-registered agent.
712
+ *
713
+ * Session keys allow the agent to make payments within the specified limits.
714
+ * The private key is returned ONCE - store it securely!
715
+ *
716
+ * @param options - Session key options
717
+ * @returns Session key result with the sk_live_ format key
718
+ * @throws {MixrPayError} If session key creation fails
719
+ *
720
+ * @example
721
+ * ```typescript
722
+ * const result = await AgentWallet.getSessionKey({
723
+ * privateKey: process.env.AGENT_WALLET_KEY as `0x${string}`,
724
+ * spendingLimitUsd: 100,
725
+ * durationDays: 30,
726
+ * });
727
+ *
728
+ * // Store this securely - it's your payment key!
729
+ * console.log(`Session key: ${result.sessionKey}`);
730
+ *
731
+ * // Use it to create an AgentWallet
732
+ * const wallet = new AgentWallet({ sessionKey: result.sessionKey });
733
+ * ```
734
+ */
735
+ static async getSessionKey(options) {
736
+ const { privateKey, spendingLimitUsd, maxPerTxUsd, maxDailyUsd, durationDays } = options;
737
+ const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
738
+ const account = (0, import_accounts2.privateKeyToAccount)(privateKey);
739
+ const walletAddress = account.address;
740
+ const challengeResponse = await fetch(
741
+ `${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=session-key`
742
+ );
743
+ if (!challengeResponse.ok) {
744
+ const error = await challengeResponse.json().catch(() => ({}));
745
+ throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
746
+ }
747
+ const { challenge, message } = await challengeResponse.json();
748
+ const signature = await (0, import_accounts2.signMessage)({ message, privateKey });
749
+ const sessionKeyResponse = await fetch(`${baseUrl}/api/v1/agent/session-key`, {
750
+ method: "POST",
751
+ headers: { "Content-Type": "application/json" },
752
+ body: JSON.stringify({
753
+ challenge,
754
+ external_wallet: walletAddress,
755
+ signature,
756
+ spending_limit_usd: spendingLimitUsd,
757
+ max_per_tx_usd: maxPerTxUsd,
758
+ max_daily_usd: maxDailyUsd,
759
+ duration_days: durationDays
760
+ })
761
+ });
762
+ if (!sessionKeyResponse.ok) {
763
+ const error = await sessionKeyResponse.json().catch(() => ({}));
764
+ throw new MixrPayError(error.error || `Session key creation failed: ${sessionKeyResponse.status}`);
765
+ }
766
+ const data = await sessionKeyResponse.json();
767
+ return {
768
+ sessionKey: data.session_key,
769
+ address: data.address,
770
+ sessionKeyId: data.session_key_id,
771
+ expiresAt: new Date(data.expires_at),
772
+ limits: {
773
+ maxTotalUsd: data.limits.max_total_usd,
774
+ maxPerTxUsd: data.limits.max_per_tx_usd,
775
+ maxDailyUsd: data.limits.max_daily_usd
776
+ }
777
+ };
778
+ }
779
+ /**
780
+ * Get the status of a registered agent.
781
+ *
782
+ * Returns balance, active sessions, and spending information.
783
+ *
784
+ * @param options - Status options
785
+ * @returns Agent status
786
+ * @throws {MixrPayError} If status fetch fails
787
+ *
788
+ * @example
789
+ * ```typescript
790
+ * const status = await AgentWallet.getStatus({
791
+ * privateKey: process.env.AGENT_WALLET_KEY as `0x${string}`,
792
+ * });
793
+ *
794
+ * console.log(`Balance: $${status.balanceUsd}`);
795
+ * console.log(`Active sessions: ${status.activeSessions.length}`);
796
+ * ```
797
+ */
798
+ static async getStatus(options) {
799
+ const { privateKey } = options;
800
+ const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
801
+ const account = (0, import_accounts2.privateKeyToAccount)(privateKey);
802
+ const walletAddress = account.address;
803
+ const challengeResponse = await fetch(
804
+ `${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=status`
805
+ );
806
+ if (!challengeResponse.ok) {
807
+ const error = await challengeResponse.json().catch(() => ({}));
808
+ throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
809
+ }
810
+ const { challenge, message } = await challengeResponse.json();
811
+ const signature = await (0, import_accounts2.signMessage)({ message, privateKey });
812
+ const statusResponse = await fetch(
813
+ `${baseUrl}/api/v1/agent/status?challenge=${challenge}&external_wallet=${walletAddress}&signature=${encodeURIComponent(signature)}`
814
+ );
815
+ if (!statusResponse.ok) {
816
+ const error = await statusResponse.json().catch(() => ({}));
817
+ throw new MixrPayError(error.error || `Failed to get status: ${statusResponse.status}`);
818
+ }
819
+ const data = await statusResponse.json();
820
+ return {
821
+ depositAddress: data.deposit_address,
822
+ balanceUsd: data.balance_usd,
823
+ activeSessions: data.active_sessions.map((s) => ({
824
+ id: s.id,
825
+ expiresAt: new Date(s.expires_at),
826
+ totalSpentUsd: s.total_spent_usd,
827
+ remainingUsd: s.remaining_usd,
828
+ maxTotalUsd: s.max_total_usd
829
+ })),
830
+ totalSpentUsd: data.total_spent_usd
831
+ };
832
+ }
833
+ /**
834
+ * Revoke a session key.
835
+ *
836
+ * After revocation, the session key can no longer be used for payments.
837
+ *
838
+ * @param options - Revoke options
839
+ * @returns true if revoked successfully
840
+ * @throws {MixrPayError} If revocation fails
841
+ *
842
+ * @example
843
+ * ```typescript
844
+ * const success = await AgentWallet.revokeSessionKey({
845
+ * privateKey: process.env.AGENT_WALLET_KEY as `0x${string}`,
846
+ * sessionKeyId: 'session-key-uuid',
847
+ * });
848
+ *
849
+ * if (success) {
850
+ * console.log('Session key revoked');
851
+ * }
852
+ * ```
853
+ */
854
+ static async revokeSessionKey(options) {
855
+ const { privateKey, sessionKeyId } = options;
856
+ const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
857
+ const account = (0, import_accounts2.privateKeyToAccount)(privateKey);
858
+ const walletAddress = account.address;
859
+ const challengeResponse = await fetch(
860
+ `${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=revoke`
861
+ );
862
+ if (!challengeResponse.ok) {
863
+ const error = await challengeResponse.json().catch(() => ({}));
864
+ throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
865
+ }
866
+ const { challenge, message } = await challengeResponse.json();
867
+ const signature = await (0, import_accounts2.signMessage)({ message, privateKey });
868
+ const revokeResponse = await fetch(`${baseUrl}/api/v1/agent/session-key/revoke`, {
869
+ method: "POST",
870
+ headers: { "Content-Type": "application/json" },
871
+ body: JSON.stringify({
872
+ challenge,
873
+ external_wallet: walletAddress,
874
+ signature,
875
+ session_key_id: sessionKeyId
876
+ })
877
+ });
878
+ if (!revokeResponse.ok) {
879
+ const error = await revokeResponse.json().catch(() => ({}));
880
+ throw new MixrPayError(error.error || `Revocation failed: ${revokeResponse.status}`);
881
+ }
882
+ return true;
883
+ }
884
+ // ===========================================================================
589
885
  // Core Methods
590
886
  // ===========================================================================
591
887
  /**
@@ -623,6 +919,8 @@ var AgentWallet = class {
623
919
  */
624
920
  async fetch(url, init) {
625
921
  this.logger.debug(`Fetching ${init?.method || "GET"} ${url}`);
922
+ const requestId = crypto.randomUUID();
923
+ const correlationId = this.extractCorrelationId(init?.headers);
626
924
  const controller = new AbortController();
627
925
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
628
926
  try {
@@ -633,7 +931,7 @@ var AgentWallet = class {
633
931
  this.logger.debug(`Initial response: ${response.status}`);
634
932
  if (response.status === 402) {
635
933
  this.logger.info(`Payment required for ${url}`);
636
- response = await this.handlePaymentRequired(url, init, response);
934
+ response = await this.handlePaymentRequired(url, init, response, requestId, correlationId);
637
935
  }
638
936
  return response;
639
937
  } catch (error) {
@@ -645,10 +943,27 @@ var AgentWallet = class {
645
943
  clearTimeout(timeoutId);
646
944
  }
647
945
  }
946
+ /**
947
+ * Extract correlation ID from request headers.
948
+ */
949
+ extractCorrelationId(headers) {
950
+ if (!headers) return void 0;
951
+ if (headers instanceof Headers) {
952
+ return headers.get("X-Correlation-Id") || headers.get("x-correlation-id") || void 0;
953
+ }
954
+ if (Array.isArray(headers)) {
955
+ const entry = headers.find(
956
+ ([key]) => key.toLowerCase() === "x-correlation-id"
957
+ );
958
+ return entry ? entry[1] : void 0;
959
+ }
960
+ const record = headers;
961
+ return record["X-Correlation-Id"] || record["x-correlation-id"] || void 0;
962
+ }
648
963
  /**
649
964
  * Handle a 402 Payment Required response.
650
965
  */
651
- async handlePaymentRequired(url, init, response) {
966
+ async handlePaymentRequired(url, init, response, requestId, correlationId) {
652
967
  let requirements;
653
968
  try {
654
969
  requirements = await parse402Response(response);
@@ -704,7 +1019,9 @@ var AgentWallet = class {
704
1019
  txHash: retryResponse.headers.get("X-Payment-TxHash"),
705
1020
  timestamp: /* @__PURE__ */ new Date(),
706
1021
  description: requirements.description,
707
- url
1022
+ url,
1023
+ requestId,
1024
+ correlationId
708
1025
  };
709
1026
  this.payments.push(payment);
710
1027
  this.totalSpentUsd += amountUsd;
@@ -803,6 +1120,36 @@ var AgentWallet = class {
803
1120
  this.logger.debug("Using estimated balance based on tracking");
804
1121
  return Math.max(0, 100 - this.totalSpentUsd);
805
1122
  }
1123
+ /**
1124
+ * Check if the wallet can afford a specific amount.
1125
+ *
1126
+ * This is a convenience method to check balance before making a request
1127
+ * when you know the expected cost.
1128
+ *
1129
+ * @param amountUsd - Amount to check in USD
1130
+ * @returns Object with affordability information
1131
+ *
1132
+ * @example
1133
+ * ```typescript
1134
+ * const check = await wallet.canAfford(5.00);
1135
+ * if (check.canAfford) {
1136
+ * console.log(`Can afford! Will have $${check.remainingAfter.toFixed(2)} left`);
1137
+ * await wallet.fetch(url);
1138
+ * } else {
1139
+ * console.log(`Need $${check.shortfall.toFixed(2)} more`);
1140
+ * }
1141
+ * ```
1142
+ */
1143
+ async canAfford(amountUsd) {
1144
+ const balance = await this.getBalance();
1145
+ const canAfford = balance >= amountUsd;
1146
+ return {
1147
+ canAfford,
1148
+ balance,
1149
+ shortfall: canAfford ? 0 : amountUsd - balance,
1150
+ remainingAfter: canAfford ? balance - amountUsd : 0
1151
+ };
1152
+ }
806
1153
  /**
807
1154
  * Get information about the session key.
808
1155
  *
@@ -943,56 +1290,100 @@ var AgentWallet = class {
943
1290
  async runDiagnostics() {
944
1291
  this.logger.info("Running diagnostics...");
945
1292
  const issues = [];
1293
+ const recommendations = [];
946
1294
  const checks = {};
1295
+ let latencyMs;
1296
+ let sessionLimits;
947
1297
  checks.sessionKeyFormat = true;
948
1298
  try {
1299
+ const startTime = Date.now();
949
1300
  const response = await fetch(`${this.baseUrl}/health`, {
950
1301
  method: "GET",
951
1302
  signal: AbortSignal.timeout(5e3)
952
1303
  });
1304
+ latencyMs = Date.now() - startTime;
953
1305
  checks.apiConnectivity = response.ok;
954
1306
  if (!response.ok) {
955
1307
  issues.push(`API server returned ${response.status}. Check baseUrl configuration.`);
1308
+ recommendations.push("Verify the baseUrl configuration points to a valid MixrPay server.");
1309
+ }
1310
+ if (latencyMs > 2e3) {
1311
+ issues.push(`High API latency: ${latencyMs}ms. This may cause timeouts.`);
1312
+ recommendations.push("Consider using a server closer to your region or check network connectivity.");
956
1313
  }
957
1314
  } catch {
958
1315
  checks.apiConnectivity = false;
959
1316
  issues.push("Cannot connect to MixrPay API. Check your network connection and baseUrl.");
1317
+ recommendations.push("Verify network connectivity and that the MixrPay server is running.");
960
1318
  }
961
1319
  try {
962
1320
  const info = await this.getSessionKeyInfo(true);
963
1321
  checks.sessionKeyValid = info.isValid;
964
1322
  if (!info.isValid) {
965
1323
  issues.push("Session key is invalid or has been revoked.");
1324
+ recommendations.push("Request a new session key from the wallet owner or create one at /wallet/sessions.");
1325
+ }
1326
+ const now = /* @__PURE__ */ new Date();
1327
+ let expiresInHours = null;
1328
+ if (info.expiresAt) {
1329
+ expiresInHours = (info.expiresAt.getTime() - now.getTime()) / (1e3 * 60 * 60);
1330
+ if (info.expiresAt < now) {
1331
+ checks.sessionKeyValid = false;
1332
+ issues.push(`Session key expired on ${info.expiresAt.toISOString()}`);
1333
+ recommendations.push("Create a new session key to continue making payments.");
1334
+ } else if (expiresInHours < 24) {
1335
+ issues.push(`Session key expires in ${expiresInHours.toFixed(1)} hours.`);
1336
+ recommendations.push("Consider creating a new session key before the current one expires.");
1337
+ }
1338
+ }
1339
+ const stats = await this.getSpendingStats();
1340
+ sessionLimits = {
1341
+ remainingDailyUsd: stats.remainingDailyUsd,
1342
+ remainingTotalUsd: stats.remainingTotalUsd,
1343
+ expiresAt: info.expiresAt,
1344
+ expiresInHours
1345
+ };
1346
+ if (stats.remainingDailyUsd !== null && stats.remainingDailyUsd < 1) {
1347
+ issues.push(`Daily limit nearly exhausted: $${stats.remainingDailyUsd.toFixed(2)} remaining.`);
1348
+ recommendations.push("Wait until tomorrow for daily limit to reset, or request a higher daily limit.");
966
1349
  }
967
- if (info.expiresAt && info.expiresAt < /* @__PURE__ */ new Date()) {
968
- checks.sessionKeyValid = false;
969
- issues.push(`Session key expired on ${info.expiresAt.toISOString()}`);
1350
+ if (stats.remainingTotalUsd !== null && stats.remainingTotalUsd < 1) {
1351
+ issues.push(`Total limit nearly exhausted: $${stats.remainingTotalUsd.toFixed(2)} remaining.`);
1352
+ recommendations.push("Request a new session key with a higher total limit.");
970
1353
  }
971
1354
  } catch {
972
1355
  checks.sessionKeyValid = false;
973
1356
  issues.push("Could not verify session key validity.");
1357
+ recommendations.push("Check network connectivity and try again.");
974
1358
  }
1359
+ let balance = 0;
975
1360
  try {
976
- const balance = await this.getBalance();
1361
+ balance = await this.getBalance();
977
1362
  checks.hasBalance = balance > 0;
978
1363
  if (balance <= 0) {
979
1364
  issues.push("Wallet has no USDC balance. Top up at your MixrPay server /wallet");
1365
+ recommendations.push("Deposit USDC to your wallet address to enable payments.");
980
1366
  } else if (balance < 1) {
981
1367
  issues.push(`Low balance: $${balance.toFixed(2)}. Consider topping up.`);
1368
+ recommendations.push("Top up your wallet balance to avoid payment failures.");
982
1369
  }
983
1370
  } catch {
984
1371
  checks.hasBalance = false;
985
1372
  issues.push("Could not fetch wallet balance.");
1373
+ recommendations.push("Check network connectivity and try again.");
986
1374
  }
987
1375
  const healthy = issues.length === 0;
988
- this.logger.info("Diagnostics complete:", { healthy, issues });
1376
+ this.logger.info("Diagnostics complete:", { healthy, issues, latencyMs });
989
1377
  return {
990
1378
  healthy,
991
1379
  issues,
992
1380
  checks,
993
1381
  sdkVersion: SDK_VERSION,
994
1382
  network: this.getNetwork().name,
995
- walletAddress: this.walletAddress
1383
+ walletAddress: this.walletAddress,
1384
+ sessionLimits,
1385
+ latencyMs,
1386
+ recommendations
996
1387
  };
997
1388
  }
998
1389
  /**
@@ -1401,7 +1792,9 @@ var AgentWallet = class {
1401
1792
  txHash: response.headers.get("X-Payment-TxHash"),
1402
1793
  timestamp: /* @__PURE__ */ new Date(),
1403
1794
  description: feature || "API call",
1404
- url
1795
+ url,
1796
+ requestId: crypto.randomUUID(),
1797
+ correlationId: this.extractCorrelationId(customHeaders)
1405
1798
  };
1406
1799
  this.payments.push(payment);
1407
1800
  this.totalSpentUsd += amountUsd;
@@ -1600,7 +1993,8 @@ Timestamp: ${timestamp}`;
1600
1993
  txHash: mixrpay.txHash,
1601
1994
  timestamp: /* @__PURE__ */ new Date(),
1602
1995
  description: `MCP: ${toolName}`,
1603
- url: `${this.baseUrl}/api/mcp`
1996
+ url: `${this.baseUrl}/api/mcp`,
1997
+ requestId: crypto.randomUUID()
1604
1998
  };
1605
1999
  this.payments.push(payment);
1606
2000
  this.totalSpentUsd += mixrpay.chargedUsd;
@@ -1717,7 +2111,8 @@ Timestamp: ${timestamp}`;
1717
2111
  txHash: data.tx_hash,
1718
2112
  timestamp: /* @__PURE__ */ new Date(),
1719
2113
  description: `Agent run: ${data.run_id}`,
1720
- url: `${this.baseUrl}/api/v2/agent/run`
2114
+ url: `${this.baseUrl}/api/v2/agent/run`,
2115
+ requestId: idempotencyKey || crypto.randomUUID()
1721
2116
  };
1722
2117
  this.payments.push(payment);
1723
2118
  this.totalSpentUsd += data.cost.total_usd;
@@ -1809,7 +2204,8 @@ Timestamp: ${timestamp}`;
1809
2204
  txHash: data.tx_hash,
1810
2205
  timestamp: /* @__PURE__ */ new Date(),
1811
2206
  description: `Agent run: ${data.run_id}`,
1812
- url: `${this.baseUrl}/api/v2/agent/run`
2207
+ url: `${this.baseUrl}/api/v2/agent/run`,
2208
+ requestId: body.idempotency_key || crypto.randomUUID()
1813
2209
  };
1814
2210
  this.payments.push(payment);
1815
2211
  this.totalSpentUsd += data.total_cost_usd;
@@ -1985,7 +2381,8 @@ Timestamp: ${timestamp}`;
1985
2381
  txHash: mixrpay.txHash,
1986
2382
  timestamp: /* @__PURE__ */ new Date(),
1987
2383
  description: `MCP: ${toolName}`,
1988
- url: `${this.baseUrl}/api/mcp`
2384
+ url: `${this.baseUrl}/api/mcp`,
2385
+ requestId: crypto.randomUUID()
1989
2386
  };
1990
2387
  this.payments.push(payment);
1991
2388
  this.totalSpentUsd += mixrpay.chargedUsd;
@@ -2016,5 +2413,7 @@ Timestamp: ${timestamp}`;
2016
2413
  SessionNotFoundError,
2017
2414
  SessionRevokedError,
2018
2415
  SpendingLimitExceededError,
2416
+ X402ProtocolError,
2417
+ getErrorMessage,
2019
2418
  isMixrPayError
2020
2419
  });