@polkadot-api/ws-middleware 1.0.0-canary.3789023

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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/esm/index.mjs +12 -0
  4. package/dist/esm/index.mjs.map +1 -0
  5. package/dist/esm/legacy/downstream/archive.mjs +96 -0
  6. package/dist/esm/legacy/downstream/archive.mjs.map +1 -0
  7. package/dist/esm/legacy/downstream/chain-head.mjs +214 -0
  8. package/dist/esm/legacy/downstream/chain-head.mjs.map +1 -0
  9. package/dist/esm/legacy/downstream/chainspec.mjs +18 -0
  10. package/dist/esm/legacy/downstream/chainspec.mjs.map +1 -0
  11. package/dist/esm/legacy/downstream/downstream.mjs +107 -0
  12. package/dist/esm/legacy/downstream/downstream.mjs.map +1 -0
  13. package/dist/esm/legacy/downstream/storage.mjs +57 -0
  14. package/dist/esm/legacy/downstream/storage.mjs.map +1 -0
  15. package/dist/esm/legacy/downstream/transaction.mjs +48 -0
  16. package/dist/esm/legacy/downstream/transaction.mjs.map +1 -0
  17. package/dist/esm/legacy/upstream/blocks/blocks.mjs +309 -0
  18. package/dist/esm/legacy/upstream/blocks/blocks.mjs.map +1 -0
  19. package/dist/esm/legacy/upstream/blocks/index.mjs +7 -0
  20. package/dist/esm/legacy/upstream/blocks/index.mjs.map +1 -0
  21. package/dist/esm/legacy/upstream/blocks/upstream-events.mjs +92 -0
  22. package/dist/esm/legacy/upstream/blocks/upstream-events.mjs.map +1 -0
  23. package/dist/esm/legacy/upstream/proofs.mjs +41 -0
  24. package/dist/esm/legacy/upstream/proofs.mjs.map +1 -0
  25. package/dist/esm/legacy/upstream/upstream.mjs +108 -0
  26. package/dist/esm/legacy/upstream/upstream.mjs.map +1 -0
  27. package/dist/esm/legacy/utils/create-opaque-token.mjs +7 -0
  28. package/dist/esm/legacy/utils/create-opaque-token.mjs.map +1 -0
  29. package/dist/esm/legacy/utils/fromShittyHeader.mjs +31 -0
  30. package/dist/esm/legacy/utils/fromShittyHeader.mjs.map +1 -0
  31. package/dist/esm/legacy/utils/get-hasher-from-block.mjs +12 -0
  32. package/dist/esm/legacy/utils/get-hasher-from-block.mjs.map +1 -0
  33. package/dist/esm/legacy/utils/message-from-error.mjs +8 -0
  34. package/dist/esm/legacy/utils/message-from-error.mjs.map +1 -0
  35. package/dist/esm/legacy/utils/share-latest.mjs +9 -0
  36. package/dist/esm/legacy/utils/share-latest.mjs.map +1 -0
  37. package/dist/esm/legacy/utils/with-latest-from-bp.mjs +40 -0
  38. package/dist/esm/legacy/utils/with-latest-from-bp.mjs.map +1 -0
  39. package/dist/esm/methods-router.mjs +41 -0
  40. package/dist/esm/methods-router.mjs.map +1 -0
  41. package/dist/esm/methods.mjs +40 -0
  42. package/dist/esm/methods.mjs.map +1 -0
  43. package/dist/esm/middleware.mjs +22 -0
  44. package/dist/esm/middleware.mjs.map +1 -0
  45. package/dist/esm/modern/fix-follow.mjs +79 -0
  46. package/dist/esm/modern/fix-follow.mjs.map +1 -0
  47. package/dist/esm/modern/fix-premature-blocks.mjs +94 -0
  48. package/dist/esm/modern/fix-premature-blocks.mjs.map +1 -0
  49. package/dist/esm/modern/fix-unordered-blocks.mjs +100 -0
  50. package/dist/esm/modern/fix-unordered-blocks.mjs.map +1 -0
  51. package/dist/esm/modern/fix-unordered-events.mjs +101 -0
  52. package/dist/esm/modern/fix-unordered-events.mjs.map +1 -0
  53. package/dist/esm/modern/modern.mjs +19 -0
  54. package/dist/esm/modern/modern.mjs.map +1 -0
  55. package/dist/esm/modern/patch-chainhead-events.mjs +16 -0
  56. package/dist/esm/modern/patch-chainhead-events.mjs.map +1 -0
  57. package/dist/esm/modern/unpin-hash.mjs +22 -0
  58. package/dist/esm/modern/unpin-hash.mjs.map +1 -0
  59. package/dist/esm/numeric-ids.mjs +37 -0
  60. package/dist/esm/numeric-ids.mjs.map +1 -0
  61. package/dist/esm/utils/get-async-middleware.mjs +60 -0
  62. package/dist/esm/utils/get-async-middleware.mjs.map +1 -0
  63. package/dist/esm/utils/utils.mjs +11 -0
  64. package/dist/esm/utils/utils.mjs.map +1 -0
  65. package/dist/index.d.ts +27 -0
  66. package/dist/index.js +1706 -0
  67. package/dist/index.js.map +1 -0
  68. package/package.json +57 -0
