@polkadot-api/ws-middleware 0.2.3 → 0.2.4-canary.5629cfc

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
@@ -1,9 +1,47 @@
1
1
  'use strict';
2
2
 
3
- var utils = require('@polkadot-api/utils');
4
3
  var rxjs = require('rxjs');
5
- var substrateBindings = require('@polkadot-api/substrate-bindings');
6
4
  var rawClient = require('@polkadot-api/raw-client');
5
+ var utils = require('@polkadot-api/utils');
6
+ var substrateBindings = require('@polkadot-api/substrate-bindings');
7
+
8
+ const chainHead = {
9
+ body: "",
10
+ call: "",
11
+ continue: "",
12
+ follow: "",
13
+ header: "",
14
+ stopOperation: "",
15
+ storage: "",
16
+ unfollow: "",
17
+ unpin: ""
18
+ };
19
+ const archive = {
20
+ body: "",
21
+ call: "",
22
+ finalizedHeight: "",
23
+ genesisHash: "",
24
+ hashByHeight: "",
25
+ header: "",
26
+ stopStorage: "",
27
+ storage: ""
28
+ };
29
+ const transaction = {
30
+ broadcast: "",
31
+ stop: ""
32
+ };
33
+ const chainSpec = {
34
+ chainName: "",
35
+ genesisHash: "",
36
+ properties: ""
37
+ };
38
+ Object.entries({ chainHead, chainSpec, transaction, archive }).forEach(
39
+ ([fnGroupName, methods]) => {
40
+ Object.keys(methods).forEach((methodName) => {
41
+ methods[methodName] = `${fnGroupName}_v1_${methodName}`;
42
+ });
43
+ }
44
+ );
7
45
 
