@routstr/sdk 0.2.2 → 0.2.3
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.d.mts +43 -4
- package/dist/client/index.d.ts +43 -4
- package/dist/client/index.js +127 -16
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +127 -16
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.js +127 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +127 -16
- package/dist/index.mjs.map +1 -1
- package/dist/wallet/index.js +32 -4
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +32 -4
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/client/index.mjs
CHANGED
|
@@ -79,7 +79,7 @@ var auditLogger = AuditLogger.getInstance();
|
|
|
79
79
|
|
|
80
80
|
// wallet/tokenUtils.ts
|
|
81
81
|
function isNetworkErrorMessage(message) {
|
|
82
|
-
return message.includes("NetworkError when attempting to fetch resource") || message.includes("Failed to fetch") || message.includes("Load failed");
|
|
82
|
+
return message.includes("NetworkError when attempting to fetch resource") || message.includes("Failed to fetch") || message.includes("Load failed") || message.includes("ERR_TLS_CERT_ALTNAME_INVALID") || message.includes("ERR_TLS_CERT_NOT_YET_VALID") || message.includes("ERR_TLS_CERT_EXPIRED") || message.includes("UNABLE_TO_VERIFY_LEAF_SIGNATURE") || message.includes("SELF_SIGNED_CERT_IN_CHAIN");
|
|
83
83
|
}
|
|
84
84
|
function getBalanceInSats(balance, unit) {
|
|
85
85
|
return unit === "msat" ? balance / 1e3 : balance;
|
|
@@ -369,7 +369,26 @@ var CashuSpender = class {
|
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
if (token && baseUrl) {
|
|
372
|
-
|
|
372
|
+
try {
|
|
373
|
+
this.storageAdapter.setToken(baseUrl, token);
|
|
374
|
+
} catch (error) {
|
|
375
|
+
if (error instanceof Error && error.message.includes("Token already exists")) {
|
|
376
|
+
this._log(
|
|
377
|
+
"DEBUG",
|
|
378
|
+
`[CashuSpender] _spendInternal: Token already exists for ${baseUrl}, receiving newly created token and using existing`
|
|
379
|
+
);
|
|
380
|
+
const receiveResult = await this.receiveToken(token);
|
|
381
|
+
if (receiveResult.success) {
|
|
382
|
+
this._log(
|
|
383
|
+
"DEBUG",
|
|
384
|
+
`[CashuSpender] _spendInternal: Token restored successfully, amount=${receiveResult.amount}`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
token = this.storageAdapter.getToken(baseUrl);
|
|
388
|
+
} else {
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
373
392
|
}
|
|
374
393
|
this._logTransaction("spend", {
|
|
375
394
|
amount: spentAmount,
|
|
@@ -847,7 +866,9 @@ var BalanceManager = class {
|
|
|
847
866
|
p2pkPubkey
|
|
848
867
|
} = options;
|
|
849
868
|
const adjustedAmount = Math.ceil(amount);
|
|
869
|
+
console.log(`[BalanceManager.createProviderToken] Starting: baseUrl=${baseUrl}, mintUrl=${mintUrl}, amount=${amount}, adjustedAmount=${adjustedAmount}, retryCount=${retryCount}`);
|
|
850
870
|
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
871
|
+
console.error(`[BalanceManager.createProviderToken] FAILURE: Invalid amount - amount=${amount}, adjustedAmount=${adjustedAmount}`);
|
|
851
872
|
return { success: false, error: "Invalid top up amount" };
|
|
852
873
|
}
|
|
853
874
|
const balanceState = await this.getBalanceState();
|
|
@@ -878,6 +899,7 @@ var BalanceManager = class {
|
|
|
878
899
|
{ url: "", balance: 0 }
|
|
879
900
|
).url
|
|
880
901
|
);
|
|
902
|
+
console.error(`[BalanceManager.createProviderToken] FAILURE: Insufficient balance - required=${adjustedAmount}, available=${totalMintBalance + targetProviderBalance}, totalMintBalance=${totalMintBalance}, targetProviderBalance=${targetProviderBalance}, refundableProviderBalance=${refundableProviderBalance}`);
|
|
881
903
|
return { success: false, error: error.message };
|
|
882
904
|
}
|
|
883
905
|
if (targetProviderBalance >= adjustedAmount) {
|
|
@@ -919,6 +941,7 @@ var BalanceManager = class {
|
|
|
919
941
|
maxMintUrl = mintUrl2;
|
|
920
942
|
}
|
|
921
943
|
}
|
|
944
|
+
console.error(`[BalanceManager.createProviderToken] FAILURE: No candidate mints found - requiredAmount=${requiredAmount}, totalMintBalance=${totalMintBalance}, maxBalance=${maxBalance}, maxMintUrl=${maxMintUrl}, providerMints=${JSON.stringify(providerMints)}`);
|
|
922
945
|
const error = new InsufficientBalanceError(
|
|
923
946
|
adjustedAmount,
|
|
924
947
|
totalMintBalance,
|
|
@@ -930,11 +953,13 @@ var BalanceManager = class {
|
|
|
930
953
|
let lastError;
|
|
931
954
|
for (const candidateMint of candidates) {
|
|
932
955
|
try {
|
|
956
|
+
console.log(`[BalanceManager.createProviderToken] Attempting mint: ${candidateMint}, amount: ${requiredAmount}`);
|
|
933
957
|
const token = await this.walletAdapter.sendToken(
|
|
934
958
|
candidateMint,
|
|
935
959
|
requiredAmount,
|
|
936
960
|
p2pkPubkey
|
|
937
961
|
);
|
|
962
|
+
console.log(`[BalanceManager.createProviderToken] SUCCESS: Token created from mint ${candidateMint}`);
|
|
938
963
|
return {
|
|
939
964
|
success: true,
|
|
940
965
|
token,
|
|
@@ -942,9 +967,12 @@ var BalanceManager = class {
|
|
|
942
967
|
amountSpent: requiredAmount
|
|
943
968
|
};
|
|
944
969
|
} catch (error) {
|
|
970
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
971
|
+
console.error(`[BalanceManager.createProviderToken] FAILURE: Mint ${candidateMint} failed with error: ${errorMsg}`);
|
|
945
972
|
if (error instanceof Error) {
|
|
946
|
-
lastError =
|
|
973
|
+
lastError = errorMsg;
|
|
947
974
|
if (isNetworkErrorMessage(error.message)) {
|
|
975
|
+
console.warn(`[BalanceManager.createProviderToken] Network error from ${candidateMint}, trying next mint...`);
|
|
948
976
|
continue;
|
|
949
977
|
}
|
|
950
978
|
}
|
|
@@ -954,6 +982,7 @@ var BalanceManager = class {
|
|
|
954
982
|
};
|
|
955
983
|
}
|
|
956
984
|
}
|
|
985
|
+
console.error(`[BalanceManager.createProviderToken] FAILURE: All candidate mints exhausted - lastError=${lastError}, candidates=${JSON.stringify(candidates)}`);
|
|
957
986
|
return {
|
|
958
987
|
success: false,
|
|
959
988
|
error: lastError || "All candidate mints failed while creating top up token"
|
|
@@ -1239,7 +1268,6 @@ var BalanceManager = class {
|
|
|
1239
1268
|
});
|
|
1240
1269
|
if (response.ok) {
|
|
1241
1270
|
const data = await response.json();
|
|
1242
|
-
console.log("TOKENA FASJDFAS", data);
|
|
1243
1271
|
return {
|
|
1244
1272
|
amount: data.balance,
|
|
1245
1273
|
reserved: data.reserved ?? 0,
|
|
@@ -1612,22 +1640,101 @@ function calculateImageTokens(width, height, detail = "auto") {
|
|
|
1612
1640
|
function isInsecureHttpUrl(url) {
|
|
1613
1641
|
return url.startsWith("http://");
|
|
1614
1642
|
}
|
|
1615
|
-
var ProviderManager = class {
|
|
1643
|
+
var ProviderManager = class _ProviderManager {
|
|
1616
1644
|
constructor(providerRegistry) {
|
|
1617
1645
|
this.providerRegistry = providerRegistry;
|
|
1618
1646
|
}
|
|
1619
1647
|
failedProviders = /* @__PURE__ */ new Set();
|
|
1648
|
+
/** Track when each provider last failed (provider URL -> timestamp) */
|
|
1649
|
+
lastFailed = /* @__PURE__ */ new Map();
|
|
1650
|
+
/** Providers on cooldown: [provider_url, cooldown_started_timestamp][] */
|
|
1651
|
+
providersOnCoolDown = [];
|
|
1652
|
+
/** Cooldown duration in milliseconds (5 minutes) */
|
|
1653
|
+
static COOLDOWN_DURATION_MS = 5 * 60 * 1e3;
|
|
1654
|
+
/**
|
|
1655
|
+
* Clean up expired cooldown entries
|
|
1656
|
+
*/
|
|
1657
|
+
cleanupExpiredCooldowns() {
|
|
1658
|
+
const now = Date.now();
|
|
1659
|
+
this.providersOnCoolDown = this.providersOnCoolDown.filter(
|
|
1660
|
+
([, timestamp]) => now - timestamp < _ProviderManager.COOLDOWN_DURATION_MS
|
|
1661
|
+
);
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* Get the cooldown duration in milliseconds
|
|
1665
|
+
*/
|
|
1666
|
+
getCooldownDurationMs() {
|
|
1667
|
+
return _ProviderManager.COOLDOWN_DURATION_MS;
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* Check if a provider is currently on cooldown
|
|
1671
|
+
*/
|
|
1672
|
+
isOnCooldown(baseUrl) {
|
|
1673
|
+
this.cleanupExpiredCooldowns();
|
|
1674
|
+
return this.providersOnCoolDown.some(([url]) => url === baseUrl);
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* Get all providers currently on cooldown
|
|
1678
|
+
*/
|
|
1679
|
+
getProvidersOnCooldown() {
|
|
1680
|
+
this.cleanupExpiredCooldowns();
|
|
1681
|
+
return [...this.providersOnCoolDown];
|
|
1682
|
+
}
|
|
1620
1683
|
/**
|
|
1621
1684
|
* Reset the failed providers list
|
|
1622
1685
|
*/
|
|
1623
1686
|
resetFailedProviders() {
|
|
1624
1687
|
this.failedProviders.clear();
|
|
1625
1688
|
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Get the last failed timestamp for a provider
|
|
1691
|
+
*/
|
|
1692
|
+
getLastFailed(baseUrl) {
|
|
1693
|
+
return this.lastFailed.get(baseUrl);
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Get all providers with their last failed timestamps
|
|
1697
|
+
*/
|
|
1698
|
+
getAllLastFailed() {
|
|
1699
|
+
return new Map(this.lastFailed);
|
|
1700
|
+
}
|
|
1626
1701
|
/**
|
|
1627
1702
|
* Mark a provider as failed
|
|
1703
|
+
* If a provider fails twice within 5 minutes, it's added to cooldown
|
|
1628
1704
|
*/
|
|
1629
1705
|
markFailed(baseUrl) {
|
|
1706
|
+
const now = Date.now();
|
|
1707
|
+
const lastFailure = this.lastFailed.get(baseUrl);
|
|
1708
|
+
this.lastFailed.set(baseUrl, now);
|
|
1630
1709
|
this.failedProviders.add(baseUrl);
|
|
1710
|
+
if (lastFailure !== void 0 && now - lastFailure < _ProviderManager.COOLDOWN_DURATION_MS) {
|
|
1711
|
+
if (!this.isOnCooldown(baseUrl)) {
|
|
1712
|
+
this.providersOnCoolDown.push([baseUrl, now]);
|
|
1713
|
+
console.log(
|
|
1714
|
+
`Provider ${baseUrl} added to cooldown after second failure within 5 minutes`
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Remove a provider from cooldown (e.g., after successful request)
|
|
1721
|
+
*/
|
|
1722
|
+
removeFromCooldown(baseUrl) {
|
|
1723
|
+
this.providersOnCoolDown = this.providersOnCoolDown.filter(
|
|
1724
|
+
([url]) => url !== baseUrl
|
|
1725
|
+
);
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Clear all cooldown tracking
|
|
1729
|
+
*/
|
|
1730
|
+
clearCooldowns() {
|
|
1731
|
+
this.providersOnCoolDown = [];
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Clear all failure tracking (lastFailed timestamps)
|
|
1735
|
+
*/
|
|
1736
|
+
clearFailureHistory() {
|
|
1737
|
+
this.lastFailed.clear();
|
|
1631
1738
|
}
|
|
1632
1739
|
/**
|
|
1633
1740
|
* Check if a provider has failed
|
|
@@ -1656,7 +1763,7 @@ var ProviderManager = class {
|
|
|
1656
1763
|
const allProviders = this.providerRegistry.getAllProvidersModels();
|
|
1657
1764
|
const candidates = [];
|
|
1658
1765
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
1659
|
-
if (baseUrl === currentBaseUrl || this.failedProviders.has(baseUrl) || disabledProviders.has(baseUrl)) {
|
|
1766
|
+
if (baseUrl === currentBaseUrl || this.failedProviders.has(baseUrl) || disabledProviders.has(baseUrl) || this.isOnCooldown(baseUrl)) {
|
|
1660
1767
|
continue;
|
|
1661
1768
|
}
|
|
1662
1769
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
|
|
@@ -1703,6 +1810,7 @@ var ProviderManager = class {
|
|
|
1703
1810
|
const torMode = isTorContext();
|
|
1704
1811
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
1705
1812
|
if (disabledProviders.has(baseUrl)) continue;
|
|
1813
|
+
if (this.isOnCooldown(baseUrl)) continue;
|
|
1706
1814
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl)))
|
|
1707
1815
|
continue;
|
|
1708
1816
|
const model = models.find((m) => m.id === modelId);
|
|
@@ -1726,6 +1834,7 @@ var ProviderManager = class {
|
|
|
1726
1834
|
const results = [];
|
|
1727
1835
|
for (const [baseUrl, models] of Object.entries(allModels)) {
|
|
1728
1836
|
if (!includeDisabled && disabledProviders.has(baseUrl)) continue;
|
|
1837
|
+
if (this.isOnCooldown(baseUrl)) continue;
|
|
1729
1838
|
if (torMode && !baseUrl.includes(".onion")) continue;
|
|
1730
1839
|
if (!torMode && (baseUrl.includes(".onion") || isInsecureHttpUrl(baseUrl)))
|
|
1731
1840
|
continue;
|
|
@@ -2139,7 +2248,6 @@ var RoutstrClient = class {
|
|
|
2139
2248
|
body: body === void 0 || method === "GET" ? void 0 : JSON.stringify(body)
|
|
2140
2249
|
});
|
|
2141
2250
|
if (this.mode === "xcashu") this._log("DEBUG", "response,", response);
|
|
2142
|
-
this._log("DEBUG", "response,", response);
|
|
2143
2251
|
response.baseUrl = baseUrl;
|
|
2144
2252
|
response.token = token;
|
|
2145
2253
|
if (!response.ok) {
|
|
@@ -2162,7 +2270,7 @@ var RoutstrClient = class {
|
|
|
2162
2270
|
}
|
|
2163
2271
|
return response;
|
|
2164
2272
|
} catch (error) {
|
|
2165
|
-
if (
|
|
2273
|
+
if (isNetworkErrorMessage(error?.message || "")) {
|
|
2166
2274
|
return await this._handleErrorResponse(
|
|
2167
2275
|
params,
|
|
2168
2276
|
token,
|
|
@@ -2297,7 +2405,13 @@ var RoutstrClient = class {
|
|
|
2297
2405
|
"DEBUG",
|
|
2298
2406
|
`[RoutstrClient] _handleErrorResponse: Insufficient balance, need=${required}, have=${available}`
|
|
2299
2407
|
);
|
|
2300
|
-
throw new InsufficientBalanceError(
|
|
2408
|
+
throw new InsufficientBalanceError(
|
|
2409
|
+
required,
|
|
2410
|
+
available,
|
|
2411
|
+
0,
|
|
2412
|
+
"",
|
|
2413
|
+
message
|
|
2414
|
+
);
|
|
2301
2415
|
} else {
|
|
2302
2416
|
this._log(
|
|
2303
2417
|
"DEBUG",
|
|
@@ -2510,7 +2624,10 @@ var RoutstrClient = class {
|
|
|
2510
2624
|
retryCount: 0
|
|
2511
2625
|
});
|
|
2512
2626
|
}
|
|
2513
|
-
throw new FailoverError(
|
|
2627
|
+
throw new FailoverError(
|
|
2628
|
+
baseUrl,
|
|
2629
|
+
Array.from(this.providerManager.getFailedProviders())
|
|
2630
|
+
);
|
|
2514
2631
|
}
|
|
2515
2632
|
/**
|
|
2516
2633
|
* Handle post-response balance update for all modes
|
|
@@ -2660,12 +2777,6 @@ var RoutstrClient = class {
|
|
|
2660
2777
|
const distribution = this.storageAdapter.getCachedTokenDistribution();
|
|
2661
2778
|
return distribution.reduce((total, item) => total + item.amount, 0);
|
|
2662
2779
|
}
|
|
2663
|
-
/**
|
|
2664
|
-
* Check if error message indicates a network error
|
|
2665
|
-
*/
|
|
2666
|
-
_isNetworkError(message) {
|
|
2667
|
-
return message.includes("NetworkError when attempting to fetch resource") || message.includes("Failed to fetch") || message.includes("Load failed");
|
|
2668
|
-
}
|
|
2669
2780
|
/**
|
|
2670
2781
|
* Handle errors and notify callbacks
|
|
2671
2782
|
*/
|