ton-provider-system 0.1.10 → 0.1.11

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 CHANGED
@@ -217,7 +217,8 @@ function resolveProvider(id, config) {
217
217
  apiKey,
218
218
  rps: config.rps,
219
219
  priority: config.priority,
220
- isDynamic: config.isDynamic || false
220
+ isDynamic: config.isDynamic || false,
221
+ browserCompatible: config.browserCompatible !== void 0 ? config.browserCompatible : true
221
222
  };
222
223
  }
223
224
  function resolveAllProviders(config) {
@@ -776,7 +777,8 @@ var HealthChecker = class {
776
777
  latencyMs: null,
777
778
  seqno: null,
778
779
  blocksBehind: 0,
779
- lastTested: null
780
+ lastTested: null,
781
+ browserCompatible: provider.browserCompatible
780
782
  };
781
783
  this.results.set(key, testingResult);
782
784
  try {
@@ -836,7 +838,8 @@ var HealthChecker = class {
836
838
  seqno,
837
839
  blocksBehind,
838
840
  lastTested: /* @__PURE__ */ new Date(),
839
- cachedEndpoint: normalizedEndpoint
841
+ cachedEndpoint: normalizedEndpoint,
842
+ browserCompatible: provider.browserCompatible
840
843
  };
841
844
  this.results.set(key, result);
842
845
  this.logger.debug(
@@ -847,6 +850,7 @@ var HealthChecker = class {
847
850
  const endTime = performance.now();
848
851
  const latencyMs = Math.round(endTime - startTime);
849
852
  const errorMsg = error.message || String(error) || "Unknown error";
853
+ const isCorsError = this.isCorsError(error, errorMsg);
850
854
  const is429 = errorMsg.includes("429") || errorMsg.toLowerCase().includes("rate limit");
851
855
  const is404 = errorMsg.includes("404") || errorMsg.toLowerCase().includes("not found");
852
856
  const is503 = errorMsg.includes("503") || errorMsg.toLowerCase().includes("service unavailable");
@@ -861,6 +865,7 @@ var HealthChecker = class {
861
865
  } else if (isTimeout) {
862
866
  status = "offline";
863
867
  }
868
+ const browserCompatible = isCorsError ? false : provider.browserCompatible;
864
869
  const result = {
865
870
  id: provider.id,
866
871
  network: provider.network,
@@ -870,7 +875,8 @@ var HealthChecker = class {
870
875
  seqno: null,
871
876
  blocksBehind: 0,
872
877
  lastTested: /* @__PURE__ */ new Date(),
873
- error: errorMsg
878
+ error: errorMsg,
879
+ browserCompatible
874
880
  };
875
881
  this.results.set(key, result);
876
882
  this.logger.warn(`Provider ${provider.id} health check failed: ${result.error}`);
@@ -956,7 +962,8 @@ var HealthChecker = class {
956
962
  // Degraded providers are still usable, just slower/rate-limited
957
963
  status: "degraded",
958
964
  error: error || "Marked as degraded",
959
- lastTested: /* @__PURE__ */ new Date()
965
+ lastTested: /* @__PURE__ */ new Date(),
966
+ browserCompatible: existing.browserCompatible ?? true
960
967
  } : {
961
968
  id: providerId,
962
969
  network,
@@ -967,7 +974,9 @@ var HealthChecker = class {
967
974
  seqno: null,
968
975
  blocksBehind: 0,
969
976
  lastTested: /* @__PURE__ */ new Date(),
970
- error: error || "Marked as degraded"
977
+ error: error || "Marked as degraded",
978
+ browserCompatible: true
979
+ // Default to compatible if unknown
971
980
  };
972
981
  this.results.set(key, result);
973
982
  }
@@ -983,7 +992,8 @@ var HealthChecker = class {
983
992
  success: false,
984
993
  // Ensure success is false for offline providers
985
994
  error: error || "Marked as offline",
986
- lastTested: /* @__PURE__ */ new Date()
995
+ lastTested: /* @__PURE__ */ new Date(),
996
+ browserCompatible: existing.browserCompatible ?? true
987
997
  } : {
988
998
  id: providerId,
989
999
  network,
@@ -993,7 +1003,9 @@ var HealthChecker = class {
993
1003
  seqno: null,
994
1004
  blocksBehind: 0,
995
1005
  lastTested: /* @__PURE__ */ new Date(),
996
- error: error || "Marked as offline"
1006
+ error: error || "Marked as offline",
1007
+ browserCompatible: true
1008
+ // Default to compatible if unknown
997
1009
  };
998
1010
  this.results.set(key, result);
999
1011
  }
@@ -1125,6 +1137,24 @@ var HealthChecker = class {
1125
1137
  sleep(ms) {
1126
1138
  return new Promise((resolve) => setTimeout(resolve, ms));
1127
1139
  }
1140
+ /**
1141
+ * Detect CORS errors (browser compatibility issues)
1142
+ *
1143
+ * CORS errors occur when:
1144
+ * - Request header field is not allowed by Access-Control-Allow-Headers
1145
+ * - Specifically, x-ton-client-version header is blocked by some providers
1146
+ * - Error message contains "CORS", "Access-Control", or "x-ton-client-version"
1147
+ */
1148
+ isCorsError(error, errorMsg) {
1149
+ const msg = errorMsg.toLowerCase();
1150
+ if (msg.includes("cors") || msg.includes("access-control") || msg.includes("x-ton-client-version") || msg.includes("not allowed by access-control-allow-headers") || msg.includes("blocked by cors policy")) {
1151
+ return true;
1152
+ }
1153
+ if (error.name === "TypeError" && (msg.includes("failed to fetch") || msg.includes("network error"))) {
1154
+ return false;
1155
+ }
1156
+ return false;
1157
+ }
1128
1158
  };
1129
1159
  function createHealthChecker(config, logger, rateLimiter) {
1130
1160
  return new HealthChecker(config, logger, rateLimiter);
@@ -1569,7 +1599,7 @@ var DEFAULT_CONFIG2 = {
1569
1599
  minStatus: ["available", "degraded"]
1570
1600
  };
1571
1601
  var ProviderSelector = class {
1572
- constructor(registry, healthChecker, config, logger) {
1602
+ constructor(registry, healthChecker, config, logger, adapter = "node") {
1573
1603
  // Selection state
1574
1604
  this.selectedProviderId = null;
1575
1605
  this.autoSelect = true;
@@ -1581,6 +1611,7 @@ var ProviderSelector = class {
1581
1611
  this.healthChecker = healthChecker;
1582
1612
  this.config = { ...DEFAULT_CONFIG2, ...config };
1583
1613
  this.logger = logger || consoleLogger4;
1614
+ this.adapter = adapter;
1584
1615
  }
1585
1616
  // ========================================================================
1586
1617
  // Selection Methods
@@ -1621,9 +1652,19 @@ var ProviderSelector = class {
1621
1652
  * Find the best provider for a network (recalculates)
1622
1653
  */
1623
1654
  findBestProvider(network) {
1624
- const providers = this.registry.getProvidersForNetwork(network);
1655
+ let providers = this.registry.getProvidersForNetwork(network);
1656
+ if (this.adapter === "browser") {
1657
+ const beforeCount = providers.length;
1658
+ providers = this.filterBrowserCompatible(providers, network);
1659
+ const filteredCount = beforeCount - providers.length;
1660
+ if (filteredCount > 0) {
1661
+ this.logger.debug(
1662
+ `Filtered out ${filteredCount} browser-incompatible provider(s) for ${network}`
1663
+ );
1664
+ }
1665
+ }
1625
1666
  if (providers.length === 0) {
1626
- this.logger.warn(`No providers available for ${network}`);
1667
+ this.logger.warn(`No browser-compatible providers available for ${network}`);
1627
1668
  return null;
1628
1669
  }
1629
1670
  const scored = providers.map((provider) => ({
@@ -1704,7 +1745,10 @@ var ProviderSelector = class {
1704
1745
  * Get all available providers for a network, sorted by score
1705
1746
  */
1706
1747
  getAvailableProviders(network) {
1707
- const providers = this.registry.getProvidersForNetwork(network);
1748
+ let providers = this.registry.getProvidersForNetwork(network);
1749
+ if (this.adapter === "browser") {
1750
+ providers = this.filterBrowserCompatible(providers, network);
1751
+ }
1708
1752
  return providers.map((provider) => ({
1709
1753
  provider,
1710
1754
  score: this.scoreProvider(provider, network)
@@ -1714,7 +1758,10 @@ var ProviderSelector = class {
1714
1758
  * Get the next best provider (for failover)
1715
1759
  */
1716
1760
  getNextProvider(network, excludeIds) {
1717
- const providers = this.registry.getProvidersForNetwork(network);
1761
+ let providers = this.registry.getProvidersForNetwork(network);
1762
+ if (this.adapter === "browser") {
1763
+ providers = this.filterBrowserCompatible(providers, network);
1764
+ }
1718
1765
  const available = providers.filter((p) => !excludeIds.includes(p.id)).map((provider) => ({
1719
1766
  provider,
1720
1767
  score: this.scoreProvider(provider, network)
@@ -1905,12 +1952,39 @@ var ProviderSelector = class {
1905
1952
  endpointV2: this.customEndpoint,
1906
1953
  rps: 10,
1907
1954
  priority: 0,
1908
- isDynamic: false
1955
+ isDynamic: false,
1956
+ browserCompatible: true
1957
+ // Custom endpoints are assumed compatible
1909
1958
  };
1910
1959
  }
1960
+ /**
1961
+ * Filter providers to only include browser-compatible ones
1962
+ *
1963
+ * Checks both:
1964
+ * 1. Provider config browserCompatible flag
1965
+ * 2. Health check result browserCompatible flag (if health check was performed)
1966
+ */
1967
+ filterBrowserCompatible(providers, network) {
1968
+ return providers.filter((provider) => {
1969
+ if (!provider.browserCompatible) {
1970
+ this.logger.debug(
1971
+ `Provider ${provider.id} marked as browser-incompatible in config`
1972
+ );
1973
+ return false;
1974
+ }
1975
+ const health = this.healthChecker.getResult(provider.id, network);
1976
+ if (health && health.browserCompatible === false) {
1977
+ this.logger.debug(
1978
+ `Provider ${provider.id} marked as browser-incompatible by health check (CORS error detected)`
1979
+ );
1980
+ return false;
1981
+ }
1982
+ return true;
1983
+ });
1984
+ }
1911
1985
  };
1912
- function createSelector(registry, healthChecker, config, logger) {
1913
- return new ProviderSelector(registry, healthChecker, config, logger);
1986
+ function createSelector(registry, healthChecker, config, logger, adapter = "node") {
1987
+ return new ProviderSelector(registry, healthChecker, config, logger, adapter);
1914
1988
  }
1915
1989
 
1916
1990
  // src/core/manager.ts
@@ -2017,7 +2091,8 @@ var _ProviderManager = class _ProviderManager {
2017
2091
  this.registry,
2018
2092
  this.healthChecker,
2019
2093
  void 0,
2020
- this.options.logger
2094
+ this.options.logger,
2095
+ this.options.adapter
2021
2096
  );
2022
2097
  this.initialized = true;
2023
2098
  this.notifyListeners();
@@ -2284,7 +2359,20 @@ var _ProviderManager = class _ProviderManager {
2284
2359
  */
2285
2360
  getProviders() {
2286
2361
  if (!this.initialized || !this.network) return [];
2287
- return this.registry.getProvidersForNetwork(this.network);
2362
+ let providers = this.registry.getProvidersForNetwork(this.network);
2363
+ if (this.options.adapter === "browser") {
2364
+ providers = providers.filter((provider) => {
2365
+ if (!provider.browserCompatible) {
2366
+ return false;
2367
+ }
2368
+ const health = this.healthChecker.getResult(provider.id, this.network);
2369
+ if (health && health.browserCompatible === false) {
2370
+ return false;
2371
+ }
2372
+ return true;
2373
+ });
2374
+ }
2375
+ return providers;
2288
2376
  }
2289
2377
  /**
2290
2378
  * Get provider health results for current network
@@ -2330,7 +2418,8 @@ var _ProviderManager = class _ProviderManager {
2330
2418
  latencyMs: null,
2331
2419
  seqno: null,
2332
2420
  blocksBehind: 0,
2333
- lastTested: null
2421
+ lastTested: null,
2422
+ browserCompatible: provider.browserCompatible
2334
2423
  },
2335
2424
  rateLimit: rateLimit || {
2336
2425
  tokens: 0,