ton-provider-system 0.1.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/README.md ADDED
@@ -0,0 +1,421 @@
1
+ # Unified TON Provider System
2
+
3
+ A bullet-proof TON RPC provider management system for multi-project use.
4
+
5
+ ## Features
6
+
7
+ - **Multi-provider support** with automatic failover
8
+ - **Health checking** with latency and block height monitoring
9
+ - **Token bucket rate limiting** per provider
10
+ - **Automatic best provider selection** based on health, latency, and priority
11
+ - **Custom endpoint override** for testing
12
+ - **Environment-based configuration** via `.env` file
13
+ - **Cross-platform** - works in Node.js and Browser environments
14
+
15
+ ## Installation
16
+
17
+ ### NPM Package
18
+
19
+ ```bash
20
+ # Using npm
21
+ npm install ton-provider-system
22
+
23
+ # Using pnpm
24
+ pnpm add ton-provider-system
25
+
26
+ # Using yarn
27
+ yarn add ton-provider-system
28
+ ```
29
+
30
+ ### Peer Dependencies
31
+
32
+ This package requires the following peer dependencies (you must install them in your project):
33
+
34
+ ```bash
35
+ pnpm add @ton/core @ton/ton @orbs-network/ton-access
36
+ ```
37
+
38
+ Or add to your `package.json`:
39
+
40
+ ```json
41
+ {
42
+ "dependencies": {
43
+ "ton-provider-system": "^0.1.0",
44
+ "@orbs-network/ton-access": "^2.3.0",
45
+ "@ton/core": "^0.59.0",
46
+ "@ton/ton": "^15.0.0"
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ### Node.js (Scripts, Telegram Bot)
54
+
55
+ ```typescript
56
+ import { ProviderManager, getTonClient } from 'ton-provider-system';
57
+
58
+ // Initialize
59
+ const pm = ProviderManager.getInstance();
60
+ await pm.init('testnet');
61
+
62
+ // Get TonClient for blockchain operations
63
+ const client = await getTonClient(pm);
64
+
65
+ // Use the client
66
+ const balance = await client.getBalance(address);
67
+ ```
68
+
69
+ ### Browser (React/Next.js)
70
+
71
+ ```typescript
72
+ import { ProviderManager, BrowserAdapter } from 'ton-provider-system';
73
+
74
+ // Create instance (not singleton for React)
75
+ const pm = new ProviderManager({ adapter: 'browser' });
76
+ await pm.init(network);
77
+
78
+ // Use browser adapter for fetch-based operations
79
+ const adapter = new BrowserAdapter(pm);
80
+ const balance = await adapter.getAddressBalance(address);
81
+ ```
82
+
83
+ ## Configuration
84
+
85
+ ### Provider Definitions
86
+
87
+ The package includes default provider definitions in `rpc.json` (bundled with the package).
88
+ This file contains:
89
+ - Provider endpoints with `{key}` placeholders
90
+ - Environment variable names for API keys
91
+ - RPS limits and priorities
92
+ - Default provider order per network
93
+
94
+ The JSON Schema (`rpc-schema.json`) provides validation and IDE autocomplete.
95
+
96
+ **Note**: The default `rpc.json` is included in the package. You can override it by providing a custom path when creating the registry.
97
+
98
+ ### Environment Variables
99
+
100
+ Set API keys in your `.env` file. See `env.example` for a complete template.
101
+
102
+ ```bash
103
+ # TON Center (10 RPS with API key, 1 RPS without)
104
+ TONCENTER_API_KEY=your-toncenter-api-key
105
+
106
+ # Chainstack (25 RPS) - extract key from URL
107
+ # URL: https://ton-testnet.core.chainstack.com/YOUR_KEY/api/v2
108
+ CHAINSTACK_KEY_TESTNET=your-chainstack-key
109
+
110
+ # QuickNode (15 RPS) - use subdomain from URL
111
+ QUICKNODE_KEY_MAINNET=your-quicknode-subdomain
112
+
113
+ # GetBlock (20 RPS) - use the access token
114
+ GETBLOCK_KEY_MAINNET=your-getblock-token
115
+
116
+ # OnFinality (4 RPS) - use apikey from URL
117
+ ONFINALITY_KEY_TESTNET=your-onfinality-apikey
118
+
119
+ # Tatum (3 RPS) - separate keys for testnet/mainnet
120
+ TATUM_API_KEY_TESTNET=your-tatum-testnet-key
121
+ TATUM_API_KEY_MAINNET=your-tatum-mainnet-key
122
+ ```
123
+
124
+ The `{key}` placeholder in endpoint URLs is replaced with the env var value.
125
+
126
+ ## API Reference
127
+
128
+ ### ProviderManager
129
+
130
+ Main entry point for the provider system.
131
+
132
+ ```typescript
133
+ // Singleton (recommended for Node.js)
134
+ const pm = ProviderManager.getInstance();
135
+
136
+ // Instance (recommended for Browser/React)
137
+ const pm = new ProviderManager({ adapter: 'browser' });
138
+
139
+ // Initialize for a network
140
+ await pm.init('testnet');
141
+ await pm.init('mainnet');
142
+
143
+ // Get endpoint URL
144
+ const endpoint = await pm.getEndpoint();
145
+
146
+ // Get endpoint with rate limiting
147
+ const endpoint = await pm.getEndpointWithRateLimit(5000);
148
+
149
+ // Test all providers
150
+ const results = await pm.testAllProviders();
151
+
152
+ // Report errors (for automatic failover)
153
+ pm.reportError(error);
154
+ pm.reportSuccess();
155
+
156
+ // Manual provider selection
157
+ pm.setSelectedProvider('chainstack_testnet');
158
+ pm.setAutoSelect(true);
159
+
160
+ // Custom endpoint override
161
+ pm.setCustomEndpoint('https://custom.endpoint/api/v2');
162
+ ```
163
+
164
+ ### NodeAdapter
165
+
166
+ Node.js adapter with TonClient and REST API support.
167
+
168
+ ```typescript
169
+ import { NodeAdapter, getTonClient } from './provider_system';
170
+
171
+ const adapter = new NodeAdapter(pm);
172
+
173
+ // Get TonClient
174
+ const client = await adapter.getClient();
175
+
176
+ // REST API methods
177
+ const state = await adapter.getAddressState(address);
178
+ const balance = await adapter.getAddressBalance(address);
179
+ const result = await adapter.runGetMethod(address, 'get_data', []);
180
+ await adapter.sendBoc(boc);
181
+ const deployed = await adapter.isContractDeployed(address);
182
+ ```
183
+
184
+ ### BrowserAdapter
185
+
186
+ Browser-compatible adapter using fetch.
187
+
188
+ ```typescript
189
+ import { BrowserAdapter } from './provider_system';
190
+
191
+ const adapter = new BrowserAdapter(pm);
192
+
193
+ // REST API methods
194
+ const state = await adapter.getAddressState(address);
195
+ const balance = await adapter.getAddressBalance(address);
196
+ const info = await adapter.getAddressInfo(address);
197
+ const result = await adapter.runGetMethod(address, 'get_data', []);
198
+
199
+ // JSON-RPC method
200
+ const data = await adapter.jsonRpc('getMasterchainInfo');
201
+ ```
202
+
203
+ ### HealthChecker
204
+
205
+ Test provider health and connectivity.
206
+
207
+ ```typescript
208
+ import { createHealthChecker, createRegistry } from './provider_system';
209
+
210
+ const registry = await createRegistry();
211
+ const healthChecker = createHealthChecker({
212
+ timeoutMs: 10000,
213
+ maxBlocksBehind: 10,
214
+ });
215
+
216
+ // Test single provider
217
+ const result = await healthChecker.testProvider(provider);
218
+
219
+ // Test multiple providers
220
+ const results = await healthChecker.testProviders(providers);
221
+
222
+ // Get best provider
223
+ const best = healthChecker.getBestProvider('testnet');
224
+ ```
225
+
226
+ ### RateLimiterManager
227
+
228
+ Per-provider rate limiting with token bucket algorithm.
229
+
230
+ ```typescript
231
+ import { createRateLimiterManager } from './provider_system';
232
+
233
+ const rateLimiter = createRateLimiterManager();
234
+
235
+ // Configure for a provider
236
+ rateLimiter.setConfig('chainstack_testnet', {
237
+ rps: 25,
238
+ burstSize: 30,
239
+ minDelayMs: 40,
240
+ backoffMultiplier: 2,
241
+ maxBackoffMs: 10000,
242
+ });
243
+
244
+ // Acquire token before making request
245
+ const acquired = await rateLimiter.acquire('chainstack_testnet', 5000);
246
+ if (acquired) {
247
+ // Make request
248
+ rateLimiter.reportSuccess('chainstack_testnet');
249
+ } else {
250
+ // Rate limit timeout
251
+ }
252
+
253
+ // Report rate limit error
254
+ rateLimiter.reportRateLimitError('chainstack_testnet');
255
+ ```
256
+
257
+ ## File Structure
258
+
259
+ ```
260
+ provider_system/
261
+ ├── rpc.json # Provider definitions (main config)
262
+ ├── rpc-schema.json # JSON Schema for validation
263
+ ├── README.md # This file
264
+ ├── index.ts # Main exports
265
+ ├── types.ts # TypeScript interfaces
266
+ ├── config/
267
+ │ ├── schema.ts # Zod schema validation
268
+ │ ├── parser.ts # Config loading and env resolution
269
+ │ └── index.ts # Config exports
270
+ ├── core/
271
+ │ ├── registry.ts # Provider registry
272
+ │ ├── healthChecker.ts # Health/latency checks
273
+ │ ├── rateLimiter.ts # Token bucket rate limiter
274
+ │ ├── selector.ts # Best provider selection
275
+ │ ├── manager.ts # Main ProviderManager
276
+ │ └── index.ts # Core exports
277
+ ├── adapters/
278
+ │ ├── node.ts # Node.js adapter (TonClient)
279
+ │ ├── browser.ts # Browser adapter (fetch)
280
+ │ └── index.ts # Adapter exports
281
+ ├── utils/
282
+ │ ├── endpoint.ts # URL normalization
283
+ │ ├── timeout.ts # Timeout utilities
284
+ │ └── index.ts # Utils exports
285
+ └── test.ts # Test script
286
+ ```
287
+
288
+ ## Integration Guide
289
+
290
+ ### Node.js Project
291
+
292
+ 1. Install the package:
293
+
294
+ ```bash
295
+ pnpm add ton-provider-system @ton/core @ton/ton @orbs-network/ton-access
296
+ ```
297
+
298
+ 2. Use in your code:
299
+
300
+ ```typescript
301
+ import { ProviderManager, getTonClient } from 'ton-provider-system';
302
+
303
+ const pm = ProviderManager.getInstance();
304
+ await pm.init('testnet');
305
+ const client = await getTonClient(pm);
306
+ ```
307
+
308
+ ### Next.js/React (Browser)
309
+
310
+ 1. Install the package:
311
+
312
+ ```bash
313
+ pnpm add ton-provider-system @ton/core @orbs-network/ton-access
314
+ ```
315
+
316
+ 2. Use in your React component:
317
+
318
+ ```typescript
319
+ import { ProviderManager, BrowserAdapter } from 'ton-provider-system';
320
+
321
+ export function ProviderProvider({ children }) {
322
+ const { network } = useNetwork();
323
+ const [manager] = useState(() => new ProviderManager({ adapter: 'browser' }));
324
+ const [adapter, setAdapter] = useState<BrowserAdapter | null>(null);
325
+
326
+ useEffect(() => {
327
+ manager.init(network).then(() => {
328
+ setAdapter(new BrowserAdapter(manager));
329
+ });
330
+ }, [network, manager]);
331
+
332
+ // ...
333
+ }
334
+ ```
335
+
336
+ ### Telegram Bot
337
+
338
+ 1. Install the package:
339
+
340
+ ```bash
341
+ pnpm add ton-provider-system @ton/core @ton/ton @orbs-network/ton-access
342
+ ```
343
+
344
+ 2. Initialize on bot startup:
345
+
346
+ ```typescript
347
+ // src/bot.ts
348
+ import { ProviderManager } from 'ton-provider-system';
349
+
350
+ const pm = ProviderManager.getInstance();
351
+
352
+ async function startBot() {
353
+ // Initialize provider system
354
+ await pm.init(getNetwork());
355
+
356
+ // Optionally re-test providers periodically
357
+ setInterval(() => {
358
+ pm.testAllProviders().catch(console.error);
359
+ }, 5 * 60 * 1000); // Every 5 minutes
360
+
361
+ // Start bot
362
+ bot.start();
363
+ }
364
+ ```
365
+
366
+ ## Development
367
+
368
+ ### Building
369
+
370
+ ```bash
371
+ # Build the library
372
+ pnpm build
373
+
374
+ # Watch mode for development
375
+ pnpm dev
376
+ ```
377
+
378
+ ### Testing
379
+
380
+ ```bash
381
+ # Run full test suite
382
+ pnpm test
383
+
384
+ # Quick test (skip network tests)
385
+ pnpm test:quick
386
+
387
+ # Verbose test output
388
+ pnpm test:verbose
389
+ ```
390
+
391
+ **Note**: Tests require environment variables to be set in `.env` file. See `env.example` for template.
392
+
393
+ ## Troubleshooting
394
+
395
+ ### No providers available
396
+
397
+ 1. Check `.env` file has API keys configured
398
+ 2. Run `pnpm check-connection` to test providers
399
+
400
+ ### Rate limit errors
401
+
402
+ 1. The system automatically switches to next provider on 429 errors
403
+ 2. Configure more providers in `.env` for redundancy
404
+
405
+ ### Block height mismatch (stale provider)
406
+
407
+ 1. Provider is returning old data
408
+ 2. System marks it as `stale` and prefers fresh providers
409
+
410
+ ## Publishing
411
+
412
+ This package is published to NPM. To publish a new version:
413
+
414
+ 1. Update version in `package.json` (follow semver)
415
+ 2. Run `pnpm build` to ensure latest code is built
416
+ 3. Run `npm pack --dry-run` to verify what will be published
417
+ 4. Publish: `npm publish --access public` (if scoped package)
418
+
419
+ ## License
420
+
421
+ MIT