ton-provider-system 0.3.0 → 0.4.0

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
@@ -2,6 +2,7 @@
2
2
 
3
3
  var zod = require('zod');
4
4
  var ton = require('@ton/ton');
5
+ var core = require('@ton/core');
5
6
 
6
7
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
7
8
  // src/types.ts
@@ -324,7 +325,13 @@ var DEFAULT_PROVIDERS = {
324
325
  },
325
326
  rps: 1,
326
327
  // Without API key
327
- priority: 100,
328
+ // Preferred on testnet: Toncenter serves the full v2 surface incl.
329
+ // getTransactions (curl-proven 200). Orbs only proxies liteserver
330
+ // get-methods/state and 403s on getTransactions, so it must NOT be the
331
+ // primary testnet provider (it stays a fallback for get-method reads).
332
+ // Selection is score-based and priority is the lever (lower = better),
333
+ // so this gives Toncenter the testnet edge over Orbs (priority 90).
334
+ priority: 10,
328
335
  enabled: true,
329
336
  description: "Official TON Center public endpoint"
330
337
  },
@@ -336,7 +343,9 @@ var DEFAULT_PROVIDERS = {
336
343
  v2: "https://ton-testnet.orbs.network/api/v2"
337
344
  },
338
345
  rps: 10,
339
- priority: 50,
346
+ // Demoted below toncenter_testnet (priority 10): Orbs is the decentralised
347
+ // fallback for non-transaction (get-method/state) testnet reads only.
348
+ priority: 90,
340
349
  enabled: true,
341
350
  isDynamic: true,
342
351
  description: "Decentralized gateway - no API key needed"
@@ -373,7 +382,12 @@ function createDefaultConfig() {
373
382
  version: "1.0",
374
383
  providers: { ...DEFAULT_PROVIDERS },
375
384
  defaults: {
376
- testnet: ["orbs_testnet", "toncenter_testnet"],
385
+ // Testnet: Toncenter first (transactions-capable), Orbs as fallback.
386
+ // This default order only governs the no-healthy-providers fallback
387
+ // path; the primary, score-based selection is driven by priority
388
+ // (see toncenter_testnet/orbs_testnet above). Mainnet order is left
389
+ // unchanged (Orbs stays primary there — no regression).
390
+ testnet: ["toncenter_testnet", "orbs_testnet"],
377
391
  mainnet: ["orbs_mainnet", "toncenter_mainnet"]
378
392
  }
379
393
  };
@@ -3236,6 +3250,74 @@ var NodeAdapter = class {
3236
3250
  };
3237
3251
  }
3238
3252
  // ========================================================================
3253
+ // Failover-aware high-level reads
3254
+ // ========================================================================
3255
+ /**
3256
+ * Get account transactions with provider failover.
3257
+ *
3258
+ * Unlike `getClient().getTransactions(...)`, this loops across the network's
3259
+ * providers: a provider that passes the `getMasterchainInfo` health probe but
3260
+ * fails the v2 `getTransactions` call (e.g. Chainstack/Orbs testnet, which
3261
+ * 403 on transaction reads) is no longer able to permanently break this path.
3262
+ *
3263
+ * Semantics:
3264
+ * 1. Pick the current best provider (the selector's scored top).
3265
+ * 2. Acquire a rate-limit token for THAT provider, bind a short-lived
3266
+ * `TonClient` to its endpoint, and call `getTransactions`.
3267
+ * 3. On success → `reportSuccess()` and return.
3268
+ * 4. On error → `reportError()` (marks the provider success:false, scoring 0
3269
+ * within its cooldown, and clears the selection cache) so the next pick is
3270
+ * a DIFFERENT, still-eligible provider, then retry.
3271
+ * 5. When every candidate has been tried, re-throw the last error so the
3272
+ * caller's retry/dead-letter logic still triggers — but only after a
3273
+ * genuine failover across all providers.
3274
+ *
3275
+ * Returns the same `Transaction[]` `TonClient.getTransactions` returns, so a
3276
+ * consumer can swap `client.getTransactions(addr, opts)` for
3277
+ * `adapter.getTransactions(addr, opts)` with no shape change.
3278
+ */
3279
+ async getTransactions(address, opts = {}, timeoutMs = 15e3) {
3280
+ const network = this.manager.getNetwork();
3281
+ if (!network) {
3282
+ throw new Error("ProviderManager not initialized");
3283
+ }
3284
+ const addr = typeof address === "string" ? core.Address.parse(address) : address;
3285
+ const reqOpts = { limit: opts.limit ?? 20, ...opts };
3286
+ const maxAttempts = Math.max(1, this.manager.getProviders().length);
3287
+ const rateLimiter = this.manager.getRateLimiter();
3288
+ const tried = /* @__PURE__ */ new Set();
3289
+ let lastError;
3290
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
3291
+ const provider = this.manager.getActiveProvider();
3292
+ if (!provider) break;
3293
+ if (tried.has(provider.id)) break;
3294
+ tried.add(provider.id);
3295
+ if (rateLimiter) {
3296
+ await rateLimiter.acquire(provider.id, timeoutMs);
3297
+ }
3298
+ const endpoint = await this.manager.getEndpoint();
3299
+ const apiKey = this.manager.getActiveProvider()?.apiKey;
3300
+ const client = new ton.TonClient({ endpoint, apiKey });
3301
+ try {
3302
+ const result = await withTimeout(
3303
+ client.getTransactions(addr, reqOpts),
3304
+ timeoutMs,
3305
+ `getTransactions(${provider.id})`
3306
+ );
3307
+ this.manager.reportSuccess();
3308
+ return result;
3309
+ } catch (error) {
3310
+ lastError = error;
3311
+ this.logger.warn(
3312
+ `getTransactions failed on ${provider.id}, failing over`,
3313
+ { error: error?.message || String(error) }
3314
+ );
3315
+ this.manager.reportError(error);
3316
+ }
3317
+ }
3318
+ throw lastError || new Error(`getTransactions: no available provider for ${network}`);
3319
+ }
3320
+ // ========================================================================
3239
3321
  // Direct REST API Methods
3240
3322
  // ========================================================================
3241
3323
  /**