@routstr/sdk 0.1.6 → 0.1.8
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/client/index.js +190 -66
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +190 -66
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +206 -73
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +206 -73
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +31 -0
- package/dist/storage/index.d.ts +31 -0
- package/dist/storage/index.js +16 -7
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +16 -7
- package/dist/storage/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +8 -1
- package/dist/wallet/index.d.ts +8 -1
- package/dist/wallet/index.js +93 -39
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +93 -39
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -766,6 +766,9 @@ var CashuSpender = class {
|
|
|
766
766
|
return result;
|
|
767
767
|
}
|
|
768
768
|
async _getBalanceState() {
|
|
769
|
+
if (this.balanceManager) {
|
|
770
|
+
return this.balanceManager.getBalanceState();
|
|
771
|
+
}
|
|
769
772
|
const mintBalances = await this.walletAdapter.getBalances();
|
|
770
773
|
const units = this.walletAdapter.getMintUnits();
|
|
771
774
|
let totalMintBalance = 0;
|
|
@@ -781,15 +784,16 @@ var CashuSpender = class {
|
|
|
781
784
|
const providerBalances = {};
|
|
782
785
|
let totalProviderBalance = 0;
|
|
783
786
|
for (const pending of pendingDistribution) {
|
|
784
|
-
providerBalances[pending.baseUrl] = pending.amount;
|
|
787
|
+
providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
|
|
785
788
|
totalProviderBalance += pending.amount;
|
|
786
789
|
}
|
|
787
790
|
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
788
791
|
for (const apiKey of apiKeys) {
|
|
789
792
|
if (!providerBalances[apiKey.baseUrl]) {
|
|
790
|
-
providerBalances[apiKey.baseUrl] =
|
|
791
|
-
totalProviderBalance += apiKey.balance;
|
|
793
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
792
794
|
}
|
|
795
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
796
|
+
totalProviderBalance += apiKey.balance;
|
|
793
797
|
}
|
|
794
798
|
return {
|
|
795
799
|
totalBalance: totalMintBalance + totalProviderBalance,
|
|
@@ -938,25 +942,12 @@ var CashuSpender = class {
|
|
|
938
942
|
`[CashuSpender] _spendInternal: Could not reuse token, will create new token`
|
|
939
943
|
);
|
|
940
944
|
}
|
|
941
|
-
const
|
|
942
|
-
const
|
|
943
|
-
let totalBalance = 0;
|
|
944
|
-
for (const url in balances) {
|
|
945
|
-
const balance = balances[url];
|
|
946
|
-
const unit = units[url];
|
|
947
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
948
|
-
totalBalance += balanceInSats;
|
|
949
|
-
}
|
|
950
|
-
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
951
|
-
const totalPending = pendingDistribution.reduce(
|
|
952
|
-
(sum, item) => sum + item.amount,
|
|
953
|
-
0
|
|
954
|
-
);
|
|
945
|
+
const balanceState = await this._getBalanceState();
|
|
946
|
+
const totalAvailableBalance = balanceState.totalBalance;
|
|
955
947
|
this._log(
|
|
956
948
|
"DEBUG",
|
|
957
|
-
`[CashuSpender] _spendInternal:
|
|
949
|
+
`[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`
|
|
958
950
|
);
|
|
959
|
-
const totalAvailableBalance = totalBalance + totalPending;
|
|
960
951
|
if (totalAvailableBalance < adjustedAmount) {
|
|
961
952
|
this._log(
|
|
962
953
|
"ERROR",
|
|
@@ -964,8 +955,7 @@ var CashuSpender = class {
|
|
|
964
955
|
);
|
|
965
956
|
return this._createInsufficientBalanceError(
|
|
966
957
|
adjustedAmount,
|
|
967
|
-
|
|
968
|
-
units,
|
|
958
|
+
balanceState.mintBalances,
|
|
969
959
|
totalAvailableBalance
|
|
970
960
|
);
|
|
971
961
|
}
|
|
@@ -985,8 +975,7 @@ var CashuSpender = class {
|
|
|
985
975
|
if ((tokenResult.error || "").includes("Insufficient balance")) {
|
|
986
976
|
return this._createInsufficientBalanceError(
|
|
987
977
|
adjustedAmount,
|
|
988
|
-
|
|
989
|
-
units,
|
|
978
|
+
balanceState.mintBalances,
|
|
990
979
|
totalAvailableBalance
|
|
991
980
|
);
|
|
992
981
|
}
|
|
@@ -1031,6 +1020,7 @@ var CashuSpender = class {
|
|
|
1031
1020
|
"DEBUG",
|
|
1032
1021
|
`[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`
|
|
1033
1022
|
);
|
|
1023
|
+
const units = this.walletAdapter.getMintUnits();
|
|
1034
1024
|
return {
|
|
1035
1025
|
token,
|
|
1036
1026
|
status: "success",
|
|
@@ -1168,13 +1158,11 @@ var CashuSpender = class {
|
|
|
1168
1158
|
/**
|
|
1169
1159
|
* Create an insufficient balance error result
|
|
1170
1160
|
*/
|
|
1171
|
-
_createInsufficientBalanceError(required,
|
|
1161
|
+
_createInsufficientBalanceError(required, normalizedBalances, availableBalance) {
|
|
1172
1162
|
let maxBalance = 0;
|
|
1173
1163
|
let maxMintUrl = "";
|
|
1174
|
-
for (const mintUrl in
|
|
1175
|
-
const
|
|
1176
|
-
const unit = units[mintUrl];
|
|
1177
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
1164
|
+
for (const mintUrl in normalizedBalances) {
|
|
1165
|
+
const balanceInSats = normalizedBalances[mintUrl];
|
|
1178
1166
|
if (balanceInSats > maxBalance) {
|
|
1179
1167
|
maxBalance = balanceInSats;
|
|
1180
1168
|
maxMintUrl = mintUrl;
|
|
@@ -1235,6 +1223,39 @@ var BalanceManager = class {
|
|
|
1235
1223
|
}
|
|
1236
1224
|
}
|
|
1237
1225
|
cashuSpender;
|
|
1226
|
+
async getBalanceState() {
|
|
1227
|
+
const mintBalances = await this.walletAdapter.getBalances();
|
|
1228
|
+
const units = this.walletAdapter.getMintUnits();
|
|
1229
|
+
let totalMintBalance = 0;
|
|
1230
|
+
const normalizedMintBalances = {};
|
|
1231
|
+
for (const url in mintBalances) {
|
|
1232
|
+
const balance = mintBalances[url];
|
|
1233
|
+
const unit = units[url];
|
|
1234
|
+
const balanceInSats = getBalanceInSats(balance, unit);
|
|
1235
|
+
normalizedMintBalances[url] = balanceInSats;
|
|
1236
|
+
totalMintBalance += balanceInSats;
|
|
1237
|
+
}
|
|
1238
|
+
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
1239
|
+
const providerBalances = {};
|
|
1240
|
+
let totalProviderBalance = 0;
|
|
1241
|
+
for (const pending of pendingDistribution) {
|
|
1242
|
+
providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
|
|
1243
|
+
totalProviderBalance += pending.amount;
|
|
1244
|
+
}
|
|
1245
|
+
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
1246
|
+
for (const apiKey of apiKeys) {
|
|
1247
|
+
if (!providerBalances[apiKey.baseUrl]) {
|
|
1248
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
1249
|
+
}
|
|
1250
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
1251
|
+
totalProviderBalance += apiKey.balance;
|
|
1252
|
+
}
|
|
1253
|
+
return {
|
|
1254
|
+
totalBalance: totalMintBalance + totalProviderBalance,
|
|
1255
|
+
providerBalances,
|
|
1256
|
+
mintBalances: normalizedMintBalances
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1238
1259
|
/**
|
|
1239
1260
|
* Unified refund - handles both NIP-60 and legacy wallet refunds
|
|
1240
1261
|
*/
|
|
@@ -1464,17 +1485,17 @@ var BalanceManager = class {
|
|
|
1464
1485
|
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
1465
1486
|
return { success: false, error: "Invalid top up amount" };
|
|
1466
1487
|
}
|
|
1488
|
+
const balanceState = await this.getBalanceState();
|
|
1467
1489
|
const balances = await this.walletAdapter.getBalances();
|
|
1468
1490
|
const units = this.walletAdapter.getMintUnits();
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
if (totalMintBalance < adjustedAmount && totalMintBalance + refundablePending >= adjustedAmount && retryCount < 1) {
|
|
1491
|
+
const totalMintBalance = Object.values(balanceState.mintBalances).reduce(
|
|
1492
|
+
(sum, value) => sum + value,
|
|
1493
|
+
0
|
|
1494
|
+
);
|
|
1495
|
+
const refundableProviderBalance = Object.entries(
|
|
1496
|
+
balanceState.providerBalances
|
|
1497
|
+
).filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl).reduce((sum, [, value]) => sum + value, 0);
|
|
1498
|
+
if (totalMintBalance < adjustedAmount && totalMintBalance + refundableProviderBalance >= adjustedAmount && retryCount < 1) {
|
|
1478
1499
|
await this._refundOtherProvidersForTopUp(baseUrl, mintUrl);
|
|
1479
1500
|
return this.createProviderToken({
|
|
1480
1501
|
...options,
|
|
@@ -1596,10 +1617,14 @@ var BalanceManager = class {
|
|
|
1596
1617
|
}
|
|
1597
1618
|
async _refundOtherProvidersForTopUp(baseUrl, mintUrl) {
|
|
1598
1619
|
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
1620
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
1599
1621
|
const toRefund = pendingDistribution.filter(
|
|
1600
1622
|
(pending) => pending.baseUrl !== baseUrl
|
|
1601
1623
|
);
|
|
1602
|
-
const
|
|
1624
|
+
const apiKeysToRefund = apiKeyDistribution.filter(
|
|
1625
|
+
(apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0
|
|
1626
|
+
);
|
|
1627
|
+
const tokenRefundResults = await Promise.allSettled(
|
|
1603
1628
|
toRefund.map(async (pending) => {
|
|
1604
1629
|
const token = this.storageAdapter.getToken(pending.baseUrl);
|
|
1605
1630
|
if (!token) {
|
|
@@ -1617,11 +1642,32 @@ var BalanceManager = class {
|
|
|
1617
1642
|
return { baseUrl: pending.baseUrl, success: result.success };
|
|
1618
1643
|
})
|
|
1619
1644
|
);
|
|
1620
|
-
for (const result of
|
|
1645
|
+
for (const result of tokenRefundResults) {
|
|
1621
1646
|
if (result.status === "fulfilled" && result.value.success) {
|
|
1622
1647
|
this.storageAdapter.removeToken(result.value.baseUrl);
|
|
1623
1648
|
}
|
|
1624
1649
|
}
|
|
1650
|
+
const apiKeyRefundResults = await Promise.allSettled(
|
|
1651
|
+
apiKeysToRefund.map(async (apiKeyEntry) => {
|
|
1652
|
+
const fullApiKeyEntry = this.storageAdapter.getApiKey(
|
|
1653
|
+
apiKeyEntry.baseUrl
|
|
1654
|
+
);
|
|
1655
|
+
if (!fullApiKeyEntry) {
|
|
1656
|
+
return { baseUrl: apiKeyEntry.baseUrl, success: false };
|
|
1657
|
+
}
|
|
1658
|
+
const result = await this.refundApiKey({
|
|
1659
|
+
mintUrl,
|
|
1660
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
1661
|
+
apiKey: fullApiKeyEntry.key
|
|
1662
|
+
});
|
|
1663
|
+
return { baseUrl: apiKeyEntry.baseUrl, success: result.success };
|
|
1664
|
+
})
|
|
1665
|
+
);
|
|
1666
|
+
for (const result of apiKeyRefundResults) {
|
|
1667
|
+
if (result.status === "fulfilled" && result.value.success) {
|
|
1668
|
+
this.storageAdapter.updateApiKeyBalance(result.value.baseUrl, 0);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1625
1671
|
}
|
|
1626
1672
|
/**
|
|
1627
1673
|
* Fetch refund token from provider API
|
|
@@ -1820,6 +1866,14 @@ var BalanceManager = class {
|
|
|
1820
1866
|
console.log(response.status);
|
|
1821
1867
|
const data = await response.json();
|
|
1822
1868
|
console.log("FAILED ", data);
|
|
1869
|
+
const isInvalidApiKey = response.status === 401 && data?.code === "invalid_api_key" && data?.message?.includes("proofs already spent");
|
|
1870
|
+
return {
|
|
1871
|
+
amount: -1,
|
|
1872
|
+
reserved: data.reserved ?? 0,
|
|
1873
|
+
unit: "msat",
|
|
1874
|
+
apiKey: data.api_key,
|
|
1875
|
+
isInvalidApiKey
|
|
1876
|
+
};
|
|
1823
1877
|
}
|
|
1824
1878
|
} catch (error) {
|
|
1825
1879
|
console.error("ERRORR IN RESTPONSE", error);
|
|
@@ -2768,7 +2822,8 @@ var RoutstrClient = class {
|
|
|
2768
2822
|
response.status,
|
|
2769
2823
|
requestId,
|
|
2770
2824
|
this.mode === "xcashu" ? response.headers.get("x-cashu") ?? void 0 : void 0,
|
|
2771
|
-
bodyText
|
|
2825
|
+
bodyText,
|
|
2826
|
+
params.retryCount ?? 0
|
|
2772
2827
|
);
|
|
2773
2828
|
}
|
|
2774
2829
|
return response;
|
|
@@ -2777,8 +2832,12 @@ var RoutstrClient = class {
|
|
|
2777
2832
|
return await this._handleErrorResponse(
|
|
2778
2833
|
params,
|
|
2779
2834
|
token,
|
|
2780
|
-
-1
|
|
2835
|
+
-1,
|
|
2781
2836
|
// just for Network Error to skip all statuses
|
|
2837
|
+
void 0,
|
|
2838
|
+
void 0,
|
|
2839
|
+
void 0,
|
|
2840
|
+
params.retryCount ?? 0
|
|
2782
2841
|
);
|
|
2783
2842
|
}
|
|
2784
2843
|
throw error;
|
|
@@ -2787,7 +2846,8 @@ var RoutstrClient = class {
|
|
|
2787
2846
|
/**
|
|
2788
2847
|
* Handle error responses with failover
|
|
2789
2848
|
*/
|
|
2790
|
-
async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody) {
|
|
2849
|
+
async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody, retryCount = 0) {
|
|
2850
|
+
const MAX_RETRIES_PER_PROVIDER = 2;
|
|
2791
2851
|
const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
2792
2852
|
let tryNextProvider = false;
|
|
2793
2853
|
this._log(
|
|
@@ -2858,10 +2918,34 @@ var RoutstrClient = class {
|
|
|
2858
2918
|
}
|
|
2859
2919
|
}
|
|
2860
2920
|
if (status === 402 && !tryNextProvider && (this.mode === "apikeys" || this.mode === "lazyrefund")) {
|
|
2921
|
+
this.storageAdapter.getApiKey(baseUrl);
|
|
2922
|
+
let topupAmount = params.requiredSats;
|
|
2923
|
+
try {
|
|
2924
|
+
let currentBalance = 0;
|
|
2925
|
+
if (this.mode === "apikeys") {
|
|
2926
|
+
const currentBalanceInfo = await this.balanceManager.getTokenBalance(
|
|
2927
|
+
params.token,
|
|
2928
|
+
baseUrl
|
|
2929
|
+
);
|
|
2930
|
+
currentBalance = currentBalanceInfo.unit === "msat" ? currentBalanceInfo.amount / 1e3 : currentBalanceInfo.amount;
|
|
2931
|
+
} else if (this.mode === "lazyrefund") {
|
|
2932
|
+
const distribution = this.storageAdapter.getCachedTokenDistribution();
|
|
2933
|
+
const tokenEntry = distribution.find((t) => t.baseUrl === baseUrl);
|
|
2934
|
+
currentBalance = tokenEntry?.amount ?? 0;
|
|
2935
|
+
}
|
|
2936
|
+
const shortfall = Math.max(0, params.requiredSats - currentBalance);
|
|
2937
|
+
topupAmount = shortfall > 0 ? shortfall : params.requiredSats;
|
|
2938
|
+
} catch (e) {
|
|
2939
|
+
this._log(
|
|
2940
|
+
"WARN",
|
|
2941
|
+
"Could not get current token balance for topup calculation:",
|
|
2942
|
+
e
|
|
2943
|
+
);
|
|
2944
|
+
}
|
|
2861
2945
|
const topupResult = await this.balanceManager.topUp({
|
|
2862
2946
|
mintUrl,
|
|
2863
2947
|
baseUrl,
|
|
2864
|
-
amount:
|
|
2948
|
+
amount: topupAmount * TOPUP_MARGIN,
|
|
2865
2949
|
token: params.token
|
|
2866
2950
|
});
|
|
2867
2951
|
this._log(
|
|
@@ -2893,12 +2977,26 @@ var RoutstrClient = class {
|
|
|
2893
2977
|
`[RoutstrClient] _handleErrorResponse: Topup successful, will retry with new token`
|
|
2894
2978
|
);
|
|
2895
2979
|
}
|
|
2896
|
-
if (!tryNextProvider)
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2980
|
+
if (!tryNextProvider) {
|
|
2981
|
+
if (retryCount < MAX_RETRIES_PER_PROVIDER) {
|
|
2982
|
+
this._log(
|
|
2983
|
+
"DEBUG",
|
|
2984
|
+
`[RoutstrClient] _handleErrorResponse: Retrying 402 (attempt ${retryCount + 1}/${MAX_RETRIES_PER_PROVIDER})`
|
|
2985
|
+
);
|
|
2986
|
+
return this._makeRequest({
|
|
2987
|
+
...params,
|
|
2988
|
+
token: params.token,
|
|
2989
|
+
headers: this._withAuthHeader(params.baseHeaders, params.token),
|
|
2990
|
+
retryCount: retryCount + 1
|
|
2991
|
+
});
|
|
2992
|
+
} else {
|
|
2993
|
+
this._log(
|
|
2994
|
+
"DEBUG",
|
|
2995
|
+
`[RoutstrClient] _handleErrorResponse: 402 retry limit reached (${retryCount}/${MAX_RETRIES_PER_PROVIDER}), failing over to next provider`
|
|
2996
|
+
);
|
|
2997
|
+
tryNextProvider = true;
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
2902
3000
|
}
|
|
2903
3001
|
const isInsufficientBalance413 = status === 413 && responseBody?.includes("Insufficient balance");
|
|
2904
3002
|
if (isInsufficientBalance413 && !tryNextProvider && this.mode === "apikeys") {
|
|
@@ -2908,19 +3006,31 @@ var RoutstrClient = class {
|
|
|
2908
3006
|
params.token,
|
|
2909
3007
|
baseUrl
|
|
2910
3008
|
);
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
3009
|
+
if (latestBalanceInfo.isInvalidApiKey) {
|
|
3010
|
+
this._log(
|
|
3011
|
+
"DEBUG",
|
|
3012
|
+
`[RoutstrClient] _handleErrorResponse: Invalid API key (proofs already spent), removing for ${baseUrl}`
|
|
3013
|
+
);
|
|
3014
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
3015
|
+
tryNextProvider = true;
|
|
3016
|
+
} else {
|
|
3017
|
+
const latestTokenBalance = latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
|
|
3018
|
+
if (latestBalanceInfo.apiKey) {
|
|
3019
|
+
const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
3020
|
+
if (storedApiKeyEntry?.key !== latestBalanceInfo.apiKey) {
|
|
3021
|
+
if (storedApiKeyEntry) {
|
|
3022
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
3023
|
+
}
|
|
3024
|
+
this.storageAdapter.setApiKey(baseUrl, latestBalanceInfo.apiKey);
|
|
2917
3025
|
}
|
|
2918
|
-
|
|
3026
|
+
retryToken = latestBalanceInfo.apiKey;
|
|
3027
|
+
}
|
|
3028
|
+
if (latestTokenBalance >= 0) {
|
|
3029
|
+
this.storageAdapter.updateApiKeyBalance(
|
|
3030
|
+
baseUrl,
|
|
3031
|
+
latestTokenBalance
|
|
3032
|
+
);
|
|
2919
3033
|
}
|
|
2920
|
-
retryToken = latestBalanceInfo.apiKey;
|
|
2921
|
-
}
|
|
2922
|
-
if (latestTokenBalance >= 0) {
|
|
2923
|
-
this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
|
|
2924
3034
|
}
|
|
2925
3035
|
} catch (error) {
|
|
2926
3036
|
this._log(
|
|
@@ -2929,11 +3039,24 @@ var RoutstrClient = class {
|
|
|
2929
3039
|
error
|
|
2930
3040
|
);
|
|
2931
3041
|
}
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
3042
|
+
if (retryCount < MAX_RETRIES_PER_PROVIDER) {
|
|
3043
|
+
this._log(
|
|
3044
|
+
"DEBUG",
|
|
3045
|
+
`[RoutstrClient] _handleErrorResponse: Retrying 413 (attempt ${retryCount + 1}/${MAX_RETRIES_PER_PROVIDER})`
|
|
3046
|
+
);
|
|
3047
|
+
return this._makeRequest({
|
|
3048
|
+
...params,
|
|
3049
|
+
token: retryToken,
|
|
3050
|
+
headers: this._withAuthHeader(params.baseHeaders, retryToken),
|
|
3051
|
+
retryCount: retryCount + 1
|
|
3052
|
+
});
|
|
3053
|
+
} else {
|
|
3054
|
+
this._log(
|
|
3055
|
+
"DEBUG",
|
|
3056
|
+
`[RoutstrClient] _handleErrorResponse: 413 retry limit reached (${retryCount}/${MAX_RETRIES_PER_PROVIDER}), failing over to next provider`
|
|
3057
|
+
);
|
|
3058
|
+
tryNextProvider = true;
|
|
3059
|
+
}
|
|
2937
3060
|
}
|
|
2938
3061
|
if ((status === 401 || status === 403 || status === 413 || status === 400 || status === 500 || status === 502 || status === 503 || status === 504 || status === 521) && !tryNextProvider) {
|
|
2939
3062
|
this._log(
|
|
@@ -3049,7 +3172,8 @@ var RoutstrClient = class {
|
|
|
3049
3172
|
selectedModel: newModel,
|
|
3050
3173
|
token: spendResult.token,
|
|
3051
3174
|
requiredSats: newRequiredSats,
|
|
3052
|
-
headers: this._withAuthHeader(params.baseHeaders, spendResult.token)
|
|
3175
|
+
headers: this._withAuthHeader(params.baseHeaders, spendResult.token),
|
|
3176
|
+
retryCount: 0
|
|
3053
3177
|
});
|
|
3054
3178
|
}
|
|
3055
3179
|
throw new FailoverError(baseUrl, Array.from(this.providerManager));
|
|
@@ -3679,12 +3803,13 @@ var SDK_STORAGE_KEYS = {
|
|
|
3679
3803
|
CHILD_KEYS: "child_keys",
|
|
3680
3804
|
ROUTSTR21_MODELS: "routstr21Models",
|
|
3681
3805
|
LAST_ROUTSTR21_MODELS_UPDATE: "lastRoutstr21ModelsUpdate",
|
|
3682
|
-
CACHED_RECEIVE_TOKENS: "cached_receive_tokens"
|
|
3806
|
+
CACHED_RECEIVE_TOKENS: "cached_receive_tokens",
|
|
3807
|
+
USAGE_TRACKING: "usage_tracking"
|
|
3683
3808
|
};
|
|
3684
3809
|
|
|
3685
3810
|
// storage/store.ts
|
|
3686
3811
|
var normalizeBaseUrl = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
3687
|
-
var
|
|
3812
|
+
var getCashuTokenBalance = (token) => {
|
|
3688
3813
|
try {
|
|
3689
3814
|
const decoded = getDecodedToken(token);
|
|
3690
3815
|
const unitDivisor = decoded.unit === "msat" ? 1e3 : 1;
|
|
@@ -3714,7 +3839,8 @@ var createSdkStore = async ({
|
|
|
3714
3839
|
rawChildKeys,
|
|
3715
3840
|
rawRoutstr21Models,
|
|
3716
3841
|
rawLastRoutstr21ModelsUpdate,
|
|
3717
|
-
rawCachedReceiveTokens
|
|
3842
|
+
rawCachedReceiveTokens,
|
|
3843
|
+
rawUsageTracking
|
|
3718
3844
|
] = await Promise.all([
|
|
3719
3845
|
driver.getItem(
|
|
3720
3846
|
SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
|
|
@@ -3744,7 +3870,8 @@ var createSdkStore = async ({
|
|
|
3744
3870
|
SDK_STORAGE_KEYS.LAST_ROUTSTR21_MODELS_UPDATE,
|
|
3745
3871
|
null
|
|
3746
3872
|
),
|
|
3747
|
-
driver.getItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, [])
|
|
3873
|
+
driver.getItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, []),
|
|
3874
|
+
driver.getItem(SDK_STORAGE_KEYS.USAGE_TRACKING, [])
|
|
3748
3875
|
]);
|
|
3749
3876
|
const modelsFromAllProviders = Object.fromEntries(
|
|
3750
3877
|
Object.entries(rawModels).map(([baseUrl, models]) => [
|
|
@@ -3777,7 +3904,7 @@ var createSdkStore = async ({
|
|
|
3777
3904
|
const cachedTokens = rawCachedTokens.map((entry) => ({
|
|
3778
3905
|
...entry,
|
|
3779
3906
|
baseUrl: normalizeBaseUrl(entry.baseUrl),
|
|
3780
|
-
balance: typeof entry.balance === "number" ? entry.balance :
|
|
3907
|
+
balance: typeof entry.balance === "number" ? entry.balance : getCashuTokenBalance(entry.token),
|
|
3781
3908
|
lastUsed: entry.lastUsed ?? null
|
|
3782
3909
|
}));
|
|
3783
3910
|
const apiKeys = rawApiKeys.map((entry) => ({
|
|
@@ -3802,6 +3929,7 @@ var createSdkStore = async ({
|
|
|
3802
3929
|
unit: entry.unit || "sat",
|
|
3803
3930
|
createdAt: entry.createdAt ?? Date.now()
|
|
3804
3931
|
}));
|
|
3932
|
+
const usageTracking = rawUsageTracking;
|
|
3805
3933
|
return createStore((set, get) => ({
|
|
3806
3934
|
modelsFromAllProviders,
|
|
3807
3935
|
lastUsedModel,
|
|
@@ -3817,6 +3945,7 @@ var createSdkStore = async ({
|
|
|
3817
3945
|
routstr21Models,
|
|
3818
3946
|
lastRoutstr21ModelsUpdate,
|
|
3819
3947
|
cachedReceiveTokens,
|
|
3948
|
+
usageTracking,
|
|
3820
3949
|
setModelsFromAllProviders: (value) => {
|
|
3821
3950
|
const normalized = {};
|
|
3822
3951
|
for (const [baseUrl, models] of Object.entries(value)) {
|
|
@@ -3881,7 +4010,7 @@ var createSdkStore = async ({
|
|
|
3881
4010
|
const normalized = updates.map((entry) => ({
|
|
3882
4011
|
...entry,
|
|
3883
4012
|
baseUrl: normalizeBaseUrl(entry.baseUrl),
|
|
3884
|
-
balance: typeof entry.balance === "number" ? entry.balance :
|
|
4013
|
+
balance: typeof entry.balance === "number" ? entry.balance : getCashuTokenBalance(entry.token),
|
|
3885
4014
|
lastUsed: entry.lastUsed ?? null
|
|
3886
4015
|
}));
|
|
3887
4016
|
void driver.setItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, normalized);
|
|
@@ -3933,6 +4062,10 @@ var createSdkStore = async ({
|
|
|
3933
4062
|
}));
|
|
3934
4063
|
void driver.setItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, normalized);
|
|
3935
4064
|
set({ cachedReceiveTokens: normalized });
|
|
4065
|
+
},
|
|
4066
|
+
setUsageTracking: (value) => {
|
|
4067
|
+
void driver.setItem(SDK_STORAGE_KEYS.USAGE_TRACKING, value);
|
|
4068
|
+
set({ usageTracking: value });
|
|
3936
4069
|
}
|
|
3937
4070
|
}));
|
|
3938
4071
|
};
|
|
@@ -3980,7 +4113,7 @@ var createStorageAdapterFromStore = (store) => ({
|
|
|
3980
4113
|
setToken: (baseUrl, token) => {
|
|
3981
4114
|
const normalized = normalizeBaseUrl(baseUrl);
|
|
3982
4115
|
const tokens = store.getState().cachedTokens;
|
|
3983
|
-
const balance =
|
|
4116
|
+
const balance = getCashuTokenBalance(token);
|
|
3984
4117
|
const existingIndex = tokens.findIndex(
|
|
3985
4118
|
(entry) => entry.baseUrl === normalized
|
|
3986
4119
|
);
|