8
46
  const shareLatest = rxjs.shareReplay({
9
47
  refCount: true,
@@ -350,18 +388,23 @@ const getHasherFromBlock = (shitHeader) => (hash) => hashers[fns.findIndex((fn)
350
388
  const withLatestFromBp = (latest$) => (base$) => new rxjs.Observable((observer) => {
351
389
  let latest;
352
390
  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
- });
391
+ let finished = false;
392
+ const subscription = new rxjs.Subscription();
393
+ subscription.add(
394
+ base$.subscribe({
395
+ next(v) {
396
+ if (prev) prev.push(v);
397
+ else observer.next([latest, v]);
398
+ },
399
+ error(e) {
400
+ observer.error(e);
401
+ },
402
+ complete() {
403
+ if (prev) finished = true;
404
+ else observer.complete();
405
+ }
406
+ })
407
+ );
365
408
  subscription.add(
366
409
  latest$.subscribe({
367
410
  next(v) {
@@ -371,6 +414,7 @@ const withLatestFromBp = (latest$) => (base$) => new rxjs.Observable((observer)
371
414
  prev = null;
372
415
  copy.forEach((p) => observer.next([latest, p]));
373
416
  }
417
+ if (finished) observer.complete();
374
418
  },
375
419
  error(e) {
376
420
  observer.error(e);
@@ -519,13 +563,15 @@ const createUpstream = (request) => {
519
563
  }
520
564
  )
521
565
  );
522
- const {
523
- upstream: getBlocks,
524
- finalized$,
525
- getHeader$,
526
- hasher$,
527
- clean
528
- } = getBlocks$(request, obsRequest);
566
+ let blockSubscription = null;
567
+ const subscribeBlocks = () => {
568
+ blockSubscription ?? (blockSubscription = getBlocks$(request, obsRequest));
569
+ return {
570
+ ...blockSubscription,
571
+ getBlocks: blockSubscription.upstream
572
+ };
573
+ };
574
+ const clean = () => blockSubscription?.clean();
529
575
  const runtimeCall = (atBlock, method, data) => obsRequest("state_call", [
530
576
  method,
531
577
  data,
@@ -559,7 +605,7 @@ const createUpstream = (request) => {
559
605
  return getKeys().pipe(rxjs.mergeMap((keys) => getValues(keys)));
560
606
  };
561
607
  const stgDescendantHashes = (at, rootKey) => stgDescendantValues(at, rootKey).pipe(
562
- withLatestFromBp(hasher$),
608
+ withLatestFromBp(subscribeBlocks().hasher$),
563
609
  rxjs.map(
564
610
  ([hasher, results]) => results.map(
565
611
  ([key, value]) => [key, utils.toHex(hasher(utils.fromHex(value)))]
@@ -583,10 +629,8 @@ const createUpstream = (request) => {
583
629
  const getBlockHash$ = (height) => obsRequest("chain_getBlockHash", [height]);
584
630
  const genesisHash = getBlockHash$(0);
585
631
  return {
586
- getBlocks,
587
- finalized$,
632
+ subscribeBlocks,
588
633
  getBlockHash$,
589
- getHeader$,
590
634
  stgValue,
591
635
  stgHash,
592
636
  stgDescendantValues,
@@ -597,26 +641,10 @@ const createUpstream = (request) => {
597
641
  chainName,
598
642
  properties,
599
643
  genesisHash,
600
- clean,
601
644
  methods,
602
645
  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
- );
646
+ obsRequest,
647
+ clean
620
648
  };
621
649
  };
622
650
 
@@ -684,45 +712,155 @@ const getMsgFromErr = (e) => {
684
712
  return "Unhandled exception";
685
713
  };
686
714
 
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: ""
715
+ const {
716
+ body: body$2,
717
+ call: call$2,
718
+ finalizedHeight,
719
+ genesisHash,
720
+ hashByHeight,
721
+ header: header$1,
722
+ stopStorage,
723
+ storage: storage$2
724
+ } = archive;
725
+ const createArchive = (upstream, reply, err, notification) => {
726
+ const stgSubscriptions = /* @__PURE__ */ new Map();
727
+ const stg = (reply2, at, items) => {
728
+ const subId = createOpaqueToken();
729
+ reply2(subId);
730
+ const innerNotifiaction = (result2) => {
731
+ notification("archive_v1_storageEvent", subId, result2);
732
+ };
733
+ const subscription = getStg$(upstream, at, items).pipe(
734
+ rxjs.finalize(() => {
735
+ stgSubscriptions.delete(subId);
736
+ })
737
+ ).subscribe(
738
+ (items2) => {
739
+ items2.forEach(
740
+ (item) => innerNotifiaction({ event: "storage", ...item })
741
+ );
742
+ },
743
+ (e) => {
744
+ innerNotifiaction({ event: "storageError", error: getMsgFromErr(e) });
745
+ },
746
+ () => {
747
+ innerNotifiaction({ event: "storageDone" });
748
+ }
749
+ );
750
+ if (!subscription.closed) stgSubscriptions.set(subId, subscription);
751
+ };
752
+ const result = (rId, name, params) => {
753
+ const innerReply = (value) => {
754
+ reply(rId, value);
755
+ };
756
+ const obsReply = (input) => {
757
+ input.subscribe({
758
+ next: innerReply,
759
+ error: (e) => {
760
+ err(rId, e.code ?? -1, getMsgFromErr(e));
761
+ }
762
+ });
763
+ };
764
+ const [firstArg, secondArg, thirdArg] = params;
765
+ switch (name) {
766
+ case body$2:
767
+ return obsReply(
768
+ upstream.getBody(firstArg).pipe(rxjs.map(({ block }) => block.extrinsics))
769
+ );
770
+ case call$2:
771
+ return obsReply(
772
+ upstream.runtimeCall(firstArg, secondArg, thirdArg).pipe(rxjs.map((value) => ({ success: true, value })))
773
+ );
774
+ case finalizedHeight:
775
+ return obsReply(
776
+ upstream.subscribeBlocks().finalized$.pipe(
777
+ rxjs.map((x) => x.number),
778
+ rxjs.take(1)
779
+ )
780
+ );
781
+ case genesisHash:
782
+ return obsReply(upstream.genesisHash);
783
+ case hashByHeight:
784
+ return obsReply(upstream.getBlockHash$(firstArg).pipe(rxjs.map((x) => [x])));
785
+ case header$1:
786
+ return obsReply(
787
+ upstream.subscribeBlocks().getHeader$(firstArg).pipe(rxjs.map((h) => h.header))
788
+ );
789
+ case stopStorage: {
790
+ const sub = stgSubscriptions.get(firstArg);
791
+ return sub ? sub.unsubscribe() : err(rId, -32602, "Invalid args");
792
+ }
793
+ case storage$2:
794
+ return areItemsValid(secondArg) ? stg(innerReply, firstArg, secondArg) : err(rId, -32602, "Invalid args");
795
+ }
796
+ throw null;
797
+ };
798
+ result.stop = () => {
799
+ [...stgSubscriptions].forEach(([, s]) => s.unsubscribe());
800
+ stgSubscriptions.clear();
801
+ };
802
+ return result;
707
803
  };
708
- const transaction = {
709
- broadcast: "",
710
- stop: ""
804
+
805
+ const createChainSpec = (upstream, reply, err) => {
806
+ return (rId, method) => {
807
+ const [, , name] = method.split("_");
808
+ const observable = upstream[name];
809
+ if (!observable) throw null;
810
+ observable.subscribe(
811
+ (result) => {
812
+ reply(rId, result);
813
+ },
814
+ () => {
815
+ err(rId, -32602, "Invalid");
816
+ }
817
+ );
818
+ };
711
819
  };
712
- const chainSpec = {
713
- chainName: "",
714
- genesisHash: "",
715
- properties: ""
820
+
821
+ const { stop, broadcast } = transaction;
822
+ const createTransactionFns = (upstream, reply) => {
823
+ const ongoing = /* @__PURE__ */ new Map();
824
+ const result = (rId, method, args) => {
825
+ if (method === stop) {
826
+ const [token] = args;
827
+ ongoing.get(token)?.unsubscribe();
828
+ ongoing.delete(token);
829
+ reply(rId, null);
830
+ } else if (method === broadcast) {
831
+ const token = createOpaqueToken();
832
+ ongoing.set(
833
+ token,
834
+ upstream.obsRequest("author_submitExtrinsic", args).pipe(
835
+ // We want to make sure that we keep on retrying if there
836
+ // are errors with the `author_submitExtrinsic` request
837
+ rxjs.catchError((_, source) => rxjs.concat(rxjs.timer(5e3), source)),
838
+ // This logic ensures that the subscription dies if an
839
+ // upstream error (like the client being destroyed) takes place
840
+ rxjs.takeUntil(
841
+ upstream.subscribeBlocks().finalized$.pipe(
842
+ rxjs.ignoreElements(),
843
+ rxjs.catchError(() => {
844
+ ongoing.delete(token);
845
+ return [null];
846
+ })
847
+ )
848
+ )
849
+ ).subscribe()
850
+ );
851
+ reply(rId, token);
852
+ } else {
853
+ throw null;
854
+ }
855
+ };
856
+ result.stop = () => {
857
+ ongoing.forEach((s) => s.unsubscribe());
858
+ ongoing.clear();
859
+ };
860
+ return result;
716
861
  };
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
862
 
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;
863
+ const { follow: follow$4, header, storage: storage$1, body: body$1, call: call$1, unfollow: unfollow$4, stopOperation: stopOperation$1, unpin: unpin$2 } = chainHead;
726
864
  const createChainHead = (upstream, reply, err, notification) => {
727
865
  const subscriptions = /* @__PURE__ */ new Map();
728
866
  const _follow = (rId) => {
@@ -731,7 +869,7 @@ const createChainHead = (upstream, reply, err, notification) => {
731
869
  }
732
870
  const token = createOpaqueToken();
733
871
  const fNotification = (result2) => notification("chainHead_v1_followEvent", token, result2);
734
- const up = upstream.getBlocks(token);
872
+ const up = upstream.subscribeBlocks().getBlocks(token);
735
873
  const operations = /* @__PURE__ */ new Map();
736
874
  subscriptions.set(token, {
737
875
  id: token,
@@ -783,7 +921,7 @@ const createChainHead = (upstream, reply, err, notification) => {
783
921
  const operationId = createOpaqueToken();
784
922
  reply2({ result: "started", operationId });
785
923
  const cNotification = (output, isErr = false) => notification(
786
- call$2,
924
+ call$1,
787
925
  followId,
788
926
  isErr ? {
789
927
  operationId,
@@ -817,7 +955,7 @@ const createChainHead = (upstream, reply, err, notification) => {
817
955
  const subscription = upstream.getBody(at).subscribe(
818
956
  ({ block: { extrinsics: value } }) => {
819
957
  operations.delete(operationId);
820
- notification(body$2, followId, {
958
+ notification(body$1, followId, {
821
959
  event: "operationBodyDone",
822
960
  operationId,
823
961
  value
@@ -825,7 +963,7 @@ const createChainHead = (upstream, reply, err, notification) => {
825
963
  },
826
964
  (e) => {
827
965
  operations.delete(operationId);
828
- notification(body$2, followId, {
966
+ notification(body$1, followId, {
829
967
  event: "operationError",
830
968
  operationId,
831
969
  error: getMsgFromErr(e)
@@ -842,7 +980,7 @@ const createChainHead = (upstream, reply, err, notification) => {
842
980
  const operationId = createOpaqueToken();
843
981
  reply2({ result: "started", operationId });
844
982
  const innerNotifiaction = (msg) => {
845
- notification(storage$2, followId, msg);
983
+ notification(storage$1, followId, msg);
846
984
  };
847
985
  const subscription = getStg$(upstream, at, items).pipe(
848
986
  rxjs.finalize(() => {
@@ -900,17 +1038,17 @@ const createChainHead = (upstream, reply, err, notification) => {
900
1038
  const [at, ...other] = rest;
901
1039
  if (!ctx.up.isPinned(at)) return err(rId, -32801, "Block not pinned");
902
1040
  switch (method) {
903
- case header$1:
1041
+ case header:
904
1042
  return _header(ctx, innerReply, at);
905
- case body$2:
1043
+ case body$1:
906
1044
  return _body(ctx, innerReply, at);
907
- case call$2: {
1045
+ case call$1: {
908
1046
  const [method2, data] = other;
909
1047
  if (typeof method2 !== "string" || typeof data !== "string")
910
1048
  return err(rId, -32602, "Invalid args");
911
1049
  return _call(ctx, innerReply, at, method2, data);
912
1050
  }
913
- case storage$2: {
1051
+ case storage$1: {
914
1052
  const [items] = other;
915
1053
  return areItemsValid(items) ? _stg(ctx, innerReply, at, items) : err(rId, -32602, "Invalid args");
916
1054
  }
@@ -927,138 +1065,6 @@ const createChainHead = (upstream, reply, err, notification) => {
927
1065
  return result;
928
1066
  };
929
1067
 
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(
1025
- upstream.getBody(firstArg).pipe(rxjs.map(({ block }) => block.extrinsics))
1026
- );
1027
- case call$1:
1028
- return obsReply(
1029
- upstream.runtimeCall(firstArg, secondArg, thirdArg).pipe(rxjs.map((value) => ({ success: true, value })))
1030
- );
1031
- case finalizedHeight:
1032
- return obsReply(
1033
- upstream.finalized$.pipe(
1034
- rxjs.map((x) => x.number),
1035
- rxjs.take(1)
1036
- )
1037
- );
1038
- case genesisHash:
1039
- return obsReply(upstream.genesisHash);
1040
- case hashByHeight:
1041
- return obsReply(upstream.getBlockHash$(firstArg).pipe(rxjs.map((x) => [x])));
1042
- case header:
1043
- return obsReply(
1044
- upstream.getHeader$(firstArg).pipe(rxjs.map((h) => h.header))
1045
- );
1046
- case stopStorage: {
1047
- const sub = stgSubscriptions.get(firstArg);
1048
- return sub ? sub.unsubscribe() : err(rId, -32602, "Invalid args");
1049
- }
1050
- case storage$1:
1051
- return areItemsValid(secondArg) ? stg(innerReply, firstArg, secondArg) : err(rId, -32602, "Invalid args");
1052
- }
1053
- throw null;
1054
- };
1055
- result.stop = () => {
1056
- [...stgSubscriptions].forEach(([, s]) => s.unsubscribe());
1057
- stgSubscriptions.clear();
1058
- };
1059
- return result;
1060
- };
1061
-
1062
1068
  const supportedMethods = new Set(
1063
1069
  [chainHead, chainSpec, archive, transaction].map((methods) => Object.values(methods)).flat()
1064
1070
  );
@@ -1092,16 +1098,22 @@ const withLegacy = (base) => (onMessage, onHalt) => {
1092
1098
  const notification = (method, subscription, result) => {
1093
1099
  jsonRpc({ method, params: { subscription, result } });
1094
1100
  };
1095
- const groups = {
1096
- chainSpec: createChainSpec(upstream, reply, err),
1097
- chainHead: createChainHead(upstream, reply, err, notification),
1098
- archive: createArchive(upstream, reply, err, notification),
1099
- transaction: createTransactionFns(upstream, reply)
1101
+ const groupsCtor = {
1102
+ chainSpec: () => createChainSpec(upstream, reply, err),
1103
+ chainHead: () => createChainHead(upstream, reply, err, notification),
1104
+ archive: () => createArchive(upstream, reply, err, notification),
1105
+ transaction: () => createTransactionFns(upstream, reply)
1106
+ };
1107
+ const groups = {};
1108
+ const getGroup = (name) => {
1109
+ if (name in groups) return groups[name];
1110
+ if (name in groupsCtor) return groups[name] = groupsCtor[name]();
1111
+ return null;
1100
1112
  };
1101
1113
  clean = () => {
1102
- groups.chainHead.stop();
1103
- groups.archive.stop();
1104
- groups.transaction.stop();
1114
+ groups.chainHead?.stop();
1115
+ groups.archive?.stop();
1116
+ groups.transaction?.stop();
1105
1117
  upstream.clean();
1106
1118
  };
1107
1119
  return {
@@ -1130,9 +1142,10 @@ ${JSON.stringify(parsedMsg)}`);
1130
1142
  );
1131
1143
  }
1132
1144
  const [groupName] = method.split("_");
1133
- if (groupName in groups) {
1145
+ const group = getGroup(groupName);
1146
+ if (group) {
1134
1147
  try {
1135
- return groups[groupName](id, method, params);
1148
+ return group(id, method, params);
1136
1149
  } catch (e) {
1137
1150
  if (e !== null) throw e;
1138
1151
  }
@@ -1155,113 +1168,6 @@ ${JSON.stringify(parsedMsg)}`);
1155
1168
  };
1156
1169
  };
1157
1170
 
1158
- const apply = (...middlewares) => (base) => middlewares.reduce((a, b) => b(a), base);
1159
- const jsonObj = (input) => ({
1160
- jsonrpc: "2.0",
1161
- ...input
1162
- });
1163
- const operationNotification = (subscription, event, operationId, innerResult = {}) => jsonObj({
1164
- method: "chainHead_v1_followEvent",
1165
- params: {
1166
- subscription,
1167
- result: {
1168
- event,
1169
- operationId,
1170
- ...innerResult
1171
- }
1172
- }
1173
- });
1174
-
1175
- const getAsyncMiddleware = (input) => (base) => (onMessageOut, onHaltOut) => {
1176
- let interceptedMessage = utils.noop;
1177
- let pending = [];
1178
- let send = (msg) => {
1179
- pending.push(msg);
1180
- };
1181
- let stopRequest = utils.noop;
1182
- let isOn = true;
1183
- let done = () => {
1184
- isOn = false;
1185
- pending = [];
1186
- stopRequest();
1187
- done = interceptedMessage = interceptedHalt = stopRequest = utils.noop;
1188
- };
1189
- let interceptedHalt = (e) => {
1190
- done();
1191
- onHaltOut(e);
1192
- };
1193
- const innerCon = base(
1194
- (msg) => interceptedMessage(msg),
1195
- (e) => interceptedHalt(e)
1196
- );
1197
- let { disconnect } = innerCon;
1198
- const { request } = rawClient.createClient((innerClientOnMsg) => {
1199
- interceptedMessage = innerClientOnMsg;
1200
- return { ...innerCon, disconnect: utils.noop };
1201
- });
1202
- if (isOn)
1203
- stopRequest = input((cb) => {
1204
- stopRequest = utils.noop;
1205
- if (!cb) interceptedHalt();
1206
- else {
1207
- ({ send, disconnect } = cb((onMiddleMsg, onMiddleHalt) => {
1208
- interceptedHalt = (e) => {
1209
- done();
1210
- onMiddleHalt(e);
1211
- };
1212
- interceptedMessage = onMiddleMsg;
1213
- return innerCon;
1214
- })(onMessageOut, onHaltOut));
1215
- pending.forEach(send);
1216
- pending = [];
1217
- }
1218
- }, request);
1219
- return {
1220
- send: (msg) => {
1221
- send(msg);
1222
- },
1223
- disconnect: () => {
1224
- done();
1225
- disconnect();
1226
- }
1227
- };
1228
- };
1229
-
1230
- const RPC_METHODS = "rpc_methods";
1231
- const withMethods = (methods) => (base) => (onMsg, onHalt) => {
1232
- const result = { methods };
1233
- const { send, disconnect } = base(onMsg, onHalt);
1234
- return {
1235
- disconnect,
1236
- send(msg) {
1237
- if (msg.id && msg.method === RPC_METHODS) {
1238
- onMsg(jsonObj({ id: msg.id, result }));
1239
- } else send(msg);
1240
- }
1241
- };
1242
- };
1243
- const methodsRouter = (getMiddleware) => getAsyncMiddleware((onReady, request) => {
1244
- let nTries = 0;
1245
- let stopRequest = utils.noop;
1246
- const getMethods = () => {
1247
- nTries++;
1248
- stopRequest = request(RPC_METHODS, [], {
1249
- onSuccess: ({ methods }) => {
1250
- onReady(apply(withMethods(methods), getMiddleware(methods)));
1251
- },
1252
- onError: () => {
1253
- if (nTries > 3) onReady(null);
1254
- else {
1255
- const token = setTimeout(getMethods, 500);
1256
- stopRequest = () => clearTimeout(token);
1257
- }
1258
- }
1259
- });
1260
- };
1261
- getMethods();
1262
- return () => stopRequest();
1263
- });
1264
-
1265
1171
  const { follow: follow$3, unfollow: unfollow$3 } = chainHead;
1266
1172
  const resetStops = () => ({ latest: Date.now(), count: 0 });
1267
1173
  const followEnhancer = (base) => (onMsg, onHalt) => {
@@ -1652,6 +1558,23 @@ const unpinHash = (base) => (...args) => {
1652
1558
  return { send, disconnect };
1653
1559
  };
1654
1560
 
1561
+ const apply = (...middlewares) => (base) => middlewares.reduce((a, b) => b(a), base);
1562
+ const jsonObj = (input) => ({
1563
+ jsonrpc: "2.0",
1564
+ ...input
1565
+ });
1566
+ const operationNotification = (subscription, event, operationId, innerResult = {}) => jsonObj({
1567
+ method: "chainHead_v1_followEvent",
1568
+ params: {
1569
+ subscription,
1570
+ result: {
1571
+ event,
1572
+ operationId,
1573
+ ...innerResult
1574
+ }
1575
+ }
1576
+ });
1577
+
1655
1578
  const cancelEvents = /* @__PURE__ */ new Set(["newBlock", "bestBlockChanged", "stop"]);
1656
1579
  const fixMissingInitialBest = (base) => (onMsg, onHalt) => {
1657
1580
  const pendingChainHeadSubs = /* @__PURE__ */ new Set();
@@ -1723,6 +1646,185 @@ const modern = apply(
1723
1646
  followEnhancer
1724
1647
  );
1725
1648
 
1649
+ const modernGroups = ["chainHead", "transaction", "chainSpec", "archive"].map(
1650
+ (name) => `${name}_v1`
1651
+ );
1652
+ const hybridMiddleware = (methods) => {
1653
+ const individualChecks = Object.fromEntries(
1654
+ modernGroups.map((group) => [
1655
+ group,
1656
+ !!methods.find((v) => v.startsWith(group))
1657
+ ])
1658
+ );
1659
+ return (base) => {
1660
+ const multiplexed = multiplex(base);
1661
+ const modernProvider = modern(multiplexed);
1662
+ const legacyProvider = withLegacy(multiplexed);
1663
+ return (onMsg, onHalt) => {
1664
+ const modernConnection = modernProvider((message) => {
1665
+ if ("error" in message && message.error.code === -32800) {
1666
+ console.warn("Max follow connections received: chainHead_v1 disabled");
1667
+ individualChecks.chainHead_v1 = false;
1668
+ }
1669
+ onMsg(message);
1670
+ }, onHalt);
1671
+ const legacyConnection = legacyProvider(onMsg, onHalt);
1672
+ return {
1673
+ send(message) {
1674
+ for (const group of modernGroups) {
1675
+ if (message.method.startsWith(group)) {
1676
+ if (individualChecks[group]) {
1677
+ modernConnection.send(message);
1678
+ } else {
1679
+ legacyConnection.send(message);
1680
+ }
1681
+ return;
1682
+ }
1683
+ }
1684
+ modernConnection.send(message);
1685
+ },
1686
+ disconnect() {
1687
+ modernConnection.disconnect();
1688
+ legacyConnection.disconnect();
1689
+ }
1690
+ };
1691
+ };
1692
+ };
1693
+ };
1694
+ const multiplex = (base) => {
1695
+ const halt$ = new rxjs.Subject();
1696
+ const msg$ = new rxjs.Subject();
1697
+ let refCount = 0;
1698
+ let baseConnection = null;
1699
+ return (onMsg, onHalt) => {
1700
+ refCount++;
1701
+ baseConnection ?? (baseConnection = base(
1702
+ (msg) => msg$.next(msg),
1703
+ (e) => halt$.next(e)
1704
+ ));
1705
+ const notificationSub = msg$.pipe(rxjs.filter((v) => v.id == null)).subscribe(onMsg);
1706
+ const haltSub = halt$.subscribe(onHalt);
1707
+ const responseSubs = /* @__PURE__ */ new Set();
1708
+ return {
1709
+ send(message) {
1710
+ if (message.id == null) {
1711
+ return baseConnection?.send(message);
1712
+ }
1713
+ const id = message.id;
1714
+ const responseSub = msg$.pipe(
1715
+ rxjs.filter((r) => r.id === id),
1716
+ rxjs.take(1)
1717
+ ).subscribe((msg) => {
1718
+ onMsg(msg);
1719
+ if (!responseSub) throw new Error("unreachable");
1720
+ responseSubs.delete(responseSub);
1721
+ });
1722
+ responseSubs.add(responseSub);
1723
+ baseConnection?.send(message);
1724
+ },
1725
+ disconnect() {
1726
+ notificationSub.unsubscribe();
1727
+ haltSub.unsubscribe();
1728
+ responseSubs.forEach((s) => s.unsubscribe());
1729
+ refCount--;
1730
+ if (refCount === 0) {
1731
+ baseConnection?.disconnect();
1732
+ }
1733
+ }
1734
+ };
1735
+ };
1736
+ };
1737
+
1738
+ const getAsyncMiddleware = (input) => (base) => (onMessageOut, onHaltOut) => {
1739
+ let interceptedMessage = utils.noop;
1740
+ let pending = [];
1741
+ let send = (msg) => {
1742
+ pending.push(msg);
1743
+ };
1744
+ let stopRequest = utils.noop;
1745
+ let isOn = true;
1746
+ let done = () => {
1747
+ isOn = false;
1748
+ pending = [];
1749
+ stopRequest();
1750
+ done = interceptedMessage = interceptedHalt = stopRequest = utils.noop;
1751
+ };
1752
+ let interceptedHalt = (e) => {
1753
+ done();
1754
+ onHaltOut(e);
1755
+ };
1756
+ const innerCon = base(
1757
+ (msg) => interceptedMessage(msg),
1758
+ (e) => interceptedHalt(e)
1759
+ );
1760
+ let { disconnect } = innerCon;
1761
+ const { request } = rawClient.createClient((innerClientOnMsg) => {
1762
+ interceptedMessage = innerClientOnMsg;
1763
+ return { ...innerCon, disconnect: utils.noop };
1764
+ });
1765
+ if (isOn)
1766
+ stopRequest = input((cb) => {
1767
+ stopRequest = utils.noop;
1768
+ if (!cb) interceptedHalt();
1769
+ else {
1770
+ ({ send, disconnect } = cb((onMiddleMsg, onMiddleHalt) => {
1771
+ interceptedHalt = (e) => {
1772
+ done();
1773
+ onMiddleHalt(e);
1774
+ };
1775
+ interceptedMessage = onMiddleMsg;
1776
+ return innerCon;
1777
+ })(onMessageOut, onHaltOut));
1778
+ pending.forEach(send);
1779
+ pending = [];
1780
+ }
1781
+ }, request);
1782
+ return {
1783
+ send: (msg) => {
1784
+ send(msg);
1785
+ },
1786
+ disconnect: () => {
1787
+ done();
1788
+ disconnect();
1789
+ }
1790
+ };
1791
+ };
1792
+
1793
+ const RPC_METHODS = "rpc_methods";
1794
+ const withMethods = (methods) => (base) => (onMsg, onHalt) => {
1795
+ const result = { methods };
1796
+ const { send, disconnect } = base(onMsg, onHalt);
1797
+ return {
1798
+ disconnect,
1799
+ send(msg) {
1800
+ if (msg.id && msg.method === RPC_METHODS) {
1801
+ onMsg(jsonObj({ id: msg.id, result }));
1802
+ } else send(msg);
1803
+ }
1804
+ };
1805
+ };
1806
+ const methodsRouter = (getMiddleware) => getAsyncMiddleware((onReady, request) => {
1807
+ let nTries = 0;
1808
+ let stopRequest = utils.noop;
1809
+ const getMethods = () => {
1810
+ nTries++;
1811
+ stopRequest = request(RPC_METHODS, [], {
1812
+ onSuccess: ({ methods }) => {
1813
+ onReady(apply(withMethods(methods), getMiddleware(methods)));
1814
+ },
1815
+ onError: () => {
1816
+ if (nTries > 3) onReady(null);
1817
+ else {
1818
+ const token = setTimeout(getMethods, 500);
1819
+ stopRequest = () => clearTimeout(token);
1820
+ }
1821
+ }
1822
+ });
1823
+ };
1824
+ getMethods();
1825
+ return () => stopRequest();
1826
+ });
1827
+
1726
1828
  const withNumericIds = (base) => (onMsg, onHalt) => {
1727
1829
  let nextId = 0;
1728
1830
  const numberToOriginal = /* @__PURE__ */ new Map();
@@ -1758,16 +1860,7 @@ const withNumericIds = (base) => (onMsg, onHalt) => {
1758
1860
  };
1759
1861
  };
1760
1862
 
1761
- const modernGroups = [
1762
- "chainHead",
1763
- "transaction",
1764
- "chainSpec"
1765
- ].map((name) => `${name}_v1`);
1766
- const isModern = (methods) => modernGroups.every((group) => methods.some((m) => m.startsWith(group)));
1767
- const middleware = apply(
1768
- withNumericIds,
1769
- methodsRouter((methods) => isModern(methods) ? modern : withLegacy)
1770
- );
1863
+ const middleware = apply(withNumericIds, methodsRouter(hybridMiddleware));
1771
1864
 
1772
1865
  exports.apply = apply;
1773
1866
  exports.fixMissingInitialBest = fixMissingInitialBest;