@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.
- package/README.md +10 -2
- package/dist/client/index.d.mts +38 -11
- package/dist/client/index.d.ts +38 -11
- package/dist/client/index.js +1771 -391
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +1771 -392
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.d.mts +2 -2
- package/dist/discovery/index.d.ts +2 -2
- package/dist/discovery/index.js +1 -4
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +1 -4
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +26 -22
- package/dist/index.d.ts +26 -22
- package/dist/index.js +3005 -2107
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2997 -2108
- package/dist/index.mjs.map +1 -1
- package/dist/{interfaces-B85Wx7ni.d.mts → interfaces-B62Rw-dd.d.ts} +20 -15
- package/dist/{interfaces-DGdP8fQp.d.mts → interfaces-BWJJTCXO.d.mts} +1 -1
- package/dist/{interfaces-CC0LT9p9.d.ts → interfaces-BxDEka72.d.ts} +1 -1
- package/dist/{interfaces-BVNyAmKu.d.ts → interfaces-C5fLD3jB.d.mts} +20 -15
- package/dist/storage/index.d.mts +38 -142
- package/dist/storage/index.d.ts +38 -142
- package/dist/storage/index.js +852 -158
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +846 -159
- package/dist/storage/index.mjs.map +1 -1
- package/dist/store-BJlwiDX5.d.ts +151 -0
- package/dist/store-C5lnyX8k.d.mts +151 -0
- package/dist/{types-BlHjmWRK.d.mts → types-BYj_8c5c.d.mts} +3 -0
- package/dist/{types-BlHjmWRK.d.ts → types-BYj_8c5c.d.ts} +3 -0
- package/dist/wallet/index.d.mts +24 -26
- package/dist/wallet/index.d.ts +24 -26
- package/dist/wallet/index.js +130 -259
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +130 -259
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/wallet/index.js
CHANGED
|
@@ -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
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
|
372
|
+
* Try to reuse an existing API key
|
|
394
373
|
*/
|
|
395
374
|
async _tryReuseToken(baseUrl, amount, mintUrl) {
|
|
396
|
-
const
|
|
397
|
-
if (!
|
|
398
|
-
const
|
|
399
|
-
const balanceForBaseUrl =
|
|
400
|
-
this._log("DEBUG", "
|
|
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:
|
|
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:
|
|
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
|
-
|
|
418
|
+
apiKeyEntry.key
|
|
439
419
|
);
|
|
440
420
|
this._log("DEBUG", providerBalance);
|
|
441
421
|
if (providerBalance <= 0) {
|
|
442
|
-
this.storageAdapter.
|
|
422
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
443
423
|
}
|
|
444
424
|
}
|
|
445
425
|
return null;
|
|
446
426
|
}
|
|
447
427
|
/**
|
|
448
|
-
* Refund
|
|
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
|
|
434
|
+
async refundXcashuTokens(mintUrl, excludeBaseUrls) {
|
|
451
435
|
const results = [];
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
|
507
|
-
|
|
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
|
-
|
|
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
|
|
790
|
-
|
|
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
|
-
|
|
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 <
|
|
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
|
|
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
|
*/
|