@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 +61 -44
- package/dist/index.mjs +61 -44
- package/package.json +1 -1
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
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
(
|
|
236
|
-
|
|
237
|
-
|
|
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
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
|
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
|
|
695
|
-
|
|
696
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
(
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
|
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
|
|
564
|
-
|
|
565
|
-
|
|
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
|
-
|
|
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(
|