ton-provider-system 0.1.10 → 0.1.12

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