ton-provider-system 0.1.7 → 0.1.9
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 +103 -24
- 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 +103 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -950,14 +950,25 @@ var HealthChecker = class {
|
|
|
950
950
|
markDegraded(providerId, network, error) {
|
|
951
951
|
const key = this.getResultKey(providerId, network);
|
|
952
952
|
const existing = this.results.get(key);
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
}
|
|
953
|
+
const result = existing ? {
|
|
954
|
+
...existing,
|
|
955
|
+
success: false,
|
|
956
|
+
// CRITICAL: Always set success: false for degraded providers
|
|
957
|
+
status: "degraded",
|
|
958
|
+
error: error || "Marked as degraded",
|
|
959
|
+
lastTested: /* @__PURE__ */ new Date()
|
|
960
|
+
} : {
|
|
961
|
+
id: providerId,
|
|
962
|
+
network,
|
|
963
|
+
success: false,
|
|
964
|
+
status: "degraded",
|
|
965
|
+
latencyMs: null,
|
|
966
|
+
seqno: null,
|
|
967
|
+
blocksBehind: 0,
|
|
968
|
+
lastTested: /* @__PURE__ */ new Date(),
|
|
969
|
+
error: error || "Marked as degraded"
|
|
970
|
+
};
|
|
971
|
+
this.results.set(key, result);
|
|
961
972
|
}
|
|
962
973
|
/**
|
|
963
974
|
* Mark a provider as offline
|
|
@@ -965,14 +976,25 @@ var HealthChecker = class {
|
|
|
965
976
|
markOffline(providerId, network, error) {
|
|
966
977
|
const key = this.getResultKey(providerId, network);
|
|
967
978
|
const existing = this.results.get(key);
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
}
|
|
979
|
+
const result = existing ? {
|
|
980
|
+
...existing,
|
|
981
|
+
status: "offline",
|
|
982
|
+
success: false,
|
|
983
|
+
// Ensure success is false for offline providers
|
|
984
|
+
error: error || "Marked as offline",
|
|
985
|
+
lastTested: /* @__PURE__ */ new Date()
|
|
986
|
+
} : {
|
|
987
|
+
id: providerId,
|
|
988
|
+
network,
|
|
989
|
+
success: false,
|
|
990
|
+
status: "offline",
|
|
991
|
+
latencyMs: null,
|
|
992
|
+
seqno: null,
|
|
993
|
+
blocksBehind: 0,
|
|
994
|
+
lastTested: /* @__PURE__ */ new Date(),
|
|
995
|
+
error: error || "Marked as offline"
|
|
996
|
+
};
|
|
997
|
+
this.results.set(key, result);
|
|
976
998
|
}
|
|
977
999
|
// ========================================================================
|
|
978
1000
|
// Private Methods
|
|
@@ -1552,6 +1574,8 @@ var ProviderSelector = class {
|
|
|
1552
1574
|
this.autoSelect = true;
|
|
1553
1575
|
this.customEndpoint = null;
|
|
1554
1576
|
this.bestProviderByNetwork = /* @__PURE__ */ new Map();
|
|
1577
|
+
// Track currently active provider per network (the one actually being used)
|
|
1578
|
+
this.activeProviderByNetwork = /* @__PURE__ */ new Map();
|
|
1555
1579
|
this.registry = registry;
|
|
1556
1580
|
this.healthChecker = healthChecker;
|
|
1557
1581
|
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
@@ -1570,6 +1594,7 @@ var ProviderSelector = class {
|
|
|
1570
1594
|
if (!this.autoSelect && this.selectedProviderId) {
|
|
1571
1595
|
const provider = this.registry.getProvider(this.selectedProviderId);
|
|
1572
1596
|
if (provider && provider.network === network) {
|
|
1597
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1573
1598
|
return provider;
|
|
1574
1599
|
}
|
|
1575
1600
|
this.logger.warn(
|
|
@@ -1580,8 +1605,13 @@ var ProviderSelector = class {
|
|
|
1580
1605
|
if (cachedBestId) {
|
|
1581
1606
|
const cached = this.registry.getProvider(cachedBestId);
|
|
1582
1607
|
const health = this.healthChecker.getResult(cachedBestId, network);
|
|
1583
|
-
if (cached && health && health.success !== false &&
|
|
1608
|
+
if (cached && health && health.success !== false && health.success !== void 0 && // Explicitly check for undefined
|
|
1609
|
+
this.config.minStatus.includes(health.status)) {
|
|
1610
|
+
this.activeProviderByNetwork.set(network, cachedBestId);
|
|
1584
1611
|
return cached;
|
|
1612
|
+
} else {
|
|
1613
|
+
this.bestProviderByNetwork.delete(network);
|
|
1614
|
+
this.activeProviderByNetwork.delete(network);
|
|
1585
1615
|
}
|
|
1586
1616
|
}
|
|
1587
1617
|
return this.findBestProvider(network);
|
|
@@ -1603,10 +1633,17 @@ var ProviderSelector = class {
|
|
|
1603
1633
|
const defaults = this.registry.getDefaultOrderForNetwork(network);
|
|
1604
1634
|
for (const defaultProvider of defaults) {
|
|
1605
1635
|
const health = this.healthChecker.getResult(defaultProvider.id, network);
|
|
1606
|
-
if (!health || health.status === "untested"
|
|
1636
|
+
if (!health || health.status === "untested") {
|
|
1637
|
+
this.logger.warn(
|
|
1638
|
+
`No healthy providers for ${network}, using untested default: ${defaultProvider.id}`
|
|
1639
|
+
);
|
|
1640
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1641
|
+
return defaultProvider;
|
|
1642
|
+
} else if (health.success === true) {
|
|
1607
1643
|
this.logger.warn(
|
|
1608
1644
|
`No healthy providers for ${network}, using default: ${defaultProvider.id}`
|
|
1609
1645
|
);
|
|
1646
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1610
1647
|
return defaultProvider;
|
|
1611
1648
|
}
|
|
1612
1649
|
}
|
|
@@ -1616,6 +1653,7 @@ var ProviderSelector = class {
|
|
|
1616
1653
|
this.logger.warn(
|
|
1617
1654
|
`No tested healthy providers for ${network}, using untested: ${provider.id}`
|
|
1618
1655
|
);
|
|
1656
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1619
1657
|
return provider;
|
|
1620
1658
|
}
|
|
1621
1659
|
}
|
|
@@ -1626,10 +1664,12 @@ var ProviderSelector = class {
|
|
|
1626
1664
|
const bestHealth = this.healthChecker.getResult(best.id, network);
|
|
1627
1665
|
if (bestHealth && bestHealth.success === true) {
|
|
1628
1666
|
this.bestProviderByNetwork.set(network, best.id);
|
|
1667
|
+
this.activeProviderByNetwork.set(network, best.id);
|
|
1629
1668
|
this.logger.debug(
|
|
1630
1669
|
`Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)})`
|
|
1631
1670
|
);
|
|
1632
1671
|
} else {
|
|
1672
|
+
this.activeProviderByNetwork.set(network, best.id);
|
|
1633
1673
|
this.logger.debug(
|
|
1634
1674
|
`Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)}, untested)`
|
|
1635
1675
|
);
|
|
@@ -1769,9 +1809,16 @@ var ProviderSelector = class {
|
|
|
1769
1809
|
}
|
|
1770
1810
|
/**
|
|
1771
1811
|
* Clear cached best providers (forces recalculation)
|
|
1812
|
+
* @param network - Optional network to clear cache for. If not provided, clears all networks.
|
|
1772
1813
|
*/
|
|
1773
|
-
clearCache() {
|
|
1774
|
-
|
|
1814
|
+
clearCache(network) {
|
|
1815
|
+
if (network) {
|
|
1816
|
+
this.bestProviderByNetwork.delete(network);
|
|
1817
|
+
this.activeProviderByNetwork.delete(network);
|
|
1818
|
+
} else {
|
|
1819
|
+
this.bestProviderByNetwork.clear();
|
|
1820
|
+
this.activeProviderByNetwork.clear();
|
|
1821
|
+
}
|
|
1775
1822
|
}
|
|
1776
1823
|
/**
|
|
1777
1824
|
* Update best provider after health check
|
|
@@ -1786,8 +1833,16 @@ var ProviderSelector = class {
|
|
|
1786
1833
|
if (this.bestProviderByNetwork.get(network) === providerId) {
|
|
1787
1834
|
this.bestProviderByNetwork.delete(network);
|
|
1788
1835
|
}
|
|
1836
|
+
this.activeProviderByNetwork.delete(network);
|
|
1789
1837
|
return this.getNextProvider(network, [providerId]);
|
|
1790
1838
|
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Get the currently active provider ID for a network
|
|
1841
|
+
* (the one that was last selected and is being used)
|
|
1842
|
+
*/
|
|
1843
|
+
getActiveProviderId(network) {
|
|
1844
|
+
return this.activeProviderByNetwork.get(network) || null;
|
|
1845
|
+
}
|
|
1791
1846
|
// ========================================================================
|
|
1792
1847
|
// Info
|
|
1793
1848
|
// ========================================================================
|
|
@@ -2024,6 +2079,7 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2024
2079
|
this.options.logger.warn("No providers available, using fallback");
|
|
2025
2080
|
return this.getFallbackEndpoint();
|
|
2026
2081
|
}
|
|
2082
|
+
this.selector.getActiveProviderId(this.network) || this.selector.getBestProvider(this.network);
|
|
2027
2083
|
if (provider.isDynamic && provider.type === "orbs") {
|
|
2028
2084
|
try {
|
|
2029
2085
|
const { getHttpEndpoint } = await import('@orbs-network/ton-access');
|
|
@@ -2039,9 +2095,14 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2039
2095
|
* Get endpoint with rate limiting
|
|
2040
2096
|
*
|
|
2041
2097
|
* Waits for rate limit token before returning endpoint.
|
|
2098
|
+
*
|
|
2099
|
+
* @param forceRefresh - If true, clears cache and forces re-selection
|
|
2042
2100
|
*/
|
|
2043
|
-
async getEndpointWithRateLimit(timeoutMs) {
|
|
2101
|
+
async getEndpointWithRateLimit(timeoutMs, forceRefresh = false) {
|
|
2044
2102
|
this.ensureInitialized();
|
|
2103
|
+
if (forceRefresh) {
|
|
2104
|
+
this.selector.clearCache(this.network);
|
|
2105
|
+
}
|
|
2045
2106
|
const provider = this.selector.getBestProvider(this.network);
|
|
2046
2107
|
if (!provider) {
|
|
2047
2108
|
return this.getFallbackEndpoint();
|
|
@@ -2093,15 +2154,33 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2093
2154
|
*/
|
|
2094
2155
|
reportError(error) {
|
|
2095
2156
|
if (!this.initialized || !this.network) return;
|
|
2096
|
-
const
|
|
2157
|
+
const activeProviderId = this.selector.getActiveProviderId(this.network);
|
|
2158
|
+
let provider = null;
|
|
2159
|
+
if (activeProviderId) {
|
|
2160
|
+
provider = this.registry.getProvider(activeProviderId) || null;
|
|
2161
|
+
}
|
|
2162
|
+
if (!provider) {
|
|
2163
|
+
provider = this.selector.getBestProvider(this.network);
|
|
2164
|
+
}
|
|
2097
2165
|
if (!provider) return;
|
|
2098
|
-
const errorMsg = error instanceof Error ? error.message : error;
|
|
2099
|
-
|
|
2166
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2167
|
+
const errorMsgLower = errorMsg.toLowerCase();
|
|
2168
|
+
const is429 = errorMsgLower.includes("429") || errorMsgLower.includes("rate limit");
|
|
2169
|
+
const is503 = errorMsgLower.includes("503") || errorMsgLower.includes("service unavailable");
|
|
2170
|
+
const is502 = errorMsgLower.includes("502") || errorMsgLower.includes("bad gateway");
|
|
2171
|
+
const is404 = errorMsgLower.includes("404") || errorMsgLower.includes("not found");
|
|
2172
|
+
const isTimeout = errorMsgLower.includes("timeout") || errorMsgLower.includes("abort");
|
|
2173
|
+
if (isRateLimitError(error) || is429) {
|
|
2100
2174
|
this.rateLimiter.reportRateLimitError(provider.id);
|
|
2101
2175
|
this.healthChecker.markDegraded(provider.id, this.network, errorMsg);
|
|
2176
|
+
} else if (is503 || is502 || is404 || isTimeout) {
|
|
2177
|
+
this.rateLimiter.reportError(provider.id);
|
|
2178
|
+
this.healthChecker.markOffline(provider.id, this.network, errorMsg);
|
|
2102
2179
|
} else {
|
|
2103
2180
|
this.rateLimiter.reportError(provider.id);
|
|
2181
|
+
this.healthChecker.markDegraded(provider.id, this.network, errorMsg);
|
|
2104
2182
|
}
|
|
2183
|
+
this.selector.clearCache(this.network);
|
|
2105
2184
|
this.selector.handleProviderFailure(provider.id, this.network);
|
|
2106
2185
|
this.notifyListeners();
|
|
2107
2186
|
}
|