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.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
@@ -949,13 +949,16 @@ var HealthChecker = class {
949
949
  const existing = this.results.get(key);
950
950
  const result = existing ? {
951
951
  ...existing,
952
+ success: true,
953
+ // Degraded providers are still usable, just slower/rate-limited
952
954
  status: "degraded",
953
955
  error: error || "Marked as degraded",
954
956
  lastTested: /* @__PURE__ */ new Date()
955
957
  } : {
956
958
  id: providerId,
957
959
  network,
958
- success: false,
960
+ success: true,
961
+ // Degraded providers are still usable
959
962
  status: "degraded",
960
963
  latencyMs: null,
961
964
  seqno: null,
@@ -1569,6 +1572,8 @@ var ProviderSelector = class {
1569
1572
  this.autoSelect = true;
1570
1573
  this.customEndpoint = null;
1571
1574
  this.bestProviderByNetwork = /* @__PURE__ */ new Map();
1575
+ // Track currently active provider per network (the one actually being used)
1576
+ this.activeProviderByNetwork = /* @__PURE__ */ new Map();
1572
1577
  this.registry = registry;
1573
1578
  this.healthChecker = healthChecker;
1574
1579
  this.config = { ...DEFAULT_CONFIG2, ...config };
@@ -1587,6 +1592,7 @@ var ProviderSelector = class {
1587
1592
  if (!this.autoSelect && this.selectedProviderId) {
1588
1593
  const provider = this.registry.getProvider(this.selectedProviderId);
1589
1594
  if (provider && provider.network === network) {
1595
+ this.activeProviderByNetwork.set(network, provider.id);
1590
1596
  return provider;
1591
1597
  }
1592
1598
  this.logger.warn(
@@ -1597,8 +1603,13 @@ var ProviderSelector = class {
1597
1603
  if (cachedBestId) {
1598
1604
  const cached = this.registry.getProvider(cachedBestId);
1599
1605
  const health = this.healthChecker.getResult(cachedBestId, network);
1600
- if (cached && health && health.success !== false && this.config.minStatus.includes(health.status)) {
1606
+ if (cached && health && health.success !== false && health.success !== void 0 && // Explicitly check for undefined
1607
+ this.config.minStatus.includes(health.status)) {
1608
+ this.activeProviderByNetwork.set(network, cachedBestId);
1601
1609
  return cached;
1610
+ } else {
1611
+ this.bestProviderByNetwork.delete(network);
1612
+ this.activeProviderByNetwork.delete(network);
1602
1613
  }
1603
1614
  }
1604
1615
  return this.findBestProvider(network);
@@ -1620,12 +1631,31 @@ var ProviderSelector = class {
1620
1631
  const defaults = this.registry.getDefaultOrderForNetwork(network);
1621
1632
  for (const defaultProvider of defaults) {
1622
1633
  const health = this.healthChecker.getResult(defaultProvider.id, network);
1623
- if (!health || health.status === "untested" || health.success === true) {
1634
+ if (!health || health.status === "untested") {
1635
+ this.logger.warn(
1636
+ `No healthy providers for ${network}, using untested default: ${defaultProvider.id}`
1637
+ );
1638
+ this.activeProviderByNetwork.set(network, defaultProvider.id);
1639
+ return defaultProvider;
1640
+ }
1641
+ if (health.success === true) {
1624
1642
  this.logger.warn(
1625
1643
  `No healthy providers for ${network}, using default: ${defaultProvider.id}`
1626
1644
  );
1645
+ this.activeProviderByNetwork.set(network, defaultProvider.id);
1627
1646
  return defaultProvider;
1628
1647
  }
1648
+ if (health.success === false && health.lastTested) {
1649
+ const timeSinceFailure = Date.now() - health.lastTested.getTime();
1650
+ const cooldownMs = 3e4;
1651
+ if (timeSinceFailure > cooldownMs) {
1652
+ this.logger.warn(
1653
+ `No healthy providers for ${network}, retrying failed default after cooldown: ${defaultProvider.id}`
1654
+ );
1655
+ this.activeProviderByNetwork.set(network, defaultProvider.id);
1656
+ return defaultProvider;
1657
+ }
1658
+ }
1629
1659
  }
1630
1660
  for (const provider of providers) {
1631
1661
  const health = this.healthChecker.getResult(provider.id, network);
@@ -1633,20 +1663,34 @@ var ProviderSelector = class {
1633
1663
  this.logger.warn(
1634
1664
  `No tested healthy providers for ${network}, using untested: ${provider.id}`
1635
1665
  );
1666
+ this.activeProviderByNetwork.set(network, provider.id);
1636
1667
  return provider;
1637
1668
  }
1669
+ if (health.success === false && health.lastTested) {
1670
+ const timeSinceFailure = Date.now() - health.lastTested.getTime();
1671
+ const cooldownMs = 3e4;
1672
+ if (timeSinceFailure > cooldownMs) {
1673
+ this.logger.warn(
1674
+ `No healthy providers for ${network}, retrying failed provider after cooldown: ${provider.id}`
1675
+ );
1676
+ this.activeProviderByNetwork.set(network, provider.id);
1677
+ return provider;
1678
+ }
1679
+ }
1638
1680
  }
1639
- this.logger.error(`No available providers for ${network} (all tested and failed)`);
1681
+ this.logger.error(`No available providers for ${network} (all tested and failed, cooldown active)`);
1640
1682
  return null;
1641
1683
  }
1642
1684
  const best = scored[0].provider;
1643
1685
  const bestHealth = this.healthChecker.getResult(best.id, network);
1644
1686
  if (bestHealth && bestHealth.success === true) {
1645
1687
  this.bestProviderByNetwork.set(network, best.id);
1688
+ this.activeProviderByNetwork.set(network, best.id);
1646
1689
  this.logger.debug(
1647
1690
  `Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)})`
1648
1691
  );
1649
1692
  } else {
1693
+ this.activeProviderByNetwork.set(network, best.id);
1650
1694
  this.logger.debug(
1651
1695
  `Best provider for ${network}: ${best.id} (score: ${scored[0].score.toFixed(2)}, untested)`
1652
1696
  );
@@ -1689,6 +1733,13 @@ var ProviderSelector = class {
1689
1733
  return 0.01 * (1 / (provider.priority + 1));
1690
1734
  }
1691
1735
  if (health.success === false) {
1736
+ if (health.lastTested) {
1737
+ const timeSinceFailure = Date.now() - health.lastTested.getTime();
1738
+ const cooldownMs = 3e4;
1739
+ if (timeSinceFailure > cooldownMs) {
1740
+ return 1e-3 * (1 / (provider.priority + 1));
1741
+ }
1742
+ }
1692
1743
  return 0;
1693
1744
  }
1694
1745
  if (health.status === "offline") {
@@ -1786,9 +1837,16 @@ var ProviderSelector = class {
1786
1837
  }
1787
1838
  /**
1788
1839
  * Clear cached best providers (forces recalculation)
1840
+ * @param network - Optional network to clear cache for. If not provided, clears all networks.
1789
1841
  */
1790
- clearCache() {
1791
- this.bestProviderByNetwork.clear();
1842
+ clearCache(network) {
1843
+ if (network) {
1844
+ this.bestProviderByNetwork.delete(network);
1845
+ this.activeProviderByNetwork.delete(network);
1846
+ } else {
1847
+ this.bestProviderByNetwork.clear();
1848
+ this.activeProviderByNetwork.clear();
1849
+ }
1792
1850
  }
1793
1851
  /**
1794
1852
  * Update best provider after health check
@@ -1803,8 +1861,16 @@ var ProviderSelector = class {
1803
1861
  if (this.bestProviderByNetwork.get(network) === providerId) {
1804
1862
  this.bestProviderByNetwork.delete(network);
1805
1863
  }
1864
+ this.activeProviderByNetwork.delete(network);
1806
1865
  return this.getNextProvider(network, [providerId]);
1807
1866
  }
1867
+ /**
1868
+ * Get the currently active provider ID for a network
1869
+ * (the one that was last selected and is being used)
1870
+ */
1871
+ getActiveProviderId(network) {
1872
+ return this.activeProviderByNetwork.get(network) || null;
1873
+ }
1808
1874
  // ========================================================================
1809
1875
  // Info
1810
1876
  // ========================================================================
@@ -2041,6 +2107,7 @@ var _ProviderManager = class _ProviderManager {
2041
2107
  this.options.logger.warn("No providers available, using fallback");
2042
2108
  return this.getFallbackEndpoint();
2043
2109
  }
2110
+ this.selector.getActiveProviderId(this.network) || this.selector.getBestProvider(this.network);
2044
2111
  if (provider.isDynamic && provider.type === "orbs") {
2045
2112
  try {
2046
2113
  const { getHttpEndpoint } = await import('@orbs-network/ton-access');
@@ -2056,9 +2123,14 @@ var _ProviderManager = class _ProviderManager {
2056
2123
  * Get endpoint with rate limiting
2057
2124
  *
2058
2125
  * Waits for rate limit token before returning endpoint.
2126
+ *
2127
+ * @param forceRefresh - If true, clears cache and forces re-selection
2059
2128
  */
2060
- async getEndpointWithRateLimit(timeoutMs) {
2129
+ async getEndpointWithRateLimit(timeoutMs, forceRefresh = false) {
2061
2130
  this.ensureInitialized();
2131
+ if (forceRefresh) {
2132
+ this.selector.clearCache(this.network);
2133
+ }
2062
2134
  const provider = this.selector.getBestProvider(this.network);
2063
2135
  if (!provider) {
2064
2136
  return this.getFallbackEndpoint();
@@ -2110,7 +2182,14 @@ var _ProviderManager = class _ProviderManager {
2110
2182
  */
2111
2183
  reportError(error) {
2112
2184
  if (!this.initialized || !this.network) return;
2113
- const provider = this.selector.getBestProvider(this.network);
2185
+ const activeProviderId = this.selector.getActiveProviderId(this.network);
2186
+ let provider = null;
2187
+ if (activeProviderId) {
2188
+ provider = this.registry.getProvider(activeProviderId) || null;
2189
+ }
2190
+ if (!provider) {
2191
+ provider = this.selector.getBestProvider(this.network);
2192
+ }
2114
2193
  if (!provider) return;
2115
2194
  const errorMsg = error instanceof Error ? error.message : String(error);
2116
2195
  const errorMsgLower = errorMsg.toLowerCase();
@@ -2129,6 +2208,7 @@ var _ProviderManager = class _ProviderManager {
2129
2208
  this.rateLimiter.reportError(provider.id);
2130
2209
  this.healthChecker.markDegraded(provider.id, this.network, errorMsg);
2131
2210
  }
2211
+ this.selector.clearCache(this.network);
2132
2212
  this.selector.handleProviderFailure(provider.id, this.network);
2133
2213
  this.notifyListeners();
2134
2214
  }