@routstr/sdk 0.2.4 → 0.2.6

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.
Files changed (40) hide show
  1. package/README.md +10 -2
  2. package/dist/client/index.d.mts +38 -11
  3. package/dist/client/index.d.ts +38 -11
  4. package/dist/client/index.js +1771 -391
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/client/index.mjs +1771 -392
  7. package/dist/client/index.mjs.map +1 -1
  8. package/dist/discovery/index.d.mts +2 -2
  9. package/dist/discovery/index.d.ts +2 -2
  10. package/dist/discovery/index.js +1 -4
  11. package/dist/discovery/index.js.map +1 -1
  12. package/dist/discovery/index.mjs +1 -4
  13. package/dist/discovery/index.mjs.map +1 -1
  14. package/dist/index.d.mts +26 -22
  15. package/dist/index.d.ts +26 -22
  16. package/dist/index.js +3005 -2107
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +2997 -2108
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/{interfaces-B85Wx7ni.d.mts → interfaces-B62Rw-dd.d.ts} +20 -15
  21. package/dist/{interfaces-DGdP8fQp.d.mts → interfaces-BWJJTCXO.d.mts} +1 -1
  22. package/dist/{interfaces-CC0LT9p9.d.ts → interfaces-BxDEka72.d.ts} +1 -1
  23. package/dist/{interfaces-BVNyAmKu.d.ts → interfaces-C5fLD3jB.d.mts} +20 -15
  24. package/dist/storage/index.d.mts +38 -142
  25. package/dist/storage/index.d.ts +38 -142
  26. package/dist/storage/index.js +852 -158
  27. package/dist/storage/index.js.map +1 -1
  28. package/dist/storage/index.mjs +846 -159
  29. package/dist/storage/index.mjs.map +1 -1
  30. package/dist/store-BJlwiDX5.d.ts +151 -0
  31. package/dist/store-C5lnyX8k.d.mts +151 -0
  32. package/dist/{types-BlHjmWRK.d.mts → types-BYj_8c5c.d.mts} +3 -0
  33. package/dist/{types-BlHjmWRK.d.ts → types-BYj_8c5c.d.ts} +3 -0
  34. package/dist/wallet/index.d.mts +24 -26
  35. package/dist/wallet/index.d.ts +24 -26
  36. package/dist/wallet/index.js +130 -259
  37. package/dist/wallet/index.js.map +1 -1
  38. package/dist/wallet/index.mjs +130 -259
  39. package/dist/wallet/index.mjs.map +1 -1
  40. package/package.json +1 -1
@@ -122,13 +122,8 @@ var CashuSpender = class {
122
122
  normalizedMintBalances[url] = balanceInSats;
123
123
  totalMintBalance += balanceInSats;
124
124
  }
125
- const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
126
125
  const providerBalances = {};
127
126
  let totalProviderBalance = 0;
128
- for (const pending of pendingDistribution) {
129
- providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
130
- totalProviderBalance += pending.amount;
131
- }
132
127
  const apiKeys = this.storageAdapter.getAllApiKeys();
133
128
  for (const apiKey of apiKeys) {
134
129
  if (!providerBalances[apiKey.baseUrl]) {
@@ -349,27 +344,11 @@ var CashuSpender = class {
349
344
  };
350
345
  }
351
346
  }
