ton-provider-system 0.1.8 → 0.1.10
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/index.cjs +88 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +88 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -952,13 +952,16 @@ var HealthChecker = class {
|
|
|
952
952
|
const existing = this.results.get(key);
|
|
953
953
|
const result = existing ? {
|
|
954
954
|
...existing,
|
|
955
|
+
success: true,
|
|
956
|
+
// Degraded providers are still usable, just slower/rate-limited
|
|
955
957
|
status: "degraded",
|
|
956
958
|
error: error || "Marked as degraded",
|
|
957
959
|
lastTested: /* @__PURE__ */ new Date()
|
|
958
960
|
} : {
|
|
959
961
|
id: providerId,
|
|
960
962
|
network,
|
|
961
|
-
success:
|
|
963
|
+
success: true,
|
|
964
|
+
// Degraded providers are still usable
|
|
962
965
|
status: "degraded",
|
|
963
966
|
latencyMs: null,
|
|
964
967
|
seqno: null,
|
|
@@ -1572,6 +1575,8 @@ var ProviderSelector = class {
|
|
|
1572
1575
|
this.autoSelect = true;
|
|
1573
1576
|
this.customEndpoint = null;
|
|
1574
1577
|
this.bestProviderByNetwork = /* @__PURE__ */ new Map();
|
|
1578
|
+
// Track currently active provider per network (the one actually being used)
|
|
1579
|
+
this.activeProviderByNetwork = /* @__PURE__ */ new Map();
|
|
1575
1580
|
this.registry = registry;
|
|
1576
1581
|
this.healthChecker = healthChecker;
|
|
1577
1582
|
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
@@ -1590,6 +1595,7 @@ var ProviderSelector = class {
|
|
|
1590
1595
|
if (!this.autoSelect && this.selectedProviderId) {
|
|
1591
1596
|
const provider = this.registry.getProvider(this.selectedProviderId);
|
|
1592
1597
|
if (provider && provider.network === network) {
|
|
1598
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1593
1599
|
return provider;
|
|
1594
1600
|
}
|
|
1595
1601
|
this.logger.warn(
|
|
@@ -1600,8 +1606,13 @@ var ProviderSelector = class {
|
|
|
1600
1606
|
if (cachedBestId) {
|
|
1601
1607
|
const cached = this.registry.getProvider(cachedBestId);
|
|
1602
1608
|
const health = this.healthChecker.getResult(cachedBestId, network);
|
|
1603
|
-
if (cached && health && health.success !== false &&
|
|
1609
|
+
if (cached && health && health.success !== false && health.success !== void 0 && // Explicitly check for undefined
|
|
1610
|
+
this.config.minStatus.includes(health.status)) {
|
|
1611
|
+
this.activeProviderByNetwork.set(network, cachedBestId);
|
|
1604
1612
|
return cached;
|
|
1613
|
+
} else {
|
|
1614
|
+
this.bestProviderByNetwork.delete(network);
|
|
1615
|
+
this.activeProviderByNetwork.delete(network);
|
|
1605
1616
|
}
|
|
1606
1617
|
}
|
|
1607
1618
|
return this.findBestProvider(network);
|
|
@@ -1623,12 +1634,31 @@ var ProviderSelector = class {
|
|
|
1623
1634
|
const defaults = this.registry.getDefaultOrderForNetwork(network);
|
|
1624
1635
|
for (const defaultProvider of defaults) {
|
|
1625
1636
|
const health = this.healthChecker.getResult(defaultProvider.id, network);
|
|
1626
|
-
if (!health || health.status === "untested"
|
|
1637
|
+
if (!health || health.status === "untested") {
|
|
1638
|
+
this.logger.warn(
|
|
1639
|
+
`No healthy providers for ${network}, using untested default: ${defaultProvider.id}`
|
|
1640
|
+
);
|
|
1641
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1642
|
+
return defaultProvider;
|
|
1643
|
+
}
|
|
1644
|
+
if (health.success === true) {
|
|
1627
1645
|
this.logger.warn(
|
|
1628
1646
|
`No healthy providers for ${network}, using default: ${defaultProvider.id}`
|
|
1629
1647
|
);
|
|
1648
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1630
1649
|
return defaultProvider;
|
|
1631
1650
|
}
|
|
1651
|
+
if (health.success === false && health.lastTested) {
|
|
1652
|
+
const timeSinceFailure = Date.now() - health.lastTested.getTime();
|
|
1653
|
+
const cooldownMs = 3e4;
|
|
1654
|
+
if (timeSinceFailure > cooldownMs) {
|
|
1655
|
+
this.logger.warn(
|
|
1656
|
+
`No healthy providers for ${network}, retrying failed default after cooldown: ${defaultProvider.id}`
|
|
1657
|
+
);
|
|
1658
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1659
|
+
return defaultProvider;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1632
1662
|
}
|
|
1633
1663
|
for (const provider of providers) {
|
|
1634
1664
|
const health = this.healthChecker.getResult(provider.id, network);
|
|
@@ -1636,20 +1666,34 @@ var ProviderSelector = class {
|
|
|
1636
1666
|
this.logger.warn(
|
|
1637
1667
|
`No tested healthy providers for ${network}, using untested: ${provider.id}`
|
|
1638
1668
|
);
|
|
1669
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1639
1670
|
return provider;
|
|
1640
1671
|
}
|
|
1672
|
+
if (health.success === false && health.lastTested) {
|
|
1673
|
+
const timeSinceFailure = Date.now() - health.lastTested.getTime();
|
|
1674
|
+
const cooldownMs = 3e4;
|
|
1675
|
+
if (timeSinceFailure > cooldownMs) {
|
|
1676
|
+
this.logger.warn(
|
|
1677
|
+
`No healthy providers for ${network}, retrying failed provider after cooldown: ${provider.id}`
|
|
1678
|
+
);
|
|
1679
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1680
|
+
return provider;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1641
1683
|
}
|
|
1642
|
-
this.logger.error(`No available providers for ${network} (all tested and failed)`);
|
|
1684
|
+
this.logger.error(`No available providers for ${network} (all tested and failed, cooldown active)`);
|
|
1643
1685
|
return null;
|
|
1644
1686
|
}
|
|
1645
1687
|
const best = scored[0].provider;
|
|
1646
1688
|
const bestHealth = this.healthChecker.getResult(best.id, network);
|
|
1647
1689
|
if (bestHealth && bestHealth.success === true) {
|
|
1648
1690
|
this.bestProviderByNetwork.set(network, best.id);
|
|
1691
|
+
this.activeProviderByNetwork.set(network, best.id);
|
|
1649
1692
|
this.logger.debug(
|
|
1650
1693
|
`Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)})`
|
|
1651
1694
|
);
|
|
1652
1695
|
} else {
|
|
1696
|
+
this.activeProviderByNetwork.set(network, best.id);
|
|
1653
1697
|
this.logger.debug(
|
|
1654
1698
|
`Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)}, untested)`
|
|
1655
1699
|
);
|
|
@@ -1692,6 +1736,13 @@ var ProviderSelector = class {
|
|
|
1692
1736
|
return 0.01 * (1 / (provider.priority + 1));
|
|
1693
1737
|
}
|
|
1694
1738
|
if (health.success === false) {
|
|
1739
|
+
if (health.lastTested) {
|
|
1740
|
+
const timeSinceFailure = Date.now() - health.lastTested.getTime();
|
|
1741
|
+
const cooldownMs = 3e4;
|
|
1742
|
+
if (timeSinceFailure > cooldownMs) {
|
|
1743
|
+
return 1e-3 * (1 / (provider.priority + 1));
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1695
1746
|
return 0;
|
|
1696
1747
|
}
|
|
1697
1748
|
if (health.status === "offline") {
|
|
@@ -1789,9 +1840,16 @@ var ProviderSelector = class {
|
|
|
1789
1840
|
}
|
|
1790
1841
|
/**
|
|
1791
1842
|
* Clear cached best providers (forces recalculation)
|
|
1843
|
+
* @param network - Optional network to clear cache for. If not provided, clears all networks.
|
|
1792
1844
|
*/
|
|
1793
|
-
clearCache() {
|
|
1794
|
-
|
|
1845
|
+
clearCache(network) {
|
|
1846
|
+
if (network) {
|
|
1847
|
+
this.bestProviderByNetwork.delete(network);
|
|
1848
|
+
this.activeProviderByNetwork.delete(network);
|
|
1849
|
+
} else {
|
|
1850
|
+
this.bestProviderByNetwork.clear();
|
|
1851
|
+
this.activeProviderByNetwork.clear();
|
|
1852
|
+
}
|
|
1795
1853
|
}
|
|
1796
1854
|
/**
|
|
1797
1855
|
* Update best provider after health check
|
|
@@ -1806,8 +1864,16 @@ var ProviderSelector = class {
|
|
|
1806
1864
|
if (this.bestProviderByNetwork.get(network) === providerId) {
|
|
1807
1865
|
this.bestProviderByNetwork.delete(network);
|
|
1808
1866
|
}
|
|
1867
|
+
this.activeProviderByNetwork.delete(network);
|
|
1809
1868
|
return this.getNextProvider(network, [providerId]);
|
|
1810
1869
|
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Get the currently active provider ID for a network
|
|
1872
|
+
* (the one that was last selected and is being used)
|
|
1873
|
+
*/
|
|
1874
|
+
getActiveProviderId(network) {
|
|
1875
|
+
return this.activeProviderByNetwork.get(network) || null;
|
|
1876
|
+
}
|
|
1811
1877
|
// ========================================================================
|
|
1812
1878
|
// Info
|
|
1813
1879
|
// ========================================================================
|
|
@@ -2044,6 +2110,7 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2044
2110
|
this.options.logger.warn("No providers available, using fallback");
|
|
2045
2111
|
return this.getFallbackEndpoint();
|
|
2046
2112
|
}
|
|
2113
|
+
this.selector.getActiveProviderId(this.network) || this.selector.getBestProvider(this.network);
|
|
2047
2114
|
if (provider.isDynamic && provider.type === "orbs") {
|
|
2048
2115
|
try {
|
|
2049
2116
|
const { getHttpEndpoint } = await import('@orbs-network/ton-access');
|
|
@@ -2059,9 +2126,14 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2059
2126
|
* Get endpoint with rate limiting
|
|
2060
2127
|
*
|
|
2061
2128
|
* Waits for rate limit token before returning endpoint.
|
|
2129
|
+
*
|
|
2130
|
+
* @param forceRefresh - If true, clears cache and forces re-selection
|
|
2062
2131
|
*/
|
|
2063
|
-
async getEndpointWithRateLimit(timeoutMs) {
|
|
2132
|
+
async getEndpointWithRateLimit(timeoutMs, forceRefresh = false) {
|
|
2064
2133
|
this.ensureInitialized();
|
|
2134
|
+
if (forceRefresh) {
|
|
2135
|
+
this.selector.clearCache(this.network);
|
|
2136
|
+
}
|
|
2065
2137
|
const provider = this.selector.getBestProvider(this.network);
|
|
2066
2138
|
if (!provider) {
|
|
2067
2139
|
return this.getFallbackEndpoint();
|
|
@@ -2113,7 +2185,14 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2113
2185
|
*/
|
|
2114
2186
|
reportError(error) {
|
|
2115
2187
|
if (!this.initialized || !this.network) return;
|
|
2116
|
-
const
|
|
2188
|
+
const activeProviderId = this.selector.getActiveProviderId(this.network);
|
|
2189
|
+
let provider = null;
|
|
2190
|
+
if (activeProviderId) {
|
|
2191
|
+
provider = this.registry.getProvider(activeProviderId) || null;
|
|
2192
|
+
}
|
|
2193
|
+
if (!provider) {
|
|
2194
|
+
provider = this.selector.getBestProvider(this.network);
|
|
2195
|
+
}
|
|
2117
2196
|
if (!provider) return;
|
|
2118
2197
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2119
2198
|
const errorMsgLower = errorMsg.toLowerCase();
|
|
@@ -2132,6 +2211,7 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2132
2211
|
this.rateLimiter.reportError(provider.id);
|
|
2133
2212
|
this.healthChecker.markDegraded(provider.id, this.network, errorMsg);
|
|
2134
2213
|
}
|
|
2214
|
+
this.selector.clearCache(this.network);
|
|
2135
2215
|
this.selector.handleProviderFailure(provider.id, this.network);
|
|
2136
2216
|
this.notifyListeners();
|
|
2137
2217
|
}
|