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.d.cts
CHANGED
|
@@ -1082,6 +1082,7 @@ declare class ProviderSelector {
|
|
|
1082
1082
|
private autoSelect;
|
|
1083
1083
|
private customEndpoint;
|
|
1084
1084
|
private bestProviderByNetwork;
|
|
1085
|
+
private activeProviderByNetwork;
|
|
1085
1086
|
constructor(registry: ProviderRegistry, healthChecker: HealthChecker, config?: Partial<SelectionConfig>, logger?: Logger);
|
|
1086
1087
|
/**
|
|
1087
1088
|
* Get the best provider for a network
|
|
@@ -1137,8 +1138,9 @@ declare class ProviderSelector {
|
|
|
1137
1138
|
isUsingCustomEndpoint(): boolean;
|
|
1138
1139
|
/**
|
|
1139
1140
|
* Clear cached best providers (forces recalculation)
|
|
1141
|
+
* @param network - Optional network to clear cache for. If not provided, clears all networks.
|
|
1140
1142
|
*/
|
|
1141
|
-
clearCache(): void;
|
|
1143
|
+
clearCache(network?: Network): void;
|
|
1142
1144
|
/**
|
|
1143
1145
|
* Update best provider after health check
|
|
1144
1146
|
*/
|
|
@@ -1147,6 +1149,11 @@ declare class ProviderSelector {
|
|
|
1147
1149
|
* Handle provider failure (switch to next best)
|
|
1148
1150
|
*/
|
|
1149
1151
|
handleProviderFailure(providerId: string, network: Network): ResolvedProvider | null;
|
|
1152
|
+
/**
|
|
1153
|
+
* Get the currently active provider ID for a network
|
|
1154
|
+
* (the one that was last selected and is being used)
|
|
1155
|
+
*/
|
|
1156
|
+
getActiveProviderId(network: Network): string | null;
|
|
1150
1157
|
/**
|
|
1151
1158
|
* Get active provider info
|
|
1152
1159
|
*/
|
|
@@ -1248,8 +1255,10 @@ declare class ProviderManager {
|
|
|
1248
1255
|
* Get endpoint with rate limiting
|
|
1249
1256
|
*
|
|
1250
1257
|
* Waits for rate limit token before returning endpoint.
|
|
1258
|
+
*
|
|
1259
|
+
* @param forceRefresh - If true, clears cache and forces re-selection
|
|
1251
1260
|
*/
|
|
1252
|
-
getEndpointWithRateLimit(timeoutMs?: number): Promise<string>;
|
|
1261
|
+
getEndpointWithRateLimit(timeoutMs?: number, forceRefresh?: boolean): Promise<string>;
|
|
1253
1262
|
/**
|
|
1254
1263
|
* Get current active provider
|
|
1255
1264
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1082,6 +1082,7 @@ declare class ProviderSelector {
|
|
|
1082
1082
|
private autoSelect;
|
|
1083
1083
|
private customEndpoint;
|
|
1084
1084
|
private bestProviderByNetwork;
|
|
1085
|
+
private activeProviderByNetwork;
|
|
1085
1086
|
constructor(registry: ProviderRegistry, healthChecker: HealthChecker, config?: Partial<SelectionConfig>, logger?: Logger);
|
|
1086
1087
|
/**
|
|
1087
1088
|
* Get the best provider for a network
|
|
@@ -1137,8 +1138,9 @@ declare class ProviderSelector {
|
|
|
1137
1138
|
isUsingCustomEndpoint(): boolean;
|
|
1138
1139
|
/**
|
|
1139
1140
|
* Clear cached best providers (forces recalculation)
|
|
1141
|
+
* @param network - Optional network to clear cache for. If not provided, clears all networks.
|
|
1140
1142
|
*/
|
|
1141
|
-
clearCache(): void;
|
|
1143
|
+
clearCache(network?: Network): void;
|
|
1142
1144
|
/**
|
|
1143
1145
|
* Update best provider after health check
|
|
1144
1146
|
*/
|
|
@@ -1147,6 +1149,11 @@ declare class ProviderSelector {
|
|
|
1147
1149
|
* Handle provider failure (switch to next best)
|
|
1148
1150
|
*/
|
|
1149
1151
|
handleProviderFailure(providerId: string, network: Network): ResolvedProvider | null;
|
|
1152
|
+
/**
|
|
1153
|
+
* Get the currently active provider ID for a network
|
|
1154
|
+
* (the one that was last selected and is being used)
|
|
1155
|
+
*/
|
|
1156
|
+
getActiveProviderId(network: Network): string | null;
|
|
1150
1157
|
/**
|
|
1151
1158
|
* Get active provider info
|
|
1152
1159
|
*/
|
|
@@ -1248,8 +1255,10 @@ declare class ProviderManager {
|
|
|
1248
1255
|
* Get endpoint with rate limiting
|
|
1249
1256
|
*
|
|
1250
1257
|
* Waits for rate limit token before returning endpoint.
|
|
1258
|
+
*
|
|
1259
|
+
* @param forceRefresh - If true, clears cache and forces re-selection
|
|
1251
1260
|
*/
|
|
1252
|
-
getEndpointWithRateLimit(timeoutMs?: number): Promise<string>;
|
|
1261
|
+
getEndpointWithRateLimit(timeoutMs?: number, forceRefresh?: boolean): Promise<string>;
|
|
1253
1262
|
/**
|
|
1254
1263
|
* Get current active provider
|
|
1255
1264
|
*/
|
package/dist/index.js
CHANGED
|
@@ -947,14 +947,25 @@ var HealthChecker = class {
|
|
|
947
947
|
markDegraded(providerId, network, error) {
|
|
948
948
|
const key = this.getResultKey(providerId, network);
|
|
949
949
|
const existing = this.results.get(key);
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
}
|
|
950
|
+
const result = existing ? {
|
|
951
|
+
...existing,
|
|
952
|
+
success: false,
|
|
953
|
+
// CRITICAL: Always set success: false for degraded providers
|
|
954
|
+
status: "degraded",
|
|
955
|
+
error: error || "Marked as degraded",
|
|
956
|
+
lastTested: /* @__PURE__ */ new Date()
|
|
957
|
+
} : {
|
|
958
|
+
id: providerId,
|
|
959
|
+
network,
|
|
960
|
+
success: false,
|
|
961
|
+
status: "degraded",
|
|
962
|
+
latencyMs: null,
|
|
963
|
+
seqno: null,
|
|
964
|
+
blocksBehind: 0,
|
|
965
|
+
lastTested: /* @__PURE__ */ new Date(),
|
|
966
|
+
error: error || "Marked as degraded"
|
|
967
|
+
};
|
|
968
|
+
this.results.set(key, result);
|
|
958
969
|
}
|
|
959
970
|
/**
|
|
960
971
|
* Mark a provider as offline
|
|
@@ -962,14 +973,25 @@ var HealthChecker = class {
|
|
|
962
973
|
markOffline(providerId, network, error) {
|
|
963
974
|
const key = this.getResultKey(providerId, network);
|
|
964
975
|
const existing = this.results.get(key);
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
}
|
|
976
|
+
const result = existing ? {
|
|
977
|
+
...existing,
|
|
978
|
+
status: "offline",
|
|
979
|
+
success: false,
|
|
980
|
+
// Ensure success is false for offline providers
|
|
981
|
+
error: error || "Marked as offline",
|
|
982
|
+
lastTested: /* @__PURE__ */ new Date()
|
|
983
|
+
} : {
|
|
984
|
+
id: providerId,
|
|
985
|
+
network,
|
|
986
|
+
success: false,
|
|
987
|
+
status: "offline",
|
|
988
|
+
latencyMs: null,
|
|
989
|
+
seqno: null,
|
|
990
|
+
blocksBehind: 0,
|
|
991
|
+
lastTested: /* @__PURE__ */ new Date(),
|
|
992
|
+
error: error || "Marked as offline"
|
|
993
|
+
};
|
|
994
|
+
this.results.set(key, result);
|
|
973
995
|
}
|
|
974
996
|
// ========================================================================
|
|
975
997
|
// Private Methods
|
|
@@ -1549,6 +1571,8 @@ var ProviderSelector = class {
|
|
|
1549
1571
|
this.autoSelect = true;
|
|
1550
1572
|
this.customEndpoint = null;
|
|
1551
1573
|
this.bestProviderByNetwork = /* @__PURE__ */ new Map();
|
|
1574
|
+
// Track currently active provider per network (the one actually being used)
|
|
1575
|
+
this.activeProviderByNetwork = /* @__PURE__ */ new Map();
|
|
1552
1576
|
this.registry = registry;
|
|
1553
1577
|
this.healthChecker = healthChecker;
|
|
1554
1578
|
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
@@ -1567,6 +1591,7 @@ var ProviderSelector = class {
|
|
|
1567
1591
|
if (!this.autoSelect && this.selectedProviderId) {
|
|
1568
1592
|
const provider = this.registry.getProvider(this.selectedProviderId);
|
|
1569
1593
|
if (provider && provider.network === network) {
|
|
1594
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1570
1595
|
return provider;
|
|
1571
1596
|
}
|
|
1572
1597
|
this.logger.warn(
|
|
@@ -1577,8 +1602,13 @@ var ProviderSelector = class {
|
|
|
1577
1602
|
if (cachedBestId) {
|
|
1578
1603
|
const cached = this.registry.getProvider(cachedBestId);
|
|
1579
1604
|
const health = this.healthChecker.getResult(cachedBestId, network);
|
|
1580
|
-
if (cached && health && health.success !== false &&
|
|
1605
|
+
if (cached && health && health.success !== false && health.success !== void 0 && // Explicitly check for undefined
|
|
1606
|
+
this.config.minStatus.includes(health.status)) {
|
|
1607
|
+
this.activeProviderByNetwork.set(network, cachedBestId);
|
|
1581
1608
|
return cached;
|
|
1609
|
+
} else {
|
|
1610
|
+
this.bestProviderByNetwork.delete(network);
|
|
1611
|
+
this.activeProviderByNetwork.delete(network);
|
|
1582
1612
|
}
|
|
1583
1613
|
}
|
|
1584
1614
|
return this.findBestProvider(network);
|
|
@@ -1600,10 +1630,17 @@ var ProviderSelector = class {
|
|
|
1600
1630
|
const defaults = this.registry.getDefaultOrderForNetwork(network);
|
|
1601
1631
|
for (const defaultProvider of defaults) {
|
|
1602
1632
|
const health = this.healthChecker.getResult(defaultProvider.id, network);
|
|
1603
|
-
if (!health || health.status === "untested"
|
|
1633
|
+
if (!health || health.status === "untested") {
|
|
1634
|
+
this.logger.warn(
|
|
1635
|
+
`No healthy providers for ${network}, using untested default: ${defaultProvider.id}`
|
|
1636
|
+
);
|
|
1637
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1638
|
+
return defaultProvider;
|
|
1639
|
+
} else if (health.success === true) {
|
|
1604
1640
|
this.logger.warn(
|
|
1605
1641
|
`No healthy providers for ${network}, using default: ${defaultProvider.id}`
|
|
1606
1642
|
);
|
|
1643
|
+
this.activeProviderByNetwork.set(network, defaultProvider.id);
|
|
1607
1644
|
return defaultProvider;
|
|
1608
1645
|
}
|
|
1609
1646
|
}
|
|
@@ -1613,6 +1650,7 @@ var ProviderSelector = class {
|
|
|
1613
1650
|
this.logger.warn(
|
|
1614
1651
|
`No tested healthy providers for ${network}, using untested: ${provider.id}`
|
|
1615
1652
|
);
|
|
1653
|
+
this.activeProviderByNetwork.set(network, provider.id);
|
|
1616
1654
|
return provider;
|
|
1617
1655
|
}
|
|
1618
1656
|
}
|
|
@@ -1623,10 +1661,12 @@ var ProviderSelector = class {
|
|
|
1623
1661
|
const bestHealth = this.healthChecker.getResult(best.id, network);
|
|
1624
1662
|
if (bestHealth && bestHealth.success === true) {
|
|
1625
1663
|
this.bestProviderByNetwork.set(network, best.id);
|
|
1664
|
+
this.activeProviderByNetwork.set(network, best.id);
|
|
1626
1665
|
this.logger.debug(
|
|
1627
1666
|
`Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)})`
|
|
1628
1667
|
);
|
|
1629
1668
|
} else {
|
|
1669
|
+
this.activeProviderByNetwork.set(network, best.id);
|
|
1630
1670
|
this.logger.debug(
|
|
1631
1671
|
`Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)}, untested)`
|
|
1632
1672
|
);
|
|
@@ -1766,9 +1806,16 @@ var ProviderSelector = class {
|
|
|
1766
1806
|
}
|
|
1767
1807
|
/**
|
|
1768
1808
|
* Clear cached best providers (forces recalculation)
|
|
1809
|
+
* @param network - Optional network to clear cache for. If not provided, clears all networks.
|
|
1769
1810
|
*/
|
|
1770
|
-
clearCache() {
|
|
1771
|
-
|
|
1811
|
+
clearCache(network) {
|
|
1812
|
+
if (network) {
|
|
1813
|
+
this.bestProviderByNetwork.delete(network);
|
|
1814
|
+
this.activeProviderByNetwork.delete(network);
|
|
1815
|
+
} else {
|
|
1816
|
+
this.bestProviderByNetwork.clear();
|
|
1817
|
+
this.activeProviderByNetwork.clear();
|
|
1818
|
+
}
|
|
1772
1819
|
}
|
|
1773
1820
|
/**
|
|
1774
1821
|
* Update best provider after health check
|
|
@@ -1783,8 +1830,16 @@ var ProviderSelector = class {
|
|
|
1783
1830
|
if (this.bestProviderByNetwork.get(network) === providerId) {
|
|
1784
1831
|
this.bestProviderByNetwork.delete(network);
|
|
1785
1832
|
}
|
|
1833
|
+
this.activeProviderByNetwork.delete(network);
|
|
1786
1834
|
return this.getNextProvider(network, [providerId]);
|
|
1787
1835
|
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Get the currently active provider ID for a network
|
|
1838
|
+
* (the one that was last selected and is being used)
|
|
1839
|
+
*/
|
|
1840
|
+
getActiveProviderId(network) {
|
|
1841
|
+
return this.activeProviderByNetwork.get(network) || null;
|
|
1842
|
+
}
|
|
1788
1843
|
// ========================================================================
|
|
1789
1844
|
// Info
|
|
1790
1845
|
// ========================================================================
|
|
@@ -2021,6 +2076,7 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2021
2076
|
this.options.logger.warn("No providers available, using fallback");
|
|
2022
2077
|
return this.getFallbackEndpoint();
|
|
2023
2078
|
}
|
|
2079
|
+
this.selector.getActiveProviderId(this.network) || this.selector.getBestProvider(this.network);
|
|
2024
2080
|
if (provider.isDynamic && provider.type === "orbs") {
|
|
2025
2081
|
try {
|
|
2026
2082
|
const { getHttpEndpoint } = await import('@orbs-network/ton-access');
|
|
@@ -2036,9 +2092,14 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2036
2092
|
* Get endpoint with rate limiting
|
|
2037
2093
|
*
|
|
2038
2094
|
* Waits for rate limit token before returning endpoint.
|
|
2095
|
+
*
|
|
2096
|
+
* @param forceRefresh - If true, clears cache and forces re-selection
|
|
2039
2097
|
*/
|
|
2040
|
-
async getEndpointWithRateLimit(timeoutMs) {
|
|
2098
|
+
async getEndpointWithRateLimit(timeoutMs, forceRefresh = false) {
|
|
2041
2099
|
this.ensureInitialized();
|
|
2100
|
+
if (forceRefresh) {
|
|
2101
|
+
this.selector.clearCache(this.network);
|
|
2102
|
+
}
|
|
2042
2103
|
const provider = this.selector.getBestProvider(this.network);
|
|
2043
2104
|
if (!provider) {
|
|
2044
2105
|
return this.getFallbackEndpoint();
|
|
@@ -2090,15 +2151,33 @@ var _ProviderManager = class _ProviderManager {
|
|
|
2090
2151
|
*/
|
|
2091
2152
|
reportError(error) {
|
|
2092
2153
|
if (!this.initialized || !this.network) return;
|
|
2093
|
-
const
|
|
2154
|
+
const activeProviderId = this.selector.getActiveProviderId(this.network);
|
|
2155
|
+
let provider = null;
|
|
2156
|
+
if (activeProviderId) {
|
|
2157
|
+
provider = this.registry.getProvider(activeProviderId) || null;
|
|
2158
|
+
}
|
|
2159
|
+
if (!provider) {
|
|
2160
|
+
provider = this.selector.getBestProvider(this.network);
|
|
2161
|
+
}
|
|
2094
2162
|
if (!provider) return;
|
|
2095
|
-
const errorMsg = error instanceof Error ? error.message : error;
|
|
2096
|
-
|
|
2163
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2164
|
+
const errorMsgLower = errorMsg.toLowerCase();
|
|
2165
|
+
const is429 = errorMsgLower.includes("429") || errorMsgLower.includes("rate limit");
|
|
2166
|
+
const is503 = errorMsgLower.includes("503") || errorMsgLower.includes("service unavailable");
|
|
2167
|
+
const is502 = errorMsgLower.includes("502") || errorMsgLower.includes("bad gateway");
|
|
2168
|
+
const is404 = errorMsgLower.includes("404") || errorMsgLower.includes("not found");
|
|
2169
|
+
const isTimeout = errorMsgLower.includes("timeout") || errorMsgLower.includes("abort");
|
|
2170
|
+
if (isRateLimitError(error) || is429) {
|
|
2097
2171
|
this.rateLimiter.reportRateLimitError(provider.id);
|
|
2098
2172
|
this.healthChecker.markDegraded(provider.id, this.network, errorMsg);
|
|
2173
|
+
} else if (is503 || is502 || is404 || isTimeout) {
|
|
2174
|
+
this.rateLimiter.reportError(provider.id);
|
|
2175
|
+
this.healthChecker.markOffline(provider.id, this.network, errorMsg);
|
|
2099
2176
|
} else {
|
|
2100
2177
|
this.rateLimiter.reportError(provider.id);
|
|
2178
|
+
this.healthChecker.markDegraded(provider.id, this.network, errorMsg);
|
|
2101
2179
|
}
|
|
2180
|
+
this.selector.clearCache(this.network);
|
|
2102
2181
|
this.selector.handleProviderFailure(provider.id, this.network);
|
|
2103
2182
|
this.notifyListeners();
|
|
2104
2183
|
}
|