package/dist/index.js ADDED
@@ -0,0 +1,1706 @@
1
+ 'use strict';
2
+
3
+ var utils = require('@polkadot-api/utils');
4
+ var rxjs = require('rxjs');
5
+ var substrateBindings = require('@polkadot-api/substrate-bindings');
6
+ var rawClient = require('@polkadot-api/raw-client');
7
+
8
+ const shareLatest = rxjs.shareReplay({
9
+ refCount: true,
10
+ bufferSize: 1
11
+ });
12
+
13
+ const getBlocks = ({
14
+ allHeads$,
15
+ finalized$: finalizedWire$,
16
+ getHeader$,
17
+ hasher$,
18
+ getRecursiveHeader
19
+ }) => {
20
+ const connectedBlocks = {
21
+ blocks: /* @__PURE__ */ new Map(),
22
+ prevFin: "",
23
+ finalized: "",
24
+ best: ""
25
+ };
26
+ const getTree = (root, result = []) => {
27
+ result.push(root);
28
+ connectedBlocks.blocks.get(root).children.forEach((c) => {
29
+ getTree(c, result);
30
+ });
31
+ return result;
32
+ };
33
+ const addBlock = (block) => {
34
+ const { blocks } = connectedBlocks;
35
+ const { hash, parent } = block;
36
+ const me = {
37
+ ...block,
38
+ children: /* @__PURE__ */ new Set(),
39
+ usages: /* @__PURE__ */ new Set()
40
+ };
41
+ blocks.set(hash, me);
42
+ blocks.get(parent)?.children.add(hash);
43
+ return me;
44
+ };
45
+ const setBestFromFinalized = () => {
46
+ connectedBlocks.best = connectedBlocks.finalized;
47
+ let bestHeight = 0;
48
+ const { finalized, blocks } = connectedBlocks;
49
+ getTree(finalized).map((x) => blocks.get(x)).forEach((x) => {
50
+ if (x.number > bestHeight) {
51
+ bestHeight = x.number;
52
+ connectedBlocks.best = x.hash;
53
+ }
54
+ });
55
+ };
56
+ const pendingBlocks = /* @__PURE__ */ new Map();
57
+ const trimPending = (root) => {
58
+ const desc = [...pendingBlocks.get(root).children];
59
+ pendingBlocks.delete(root);
60
+ desc.forEach(trimPending);
61
+ };
62
+ const getPendingTree = (root, result = []) => {
63
+ const me = pendingBlocks.get(root);
64
+ if (!me.header) return result;
65
+ result.push(me.header);
66
+ me.children.forEach((c) => {
67
+ getPendingTree(c, result);
68
+ });
69
+ return result;
70
+ };
71
+ const _newBlocks$ = new rxjs.Subject();
72
+ const onError = (e) => _newBlocks$.error(e);
73
+ const _finalized$ = finalizedWire$.pipe(
74
+ rxjs.concatMap((header, idx) => {
75
+ const { hash } = header;
76
+ if (!idx) {
77
+ addBlock(header);
78
+ connectedBlocks.finalized = connectedBlocks.best = header.hash;
79
+ }
80
+ return connectedBlocks.blocks.has(hash) ? rxjs.of(hash) : _newBlocks$.pipe(
81
+ rxjs.filter((x) => x === hash),
82
+ // some of the following blocks could be prunned b/c of this finalized event.
83
+ // So, we have to make sure that this "batch" of _newBlocks has been flushed.
84
+ rxjs.debounceTime(0),
85
+ rxjs.take(1)
86
+ );
87
+ }),
88
+ rxjs.share()
89
+ );
90
+ allHeads$.subscribe((header) => {
91
+ const { parent, hash, number } = header;
92
+ if (connectedBlocks.blocks.has(hash) || !number) return;
93
+ if (connectedBlocks.blocks.has(parent)) {
94
+ addBlock(header);
95
+ _newBlocks$.next(hash);
96
+ } else {
97
+ pendingBlocks.set(hash, {
98
+ hash: header.hash,
99
+ header,
100
+ children: /* @__PURE__ */ new Set()
101
+ });
102
+ if (!pendingBlocks.has(parent)) {
103
+ pendingBlocks.set(parent, {
104
+ hash: parent,
105
+ header: null,
106
+ children: /* @__PURE__ */ new Set()
107
+ });
108
+ getRecursiveHeader(parent).pipe(
109
+ rxjs.takeWhile((result) => {
110
+ let me = pendingBlocks.get(result.hash);
111
+ if (!me) return false;
112
+ me.header = result;
113
+ const finalized = connectedBlocks.blocks.get(
114
+ connectedBlocks.finalized
115
+ );
116
+ if (finalized && result.number <= finalized.number) {
117
+ while (pendingBlocks.has(me.header?.parent ?? ""))
118
+ me = pendingBlocks.get(me.header.parent);
119
+ trimPending(me.hash);
120
+ return false;
121
+ }
122
+ if (connectedBlocks.blocks.has(result.parent)) {
123
+ let target = connectedBlocks.blocks.get(result.parent);
124
+ const diff = target.number - finalized.number;
125
+ for (let i = 0; i < diff; i++) {
126
+ const nextTarget = connectedBlocks.blocks.get(target.parent);
127
+ if (!nextTarget) break;
128
+ target = nextTarget;
129
+ }
130
+ if (target === finalized) {
131
+ const pendingOnes = getPendingTree(result.hash);
132
+ pendingOnes.forEach((h) => {
133
+ pendingBlocks.delete(h.hash);
134
+ addBlock(h);
135
+ _newBlocks$.next(h.hash);
136
+ });
137
+ } else trimPending(result.hash);
138
+ return false;
139
+ }
140
+ const pendingParent = pendingBlocks.get(result.parent);
141
+ if (pendingParent) {
142
+ pendingParent.children.add(result.hash);
143
+ return false;
144
+ }
145
+ pendingBlocks.set(result.parent, {
146
+ hash: result.parent,
147
+ header: null,
148
+ children: /* @__PURE__ */ new Set([result.hash])
149
+ });
150
+ return true;
151
+ })
152
+ ).subscribe({ error: onError });
153
+ }
154
+ pendingBlocks.get(parent).children.add(hash);
155
+ }
156
+ }, onError);
157
+ const getFinalizedEvent = () => {
158
+ const prunedBlockHashes = [];
159
+ const finalizedBlockHashes = [];
160
+ const { blocks, finalized, prevFin } = connectedBlocks;
161
+ let current = blocks.get(finalized);
162
+ let prev = blocks.get(current.parent);
163
+ while (prev) {
164
+ finalizedBlockHashes.push(current.hash);
165
+ prev.children.forEach((c) => {
166
+ if (c !== current.hash) getTree(c, prunedBlockHashes);
167
+ });
168
+ current = prev;
169
+ if (current.hash === prevFin) break;
170
+ prev = blocks.get(current.parent);
171
+ }
172
+ finalizedBlockHashes.reverse();
173
+ return { event: "finalized", prunedBlockHashes, finalizedBlockHashes };
174
+ };
175
+ let activeSubscriptions = /* @__PURE__ */ new Set();
176
+ const getNewBlockEvent = (blockHash) => {
177
+ const block = connectedBlocks.blocks.get(blockHash);
178
+ activeSubscriptions.forEach((subId) => {
179
+ block.usages.add(subId);
180
+ });
181
+ return {
182
+ event: "newBlock",
183
+ blockHash,
184
+ parentBlockHash: block.parent,
185
+ newRuntime: block.hasUpgrade ? {} : null
186
+ };
187
+ };
188
+ const tryRemove = (blockHash, up) => {
189
+ const { blocks } = connectedBlocks;
190
+ const block = blocks.get(blockHash);
191
+ if (!block || block.usages.size > 0) return;
192
+ const { parent, children } = block;
193
+ if (up !== true) children.forEach((c) => tryRemove(c, false));
194
+ if (up !== false) tryRemove(parent, true);
195
+ if (!blocks.has(parent) || !block.children.size) {
196
+ blocks.get(parent)?.children.delete(blockHash);
197
+ blocks.delete(blockHash);
198
+ }
199
+ };
200
+ const updates$ = rxjs.merge(
201
+ _newBlocks$.pipe(
202
+ rxjs.map((hash) => ({
203
+ type: "new",
204
+ value: connectedBlocks.blocks.get(hash)
205
+ }))
206
+ ),
207
+ _finalized$.pipe(rxjs.map((hash) => ({ type: "fin", value: hash })))
208
+ ).pipe(
209
+ rxjs.mergeMap((x) => {
210
+ if (x.type === "new") {
211
+ const block = x.value;
212
+ const { hash } = block;
213
+ addBlock(block);
214
+ const result2 = [getNewBlockEvent(hash)];
215
+ if (block.number > connectedBlocks.blocks.get(connectedBlocks.best).number) {
216
+ connectedBlocks.best = hash;
217
+ result2.push({ event: "bestBlockChanged", bestBlockHash: hash });
218
+ }
219
+ return result2;
220
+ }
221
+ connectedBlocks.prevFin = connectedBlocks.finalized;
222
+ connectedBlocks.finalized = x.value;
223
+ let prevBest = connectedBlocks.best;
224
+ setBestFromFinalized();
225
+ const result = [getFinalizedEvent()];
226
+ if (prevBest !== connectedBlocks.best)
227
+ result.unshift({
228
+ event: "bestBlockChanged",
229
+ bestBlockHash: connectedBlocks.best
230
+ });
231
+ return result;
232
+ }),
233
+ rxjs.share()
234
+ );
235
+ const ready$ = rxjs.defer(
236
+ () => connectedBlocks.blocks.size ? [null] : _finalized$.pipe(
237
+ rxjs.take(1),
238
+ rxjs.map(() => null)
239
+ )
240
+ ).pipe(shareLatest);
241
+ const finalized$ = _finalized$.pipe(
242
+ rxjs.map((hash) => connectedBlocks.blocks.get(hash)),
243
+ shareLatest
244
+ );
245
+ rxjs.merge(updates$, finalized$).subscribe({
246
+ error: onError
247
+ });
248
+ const upstream = (subId) => {
249
+ const getInitialized = () => {
250
+ const { blocks, finalized } = connectedBlocks;
251
+ const finalizedBlockHashes = [];
252
+ let current = blocks.get(finalized);
253
+ while (current && finalizedBlockHashes.length < 10) {
254
+ finalizedBlockHashes.push(current.hash);
255
+ current.usages.add(subId);
256
+ current = blocks.get(current.parent);
257
+ }
258
+ finalizedBlockHashes.reverse();
259
+ return {
260
+ event: "initialized",
261
+ finalizedBlockHashes
262
+ };
263
+ };
264
+ const unpin = (blockHash) => {
265
+ const block = connectedBlocks.blocks.get(blockHash);
266
+ if (block) {
267
+ block.usages.delete(subId);
268
+ tryRemove(blockHash);
269
+ }
270
+ };
271
+ const initialEvents$ = ready$.pipe(
272
+ rxjs.mergeMap(() => {
273
+ const { best, finalized } = connectedBlocks;
274
+ const others = getTree(
275
+ finalized
276
+ ).slice(1).map(getNewBlockEvent);
277
+ others.push({
278
+ event: "bestBlockChanged",
279
+ bestBlockHash: best
280
+ });
281
+ return [getInitialized(), ...others];
282
+ })
283
+ );
284
+ return {
285
+ blocks$: rxjs.concat(initialEvents$, updates$).pipe(
286
+ rxjs.tap({
287
+ subscribe: () => {
288
+ activeSubscriptions.add(subId);
289
+ },
290
+ finalize: () => {
291
+ activeSubscriptions.delete(subId);
292
+ }
293
+ }),
294
+ rxjs.share()
295
+ ),
296
+ getHeader: (blockHash) => connectedBlocks.blocks.get(blockHash)?.header ?? null,
297
+ isPinned: (blockHash) => !!connectedBlocks.blocks.get(blockHash)?.usages.has(subId),
298
+ unpin
299
+ };
300
+ };
301
+ const clean = () => {
302
+ pendingBlocks.clear();
303
+ connectedBlocks.blocks.clear();
304
+ };
305
+ return {
306
+ clean,
307
+ upstream,
308
+ finalized$,
309
+ getHeader$: (hash) => {
310
+ const block = connectedBlocks.blocks.get(hash);
311
+ return block ? rxjs.of(block) : getHeader$(hash);
312
+ },
313
+ hasher$
314
+ };
315
+ };
316
+
317
+ const getFromShittyHeader = (hasher) => ({
318
+ parentHash,
319
+ number: rawNumber,
320
+ stateRoot,
321
+ extrinsicsRoot,
322
+ digest
323
+ }) => {
324
+ const number = Number(rawNumber);
325
+ const rawDigests = digest.logs.map(utils.fromHex);
326
+ const rawHeader = utils.mergeUint8([
327
+ utils.fromHex(parentHash),
328
+ substrateBindings.compact.enc(number),
329
+ utils.fromHex(stateRoot),
330
+ utils.fromHex(extrinsicsRoot),
331
+ substrateBindings.compact.enc(digest.logs.length),
332
+ ...rawDigests
333
+ ]);
334
+ return {
335
+ parent: parentHash,
336
+ hash: utils.toHex(hasher(rawHeader)),
337
+ number,
338
+ hasUpgrade: rawDigests.some(([x]) => x === 8),
339
+ header: utils.toHex(rawHeader)
340
+ };
341
+ };
342
+
343
+ const hashers = [substrateBindings.Blake2256, substrateBindings.Keccak256];
344
+ const fns = hashers.map(getFromShittyHeader);
345
+ const noHasher = (_) => {
346
+ throw new Error("Hasher not supported");
347
+ };
348
+ const getHasherFromBlock = (shitHeader) => (hash) => hashers[fns.findIndex((fn) => fn(shitHeader).hash === hash)] || noHasher;
349
+
350
+ const withLatestFromBp = (latest$) => (base$) => new rxjs.Observable((observer) => {
351
+ let latest;
352
+ let prev = [];
353
+ const subscription = base$.subscribe({
354
+ next(v) {
355
+ if (prev) prev.push(v);
356
+ else observer.next([latest, v]);
357
+ },
358
+ error(e) {
359
+ observer.error(e);
360
+ },
361
+ complete() {
362
+ observer.complete();
363
+ }
364
+ });
365
+ subscription.add(
366
+ latest$.subscribe({
367
+ next(v) {
368
+ latest = v;
369
+ if (prev) {
370
+ const copy = [...prev];
371
+ prev = null;
372
+ copy.forEach((p) => observer.next([latest, p]));
373
+ }
374
+ },
375
+ error(e) {
376
+ observer.error(e);
377
+ },
378
+ complete() {
379
+ if (prev) observer.error(new Error("Empty complete"));
380
+ }
381
+ })
382
+ );
383
+ return subscription;
384
+ });
385
+
386
+ const INITIAL_ERROR = {};
387
+ const getUpstreamEvents = (request, request$) => {
388
+ const firstFinHeader$ = new rxjs.Subject();
389
+ const hasher$ = firstFinHeader$.pipe(
390
+ rxjs.mergeMap(
391
+ (h) => request$("chain_getBlockHash", [
392
+ h.number
393
+ ]).pipe(rxjs.map(getHasherFromBlock(h)))
394
+ ),
395
+ shareLatest
396
+ );
397
+ const fromShittyHeader$ = hasher$.pipe(rxjs.map(getFromShittyHeader), shareLatest);
398
+ const toNiceHeader = rxjs.pipe(
399
+ withLatestFromBp(fromShittyHeader$),
400
+ rxjs.map(([fromShittyHeader, shitHeader]) => fromShittyHeader(shitHeader))
401
+ );
402
+ const getHeaders$ = (startMethod, stopMethod, isFin = false) => new rxjs.Observable((observer) => {
403
+ const onError = (e) => {
404
+ observer.error(e);
405
+ };
406
+ let stop = null;
407
+ let isFirstFin = isFin;
408
+ request(startMethod, [], {
409
+ onSuccess: (subId, followSub) => {
410
+ const done = followSub(subId, {
411
+ next: (v) => {
412
+ if (isFirstFin) {
413
+ isFirstFin = false;
414
+ firstFinHeader$.next(v);
415
+ firstFinHeader$.complete();
416
+ }
417
+ observer.next(v);
418
+ },
419
+ error: onError
420
+ });
421
+ const unsubscribe = () => {
422
+ done();
423
+ try {
424
+ request(stopMethod, [subId], {
425
+ onError: utils.noop,
426
+ onSuccess: utils.noop
427
+ });
428
+ } catch {
429
+ }
430
+ };
431
+ if (stop !== null) unsubscribe();
432
+ else stop = unsubscribe;
433
+ },
434
+ onError() {
435
+ onError(INITIAL_ERROR);
436
+ }
437
+ });
438
+ return () => {
439
+ stop?.();
440
+ stop = utils.noop;
441
+ };
442
+ }).pipe(toNiceHeader);
443
+ const allHeads$ = getHeaders$(
444
+ "chain_subscribeAllHeads",
445
+ "chain_unsubscribeAllHeads"
446
+ );
447
+ const finalized$ = getHeaders$(
448
+ "chain_subscribeFinalizedHeads",
449
+ "chain_unsubscribeFinalizedHeads",
450
+ true
451
+ );
452
+ const getHeader$ = (hash) => request$("chain_getHeader", [hash]).pipe(
453
+ toNiceHeader
454
+ );
455
+ const getRecursiveHeader = (hash) => getHeader$(hash).pipe(
456
+ rxjs.mergeMap(
457
+ (header) => rxjs.concat(rxjs.of(header), getRecursiveHeader(header.parent))
458
+ )
459
+ );
460
+ return {
461
+ allHeads$,
462
+ finalized$,
463
+ hasher$,
464
+ getRecursiveHeader,
465
+ getHeader$
466
+ };
467
+ };
468
+
469
+ const getBlocks$ = (request, request$) => getBlocks(getUpstreamEvents(request, request$));
470
+
471
+ const createClosestDescendantMerkleValue = (obsRequest) => (at, key) => obsRequest("state_getReadProof", [[key], at]).pipe(
472
+ rxjs.mergeMap((x) => {
473
+ const result = substrateBindings.validateProofs(x.proof);
474
+ if (!result) throw new Error("Invalid Proof");
475
+ const { rootHash, proofs } = result;
476
+ let winnerHash = rootHash;
477
+ let current = proofs[winnerHash];
478
+ let nKeyChars = 2;
479
+ do {
480
+ const nextOne = proofs[winnerHash];
481
+ if (!nextOne || nextOne.type === "Raw") break;
482
+ current = nextOne;
483
+ winnerHash = void 0;
484
+ if (!current.partialKey.startsWith(
485
+ key.slice(nKeyChars, nKeyChars + current.partialKey.length)
486
+ ))
487
+ return [];
488
+ nKeyChars += current.partialKey.length;
489
+ if ((current.type === "LeafWithHash" || current.type === "BranchWithHash") && proofs[current.value]) {
490
+ winnerHash = current.value;
491
+ continue;
492
+ }
493
+ if ("children" in current) {
494
+ const winner = Object.entries(
495
+ current.children
496
+ ).find(([, hash]) => proofs[hash]);
497
+ if (winner) {
498
+ if (winner[0] !== key[nKeyChars++]) return [];
499
+ winnerHash = winner[1];
500
+ }
501
+ }
502
+ } while (winnerHash);
503
+ return [current.hash];
504
+ })
505
+ );
506
+
507
+ const createUpstream = (request) => {
508
+ const simpleRequest = (method, params, onSuccess, onError) => request(method, params, { onSuccess, onError });
509
+ const obsRequest = (method, params) => new rxjs.Observable(
510
+ (observer) => simpleRequest(
511
+ method,
512
+ params,
513
+ (v) => {
514
+ observer.next(v);
515
+ observer.complete();
516
+ },
517
+ (e) => {
518
+ observer.error(e);
519
+ }
520
+ )
521
+ );
522
+ const {
523
+ upstream: getBlocks,
524
+ finalized$,
525
+ getHeader$,
526
+ hasher$,
527
+ clean
528
+ } = getBlocks$(request, obsRequest);
529
+ const runtimeCall = (atBlock, method, data) => obsRequest("state_call", [
530
+ method,
531
+ data,
532
+ atBlock
533
+ ]);
534
+ const stgDescendantValues = (at, rootKey) => {
535
+ const PAGE_SIZE = 1e3;
536
+ const getKeys = (startAtKey) => {
537
+ return obsRequest(
538
+ "state_getKeysPaged",
539
+ [rootKey, PAGE_SIZE, startAtKey || void 0, at]
540
+ ).pipe(
541
+ rxjs.mergeMap((receivedKeys) => {
542
+ const keys = receivedKeys[0] === startAtKey ? receivedKeys.slice(1) : receivedKeys;
543
+ const continuation = receivedKeys.length < PAGE_SIZE ? rxjs.EMPTY : getKeys(receivedKeys.at(-1));
544
+ return rxjs.merge(rxjs.of(keys), continuation);
545
+ })
546
+ );
547
+ };
548
+ const getValues = (keys, nSplits = 0) => keys.length ? obsRequest("state_queryStorageAt", [keys, at]).pipe(
549
+ rxjs.map(([{ changes }]) => changes),
550
+ rxjs.catchError((e) => {
551
+ if (nSplits > 3) throw e;
552
+ const midIdx = Math.floor(keys.length / 2);
553
+ return rxjs.merge(
554
+ getValues(keys.slice(0, midIdx), ++nSplits),
555
+ getValues(keys.slice(midIdx), nSplits)
556
+ );
557
+ })
558
+ ) : rxjs.EMPTY;
559
+ return getKeys().pipe(rxjs.mergeMap((keys) => getValues(keys)));
560
+ };
561
+ const stgDescendantHashes = (at, rootKey) => stgDescendantValues(at, rootKey).pipe(
562
+ withLatestFromBp(hasher$),
563
+ rxjs.map(
564
+ ([hasher, results]) => results.map(
565
+ ([key, value]) => [key, utils.toHex(hasher(utils.fromHex(value)))]
566
+ )
567
+ )
568
+ );
569
+ const stgClosestDescendant = createClosestDescendantMerkleValue(obsRequest);
570
+ const [stgValue, stgHash] = ["state_getStorage", "state_getStorageHash"].map(
571
+ (method) => (atBlock, key) => obsRequest(method, [
572
+ key,
573
+ atBlock
574
+ ])
575
+ );
576
+ const methods = obsRequest("rpc_methods", []);
577
+ const chainName = obsRequest("system_name", []);
578
+ const properties = obsRequest("system_properties", []);
579
+ const getBody = (at) => obsRequest(
580
+ "chain_getBlock",
581
+ [at]
582
+ );
583
+ const getBlockHash$ = (height) => obsRequest("chain_getBlockHash", [height]);
584
+ const genesisHash = getBlockHash$(0);
585
+ return {
586
+ getBlocks,
587
+ finalized$,
588
+ getBlockHash$,
589
+ getHeader$,
590
+ stgValue,
591
+ stgHash,
592
+ stgDescendantValues,
593
+ stgDescendantHashes,
594
+ stgClosestDescendant,
595
+ runtimeCall,
596
+ getBody,
597
+ chainName,
598
+ properties,
599
+ genesisHash,
600
+ clean,
601
+ methods,
602
+ request: simpleRequest,
603
+ obsRequest
604
+ };
605
+ };
606
+
607
+ const createChainSpec = (upstream, reply, err) => {
608
+ return (rId, method) => {
609
+ const [, , name] = method.split("_");
610
+ const observable = upstream[name];
611
+ if (!observable) throw null;
612
+ observable.subscribe(
613
+ (result) => {
614
+ reply(rId, result);
615
+ },
616
+ () => {
617
+ err(rId, -32602, "Invalid");
618
+ }
619
+ );
620
+ };
621
+ };
622
+
623
+ let latestId = 1;
624
+ const createOpaqueToken = () => {
625
+ return `${latestId++}${Date.now()}`;
626
+ };
627
+
628
+ const validStorageTypes = /* @__PURE__ */ new Set([
629
+ "value",
630
+ "hash",
631
+ "closestDescendantMerkleValue",
632
+ "descendantsValues",
633
+ "descendantsHashes"
634
+ ]);
635
+ const areItemsValid = (items) => Array.isArray(items) && items.every(
636
+ (x) => typeof x === "object" && typeof x.key === "string" && validStorageTypes.has(x.type)
637
+ );
638
+ const getStg$ = (upstream, at, items) => rxjs.merge(
639
+ ...items.map(({ key, type }) => {
640
+ switch (type) {
641
+ case "value":
642
+ return upstream.stgValue(at, key).pipe(
643
+ rxjs.filter(Boolean),
644
+ rxjs.map((value) => [
645
+ {
646
+ key,
647
+ value
648
+ }
649
+ ])
650
+ );
651
+ case "hash":
652
+ return upstream.stgHash(at, key).pipe(
653
+ rxjs.filter(Boolean),
654
+ rxjs.map((hash) => [
655
+ {
656
+ key,
657
+ hash
658
+ }
659
+ ])
660
+ );
661
+ case "descendantsValues":
662
+ return upstream.stgDescendantValues(at, key).pipe(
663
+ rxjs.map((values) => values.map(([key2, value]) => ({ key: key2, value })))
664
+ );
665
+ case "descendantsHashes":
666
+ return upstream.stgDescendantHashes(at, key).pipe(rxjs.map((values) => values.map(([key2, hash]) => ({ key: key2, hash }))));
667
+ case "closestDescendantMerkleValue":
668
+ return upstream.stgClosestDescendant(at, key).pipe(
669
+ rxjs.filter(Boolean),
670
+ rxjs.map((closestDescendantMerkleValue) => [
671
+ {
672
+ key,
673
+ closestDescendantMerkleValue
674
+ }
675
+ ])
676
+ );
677
+ }
678
+ })
679
+ );
680
+
681
+ const getMsgFromErr = (e) => {
682
+ if (e instanceof Error) return e.message;
683
+ if (typeof e === "string") return e;
684
+ return "Unhandled exception";
685
+ };
686
+
687
+ const chainHead = {
688
+ body: "",
689
+ call: "",
690
+ continue: "",
691
+ follow: "",
692
+ header: "",
693
+ stopOperation: "",
694
+ storage: "",
695
+ unfollow: "",
696
+ unpin: ""
697
+ };
698
+ const archive = {
699
+ body: "",
700
+ call: "",
701
+ finalizedHeight: "",
702
+ genesisHash: "",
703
+ hashByHeight: "",
704
+ header: "",
705
+ stopStorage: "",
706
+ storage: ""
707
+ };
708
+ const transaction = {
709
+ broadcast: "",
710
+ stop: ""
711
+ };
712
+ const chainSpec = {
713
+ chainName: "",
714
+ genesisHash: "",
715
+ properties: ""
716
+ };
717
+ Object.entries({ chainHead, chainSpec, transaction, archive }).forEach(
718
+ ([fnGroupName, methods]) => {
719
+ Object.keys(methods).forEach((methodName) => {
720
+ methods[methodName] = `${fnGroupName}_v1_${methodName}`;
721
+ });
722
+ }
723
+ );
724
+
725
+ const { follow: follow$4, header: header$1, storage: storage$2, body: body$2, call: call$2, unfollow: unfollow$4, stopOperation: stopOperation$1, unpin: unpin$2 } = chainHead;
726
+ const createChainHead = (upstream, reply, err, notification) => {
727
+ const subscriptions = /* @__PURE__ */ new Map();
728
+ const _follow = (rId) => {
729
+ if (subscriptions.size === 2) {
730
+ return err(rId, -32800, "Limit reached");
731
+ }
732
+ const token = createOpaqueToken();
733
+ const fNotification = (result2) => notification("chainHead_v1_followEvent", token, result2);
734
+ const up = upstream.getBlocks(token);
735
+ const operations = /* @__PURE__ */ new Map();
736
+ subscriptions.set(token, {
737
+ id: token,
738
+ up,
739
+ operations,
740
+ cleanUp: () => {
741
+ cleanUp();
742
+ }
743
+ });
744
+ reply(rId, token);
745
+ let subscription = null;
746
+ let cleanUp = () => {
747
+ cleanUp = utils.noop;
748
+ subscription?.unsubscribe();
749
+ subscription = null;
750
+ operations.forEach((cb) => {
751
+ cb();
752
+ });
753
+ operations.clear();
754
+ subscriptions.delete(token);
755
+ };
756
+ subscription = up.blocks$.subscribe({
757
+ next(v) {
758
+ fNotification(v);
759
+ },
760
+ error() {
761
+ cleanUp();
762
+ fNotification({ event: "stop" });
763
+ }
764
+ });
765
+ if (subscription.closed) subscription = null;
766
+ };
767
+ const _unfollow = (rId, followId) => {
768
+ subscriptions.get(followId)?.cleanUp();
769
+ reply(rId, "null");
770
+ };
771
+ const _stopOperation = (rId, followId, operationId) => {
772
+ const cb = subscriptions.get(followId)?.operations.get(operationId);
773
+ if (cb) cb();
774
+ reply(rId, "null");
775
+ };
776
+ const _header = ({ up: { getHeader } }, reply2, at) => reply2(getHeader(at));
777
+ const _unpin = ({ up: { unpin: innerUnpin } }, reply2, hashOrHashes) => {
778
+ const hashes = typeof hashOrHashes === "string" ? [hashOrHashes] : hashOrHashes;
779
+ hashes.forEach(innerUnpin);
780
+ reply2(null);
781
+ };
782
+ const _call = ({ operations, id: followId }, reply2, at, method, args) => {
783
+ const operationId = createOpaqueToken();
784
+ reply2({ result: "started", operationId });
785
+ const cNotification = (output, isErr = false) => notification(
786
+ call$2,
787
+ followId,
788
+ isErr ? {
789
+ operationId,
790
+ event: "operationError",
791
+ error: output
792
+ } : {
793
+ operationId,
794
+ event: "operationCallDone",
795
+ output
796
+ }
797
+ );
798
+ const subscription = upstream.runtimeCall(at, method, args).subscribe(
799
+ (output) => {
800
+ operations.delete(operationId);
801
+ cNotification(output);
802
+ },
803
+ (e) => {
804
+ operations.delete(operationId);
805
+ cNotification(getMsgFromErr(e), true);
806
+ }
807
+ );
808
+ if (!subscription.closed)
809
+ operations.set(operationId, () => {
810
+ subscription.unsubscribe();
811
+ operations.delete(operationId);
812
+ });
813
+ };
814
+ const _body = ({ operations, id: followId }, reply2, at) => {
815
+ const operationId = createOpaqueToken();
816
+ reply2({ result: "started", operationId });
817
+ const subscription = upstream.getBody(at).subscribe(
818
+ ({ block: { extrinsics: value } }) => {
819
+ operations.delete(operationId);
820
+ notification(body$2, followId, {
821
+ event: "operationBodyDone",
822
+ operationId,
823
+ value
824
+ });
825
+ },
826
+ (e) => {
827
+ operations.delete(operationId);
828
+ notification(body$2, followId, {
829
+ event: "operationError",
830
+ operationId,
831
+ error: getMsgFromErr(e)
832
+ });
833
+ }
834
+ );
835
+ if (!subscription.closed)
836
+ operations.set(operationId, () => {
837
+ subscription.unsubscribe();
838
+ operations.delete(operationId);
839
+ });
840
+ };
841
+ const _stg = ({ operations, id: followId }, reply2, at, items) => {
842
+ const operationId = createOpaqueToken();
843
+ reply2({ result: "started", operationId });
844
+ const innerNotifiaction = (msg) => {
845
+ notification(storage$2, followId, msg);
846
+ };
847
+ const subscription = getStg$(upstream, at, items).pipe(
848
+ rxjs.finalize(() => {
849
+ operations.delete(operationId);
850
+ })
851
+ ).subscribe(
852
+ (items2) => {
853
+ innerNotifiaction({
854
+ event: "operationStorageItems",
855
+ operationId,
856
+ items: items2
857
+ });
858
+ },
859
+ (e) => {
860
+ innerNotifiaction({
861
+ event: "operationError",
862
+ operationId,
863
+ error: getMsgFromErr(e)
864
+ });
865
+ },
866
+ () => {
867
+ innerNotifiaction({
868
+ event: "operationStorageDone",
869
+ operationId
870
+ });
871
+ }
872
+ );
873
+ if (!subscription.closed)
874
+ operations.set(operationId, () => {
875
+ subscription.unsubscribe();
876
+ });
877
+ };
878
+ const result = (rId, method, params) => {
879
+ if (method === follow$4) return _follow(rId);
880
+ const [followId, ...rest] = params;
881
+ const ctx = subscriptions.get(followId);
882
+ if (!ctx) return err(rId, -32602, "Ivalid followSubscription");
883
+ const innerReply = (value) => {
884
+ reply(rId, value);
885
+ };
886
+ switch (method) {
887
+ case unfollow$4:
888
+ return _unfollow(rId, followId);
889
+ case stopOperation$1:
890
+ return _stopOperation(rId, followId, rest[0]);
891
+ case unpin$2: {
892
+ const [hashOrHashes] = rest;
893
+ if ((Array.isArray(hashOrHashes) ? hashOrHashes : [hashOrHashes]).some(
894
+ (hash) => typeof hash !== "string"
895
+ ))
896
+ return err(rId, -32602, "Invalid args");
897
+ return _unpin(ctx, innerReply, hashOrHashes);
898
+ }
899
+ default: {
900
+ const [at, ...other] = rest;
901
+ if (!ctx.up.isPinned(at)) return err(rId, -32801, "Block not pinned");
902
+ switch (method) {
903
+ case header$1:
904
+ return _header(ctx, innerReply, at);
905
+ case body$2:
906
+ return _body(ctx, innerReply, at);
907
+ case call$2: {
908
+ const [method2, data] = other;
909
+ if (typeof method2 !== "string" || typeof data !== "string")
910
+ return err(rId, -32602, "Invalid args");
911
+ return _call(ctx, innerReply, at, method2, data);
912
+ }
913
+ case storage$2: {
914
+ const [items] = other;
915
+ return areItemsValid(items) ? _stg(ctx, innerReply, at, items) : err(rId, -32602, "Invalid args");
916
+ }
917
+ }
918
+ }
919
+ }
920
+ throw null;
921
+ };
922
+ result.stop = () => {
923
+ subscriptions.forEach((x) => {
924
+ x.cleanUp();
925
+ });
926
+ };
927
+ return result;
928
+ };
929
+
930
+ const { stop, broadcast } = transaction;
931
+ const createTransactionFns = (upstream, reply) => {
932
+ const ongoing = /* @__PURE__ */ new Map();
933
+ const result = (rId, method, args) => {
934
+ if (method === stop) {
935
+ const [token] = args;
936
+ ongoing.get(token)?.unsubscribe();
937
+ ongoing.delete(token);
938
+ reply(rId, null);
939
+ } else if (method === broadcast) {
940
+ const token = createOpaqueToken();
941
+ ongoing.set(
942
+ token,
943
+ upstream.obsRequest("author_submitExtrinsic", args).pipe(
944
+ // We want to make sure that we keep on retrying if there
945
+ // are errors with the `author_submitExtrinsic` request
946
+ rxjs.catchError((_, source) => rxjs.concat(rxjs.timer(5e3), source)),
947
+ // This logic ensures that the subscription dies if an
948
+ // upstream error (like the client being destroyed) takes place
949
+ rxjs.takeUntil(
950
+ upstream.finalized$.pipe(
951
+ rxjs.ignoreElements(),
952
+ rxjs.catchError(() => {
953
+ ongoing.delete(token);
954
+ return [null];
955
+ })
956
+ )
957
+ )
958
+ ).subscribe()
959
+ );
960
+ reply(rId, token);
961
+ } else {
962
+ throw null;
963
+ }
964
+ };
965
+ result.stop = () => {
966
+ ongoing.forEach((s) => s.unsubscribe());
967
+ ongoing.clear();
968
+ };
969
+ return result;
970
+ };
971
+
972
+ const {
973
+ body: body$1,
974
+ call: call$1,
975
+ finalizedHeight,
976
+ genesisHash,
977
+ hashByHeight,
978
+ header,
979
+ stopStorage,
980
+ storage: storage$1
981
+ } = archive;
982
+ const createArchive = (upstream, reply, err, notification) => {
983
+ const stgSubscriptions = /* @__PURE__ */ new Map();
984
+ const stg = (reply2, at, items) => {
985
+ const subId = createOpaqueToken();
986
+ reply2(subId);
987
+ const innerNotifiaction = (result2) => {
988
+ notification("archive_v1_storageEvent", subId, result2);
989
+ };
990
+ const subscription = getStg$(upstream, at, items).pipe(
991
+ rxjs.finalize(() => {
992
+ stgSubscriptions.delete(subId);
993
+ })
994
+ ).subscribe(
995
+ (items2) => {
996
+ items2.forEach(
997
+ (item) => innerNotifiaction({ event: "storage", ...item })
998
+ );
999
+ },
1000
+ (e) => {
1001
+ innerNotifiaction({ event: "storageError", error: getMsgFromErr(e) });
1002
+ },
1003
+ () => {
1004
+ innerNotifiaction({ event: "storageDone" });
1005
+ }
1006
+ );
1007
+ if (!subscription.closed) stgSubscriptions.set(subId, subscription);
1008
+ };
1009
+ const result = (rId, name, params) => {
1010
+ const innerReply = (value) => {
1011
+ reply(rId, value);
1012
+ };
1013
+ const obsReply = (input) => {
1014
+ input.subscribe({
1015
+ next: innerReply,
1016
+ error: (e) => {
1017
+ err(rId, e.code ?? -1, getMsgFromErr(e));
1018
+ }
1019
+ });
1020
+ };
1021
+ const [firstArg, secondArg, thirdArg] = params;
1022
+ switch (name) {
1023
+ case body$1:
1024
+ return obsReply(upstream.getBody(firstArg));
1025
+ case call$1:
1026
+ return obsReply(
1027
+ upstream.runtimeCall(firstArg, secondArg, thirdArg).pipe(rxjs.map((value) => ({ success: true, value })))
1028
+ );
1029
+ case finalizedHeight:
1030
+ return obsReply(
1031
+ upstream.finalized$.pipe(
1032
+ rxjs.map((x) => x.number),
1033
+ rxjs.take(1)
1034
+ )
1035
+ );
1036
+ case genesisHash:
1037
+ return obsReply(upstream.genesisHash);
1038
+ case hashByHeight:
1039
+ return obsReply(upstream.getBlockHash$(firstArg));
1040
+ case header:
1041
+ return obsReply(
1042
+ upstream.getHeader$(firstArg).pipe(rxjs.map((h) => h.header))
1043
+ );
1044
+ case stopStorage: {
1045
+ const sub = stgSubscriptions.get(firstArg);
1046
+ return sub ? sub.unsubscribe() : err(rId, -32602, "Invalid args");
1047
+ }
1048
+ case storage$1:
1049
+ return areItemsValid(secondArg) ? stg(innerReply, firstArg, secondArg) : err(rId, -32602, "Invalid args");
1050
+ }
1051
+ throw null;
1052
+ };
1053
+ result.stop = () => {
1054
+ [...stgSubscriptions].forEach(([, s]) => s.unsubscribe());
1055
+ stgSubscriptions.clear();
1056
+ };
1057
+ return result;
1058
+ };
1059
+
1060
+ const supportedMethods = new Set(
1061
+ [chainHead, chainSpec, archive, transaction].map((methods) => Object.values(methods)).flat()
1062
+ );
1063
+ const withLegacy = (base) => (onMessage, onHalt) => {
1064
+ let clean = utils.noop;
1065
+ let onMsg = utils.noop;
1066
+ const innerConnection = base(
1067
+ (msg) => {
1068
+ onMsg(msg);
1069
+ },
1070
+ (e) => {
1071
+ clean();
1072
+ onHalt(e);
1073
+ }
1074
+ );
1075
+ const { disconnect, request } = rawClient.createClient((_onMsg) => {
1076
+ onMsg = _onMsg;
1077
+ return innerConnection;
1078
+ });
1079
+ const upstream = createUpstream(request);
1080
+ const jsonRpc = (input) => onMessage({
1081
+ jsonrpc: "2.0",
1082
+ ...input
1083
+ });
1084
+ const reply = (id, result) => {
1085
+ jsonRpc({ id, result });
1086
+ };
1087
+ const err = (id, code, message) => {
1088
+ jsonRpc({ id, error: { code, message } });
1089
+ };
1090
+ const notification = (method, subscription, result) => {
1091
+ jsonRpc({ method, params: { subscription, result } });
1092
+ };
1093
+ const groups = {
1094
+ chainSpec: createChainSpec(upstream, reply, err),
1095
+ chainHead: createChainHead(upstream, reply, err, notification),
1096
+ archive: createArchive(upstream, reply, err, notification),
1097
+ transaction: createTransactionFns(upstream, reply)
1098
+ };
1099
+ clean = () => {
1100
+ groups.chainHead.stop();
1101
+ groups.archive.stop();
1102
+ groups.transaction.stop();
1103
+ upstream.clean();
1104
+ };
1105
+ return {
1106
+ send: (parsedMsg) => {
1107
+ if (!parsedMsg) return;
1108
+ const { id, method, params } = parsedMsg;
1109
+ if (id !== null && typeof id !== "string" && typeof id !== "number" || typeof method !== "string") {
1110
+ console.warn(`Invalid message:
1111
+ ${JSON.stringify(parsedMsg)}`);
1112
+ return;
1113
+ }
1114
+ if (method === "rpc_methods") {
1115
+ return upstream.methods.subscribe(
1116
+ ({ methods }) => {
1117
+ reply(id, {
1118
+ methods: [
1119
+ ...supportedMethods,
1120
+ ...methods.filter((method2) => !supportedMethods.has(method2))
1121
+ ]
1122
+ });
1123
+ },
1124
+ (e) => {
1125
+ console.error(e);
1126
+ err(id, -32602, "Invalid");
1127
+ }
1128
+ );
1129
+ }
1130
+ const [groupName] = method.split("_");
1131
+ if (groupName in groups) {
1132
+ try {
1133
+ return groups[groupName](id, method, params);
1134
+ } catch (e) {
1135
+ if (e !== null) throw e;
1136
+ }
1137
+ }
1138
+ upstream.request(
1139
+ method,
1140
+ params,
1141
+ (value) => {
1142
+ reply(id, value);
1143
+ },
1144
+ (e) => {
1145
+ err(id, e?.code || -1, e?.message || "");
1146
+ }
1147
+ );
1148
+ },
1149
+ disconnect: () => {
1150
+ clean();
1151
+ disconnect();
1152
+ }
1153
+ };
1154
+ };
1155
+
1156
+ const apply = (...middlewares) => (base) => middlewares.reduce((a, b) => b(a), base);
1157
+ const jsonObj = (input) => ({
1158
+ jsonrpc: "2.0",
1159
+ ...input
1160
+ });
1161
+
1162
+ const getAsyncMiddleware = (input) => (base) => (onMessageOut, onHaltOut) => {
1163
+ let interceptedMessage = utils.noop;
1164
+ let pending = [];
1165
+ let send = (msg) => {
1166
+ pending.push(msg);
1167
+ };
1168
+ let stopRequest = utils.noop;
1169
+ let isOn = true;
1170
+ let done = () => {
1171
+ isOn = false;
1172
+ pending = [];
1173
+ stopRequest();
1174
+ done = interceptedMessage = interceptedHalt = stopRequest = utils.noop;
1175
+ };
1176
+ let interceptedHalt = (e) => {
1177
+ done();
1178
+ onHaltOut(e);
1179
+ };
1180
+ const innerCon = base(
1181
+ (msg) => interceptedMessage(msg),
1182
+ (e) => interceptedHalt(e)
1183
+ );
1184
+ let { disconnect } = innerCon;
1185
+ const { request } = rawClient.createClient((innerClientOnMsg) => {
1186
+ interceptedMessage = innerClientOnMsg;
1187
+ return { ...innerCon, disconnect: utils.noop };
1188
+ });
1189
+ if (isOn)
1190
+ stopRequest = input((cb) => {
1191
+ stopRequest = utils.noop;
1192
+ if (!cb) interceptedHalt();
1193
+ else {
1194
+ ({ send, disconnect } = cb((onMiddleMsg, onMiddleHalt) => {
1195
+ interceptedHalt = (e) => {
1196
+ done();
1197
+ onMiddleHalt(e);
1198
+ };
1199
+ interceptedMessage = onMiddleMsg;
1200
+ return innerCon;
1201
+ })(onMessageOut, onHaltOut));
1202
+ pending.forEach(send);
1203
+ pending = [];
1204
+ }
1205
+ }, request);
1206
+ return {
1207
+ send: (msg) => {
1208
+ send(msg);
1209
+ },
1210
+ disconnect: () => {
1211
+ done();
1212
+ disconnect();
1213
+ }
1214
+ };
1215
+ };
1216
+
1217
+ const RPC_METHODS = "rpc_methods";
1218
+ const withMethods = (methods) => (base) => (onMsg, onHalt) => {
1219
+ const result = { methods };
1220
+ const { send, disconnect } = base(onMsg, onHalt);
1221
+ return {
1222
+ disconnect,
1223
+ send(msg) {
1224
+ if (msg.id && msg.method === RPC_METHODS) {
1225
+ onMsg(jsonObj({ id: msg.id, result }));
1226
+ } else send(msg);
1227
+ }
1228
+ };
1229
+ };
1230
+ const methodsRouter = (getMiddleware) => getAsyncMiddleware((onReady, request) => {
1231
+ let nTries = 0;
1232
+ let stopRequest = utils.noop;
1233
+ const getMethods = () => {
1234
+ nTries++;
1235
+ stopRequest = request(RPC_METHODS, [], {
1236
+ onSuccess: ({ methods }) => {
1237
+ onReady(apply(withMethods(methods), getMiddleware(methods)));
1238
+ },
1239
+ onError: () => {
1240
+ if (nTries > 3) onReady(null);
1241
+ else {
1242
+ const token = setTimeout(getMethods, 500);
1243
+ stopRequest = () => clearTimeout(token);
1244
+ }
1245
+ }
1246
+ });
1247
+ };
1248
+ getMethods();
1249
+ return () => stopRequest();
1250
+ });
1251
+
1252
+ const { follow: follow$3, unfollow: unfollow$3 } = chainHead;
1253
+ const resetStops = () => ({ latest: Date.now(), count: 0 });
1254
+ const followEnhancer = (base) => (onMsg, onHalt) => {
1255
+ const prematureStops = /* @__PURE__ */ new Map();
1256
+ const preOpId = /* @__PURE__ */ new Map();
1257
+ const onGoing = /* @__PURE__ */ new Set();
1258
+ let nStops = resetStops();
1259
+ const cleanup = () => {
1260
+ [prematureStops, preOpId, onGoing].forEach((x) => {
1261
+ x.clear();
1262
+ });
1263
+ };
1264
+ const forceDisconnect = () => {
1265
+ disconnect();
1266
+ cleanup();
1267
+ onHalt();
1268
+ };
1269
+ const { send, disconnect } = base(
1270
+ (parsed) => {
1271
+ if ("id" in parsed) {
1272
+ const { id, result } = parsed;
1273
+ const msg = preOpId.get(id);
1274
+ if (msg) {
1275
+ preOpId.delete(id);
1276
+ const prematureStop = prematureStops.get(result);
1277
+ if (prematureStop) {
1278
+ prematureStops.delete(result);
1279
+ onMsg(parsed);
1280
+ onMsg(prematureStop);
1281
+ return;
1282
+ }
1283
+ onGoing.add(result);
1284
+ const currentSize = onGoing.size + preOpId.size;
1285
+ if (currentSize > 2)
1286
+ console.warn(
1287
+ `Too many chainHead follow subscriptions (${currentSize})`
1288
+ );
1289
+ else if (parsed.error) {
1290
+ console.warn(`chainHead follow failed on the ${currentSize} sub`);
1291
+ forceDisconnect();
1292
+ return;
1293
+ }
1294
+ }
1295
+ } else {
1296
+ const { subscription, result } = parsed.params;
1297
+ if (result?.event === "stop") {
1298
+ const diff = Date.now() - nStops.latest;
1299
+ nStops.latest += diff;
1300
+ nStops.count = diff < 1e3 ? nStops.count + 1 : 1;
1301
+ if (onGoing.has(subscription)) onGoing.delete(subscription);
1302
+ else prematureStops.set(subscription, parsed);
1303
+ }
1304
+ }
1305
+ onMsg(parsed);
1306
+ if (nStops.count > 2) {
1307
+ nStops = resetStops();
1308
+ forceDisconnect();
1309
+ }
1310
+ },
1311
+ (e) => {
1312
+ cleanup();
1313
+ onHalt(e);
1314
+ }
1315
+ );
1316
+ return {
1317
+ send(parsed) {
1318
+ const { method } = parsed;
1319
+ if (method === follow$3) preOpId.set(parsed.id, parsed);
1320
+ else if (method === unfollow$3) onGoing.delete(parsed.params[0]);
1321
+ send(parsed);
1322
+ },
1323
+ disconnect
1324
+ };
1325
+ };
1326
+
1327
+ const { follow: follow$2, unpin: unpin$1, unfollow: unfollow$2 } = chainHead;
1328
+ const fixPrematureBlocks = (base) => (onMsg, onHalt) => {
1329
+ const pendingChainHeadSubs = /* @__PURE__ */ new Set();
1330
+ const pinnedBlocksInSub = /* @__PURE__ */ new Map();
1331
+ const prematureBlocks = /* @__PURE__ */ new Map();
1332
+ const withClear = (fn) => (...args) => {
1333
+ [pendingChainHeadSubs, pinnedBlocksInSub, prematureBlocks].forEach(
1334
+ (x) => {
1335
+ x.clear();
1336
+ }
1337
+ );
1338
+ fn(...args);
1339
+ };
1340
+ const { send: originalSend, disconnect } = base((message) => {
1341
+ if ("id" in message) {
1342
+ onMsg(message);
1343
+ const { id, result } = message;
1344
+ if (pendingChainHeadSubs.has(id)) {
1345
+ pendingChainHeadSubs.delete(id);
1346
+ pinnedBlocksInSub.set(result, /* @__PURE__ */ new Set());
1347
+ prematureBlocks.set(result, /* @__PURE__ */ new Map());
1348
+ return;
1349
+ }
1350
+ } else {
1351
+ const { subscription } = message.params;
1352
+ const pinnedBlocks = pinnedBlocksInSub.get(subscription);
1353
+ const prematureSub = prematureBlocks.get(subscription);
1354
+ if (pinnedBlocks) {
1355
+ const result = message.params.result;
1356
+ const { event } = result;
1357
+ if (event === "initialized") {
1358
+ result.finalizedBlockHashes.forEach((hash) => {
1359
+ pinnedBlocks.add(hash);
1360
+ });
1361
+ }
1362
+ if (event === "newBlock") {
1363
+ const { parentBlockHash } = result;
1364
+ if (!pinnedBlocks.has(parentBlockHash)) {
1365
+ const list = prematureSub.get(parentBlockHash) ?? [];
1366
+ list.push(message);
1367
+ prematureSub.set(parentBlockHash, list);
1368
+ return;
1369
+ }
1370
+ const hash = result.blockHash;
1371
+ pinnedBlocks.add(result.blockHash);
1372
+ onMsg(message);
1373
+ const prematureMessages = prematureSub.get(hash);
1374
+ if (prematureMessages) {
1375
+ prematureSub.delete(hash);
1376
+ prematureMessages.forEach((msg) => {
1377
+ pinnedBlocks.add(msg.params.result.blockHash);
1378
+ onMsg(msg);
1379
+ });
1380
+ }
1381
+ return;
1382
+ }
1383
+ if (event === "stop") {
1384
+ pinnedBlocks.delete(subscription);
1385
+ prematureBlocks.delete(subscription);
1386
+ }
1387
+ }
1388
+ onMsg(message);
1389
+ }
1390
+ }, withClear(onHalt));
1391
+ const send = (msg) => {
1392
+ const subId = msg.params[0];
1393
+ switch (msg.method) {
1394
+ case follow$2:
1395
+ pendingChainHeadSubs.add(msg.id);
1396
+ break;
1397
+ case unpin$1:
1398
+ const [subscription, blocks] = msg.params;
1399
+ blocks.forEach((block) => {
1400
+ pinnedBlocksInSub.get(subscription)?.delete(block);
1401
+ prematureBlocks.get(subscription)?.delete(block);
1402
+ });
1403
+ break;
1404
+ case unfollow$2:
1405
+ pinnedBlocksInSub.delete(subId);
1406
+ prematureBlocks.delete(subId);
1407
+ break;
1408
+ }
1409
+ originalSend(msg);
1410
+ };
1411
+ return {
1412
+ send,
1413
+ disconnect: withClear(disconnect)
1414
+ };
1415
+ };
1416
+
1417
+ const { follow: follow$1, unpin, unfollow: unfollow$1 } = chainHead;
1418
+ const fixUnorderedBlocks = (base) => (onMsg, onHalt) => {
1419
+ const pendingChainHeadSubs = /* @__PURE__ */ new Set();
1420
+ const pinnedBlocksInSub = /* @__PURE__ */ new Map();
1421
+ const uknownBlocksNotifications = /* @__PURE__ */ new Map();
1422
+ const withClear = (fn) => (...args) => {
1423
+ [
1424
+ pendingChainHeadSubs,
1425
+ pinnedBlocksInSub,
1426
+ uknownBlocksNotifications
1427
+ ].forEach((x) => {
1428
+ x.clear();
1429
+ });
1430
+ fn(...args);
1431
+ };
1432
+ const { send: originalSend, disconnect } = base((message) => {
1433
+ if ("id" in message) {
1434
+ onMsg(message);
1435
+ const { id, result } = message;
1436
+ if (pendingChainHeadSubs.has(id)) {
1437
+ pendingChainHeadSubs.delete(id);
1438
+ pinnedBlocksInSub.set(result, /* @__PURE__ */ new Set());
1439
+ uknownBlocksNotifications.set(result, /* @__PURE__ */ new Map());
1440
+ return;
1441
+ }
1442
+ } else {
1443
+ const { subscription } = message.params;
1444
+ const pinnedBlocks = pinnedBlocksInSub.get(subscription);
1445
+ const premature = uknownBlocksNotifications.get(subscription);
1446
+ if (pinnedBlocks) {
1447
+ const result = message.params.result;
1448
+ const { event } = result;
1449
+ if (event === "initialized") {
1450
+ result.finalizedBlockHashes.forEach((hash) => {
1451
+ pinnedBlocks.add(hash);
1452
+ });
1453
+ }
1454
+ if (event === "finalized") {
1455
+ result.prunedBlockHashes = result.prunedBlockHashes.filter(
1456
+ (x) => pinnedBlocks.has(x)
1457
+ );
1458
+ }
1459
+ if (event === "newBlock") {
1460
+ pinnedBlocks.add(result.blockHash);
1461
+ const hash = result.blockHash;
1462
+ const missing = premature.get(hash);
1463
+ if (missing) {
1464
+ premature.delete(hash);
1465
+ onMsg(message);
1466
+ Promise.resolve().then(() => {
1467
+ onMsg(missing);
1468
+ });
1469
+ return;
1470
+ }
1471
+ }
1472
+ if (event === "bestBlockChanged") {
1473
+ const hash = result.bestBlockHash;
1474
+ if (!pinnedBlocks.has(hash)) {
1475
+ uknownBlocksNotifications.get(subscription).set(hash, message);
1476
+ return;
1477
+ }
1478
+ }
1479
+ if (event === "stop") {
1480
+ pinnedBlocks.delete(subscription);
1481
+ uknownBlocksNotifications.delete(subscription);
1482
+ }
1483
+ }
1484
+ onMsg(message);
1485
+ }
1486
+ }, withClear(onHalt));
1487
+ const send = (msg) => {
1488
+ const subId = msg.params[0];
1489
+ switch (msg.method) {
1490
+ case follow$1:
1491
+ pendingChainHeadSubs.add(msg.id);
1492
+ break;
1493
+ case unpin:
1494
+ const [subscription, blocks] = msg.params;
1495
+ blocks.forEach((block) => {
1496
+ pinnedBlocksInSub.get(subscription)?.delete(block);
1497
+ uknownBlocksNotifications.get(subscription)?.delete(block);
1498
+ });
1499
+ break;
1500
+ case unfollow$1:
1501
+ pinnedBlocksInSub.delete(subId);
1502
+ uknownBlocksNotifications.delete(subId);
1503
+ break;
1504
+ }
1505
+ originalSend(msg);
1506
+ };
1507
+ return {
1508
+ send,
1509
+ disconnect: withClear(disconnect)
1510
+ };
1511
+ };
1512
+
1513
+ const { follow, body, call, storage, unfollow, stopOperation } = chainHead;
1514
+ const terminalOperationEvents = new Set(
1515
+ ["BodyDone", "CallDone", "StorageDone", "Inaccessible", "Error"].map(
1516
+ (x) => "operation" + x
1517
+ )
1518
+ );
1519
+ const isTerminalNotification = (msg) => terminalOperationEvents.has(msg.params?.result?.event);
1520
+ const fixUnorderedEvents = (base) => (onMsg, onHalt) => {
1521
+ const pendingChainHeadSubs = /* @__PURE__ */ new Set();
1522
+ const pendingOperationIds = /* @__PURE__ */ new Map();
1523
+ const activeOperationIds = /* @__PURE__ */ new Map();
1524
+ const uknownOperationNotifications = /* @__PURE__ */ new Map();
1525
+ const withClear = (fn) => (...args) => {
1526
+ [
1527
+ pendingChainHeadSubs,
1528
+ pendingOperationIds,
1529
+ activeOperationIds,
1530
+ uknownOperationNotifications
1531
+ ].forEach((x) => {
1532
+ x.clear();
1533
+ });
1534
+ fn(...args);
1535
+ };
1536
+ const { send: originalSend, disconnect } = base((message) => {
1537
+ if ("id" in message) {
1538
+ onMsg(message);
1539
+ const { id, result } = message;
1540
+ if (pendingChainHeadSubs.has(id)) {
1541
+ pendingChainHeadSubs.delete(id);
1542
+ activeOperationIds.set(result, /* @__PURE__ */ new Set());
1543
+ uknownOperationNotifications.set(result, /* @__PURE__ */ new Map());
1544
+ return;
1545
+ }
1546
+ const subId = pendingOperationIds.get(id);
1547
+ if (subId !== void 0) {
1548
+ pendingOperationIds.delete(id);
1549
+ const opId = message.result?.operationId;
1550
+ if (opId !== void 0 && activeOperationIds.has(subId)) {
1551
+ const subOperations = activeOperationIds.get(subId);
1552
+ subOperations.add(opId);
1553
+ const pendingNotifications = uknownOperationNotifications.get(subId)?.get(opId);
1554
+ if (pendingNotifications) {
1555
+ pendingNotifications.forEach(onMsg);
1556
+ uknownOperationNotifications.get(subId).delete(opId);
1557
+ if (isTerminalNotification(pendingNotifications.at(-1)))
1558
+ subOperations.delete(opId);
1559
+ }
1560
+ }
1561
+ }
1562
+ } else {
1563
+ const { subscription, result } = message.params;
1564
+ const operationIds = activeOperationIds.get(subscription);
1565
+ if (operationIds) {
1566
+ const { operationId } = message.params.result;
1567
+ if (operationId !== void 0) {
1568
+ if (!operationIds.has(operationId)) {
1569
+ const subscriptionPending = uknownOperationNotifications.get(subscription);
1570
+ const pendingMessages = subscriptionPending.get(operationId) ?? [];
1571
+ pendingMessages.push(message);
1572
+ subscriptionPending.set(operationId, pendingMessages);
1573
+ return;
1574
+ } else if (isTerminalNotification(message))
1575
+ operationIds.delete(operationId);
1576
+ } else if (result?.event === "stop") {
1577
+ activeOperationIds.delete(subscription);
1578
+ uknownOperationNotifications.delete(subscription);
1579
+ }
1580
+ }
1581
+ onMsg(message);
1582
+ }
1583
+ }, withClear(onHalt));
1584
+ const send = (msg) => {
1585
+ const subId = msg.params[0];
1586
+ switch (msg.method) {
1587
+ case follow:
1588
+ pendingChainHeadSubs.add(msg.id);
1589
+ break;
1590
+ case body:
1591
+ case call:
1592
+ case storage:
1593
+ pendingOperationIds.set(msg.id, subId);
1594
+ break;
1595
+ case unfollow:
1596
+ activeOperationIds.delete(subId);
1597
+ uknownOperationNotifications.delete(subId);
1598
+ break;
1599
+ case stopOperation:
1600
+ activeOperationIds.get(subId)?.delete(msg.params[1]);
1601
+ }
1602
+ originalSend(msg);
1603
+ };
1604
+ return {
1605
+ send,
1606
+ disconnect: withClear(disconnect)
1607
+ };
1608
+ };
1609
+
1610
+ const patchChainHeadEvents = (base) => (onMsg, onHalt) => base((message) => {
1611
+ const result = message.params?.result;
1612
+ if (!("id" in message) && result) {
1613
+ const { prunedBlockHashes, finalizedBlockHash, event } = result;
1614
+ if (event === "finalized" && Array.isArray(prunedBlockHashes))
1615
+ result.prunedBlockHashes = [...new Set(result.prunedBlockHashes)];
1616
+ else if (event === "initialized" && finalizedBlockHash) {
1617
+ result.finalizedBlockHashes = [result.finalizedBlockHash];
1618
+ delete result.finalizedBlockHash;
1619
+ }
1620
+ }
1621
+ onMsg(message);
1622
+ }, onHalt);
1623
+
1624
+ const unpinHash = (base) => (...args) => {
1625
+ const { send: _send, disconnect } = base(...args);
1626
+ const send = (msg) => {
1627
+ const { method, params, id, ...rest } = msg;
1628
+ if (method == chainHead.unpin && params && Array.isArray(params[1])) {
1629
+ params[1].forEach((hash, idx) => {
1630
+ _send({
1631
+ ...rest,
1632
+ id: idx === 0 ? id : `${id}-patched-${idx}`,
1633
+ method,
1634
+ params: [params[0], hash]
1635
+ });
1636
+ });
1637
+ } else _send(msg);
1638
+ };
1639
+ return { send, disconnect };
1640
+ };
1641
+
1642
+ const modern = apply(
1643
+ fixUnorderedEvents,
1644
+ unpinHash,
1645
+ patchChainHeadEvents,
1646
+ fixPrematureBlocks,
1647
+ fixUnorderedBlocks,
1648
+ followEnhancer
1649
+ );
1650
+
1651
+ const withNumericIds = (base) => (onMsg, onHalt) => {
1652
+ let nextId = 0;
1653
+ const numberToOriginal = /* @__PURE__ */ new Map();
1654
+ const clear = () => {
1655
+ numberToOriginal.clear();
1656
+ };
1657
+ const { send: originalSend, disconnect } = base(
1658
+ (message) => {
1659
+ const { id } = message;
1660
+ if (numberToOriginal.has(id)) {
1661
+ message.id = numberToOriginal.get(id);
1662
+ numberToOriginal.delete(id);
1663
+ }
1664
+ onMsg(message);
1665
+ },
1666
+ (e) => {
1667
+ clear();
1668
+ onHalt(e);
1669
+ }
1670
+ );
1671
+ return {
1672
+ send: (msg) => {
1673
+ if (msg.id !== void 0) {
1674
+ numberToOriginal.set(nextId, msg.id);
1675
+ msg.id = nextId++;
1676
+ }
1677
+ originalSend(msg);
1678
+ },
1679
+ disconnect() {
1680
+ clear();
1681
+ disconnect();
1682
+ }
1683
+ };
1684
+ };
1685
+
1686
+ const modernGroups = ["chainHead", "transaction", "chainSpec", "archive"].map(
1687
+ (name) => `${name}_v1`
1688
+ );
1689
+ const isModern = (methods) => modernGroups.every((group) => methods.some((m) => m.startsWith(group)));
1690
+ const middleware = apply(
1691
+ withNumericIds,
1692
+ methodsRouter((methods) => isModern(methods) ? modern : withLegacy)
1693
+ );
1694
+
1695
+ exports.apply = apply;
1696
+ exports.fixPrematureBlocks = fixPrematureBlocks;
1697
+ exports.fixUnorderedBlocks = fixUnorderedBlocks;
1698
+ exports.fixUnorderedEvents = fixUnorderedEvents;
1699
+ exports.followEnhancer = followEnhancer;
1700
+ exports.methodsRouter = methodsRouter;
1701
+ exports.middleware = middleware;
1702
+ exports.modern = modern;
1703
+ exports.patchChainHeadEvents = patchChainHeadEvents;
1704
+ exports.unpinHash = unpinHash;
1705
+ exports.withLegacy = withLegacy;
1706
+ //# sourceMappingURL=index.js.map