352
- if (token && baseUrl) {
353
- try {
354
- this.storageAdapter.setToken(baseUrl, token);
355
- } catch (error) {
356
- if (error instanceof Error && error.message.includes("Token already exists")) {
357
- this._log(
358
- "DEBUG",
359
- `[CashuSpender] _spendInternal: Token already exists for ${baseUrl}, receiving newly created token and using existing`
360
- );
361
- const receiveResult = await this.receiveToken(token);
362
- if (receiveResult.success) {
363
- this._log(
364
- "DEBUG",
365
- `[CashuSpender] _spendInternal: Token restored successfully, amount=${receiveResult.amount}`
366
- );
367
- }
368
- token = this.storageAdapter.getToken(baseUrl);
369
- } else {
370
- throw error;
371
- }
372
- }
347
+ if (token) {
348
+ this._log(
349
+ "DEBUG",
350
+ `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`
351
+ );
373
352
  }
374
353
  this._logTransaction("spend", {
375
354
  amount: spentAmount,
@@ -390,19 +369,19 @@ var CashuSpender = class {
390
369
  };
391
370
  }
392
371
  /**
393
- * Try to reuse an existing token
372
+ * Try to reuse an existing API key
394
373
  */
395
374
  async _tryReuseToken(baseUrl, amount, mintUrl) {
396
- const storedToken = this.storageAdapter.getToken(baseUrl);
397
- if (!storedToken) return null;
398
- const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
399
- const balanceForBaseUrl = pendingDistribution.find((b) => b.baseUrl === baseUrl)?.amount || 0;
400
- this._log("DEBUG", "RESUINGDSR GSODGNSD", balanceForBaseUrl, amount);
375
+ const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
376
+ if (!apiKeyEntry) return null;
377
+ const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
378
+ const balanceForBaseUrl = apiKeyDistribution.find((b) => b.baseUrl === baseUrl)?.amount || 0;
379
+ this._log("DEBUG", "Reusing API key", balanceForBaseUrl, amount);
401
380
  if (balanceForBaseUrl > amount) {
402
381
  const units = this.walletAdapter.getMintUnits();
403
382
  const unit = units[mintUrl] || "sat";
404
383
  return {
405
- token: storedToken,
384
+ token: apiKeyEntry.key,
406
385
  status: "success",
407
386
  balance: balanceForBaseUrl,
408
387
  unit
@@ -413,7 +392,8 @@ var CashuSpender = class {
413
392
  const topUpResult = await this.balanceManager.topUp({
414
393
  mintUrl,
415
394
  baseUrl,
416
- amount: topUpAmount
395
+ amount: topUpAmount,
396
+ token: apiKeyEntry.key
417
397
  });
418
398
  this._log("DEBUG", "TOPUP ", topUpResult);
419
399
  if (topUpResult.success && topUpResult.toppedUpAmount) {
@@ -427,7 +407,7 @@ var CashuSpender = class {
427
407
  status: "success"
428
408
  });
429
409
  return {
430
- token: storedToken,
410
+ token: apiKeyEntry.key,
431
411
  status: "success",
432
412
  balance: newBalance,
433
413
  unit
@@ -435,83 +415,108 @@ var CashuSpender = class {
435
415
  }
436
416
  const providerBalance = await this._getProviderTokenBalance(
437
417
  baseUrl,
438
- storedToken
418
+ apiKeyEntry.key
439
419
  );
440
420
  this._log("DEBUG", providerBalance);
441
421
  if (providerBalance <= 0) {
442
- this.storageAdapter.removeToken(baseUrl);
422
+ this.storageAdapter.removeApiKey(baseUrl);
443
423
  }
444
424
  }
445
425
  return null;
446
426
  }
447
427
  /**
448
- * Refund specific providers without retrying spend
428
+ * Refund all xcashu tokens from storage and increment tryCounts on failure.
429
+ * Reuses receiveToken from BalanceManager/CashuSpender for receiving refunds.
430
+ * @param mintUrl - The mint URL for receiving tokens
431
+ * @param excludeBaseUrls - Base URLs to exclude from refund (optional)
432
+ * @returns Results for each xcashu token refund attempt
449
433
  */
450
- async refundProviders(baseUrls, mintUrl, refundApiKeys = false) {
434
+ async refundXcashuTokens(mintUrl, excludeBaseUrls) {
451
435
  const results = [];
452
- const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
453
- const toRefund = pendingDistribution.filter(
454
- (p) => baseUrls.includes(p.baseUrl)
455
- );
456
- const refundResults = await Promise.allSettled(
457
- toRefund.map(async (pending) => {
458
- const token = this.storageAdapter.getToken(pending.baseUrl);
459
- this._log("DEBUG", token, this.balanceManager);
460
- if (!token || !this.balanceManager) {
461
- return { baseUrl: pending.baseUrl, success: false };
462
- }
463
- const tokenBalance = await this.balanceManager.getTokenBalance(
464
- token,
465
- pending.baseUrl
466
- );
467
- if (tokenBalance.reserved > 0) {
468
- return { baseUrl: pending.baseUrl, success: false };
469
- }
470
- const result = await this.balanceManager.refund({
471
- mintUrl,
472
- baseUrl: pending.baseUrl,
473
- token
474
- });
475
- this._log("DEBUG", result);
476
- if (result.success) {
477
- this.storageAdapter.removeToken(pending.baseUrl);
478
- }
479
- return { baseUrl: pending.baseUrl, success: result.success };
480
- })
481
- );
482
- results.push(
483
- ...refundResults.map(
484
- (r) => r.status === "fulfilled" ? r.value : { baseUrl: "", success: false }
485
- )
486
- );
487
- if (refundApiKeys) {
488
- const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
489
- const apiKeysToRefund = apiKeyDistribution.filter(
490
- (p) => baseUrls.includes(p.baseUrl)
491
- );
492
- for (const apiKeyEntry of apiKeysToRefund) {
493
- const apiKeyEntryFull = this.storageAdapter.getApiKey(
494
- apiKeyEntry.baseUrl
495
- );
496
- if (apiKeyEntryFull && this.balanceManager) {
497
- const refundResult = await this.balanceManager.refundApiKey({
498
- mintUrl,
499
- baseUrl: apiKeyEntry.baseUrl,
500
- apiKey: apiKeyEntryFull.key
501
- });
502
- if (refundResult.success) {
503
- this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, 0);
436
+ const xcashuTokens = this.storageAdapter.getXcashuTokens();
437
+ const excludedUrls = new Set(excludeBaseUrls || []);
438
+ for (const [baseUrl, tokens] of Object.entries(xcashuTokens)) {
439
+ if (excludedUrls.has(baseUrl)) continue;
440
+ for (const xcashuToken of tokens) {
441
+ try {
442
+ const receiveResult = await this.receiveToken(xcashuToken.token);
443
+ if (receiveResult.success) {
444
+ this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
445
+ results.push({
446
+ baseUrl,
447
+ token: xcashuToken.token,
448
+ success: true
449
+ });
450
+ this._log(
451
+ "DEBUG",
452
+ `[CashuSpender] refundXcashuTokens: Successfully refunded xcashu token for ${baseUrl}, amount=${receiveResult.amount}`
453
+ );
454
+ } else {
455
+ const currentTryCount = xcashuToken.tryCount ?? 0;
456
+ const newTryCount = currentTryCount + 1;
457
+ this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
458
+ results.push({
459
+ baseUrl,
460
+ token: xcashuToken.token,
461
+ success: false,
462
+ error: receiveResult.message ?? "Refund failed"
463
+ });
464
+ this._log(
465
+ "DEBUG",
466
+ `[CashuSpender] refundXcashuTokens: Failed to refund xcashu token for ${baseUrl}, incremented tryCount to ${newTryCount}`
467
+ );
504
468
  }
469
+ } catch (error) {
470
+ const currentTryCount = xcashuToken.tryCount ?? 0;
471
+ const newTryCount = currentTryCount + 1;
472
+ this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
473
+ const errorMessage = error instanceof Error ? error.message : String(error);
505
474
  results.push({
506
- baseUrl: apiKeyEntry.baseUrl,
507
- success: refundResult.success
475
+ baseUrl,
476
+ token: xcashuToken.token,
477
+ success: false,
478
+ error: errorMessage
508
479
  });
480
+ this._log(
481
+ "ERROR",
482
+ `[CashuSpender] refundXcashuTokens: Exception during refund for ${baseUrl}: ${errorMessage}, incremented tryCount to ${newTryCount}`
483
+ );
484
+ }
485
+ }
486
+ }
487
+ return results;
488
+ }
489
+ /**
490
+ * Refund specific providers without retrying spend
491
+ */
492
+ async refundProviders(mintUrl, forceRefund) {
493
+ const results = [];
494
+ const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
495
+ for (const apiKeyEntry of apiKeyDistribution) {
496
+ const apiKeyEntryFull = this.storageAdapter.getApiKey(
497
+ apiKeyEntry.baseUrl
498
+ );
499
+ if (apiKeyEntryFull && this.balanceManager) {
500
+ const refundResult = await this.balanceManager.refundApiKey({
501
+ mintUrl,
502
+ baseUrl: apiKeyEntry.baseUrl,
503
+ apiKey: apiKeyEntryFull.key,
504
+ forceRefund
505
+ });
506
+ if (refundResult.success) {
507
+ this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
509
508
  } else {
510
- results.push({
511
- baseUrl: apiKeyEntry.baseUrl,
512
- success: false
513
- });
509
+ this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, apiKeyEntry.amount);
514
510
  }
511
+ results.push({
512
+ baseUrl: apiKeyEntry.baseUrl,
513
+ success: refundResult.success
514
+ });
515
+ } else {
516
+ results.push({
517
+ baseUrl: apiKeyEntry.baseUrl,
518
+ success: false
519
+ });
515
520
  }
516
521
  }
517
522
  return results;
@@ -596,13 +601,8 @@ var BalanceManager = class {
596
601
  normalizedMintBalances[url] = balanceInSats;
597
602
  totalMintBalance += balanceInSats;
598
603
  }
599
- const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
600
604
  const providerBalances = {};
601
605
  let totalProviderBalance = 0;
602
- for (const pending of pendingDistribution) {
603
- providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
604
- totalProviderBalance += pending.amount;
605
- }
606
606
  const apiKeys = this.storageAdapter.getAllApiKeys();
607
607
  for (const apiKey of apiKeys) {
608
608
  if (!providerBalances[apiKey.baseUrl]) {
@@ -617,65 +617,31 @@ var BalanceManager = class {
617
617
  mintBalances: normalizedMintBalances
618
618
  };
619
619
  }
620
- /**
621
- * Unified refund - handles both NIP-60 and legacy wallet refunds
622
- */
623
- async refund(options) {
624
- const { mintUrl, baseUrl, token: providedToken } = options;
625
- const storedToken = providedToken || this.storageAdapter.getToken(baseUrl);
626
- if (!storedToken) {
627
- console.log("[BalanceManager] No token to refund, returning early");
628
- return { success: true, message: "No API key to refund" };
629
- }
630
- let fetchResult;
631
- try {
632
- fetchResult = await this._fetchRefundToken(baseUrl, storedToken);
633
- if (!fetchResult.success) {
634
- return {
635
- success: false,
636
- message: fetchResult.error || "Refund failed",
637
- requestId: fetchResult.requestId
638
- };
639
- }
640
- if (!fetchResult.token) {
641
- return {
642
- success: false,
643
- message: "No token received from refund",
644
- requestId: fetchResult.requestId
645
- };
646
- }
647
- if (fetchResult.error === "No balance to refund") {
648
- console.log(
649
- "[BalanceManager] No balance to refund, removing stored token"
650
- );
651
- this.storageAdapter.removeToken(baseUrl);
652
- return { success: true, message: "No balance to refund" };
653
- }
654
- const receiveResult = await this.cashuSpender.receiveToken(
655
- fetchResult.token
656
- );
657
- const totalAmountMsat = receiveResult.unit === "msat" ? receiveResult.amount : receiveResult.amount * 1e3;
658
- if (!providedToken) {
659
- this.storageAdapter.removeToken(baseUrl);
660
- }
661
- return {
662
- success: receiveResult.success,
663
- refundedAmount: totalAmountMsat,
664
- requestId: fetchResult.requestId
665
- };
666
- } catch (error) {
667
- console.error("[BalanceManager] Refund error", error);
668
- return this._handleRefundError(error, mintUrl, fetchResult?.requestId);
669
- }
670
- }
671
620
  /**
672
621
  * Refund API key balance - convert remaining API key balance to cashu token
622
+ * @param options - Refund options including forceRefund flag
623
+ * @returns Refund result
673
624
  */
674
625
  async refundApiKey(options) {
675
- const { mintUrl, baseUrl, apiKey } = options;
626
+ const { mintUrl, baseUrl, apiKey, forceRefund } = options;
676
627
  if (!apiKey) {
677
628
  return { success: false, message: "No API key to refund" };
678
629
  }
630
+ if (!forceRefund) {
631
+ const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
632
+ if (apiKeyEntry?.lastUsed) {
633
+ const fiveMinutesAgo = Date.now() - 5 * 60 * 1e3;
634
+ if (apiKeyEntry.lastUsed > fiveMinutesAgo) {
635
+ console.log(
636
+ `[BalanceManager] Skipping refund for ${baseUrl} - used ${Math.round((Date.now() - apiKeyEntry.lastUsed) / 1e3)}s ago`
637
+ );
638
+ return {
639
+ success: false,
640
+ message: "API key was used recently, skipping refund"
641
+ };
642
+ }
643
+ }
644
+ }
679
645
  let fetchResult;
680
646
  try {
681
647
  fetchResult = await this._fetchRefundTokenWithApiKey(baseUrl, apiKey);
@@ -786,8 +752,9 @@ var BalanceManager = class {
786
752
  if (!amount || amount <= 0) {
787
753
  return { success: false, message: "Invalid top up amount" };
788
754
  }
789
- const storedToken = providedToken || this.storageAdapter.getToken(baseUrl);
790
- if (!storedToken) {
755
+ const apiKeyEntry = providedToken ? null : this.storageAdapter.getApiKey(baseUrl);
756
+ const apiKey = providedToken || apiKeyEntry?.key;
757
+ if (!apiKey) {
791
758
  return { success: false, message: "No API key available for top up" };
792
759
  }
793
760
  let cashuToken = null;
@@ -807,7 +774,7 @@ var BalanceManager = class {
807
774
  cashuToken = tokenResult.token;
808
775
  const topUpResult = await this._postTopUp(
809
776
  baseUrl,
810
- storedToken,
777
+ apiKey,
811
778
  cashuToken
812
779
  );
813
780
  requestId = topUpResult.requestId;
@@ -867,8 +834,8 @@ var BalanceManager = class {
867
834
  const refundableProviderBalance = Object.entries(
868
835
  balanceState.providerBalances
869
836
  ).filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl).reduce((sum, [, value]) => sum + value, 0);
870
- if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount < 1) {
871
- await this._refundOtherProvidersForTopUp(baseUrl, mintUrl);
837
+ if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount < 2) {
838
+ await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount);
872
839
  return this.createProviderToken({
873
840
  ...options,
874
841
  retryCount: retryCount + 1
@@ -1021,38 +988,12 @@ var BalanceManager = class {
1021
988
  }
1022
989
  return candidates;
1023
990
  }
1024
- async _refundOtherProvidersForTopUp(baseUrl, mintUrl) {
1025
- const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
991
+ async _refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount) {
1026
992
  const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
1027
- const toRefund = pendingDistribution.filter(
1028
- (pending) => pending.baseUrl !== baseUrl
1029
- );
993
+ const forceRefund = retryCount >= 2;
1030
994
  const apiKeysToRefund = apiKeyDistribution.filter(
1031
995
  (apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0
1032
996
  );
1033
- const tokenRefundResults = await Promise.allSettled(
1034
- toRefund.map(async (pending) => {
1035
- const token = this.storageAdapter.getToken(pending.baseUrl);
1036
- if (!token) {
1037
- return { baseUrl: pending.baseUrl, success: false };
1038
- }
1039
- const tokenBalance = await this.getTokenBalance(token, pending.baseUrl);
1040
- if (tokenBalance.reserved > 0) {
1041
- return { baseUrl: pending.baseUrl, success: false };
1042
- }
1043
- const result = await this.refund({
1044
- mintUrl,
1045
- baseUrl: pending.baseUrl,
1046
- token
1047
- });
1048
- return { baseUrl: pending.baseUrl, success: result.success };
1049
- })
1050
- );
1051
- for (const result of tokenRefundResults) {
1052
- if (result.status === "fulfilled" && result.value.success) {
1053
- this.storageAdapter.removeToken(result.value.baseUrl);
1054
- }
1055
- }
1056
997
  const apiKeyRefundResults = await Promise.allSettled(
1057
998
  apiKeysToRefund.map(async (apiKeyEntry) => {
1058
999
  const fullApiKeyEntry = this.storageAdapter.getApiKey(
@@ -1064,7 +1005,8 @@ var BalanceManager = class {
1064
1005
  const result = await this.refundApiKey({
1065
1006
  mintUrl,
1066
1007
  baseUrl: apiKeyEntry.baseUrl,
1067
- apiKey: fullApiKeyEntry.key
1008
+ apiKey: fullApiKeyEntry.key,
1009
+ forceRefund
1068
1010
  });
1069
1011
  return { baseUrl: apiKeyEntry.baseUrl, success: result.success };
1070
1012
  })
@@ -1075,77 +1017,6 @@ var BalanceManager = class {
1075
1017
  }
1076
1018
  }
1077
1019
  }
1078
- /**
1079
- * Fetch refund token from provider API
1080
- */
1081
- async _fetchRefundToken(baseUrl, storedToken) {
1082
- if (!baseUrl) {
1083
- return {
1084
- success: false,
1085
- error: "No base URL configured"
1086
- };
1087
- }
1088
- const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
1089
- const url = `${normalizedBaseUrl}v1/wallet/refund`;
1090
- const controller = new AbortController();
1091
- const timeoutId = setTimeout(() => {
1092
- controller.abort();
1093
- }, 6e4);
1094
- try {
1095
- const response = await fetch(url, {
1096
- method: "POST",
1097
- headers: {
1098
- Authorization: `Bearer ${storedToken}`,
1099
- "Content-Type": "application/json"
1100
- },
1101
- signal: controller.signal
1102
- });
1103
- clearTimeout(timeoutId);
1104
- const requestId = response.headers.get("x-routstr-request-id") || void 0;
1105
- if (!response.ok) {
1106
- const errorData = await response.json().catch(() => ({}));
1107
- if (response.status === 400 && errorData?.detail === "No balance to refund") {
1108
- this.storageAdapter.removeToken(baseUrl);
1109
- return {
1110
- success: false,
1111
- requestId,
1112
- error: "No balance to refund"
1113
- };
1114
- }
1115
- return {
1116
- success: false,
1117
- requestId,
1118
- error: `Refund request failed with status ${response.status}: ${errorData?.detail || response.statusText}`
1119
- };
1120
- }
1121
- const data = await response.json();
1122
- console.log("refund rsule", data);
1123
- return {
1124
- success: true,
1125
- token: data.token,
1126
- requestId
1127
- };
1128
- } catch (error) {
1129
- clearTimeout(timeoutId);
1130
- console.error("[BalanceManager._fetchRefundToken] Fetch error", error);
1131
- if (error instanceof Error) {
1132
- if (error.name === "AbortError") {
1133
- return {
1134
- success: false,
1135
- error: "Request timed out after 1 minute"
1136
- };
1137
- }
1138
- return {
1139
- success: false,
1140
- error: error.message
1141
- };
1142
- }
1143
- return {
1144
- success: false,
1145
- error: "Unknown error occurred during refund request"
1146
- };
1147
- }
1148
- }
1149
1020
  /**
1150
1021
  * Post topup request to provider API
1151
1022
  */