@routstr/sdk 0.2.6 → 0.2.7
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 +16 -2
- package/dist/client/index.d.ts +16 -2
- package/dist/client/index.js +276 -37
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +276 -37
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.js +1 -1
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +1 -1
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +281 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +281 -41
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +5 -2
- package/dist/storage/index.d.ts +5 -2
- package/dist/storage/index.js +95 -4
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +95 -4
- package/dist/storage/index.mjs.map +1 -1
- package/dist/{store-C5lnyX8k.d.mts → store-DGeLPv9E.d.mts} +21 -0
- package/dist/{store-BJlwiDX5.d.ts → store-h7m23ffq.d.ts} +21 -0
- package/dist/wallet/index.d.mts +10 -4
- package/dist/wallet/index.d.ts +10 -4
- package/dist/wallet/index.js +45 -24
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +45 -24
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/client/index.mjs
CHANGED
|
@@ -447,8 +447,9 @@ var CashuSpender = class {
|
|
|
447
447
|
return null;
|
|
448
448
|
}
|
|
449
449
|
/**
|
|
450
|
-
* Refund all xcashu tokens from storage
|
|
451
|
-
*
|
|
450
|
+
* Refund all xcashu tokens from storage by calling the provider's refund endpoint.
|
|
451
|
+
* The xcashu token acts as an API key to claim the refund, and the response contains
|
|
452
|
+
* the actual refunded Cashu token which is then received into the wallet.
|
|
452
453
|
* @param mintUrl - The mint URL for receiving tokens
|
|
453
454
|
* @param excludeBaseUrls - Base URLs to exclude from refund (optional)
|
|
454
455
|
* @returns Results for each xcashu token refund attempt
|
|
@@ -461,7 +462,20 @@ var CashuSpender = class {
|
|
|
461
462
|
if (excludedUrls.has(baseUrl)) continue;
|
|
462
463
|
for (const xcashuToken of tokens) {
|
|
463
464
|
try {
|
|
464
|
-
|
|
465
|
+
if (!this.balanceManager) {
|
|
466
|
+
throw new Error("BalanceManager not available for xcashu refund");
|
|
467
|
+
}
|
|
468
|
+
const fetchResult = await this.balanceManager.fetchRefundToken(
|
|
469
|
+
baseUrl,
|
|
470
|
+
xcashuToken.token,
|
|
471
|
+
true
|
|
472
|
+
);
|
|
473
|
+
if (!fetchResult.success || !fetchResult.token) {
|
|
474
|
+
throw new Error(
|
|
475
|
+
fetchResult.error || "Failed to fetch refund token from provider"
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
const receiveResult = await this.receiveToken(fetchResult.token);
|
|
465
479
|
if (receiveResult.success) {
|
|
466
480
|
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
467
481
|
results.push({
|
|
@@ -476,7 +490,10 @@ var CashuSpender = class {
|
|
|
476
490
|
} else {
|
|
477
491
|
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
478
492
|
const newTryCount = currentTryCount + 1;
|
|
479
|
-
this.storageAdapter.updateXcashuTokenTryCount(
|
|
493
|
+
this.storageAdapter.updateXcashuTokenTryCount(
|
|
494
|
+
xcashuToken.token,
|
|
495
|
+
newTryCount
|
|
496
|
+
);
|
|
480
497
|
results.push({
|
|
481
498
|
baseUrl,
|
|
482
499
|
token: xcashuToken.token,
|
|
@@ -485,13 +502,16 @@ var CashuSpender = class {
|
|
|
485
502
|
});
|
|
486
503
|
this._log(
|
|
487
504
|
"DEBUG",
|
|
488
|
-
`[CashuSpender] refundXcashuTokens: Failed to refund
|
|
505
|
+
`[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}`
|
|
489
506
|
);
|
|
490
507
|
}
|
|
491
508
|
} catch (error) {
|
|
492
509
|
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
493
510
|
const newTryCount = currentTryCount + 1;
|
|
494
|
-
this.storageAdapter.updateXcashuTokenTryCount(
|
|
511
|
+
this.storageAdapter.updateXcashuTokenTryCount(
|
|
512
|
+
xcashuToken.token,
|
|
513
|
+
newTryCount
|
|
514
|
+
);
|
|
495
515
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
496
516
|
results.push({
|
|
497
517
|
baseUrl,
|
|
@@ -528,7 +548,10 @@ var CashuSpender = class {
|
|
|
528
548
|
if (refundResult.success) {
|
|
529
549
|
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
530
550
|
} else {
|
|
531
|
-
this.storageAdapter.updateApiKeyBalance(
|
|
551
|
+
this.storageAdapter.updateApiKeyBalance(
|
|
552
|
+
apiKeyEntry.baseUrl,
|
|
553
|
+
apiKeyEntry.amount
|
|
554
|
+
);
|
|
532
555
|
}
|
|
533
556
|
results.push({
|
|
534
557
|
baseUrl: apiKeyEntry.baseUrl,
|
|
@@ -666,7 +689,7 @@ var BalanceManager = class {
|
|
|
666
689
|
}
|
|
667
690
|
let fetchResult;
|
|
668
691
|
try {
|
|
669
|
-
fetchResult = await this.
|
|
692
|
+
fetchResult = await this.fetchRefundToken(baseUrl, apiKey);
|
|
670
693
|
if (!fetchResult.success) {
|
|
671
694
|
return {
|
|
672
695
|
success: false,
|
|
@@ -702,9 +725,9 @@ var BalanceManager = class {
|
|
|
702
725
|
}
|
|
703
726
|
}
|
|
704
727
|
/**
|
|
705
|
-
* Fetch refund token from provider API using API key authentication
|
|
728
|
+
* Fetch refund token from provider API using API key (or xcashu token) authentication
|
|
706
729
|
*/
|
|
707
|
-
async
|
|
730
|
+
async fetchRefundToken(baseUrl, apiKeyOrToken, xCashu = false) {
|
|
708
731
|
if (!baseUrl) {
|
|
709
732
|
return {
|
|
710
733
|
success: false,
|
|
@@ -718,12 +741,17 @@ var BalanceManager = class {
|
|
|
718
741
|
controller.abort();
|
|
719
742
|
}, 6e4);
|
|
720
743
|
try {
|
|
744
|
+
const headers = {
|
|
745
|
+
"Content-Type": "application/json"
|
|
746
|
+
};
|
|
747
|
+
if (xCashu) {
|
|
748
|
+
headers["X-Cashu"] = apiKeyOrToken;
|
|
749
|
+
} else {
|
|
750
|
+
headers["Authorization"] = `Bearer ${apiKeyOrToken}`;
|
|
751
|
+
}
|
|
721
752
|
const response = await fetch(url, {
|
|
722
753
|
method: "POST",
|
|
723
|
-
headers
|
|
724
|
-
Authorization: `Bearer ${apiKey}`,
|
|
725
|
-
"Content-Type": "application/json"
|
|
726
|
-
},
|
|
754
|
+
headers,
|
|
727
755
|
signal: controller.signal
|
|
728
756
|
});
|
|
729
757
|
clearTimeout(timeoutId);
|
|
@@ -744,10 +772,7 @@ var BalanceManager = class {
|
|
|
744
772
|
};
|
|
745
773
|
} catch (error) {
|
|
746
774
|
clearTimeout(timeoutId);
|
|
747
|
-
console.error(
|
|
748
|
-
"[BalanceManager._fetchRefundTokenWithApiKey] Fetch error",
|
|
749
|
-
error
|
|
750
|
-
);
|
|
775
|
+
console.error("[BalanceManager.fetchRefundToken] Fetch error", error);
|
|
751
776
|
if (error instanceof Error) {
|
|
752
777
|
if (error.name === "AbortError") {
|
|
753
778
|
return {
|
|
@@ -794,11 +819,7 @@ var BalanceManager = class {
|
|
|
794
819
|
};
|
|
795
820
|
}
|
|
796
821
|
cashuToken = tokenResult.token;
|
|
797
|
-
const topUpResult = await this._postTopUp(
|
|
798
|
-
baseUrl,
|
|
799
|
-
apiKey,
|
|
800
|
-
cashuToken
|
|
801
|
-
);
|
|
822
|
+
const topUpResult = await this._postTopUp(baseUrl, apiKey, cashuToken);
|
|
802
823
|
requestId = topUpResult.requestId;
|
|
803
824
|
console.log(topUpResult);
|
|
804
825
|
if (!topUpResult.success) {
|
|
@@ -1164,7 +1185,7 @@ var BalanceManager = class {
|
|
|
1164
1185
|
console.log(response.status);
|
|
1165
1186
|
const data = await response.json();
|
|
1166
1187
|
console.log("FAILED ", data);
|
|
1167
|
-
const isInvalidApiKey = response.status === 401 && data?.code === "invalid_api_key" && data?.message?.includes("proofs already spent");
|
|
1188
|
+
const isInvalidApiKey = response.status === 401 && data?.detail?.error?.code === "invalid_api_key" && data?.detail?.error?.message?.includes("proofs already spent");
|
|
1168
1189
|
return {
|
|
1169
1190
|
amount: -1,
|
|
1170
1191
|
reserved: data.reserved ?? 0,
|
|
@@ -1606,8 +1627,13 @@ function isInsecureHttpUrl(url) {
|
|
|
1606
1627
|
return url.startsWith("http://");
|
|
1607
1628
|
}
|
|
1608
1629
|
var ProviderManager = class _ProviderManager {
|
|
1609
|
-
constructor(providerRegistry) {
|
|
1630
|
+
constructor(providerRegistry, store) {
|
|
1610
1631
|
this.providerRegistry = providerRegistry;
|
|
1632
|
+
this.instanceId = `pm_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
1633
|
+
if (store) {
|
|
1634
|
+
this.store = store;
|
|
1635
|
+
this.hydrateFromStore();
|
|
1636
|
+
}
|
|
1611
1637
|
}
|
|
1612
1638
|
failedProviders = /* @__PURE__ */ new Set();
|
|
1613
1639
|
/** Track when each provider last failed (provider URL -> timestamp) */
|
|
@@ -1616,14 +1642,57 @@ var ProviderManager = class _ProviderManager {
|
|
|
1616
1642
|
providersOnCoolDown = [];
|
|
1617
1643
|
/** Cooldown duration in milliseconds (5 minutes) */
|
|
1618
1644
|
static COOLDOWN_DURATION_MS = 5 * 60 * 1e3;
|
|
1645
|
+
/** Optional persistent store for failure tracking */
|
|
1646
|
+
store = null;
|
|
1647
|
+
/** Instance ID for debugging */
|
|
1648
|
+
instanceId;
|
|
1649
|
+
/**
|
|
1650
|
+
* Hydrate in-memory state from persistent store
|
|
1651
|
+
*/
|
|
1652
|
+
hydrateFromStore() {
|
|
1653
|
+
if (!this.store) return;
|
|
1654
|
+
const state = this.store.getState();
|
|
1655
|
+
this.failedProviders = new Set(state.failedProviders);
|
|
1656
|
+
this.lastFailed = new Map(Object.entries(state.lastFailed));
|
|
1657
|
+
const now = Date.now();
|
|
1658
|
+
this.providersOnCoolDown = state.providersOnCooldown.filter(
|
|
1659
|
+
(entry) => now - entry.timestamp < _ProviderManager.COOLDOWN_DURATION_MS
|
|
1660
|
+
).map((entry) => [entry.baseUrl, entry.timestamp]);
|
|
1661
|
+
console.log(`[ProviderManager:${this.instanceId}] Hydrated from store:`);
|
|
1662
|
+
console.log(` failedProviders: ${this.failedProviders.size}`);
|
|
1663
|
+
console.log(` lastFailed: ${this.lastFailed.size}`);
|
|
1664
|
+
console.log(` providersOnCooldown: ${this.providersOnCoolDown.length}`);
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Get instance ID for debugging
|
|
1668
|
+
*/
|
|
1669
|
+
getInstanceId() {
|
|
1670
|
+
return this.instanceId;
|
|
1671
|
+
}
|
|
1619
1672
|
/**
|
|
1620
1673
|
* Clean up expired cooldown entries
|
|
1621
1674
|
*/
|
|
1622
1675
|
cleanupExpiredCooldowns() {
|
|
1623
1676
|
const now = Date.now();
|
|
1677
|
+
const before = this.providersOnCoolDown.length;
|
|
1624
1678
|
this.providersOnCoolDown = this.providersOnCoolDown.filter(
|
|
1625
|
-
([, timestamp]) =>
|
|
1679
|
+
([url, timestamp]) => {
|
|
1680
|
+
const age = now - timestamp;
|
|
1681
|
+
const isExpired = age >= _ProviderManager.COOLDOWN_DURATION_MS;
|
|
1682
|
+
if (isExpired) {
|
|
1683
|
+
console.log(
|
|
1684
|
+
`[cleanupExpiredCooldowns:${this.instanceId}] Removing expired cooldown for ${url} (age: ${age}ms, cooldown: ${_ProviderManager.COOLDOWN_DURATION_MS}ms)`
|
|
1685
|
+
);
|
|
1686
|
+
}
|
|
1687
|
+
return !isExpired;
|
|
1688
|
+
}
|
|
1626
1689
|
);
|
|
1690
|
+
const after = this.providersOnCoolDown.length;
|
|
1691
|
+
if (before !== after) {
|
|
1692
|
+
console.log(
|
|
1693
|
+
`[cleanupExpiredCooldowns:${this.instanceId}] Cleaned up ${before - after} expired cooldown(s), ${after} remaining`
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1627
1696
|
}
|
|
1628
1697
|
/**
|
|
1629
1698
|
* Get the cooldown duration in milliseconds
|
|
@@ -1636,7 +1705,8 @@ var ProviderManager = class _ProviderManager {
|
|
|
1636
1705
|
*/
|
|
1637
1706
|
isOnCooldown(baseUrl) {
|
|
1638
1707
|
this.cleanupExpiredCooldowns();
|
|
1639
|
-
|
|
1708
|
+
const result = this.providersOnCoolDown.some(([url]) => url === baseUrl);
|
|
1709
|
+
return result;
|
|
1640
1710
|
}
|
|
1641
1711
|
/**
|
|
1642
1712
|
* Get all providers currently on cooldown
|
|
@@ -1650,6 +1720,9 @@ var ProviderManager = class _ProviderManager {
|
|
|
1650
1720
|
*/
|
|
1651
1721
|
resetFailedProviders() {
|
|
1652
1722
|
this.failedProviders.clear();
|
|
1723
|
+
if (this.store) {
|
|
1724
|
+
this.store.getState().setFailedProviders([]);
|
|
1725
|
+
}
|
|
1653
1726
|
}
|
|
1654
1727
|
/**
|
|
1655
1728
|
* Get the last failed timestamp for a provider
|
|
@@ -1670,13 +1743,62 @@ var ProviderManager = class _ProviderManager {
|
|
|
1670
1743
|
markFailed(baseUrl) {
|
|
1671
1744
|
const now = Date.now();
|
|
1672
1745
|
const lastFailure = this.lastFailed.get(baseUrl);
|
|
1746
|
+
console.log(`[markFailed:${this.instanceId}] baseUrl: ${baseUrl}`);
|
|
1747
|
+
console.log(
|
|
1748
|
+
`[markFailed:${this.instanceId}] lastFailure from map: ${lastFailure}`
|
|
1749
|
+
);
|
|
1750
|
+
console.log(
|
|
1751
|
+
`[markFailed:${this.instanceId}] current timestamp (now): ${now}`
|
|
1752
|
+
);
|
|
1753
|
+
console.log(
|
|
1754
|
+
`[markFailed:${this.instanceId}] COOLDOWN_DURATION_MS: ${_ProviderManager.COOLDOWN_DURATION_MS}`
|
|
1755
|
+
);
|
|
1756
|
+
if (lastFailure !== void 0) {
|
|
1757
|
+
const timeSinceLastFailure = now - lastFailure;
|
|
1758
|
+
console.log(
|
|
1759
|
+
`[markFailed:${this.instanceId}] timeSinceLastFailure: ${timeSinceLastFailure}ms`
|
|
1760
|
+
);
|
|
1761
|
+
console.log(
|
|
1762
|
+
`[markFailed:${this.instanceId}] isWithinCooldownWindow: ${timeSinceLastFailure < _ProviderManager.COOLDOWN_DURATION_MS}`
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1673
1765
|
this.lastFailed.set(baseUrl, now);
|
|
1674
1766
|
this.failedProviders.add(baseUrl);
|
|
1767
|
+
if (this.store) {
|
|
1768
|
+
this.store.getState().setLastFailedTimestamp(baseUrl, now);
|
|
1769
|
+
this.store.getState().addFailedProvider(baseUrl);
|
|
1770
|
+
}
|
|
1771
|
+
console.log(
|
|
1772
|
+
`[markFailed:${this.instanceId}] Updated lastFailed map for ${baseUrl} to ${now}`
|
|
1773
|
+
);
|
|
1774
|
+
console.log(
|
|
1775
|
+
`[markFailed:${this.instanceId}] failedProviders set size: ${this.failedProviders.size}`
|
|
1776
|
+
);
|
|
1675
1777
|
if (lastFailure !== void 0 && now - lastFailure < _ProviderManager.COOLDOWN_DURATION_MS) {
|
|
1778
|
+
console.log(
|
|
1779
|
+
`[markFailed:${this.instanceId}] Second failure detected within cooldown window for ${baseUrl}`
|
|
1780
|
+
);
|
|
1676
1781
|
if (!this.isOnCooldown(baseUrl)) {
|
|
1677
1782
|
this.providersOnCoolDown.push([baseUrl, now]);
|
|
1783
|
+
if (this.store) {
|
|
1784
|
+
this.store.getState().addProviderOnCooldown(baseUrl, now);
|
|
1785
|
+
}
|
|
1786
|
+
console.log(
|
|
1787
|
+
`[markFailed:${this.instanceId}] Provider ${baseUrl} added to cooldown after second failure within 5 minutes`
|
|
1788
|
+
);
|
|
1789
|
+
} else {
|
|
1790
|
+
console.log(
|
|
1791
|
+
`[markFailed:${this.instanceId}] Provider ${baseUrl} is already on cooldown`
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
} else {
|
|
1795
|
+
if (lastFailure === void 0) {
|
|
1678
1796
|
console.log(
|
|
1679
|
-
`
|
|
1797
|
+
`[markFailed:${this.instanceId}] First failure for ${baseUrl} - not adding to cooldown yet`
|
|
1798
|
+
);
|
|
1799
|
+
} else {
|
|
1800
|
+
console.log(
|
|
1801
|
+
`[markFailed:${this.instanceId}] Failure outside cooldown window for ${baseUrl} (timeSinceLastFailure: ${now - lastFailure}ms)`
|
|
1680
1802
|
);
|
|
1681
1803
|
}
|
|
1682
1804
|
}
|
|
@@ -1688,18 +1810,27 @@ var ProviderManager = class _ProviderManager {
|
|
|
1688
1810
|
this.providersOnCoolDown = this.providersOnCoolDown.filter(
|
|
1689
1811
|
([url]) => url !== baseUrl
|
|
1690
1812
|
);
|
|
1813
|
+
if (this.store) {
|
|
1814
|
+
this.store.getState().removeProviderFromCooldown(baseUrl);
|
|
1815
|
+
}
|
|
1691
1816
|
}
|
|
1692
1817
|
/**
|
|
1693
1818
|
* Clear all cooldown tracking
|
|
1694
1819
|
*/
|
|
1695
1820
|
clearCooldowns() {
|
|
1696
1821
|
this.providersOnCoolDown = [];
|
|
1822
|
+
if (this.store) {
|
|
1823
|
+
this.store.getState().clearProvidersOnCooldown();
|
|
1824
|
+
}
|
|
1697
1825
|
}
|
|
1698
1826
|
/**
|
|
1699
1827
|
* Clear all failure tracking (lastFailed timestamps)
|
|
1700
1828
|
*/
|
|
1701
1829
|
clearFailureHistory() {
|
|
1702
1830
|
this.lastFailed.clear();
|
|
1831
|
+
if (this.store) {
|
|
1832
|
+
this.store.getState().setLastFailed({});
|
|
1833
|
+
}
|
|
1703
1834
|
}
|
|
1704
1835
|
/**
|
|
1705
1836
|
* Check if a provider has failed
|
|
@@ -2121,7 +2252,10 @@ var SDK_STORAGE_KEYS = {
|
|
|
2121
2252
|
LAST_ROUTSTR21_MODELS_UPDATE: "lastRoutstr21ModelsUpdate",
|
|
2122
2253
|
CACHED_RECEIVE_TOKENS: "cached_receive_tokens",
|
|
2123
2254
|
USAGE_TRACKING: "usage_tracking",
|
|
2124
|
-
CLIENT_IDS: "client_ids"
|
|
2255
|
+
CLIENT_IDS: "client_ids",
|
|
2256
|
+
FAILED_PROVIDERS: "failed_providers",
|
|
2257
|
+
LAST_FAILED: "last_failed",
|
|
2258
|
+
PROVIDERS_ON_COOLDOWN: "providers_on_cooldown"
|
|
2125
2259
|
};
|
|
2126
2260
|
|
|
2127
2261
|
// storage/usageTracking/indexedDB.ts
|
|
@@ -2768,6 +2902,9 @@ var createEmptyStore = (driver) => createStore((set, get) => ({
|
|
|
2768
2902
|
lastRoutstr21ModelsUpdate: null,
|
|
2769
2903
|
cachedReceiveTokens: [],
|
|
2770
2904
|
clientIds: [],
|
|
2905
|
+
failedProviders: [],
|
|
2906
|
+
lastFailed: {},
|
|
2907
|
+
providersOnCooldown: [],
|
|
2771
2908
|
setModelsFromAllProviders: (value) => {
|
|
2772
2909
|
const normalized = {};
|
|
2773
2910
|
for (const [baseUrl, models] of Object.entries(value)) {
|
|
@@ -2907,6 +3044,71 @@ var createEmptyStore = (driver) => createStore((set, get) => ({
|
|
|
2907
3044
|
void driver.setItem(SDK_STORAGE_KEYS.CLIENT_IDS, normalized);
|
|
2908
3045
|
return { clientIds: normalized };
|
|
2909
3046
|
});
|
|
3047
|
+
},
|
|
3048
|
+
// ========== Failure Tracking ==========
|
|
3049
|
+
setFailedProviders: (value) => {
|
|
3050
|
+
const normalized = value.map((url) => normalizeBaseUrl5(url));
|
|
3051
|
+
void driver.setItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, normalized);
|
|
3052
|
+
set({ failedProviders: normalized });
|
|
3053
|
+
},
|
|
3054
|
+
addFailedProvider: (baseUrl) => {
|
|
3055
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3056
|
+
const current = get().failedProviders;
|
|
3057
|
+
if (!current.includes(normalized)) {
|
|
3058
|
+
const updated = [...current, normalized];
|
|
3059
|
+
void driver.setItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, updated);
|
|
3060
|
+
set({ failedProviders: updated });
|
|
3061
|
+
}
|
|
3062
|
+
},
|
|
3063
|
+
removeFailedProvider: (baseUrl) => {
|
|
3064
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3065
|
+
const current = get().failedProviders;
|
|
3066
|
+
const updated = current.filter((url) => url !== normalized);
|
|
3067
|
+
void driver.setItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, updated);
|
|
3068
|
+
set({ failedProviders: updated });
|
|
3069
|
+
},
|
|
3070
|
+
setLastFailed: (value) => {
|
|
3071
|
+
const normalized = {};
|
|
3072
|
+
for (const [baseUrl, timestamp] of Object.entries(value)) {
|
|
3073
|
+
normalized[normalizeBaseUrl5(baseUrl)] = timestamp;
|
|
3074
|
+
}
|
|
3075
|
+
void driver.setItem(SDK_STORAGE_KEYS.LAST_FAILED, normalized);
|
|
3076
|
+
set({ lastFailed: normalized });
|
|
3077
|
+
},
|
|
3078
|
+
setLastFailedTimestamp: (baseUrl, timestamp) => {
|
|
3079
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3080
|
+
const current = get().lastFailed;
|
|
3081
|
+
const updated = { ...current, [normalized]: timestamp };
|
|
3082
|
+
void driver.setItem(SDK_STORAGE_KEYS.LAST_FAILED, updated);
|
|
3083
|
+
set({ lastFailed: updated });
|
|
3084
|
+
},
|
|
3085
|
+
setProvidersOnCooldown: (value) => {
|
|
3086
|
+
const normalized = value.map((entry) => ({
|
|
3087
|
+
baseUrl: normalizeBaseUrl5(entry.baseUrl),
|
|
3088
|
+
timestamp: entry.timestamp
|
|
3089
|
+
}));
|
|
3090
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, normalized);
|
|
3091
|
+
set({ providersOnCooldown: normalized });
|
|
3092
|
+
},
|
|
3093
|
+
addProviderOnCooldown: (baseUrl, timestamp) => {
|
|
3094
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3095
|
+
const current = get().providersOnCooldown;
|
|
3096
|
+
if (!current.some((entry) => entry.baseUrl === normalized)) {
|
|
3097
|
+
const updated = [...current, { baseUrl: normalized, timestamp }];
|
|
3098
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, updated);
|
|
3099
|
+
set({ providersOnCooldown: updated });
|
|
3100
|
+
}
|
|
3101
|
+
},
|
|
3102
|
+
removeProviderFromCooldown: (baseUrl) => {
|
|
3103
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3104
|
+
const current = get().providersOnCooldown;
|
|
3105
|
+
const updated = current.filter((entry) => entry.baseUrl !== normalized);
|
|
3106
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, updated);
|
|
3107
|
+
set({ providersOnCooldown: updated });
|
|
3108
|
+
},
|
|
3109
|
+
clearProvidersOnCooldown: () => {
|
|
3110
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, []);
|
|
3111
|
+
set({ providersOnCooldown: [] });
|
|
2910
3112
|
}
|
|
2911
3113
|
}));
|
|
2912
3114
|
var hydrateStoreFromDriver = async (store, driver) => {
|
|
@@ -2925,7 +3127,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
2925
3127
|
rawRoutstr21Models,
|
|
2926
3128
|
rawLastRoutstr21ModelsUpdate,
|
|
2927
3129
|
rawCachedReceiveTokens,
|
|
2928
|
-
rawClientIds
|
|
3130
|
+
rawClientIds,
|
|
3131
|
+
rawFailedProviders,
|
|
3132
|
+
rawLastFailed,
|
|
3133
|
+
rawProvidersOnCooldown
|
|
2929
3134
|
] = await Promise.all([
|
|
2930
3135
|
driver.getItem(
|
|
2931
3136
|
SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
|
|
@@ -2956,7 +3161,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
2956
3161
|
null
|
|
2957
3162
|
),
|
|
2958
3163
|
driver.getItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, []),
|
|
2959
|
-
driver.getItem(SDK_STORAGE_KEYS.CLIENT_IDS, [])
|
|
3164
|
+
driver.getItem(SDK_STORAGE_KEYS.CLIENT_IDS, []),
|
|
3165
|
+
driver.getItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, []),
|
|
3166
|
+
driver.getItem(SDK_STORAGE_KEYS.LAST_FAILED, {}),
|
|
3167
|
+
driver.getItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, [])
|
|
2960
3168
|
]);
|
|
2961
3169
|
const modelsFromAllProviders = Object.fromEntries(
|
|
2962
3170
|
Object.entries(rawModels).map(([baseUrl, models]) => [
|
|
@@ -3024,6 +3232,17 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
3024
3232
|
createdAt: entry.createdAt ?? Date.now(),
|
|
3025
3233
|
lastUsed: entry.lastUsed ?? null
|
|
3026
3234
|
}));
|
|
3235
|
+
const failedProviders = rawFailedProviders.map((url) => normalizeBaseUrl5(url));
|
|
3236
|
+
const lastFailed = Object.fromEntries(
|
|
3237
|
+
Object.entries(rawLastFailed).map(([baseUrl, timestamp]) => [
|
|
3238
|
+
normalizeBaseUrl5(baseUrl),
|
|
3239
|
+
timestamp
|
|
3240
|
+
])
|
|
3241
|
+
);
|
|
3242
|
+
const providersOnCooldown = rawProvidersOnCooldown.map((entry) => ({
|
|
3243
|
+
baseUrl: normalizeBaseUrl5(entry.baseUrl),
|
|
3244
|
+
timestamp: entry.timestamp
|
|
3245
|
+
}));
|
|
3027
3246
|
store.setState({
|
|
3028
3247
|
modelsFromAllProviders,
|
|
3029
3248
|
lastUsedModel,
|
|
@@ -3039,7 +3258,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
3039
3258
|
routstr21Models,
|
|
3040
3259
|
lastRoutstr21ModelsUpdate,
|
|
3041
3260
|
cachedReceiveTokens,
|
|
3042
|
-
clientIds
|
|
3261
|
+
clientIds,
|
|
3262
|
+
failedProviders,
|
|
3263
|
+
lastFailed,
|
|
3264
|
+
providersOnCooldown
|
|
3043
3265
|
});
|
|
3044
3266
|
};
|
|
3045
3267
|
var createSdkStore = ({
|
|
@@ -3205,11 +3427,11 @@ var RoutstrClient = class {
|
|
|
3205
3427
|
this.balanceManager
|
|
3206
3428
|
);
|
|
3207
3429
|
this.streamProcessor = new StreamProcessor();
|
|
3208
|
-
this.providerManager = new ProviderManager(providerRegistry);
|
|
3209
3430
|
this.alertLevel = alertLevel;
|
|
3210
3431
|
this.mode = mode;
|
|
3211
3432
|
this.usageTrackingDriver = options.usageTrackingDriver;
|
|
3212
3433
|
this.sdkStore = options.sdkStore;
|
|
3434
|
+
this.providerManager = options.providerManager ?? new ProviderManager(providerRegistry, this.sdkStore);
|
|
3213
3435
|
}
|
|
3214
3436
|
cashuSpender;
|
|
3215
3437
|
balanceManager;
|
|
@@ -3739,6 +3961,10 @@ var RoutstrClient = class {
|
|
|
3739
3961
|
const currentBalance = currentBalanceInfo.unit === "msat" ? currentBalanceInfo.amount / 1e3 : currentBalanceInfo.amount;
|
|
3740
3962
|
const shortfall = Math.max(0, params.requiredSats - currentBalance);
|
|
3741
3963
|
topupAmount = shortfall > 0 ? shortfall : params.requiredSats;
|
|
3964
|
+
this._log(
|
|
3965
|
+
"DEBUG",
|
|
3966
|
+
`The shortfall is: ${shortfall}. requiredSats: ${params.requiredSats}. Current Balance: ${currentBalance} `
|
|
3967
|
+
);
|
|
3742
3968
|
} catch (e) {
|
|
3743
3969
|
this._log(
|
|
3744
3970
|
"WARN",
|
|
@@ -3868,6 +4094,20 @@ var RoutstrClient = class {
|
|
|
3868
4094
|
tryNextProvider = true;
|
|
3869
4095
|
}
|
|
3870
4096
|
}
|
|
4097
|
+
if (status === 401 && this.mode === "apikeys") {
|
|
4098
|
+
this._log(
|
|
4099
|
+
"DEBUG",
|
|
4100
|
+
`[RoutstrClient] _handleErrorResponse: Checking balance for ${baseUrl}, key preview=${token}`
|
|
4101
|
+
);
|
|
4102
|
+
const latestBalanceInfo = await this.balanceManager.getTokenBalance(
|
|
4103
|
+
token,
|
|
4104
|
+
baseUrl
|
|
4105
|
+
);
|
|
4106
|
+
if (latestBalanceInfo.isInvalidApiKey) {
|
|
4107
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
4108
|
+
tryNextProvider = true;
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
3871
4111
|
if ((status === 401 || status === 403 || status === 413 || status === 400 || status === 500 || status === 502 || status === 503 || status === 504 || status === 521) && !tryNextProvider) {
|
|
3872
4112
|
this._log(
|
|
3873
4113
|
"DEBUG",
|
|
@@ -3878,13 +4118,13 @@ var RoutstrClient = class {
|
|
|
3878
4118
|
"DEBUG",
|
|
3879
4119
|
`[RoutstrClient] _handleErrorResponse: Attempting API key refund for ${baseUrl}, key preview=${token}`
|
|
3880
4120
|
);
|
|
3881
|
-
const
|
|
4121
|
+
const latestBalanceInfo = await this.balanceManager.getTokenBalance(
|
|
3882
4122
|
token,
|
|
3883
4123
|
baseUrl
|
|
3884
4124
|
);
|
|
3885
4125
|
this._log(
|
|
3886
4126
|
"DEBUG",
|
|
3887
|
-
`[RoutstrClient] _handleErrorResponse: Initial API key balance: ${
|
|
4127
|
+
`[RoutstrClient] _handleErrorResponse: Initial API key balance: ${latestBalanceInfo.amount}`
|
|
3888
4128
|
);
|
|
3889
4129
|
const refundResult = await this.balanceManager.refundApiKey({
|
|
3890
4130
|
mintUrl,
|
|
@@ -3896,7 +4136,7 @@ var RoutstrClient = class {
|
|
|
3896
4136
|
"DEBUG",
|
|
3897
4137
|
`[RoutstrClient] _handleErrorResponse: API key refund result: success=${refundResult.success}, message=${refundResult.message}`
|
|
3898
4138
|
);
|
|
3899
|
-
if (!refundResult.success &&
|
|
4139
|
+
if (!refundResult.success && latestBalanceInfo.amount > 0) {
|
|
3900
4140
|
throw new ProviderError(
|
|
3901
4141
|
baseUrl,
|
|
3902
4142
|
status,
|
|
@@ -4036,7 +4276,6 @@ var RoutstrClient = class {
|
|
|
4036
4276
|
try {
|
|
4037
4277
|
const xcashuResults = await this.cashuSpender.refundXcashuTokens(mintUrl);
|
|
4038
4278
|
this._log("DEBUG", "Refund xcashu tokens results:", xcashuResults);
|
|
4039
|
-
const results = await this.cashuSpender.refundProviders(mintUrl);
|
|
4040
4279
|
} catch (error) {
|
|
4041
4280
|
this._log("ERROR", "Failed to refund providers:", error);
|
|
4042
4281
|
}
|