@orbinum/sdk 0.13.0 → 0.14.1

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.js CHANGED
@@ -172,18 +172,10 @@ var DEFAULT_MAX_RETRIES = 5;
172
172
  var DEFAULT_BASE_BACKOFF_MS = 250;
173
173
  var DEFAULT_MAX_BACKOFF_MS = 4e3;
174
174
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
175
- async function jsonRpcBatch(httpUrl, calls, options = {}) {
176
- if (calls.length === 0) return [];
175
+ async function postJsonWithRetry(httpUrl, payload, options = {}) {
177
176
  const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
178
177
  const baseBackoffMs = options.baseBackoffMs ?? DEFAULT_BASE_BACKOFF_MS;
179
178
  const maxBackoffMs = options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;
180
- const body = calls.map((c, i) => ({
181
- id: i,
182
- jsonrpc: "2.0",
183
- method: c.method,
184
- params: c.params ?? []
185
- }));
186
- const payload = JSON.stringify(body);
187
179
  let attempt = 0;
188
180
  for (; ; ) {
189
181
  const res = await fetch(httpUrl, {
@@ -191,21 +183,28 @@ async function jsonRpcBatch(httpUrl, calls, options = {}) {
191
183
  headers: { "Content-Type": "application/json" },
192
184
  body: payload
193
185
  });
194
- if (res.ok) {
195
- const arr = await res.json();
196
- const byId = new Map(arr.map((r) => [r.id, r]));
197
- return calls.map((_, i) => byId.get(i)?.result ?? null);
198
- }
199
186
  const retryable = res.status === 429 || res.status === 503;
200
- if (!retryable || attempt >= maxRetries) {
201
- throw new Error(`JSON-RPC HTTP ${res.status}: ${res.statusText}`);
202
- }
187
+ if (!retryable || attempt >= maxRetries) return res;
203
188
  const retryAfter = Number(res.headers.get("retry-after"));
204
189
  const delayMs = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1e3 : Math.min(baseBackoffMs * 2 ** attempt, maxBackoffMs);
205
190
  await sleep(delayMs);
206
191
  attempt++;
207
192
  }
208
193
  }
194
+ async function jsonRpcBatch(httpUrl, calls, options = {}) {
195
+ if (calls.length === 0) return [];
196
+ const body = calls.map((c, i) => ({
197
+ id: i,
198
+ jsonrpc: "2.0",
199
+ method: c.method,
200
+ params: c.params ?? []
201
+ }));
202
+ const res = await postJsonWithRetry(httpUrl, JSON.stringify(body), options);
203
+ if (!res.ok) throw new Error(`JSON-RPC HTTP ${res.status}: ${res.statusText}`);
204
+ const arr = await res.json();
205
+ const byId = new Map(arr.map((r) => [r.id, r]));
206
+ return calls.map((_, i) => byId.get(i)?.result ?? null);
207
+ }
209
208
  function wsUrlToHttp(wsUrl) {
210
209
  if (wsUrl.startsWith("wss://")) return "https://" + wsUrl.slice("wss://".length);
211
210
  if (wsUrl.startsWith("ws://")) return "http://" + wsUrl.slice("ws://".length);
@@ -227,17 +226,28 @@ var SubstrateClient = class _SubstrateClient {
227
226
  * Throws if the node does not respond within `timeoutMs`.
228
227
  */
229
228
  static async connect(wsUrl, timeoutMs = 15e3) {
230
- const provider = (0, import_ws.getWsProvider)(wsUrl);
229
+ const provider = (0, import_ws.getWsProvider)(wsUrl, { heartbeatTimeout: 3e4 });
231
230
  const papi = (0, import_polkadot_api.createClient)(provider);
232
- await Promise.race([
233
- papi._request("system_name", []),
234
- new Promise(
235
- (_, reject) => setTimeout(
236
- () => reject(new Error(`Connection timeout (${timeoutMs}ms) to ${wsUrl}`)),
237
- timeoutMs
238
- )
239
- )
240
- ]);
231
+ let timer;
232
+ try {
233
+ await Promise.race([
234
+ papi._request("system_name", []),
235
+ new Promise((_, reject) => {
236
+ timer = setTimeout(
237
+ () => reject(new Error(`Connection timeout (${timeoutMs}ms) to ${wsUrl}`)),
238
+ timeoutMs
239
+ );
240
+ })
241
+ ]);
242
+ } catch (err) {
243
+ try {
244
+ papi.destroy();
245
+ } catch {
246
+ }
247
+ throw err;
248
+ } finally {
249
+ clearTimeout(timer);
250
+ }
241
251
  return new _SubstrateClient(papi, wsUrlToHttp(wsUrl));
242
252
  }
243
253
  /**
@@ -612,11 +622,10 @@ var EvmClient = class {
612
622
  * Throws on HTTP errors, RPC-level errors, or a `null` result.
613
623
  */
614
624
  async request(method, params = []) {
615
- const res = await fetch(this.rpcUrl, {
616
- method: "POST",
617
- headers: { "Content-Type": "application/json" },
618
- body: JSON.stringify({ id: 1, jsonrpc: "2.0", method, params })
619
- });
625
+ const res = await postJsonWithRetry(
626
+ this.rpcUrl,
627
+ JSON.stringify({ id: 1, jsonrpc: "2.0", method, params })
628
+ );
620
629
  if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
621
630
  const json = await res.json();
622
631
  if (json.error) {
@@ -638,11 +647,7 @@ var EvmClient = class {
638
647
  method: c.method,
639
648
  params: c.params ?? []
640
649
  }));
641
- const res = await fetch(this.rpcUrl, {
642
- method: "POST",
643
- headers: { "Content-Type": "application/json" },
644
- body: JSON.stringify(body)
645
- });
650
+ const res = await postJsonWithRetry(this.rpcUrl, JSON.stringify(body));
646
651
  if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
647
652
  const arr = await res.json();
648
653
  arr.sort((a, b) => (a.id ?? 0) - (b.id ?? 0));
@@ -691,16 +696,15 @@ var EvmClient = class {
691
696
  }
692
697
  /** Returns a transaction receipt by hash, or `null` if the transaction has not been mined yet. */
693
698
  async getTransactionReceipt(txHash) {
694
- const res = await fetch(this.rpcUrl, {
695
- method: "POST",
696
- headers: { "Content-Type": "application/json" },
697
- body: JSON.stringify({
699
+ const res = await postJsonWithRetry(
700
+ this.rpcUrl,
701
+ JSON.stringify({
698
702
  id: 1,
699
703
  jsonrpc: "2.0",
700
704
  method: "eth_getTransactionReceipt",
701
705
  params: [txHash]
702
706
  })
703
- });
707
+ );
704
708
  if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
705
709
  const json = await res.json();
706
710
  if (json.error) {
@@ -3416,14 +3420,16 @@ var OrbinumClientProvider = class {
3416
3420
  this.connectTimeoutMs
3417
3421
  );
3418
3422
  });
3423
+ let clientPromise = null;
3419
3424
  try {
3420
3425
  const connectConfig = {
3421
- substrateWs: this.config.substrateWs
3426
+ substrateWs: this.config.substrateWs,
3427
+ connectTimeoutMs: this.connectTimeoutMs
3422
3428
  };
3423
3429
  if (this.config.evmRpc) connectConfig.evmRpc = this.config.evmRpc;
3424
3430
  if (this.config.circuitsBaseUrl)
3425
3431
  connectConfig.circuitsBaseUrl = this.config.circuitsBaseUrl;
3426
- const clientPromise = OrbinumClient.connect(connectConfig);
3432
+ clientPromise = OrbinumClient.connect(connectConfig);
3427
3433
  const client = await Promise.race([clientPromise, timeoutPromise]);
3428
3434
  orphanClient = client;
3429
3435
  clearTimeout(timeoutId);
@@ -3441,6 +3447,17 @@ var OrbinumClientProvider = class {
3441
3447
  orphanClient.destroy();
3442
3448
  } catch {
3443
3449
  }
3450
+ } else if (clientPromise) {
3451
+ clientPromise.then(
3452
+ (c) => {
3453
+ try {
3454
+ c.destroy();
3455
+ } catch {
3456
+ }
3457
+ },
3458
+ () => {
3459
+ }
3460
+ );
3444
3461
  }
3445
3462
  this._connectingPromise = null;
3446
3463
  this.setStatus(
package/dist/index.mjs CHANGED
@@ -41,18 +41,10 @@ var DEFAULT_MAX_RETRIES = 5;
41
41
  var DEFAULT_BASE_BACKOFF_MS = 250;
42
42
  var DEFAULT_MAX_BACKOFF_MS = 4e3;
43
43
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
44
- async function jsonRpcBatch(httpUrl, calls, options = {}) {
45
- if (calls.length === 0) return [];
44
+ async function postJsonWithRetry(httpUrl, payload, options = {}) {
46
45
  const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
47
46
  const baseBackoffMs = options.baseBackoffMs ?? DEFAULT_BASE_BACKOFF_MS;
48
47
  const maxBackoffMs = options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;
49
- const body = calls.map((c, i) => ({
50
- id: i,
51
- jsonrpc: "2.0",
52
- method: c.method,
53
- params: c.params ?? []
54
- }));
55
- const payload = JSON.stringify(body);
56
48
  let attempt = 0;
57
49
  for (; ; ) {
58
50
  const res = await fetch(httpUrl, {
@@ -60,21 +52,28 @@ async function jsonRpcBatch(httpUrl, calls, options = {}) {
60
52
  headers: { "Content-Type": "application/json" },
61
53
  body: payload
62
54
  });
63
- if (res.ok) {
64
- const arr = await res.json();
65
- const byId = new Map(arr.map((r) => [r.id, r]));
66
- return calls.map((_, i) => byId.get(i)?.result ?? null);
67
- }
68
55
  const retryable = res.status === 429 || res.status === 503;
69
- if (!retryable || attempt >= maxRetries) {
70
- throw new Error(`JSON-RPC HTTP ${res.status}: ${res.statusText}`);
71
- }
56
+ if (!retryable || attempt >= maxRetries) return res;
72
57
  const retryAfter = Number(res.headers.get("retry-after"));
73
58
  const delayMs = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1e3 : Math.min(baseBackoffMs * 2 ** attempt, maxBackoffMs);
74
59
  await sleep(delayMs);
75
60
  attempt++;
76
61
  }
77
62
  }
63
+ async function jsonRpcBatch(httpUrl, calls, options = {}) {
64
+ if (calls.length === 0) return [];
65
+ const body = calls.map((c, i) => ({
66
+ id: i,
67
+ jsonrpc: "2.0",
68
+ method: c.method,
69
+ params: c.params ?? []
70
+ }));
71
+ const res = await postJsonWithRetry(httpUrl, JSON.stringify(body), options);
72
+ if (!res.ok) throw new Error(`JSON-RPC HTTP ${res.status}: ${res.statusText}`);
73
+ const arr = await res.json();
74
+ const byId = new Map(arr.map((r) => [r.id, r]));
75
+ return calls.map((_, i) => byId.get(i)?.result ?? null);
76
+ }
78
77
  function wsUrlToHttp(wsUrl) {
79
78
  if (wsUrl.startsWith("wss://")) return "https://" + wsUrl.slice("wss://".length);
80
79
  if (wsUrl.startsWith("ws://")) return "http://" + wsUrl.slice("ws://".length);
@@ -96,17 +95,28 @@ var SubstrateClient = class _SubstrateClient {
96
95
  * Throws if the node does not respond within `timeoutMs`.
97
96
  */
98
97
  static async connect(wsUrl, timeoutMs = 15e3) {
99
- const provider = getWsProvider(wsUrl);
98
+ const provider = getWsProvider(wsUrl, { heartbeatTimeout: 3e4 });
100
99
  const papi = createClient(provider);
101
- await Promise.race([
102
- papi._request("system_name", []),
103
- new Promise(
104
- (_, reject) => setTimeout(
105
- () => reject(new Error(`Connection timeout (${timeoutMs}ms) to ${wsUrl}`)),
106
- timeoutMs
107
- )
108
- )
109
- ]);
100
+ let timer;
101
+ try {
102
+ await Promise.race([
103
+ papi._request("system_name", []),
104
+ new Promise((_, reject) => {
105
+ timer = setTimeout(
106
+ () => reject(new Error(`Connection timeout (${timeoutMs}ms) to ${wsUrl}`)),
107
+ timeoutMs
108
+ );
109
+ })
110
+ ]);
111
+ } catch (err) {
112
+ try {
113
+ papi.destroy();
114
+ } catch {
115
+ }
116
+ throw err;
117
+ } finally {
118
+ clearTimeout(timer);
119
+ }
110
120
  return new _SubstrateClient(papi, wsUrlToHttp(wsUrl));
111
121
  }
112
122
  /**
@@ -481,11 +491,10 @@ var EvmClient = class {
481
491
  * Throws on HTTP errors, RPC-level errors, or a `null` result.
482
492
  */
483
493
  async request(method, params = []) {
484
- const res = await fetch(this.rpcUrl, {
485
- method: "POST",
486
- headers: { "Content-Type": "application/json" },
487
- body: JSON.stringify({ id: 1, jsonrpc: "2.0", method, params })
488
- });
494
+ const res = await postJsonWithRetry(
495
+ this.rpcUrl,
496
+ JSON.stringify({ id: 1, jsonrpc: "2.0", method, params })
497
+ );
489
498
  if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
490
499
  const json = await res.json();
491
500
  if (json.error) {
@@ -507,11 +516,7 @@ var EvmClient = class {
507
516
  method: c.method,
508
517
  params: c.params ?? []
509
518
  }));
510
- const res = await fetch(this.rpcUrl, {
511
- method: "POST",
512
- headers: { "Content-Type": "application/json" },
513
- body: JSON.stringify(body)
514
- });
519
+ const res = await postJsonWithRetry(this.rpcUrl, JSON.stringify(body));
515
520
  if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
516
521
  const arr = await res.json();
517
522
  arr.sort((a, b) => (a.id ?? 0) - (b.id ?? 0));
@@ -560,16 +565,15 @@ var EvmClient = class {
560
565
  }
561
566
  /** Returns a transaction receipt by hash, or `null` if the transaction has not been mined yet. */
562
567
  async getTransactionReceipt(txHash) {
563
- const res = await fetch(this.rpcUrl, {
564
- method: "POST",
565
- headers: { "Content-Type": "application/json" },
566
- body: JSON.stringify({
568
+ const res = await postJsonWithRetry(
569
+ this.rpcUrl,
570
+ JSON.stringify({
567
571
  id: 1,
568
572
  jsonrpc: "2.0",
569
573
  method: "eth_getTransactionReceipt",
570
574
  params: [txHash]
571
575
  })
572
- });
576
+ );
573
577
  if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
574
578
  const json = await res.json();
575
579
  if (json.error) {
@@ -3288,14 +3292,16 @@ var OrbinumClientProvider = class {
3288
3292
  this.connectTimeoutMs
3289
3293
  );
3290
3294
  });
3295
+ let clientPromise = null;
3291
3296
  try {
3292
3297
  const connectConfig = {
3293
- substrateWs: this.config.substrateWs
3298
+ substrateWs: this.config.substrateWs,
3299
+ connectTimeoutMs: this.connectTimeoutMs
3294
3300
  };
3295
3301
  if (this.config.evmRpc) connectConfig.evmRpc = this.config.evmRpc;
3296
3302
  if (this.config.circuitsBaseUrl)
3297
3303
  connectConfig.circuitsBaseUrl = this.config.circuitsBaseUrl;
3298
- const clientPromise = OrbinumClient.connect(connectConfig);
3304
+ clientPromise = OrbinumClient.connect(connectConfig);
3299
3305
  const client = await Promise.race([clientPromise, timeoutPromise]);
3300
3306
  orphanClient = client;
3301
3307
  clearTimeout(timeoutId);
@@ -3313,6 +3319,17 @@ var OrbinumClientProvider = class {
3313
3319
  orphanClient.destroy();
3314
3320
  } catch {
3315
3321
  }
3322
+ } else if (clientPromise) {
3323
+ clientPromise.then(
3324
+ (c) => {
3325
+ try {
3326
+ c.destroy();
3327
+ } catch {
3328
+ }
3329
+ },
3330
+ () => {
3331
+ }
3332
+ );
3316
3333
  }
3317
3334
  this._connectingPromise = null;
3318
3335
  this.setStatus(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbinum/sdk",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Official TypeScript SDK for Orbinum.",
5
5
  "author": "Orbinum",
6
6
  "license": "MIT",