@polkadot-api/ws-provider 0.3.4 → 0.3.6

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.
@@ -0,0 +1,69 @@
1
+ const methods = {};
2
+ ["v1", "unstable"].forEach((version) => {
3
+ methods[`chainHead_${version}_follow`] = "follow";
4
+ methods[`chainHead_${version}_unfollow`] = "unfollow";
5
+ });
6
+ const followEnhancer = (base, forceDisconnect) => {
7
+ const prematureStops = /* @__PURE__ */ new Set();
8
+ const preOpId = /* @__PURE__ */ new Map();
9
+ const onGoing = /* @__PURE__ */ new Set();
10
+ const result = (onMsg) => {
11
+ const { send, disconnect } = base((fromProvider) => {
12
+ const parsed = JSON.parse(fromProvider);
13
+ if ("id" in parsed) {
14
+ const { id, result: result2 } = parsed;
15
+ const msg = preOpId.get(id);
16
+ if (msg) {
17
+ preOpId.delete(id);
18
+ if (prematureStops.has(result2)) {
19
+ prematureStops.delete(result2);
20
+ return;
21
+ }
22
+ onGoing.add(result2);
23
+ const currentSize = onGoing.size + preOpId.size;
24
+ if (currentSize > 2)
25
+ console.warn(
26
+ `Too many chainHead follow subscriptions (${currentSize})`
27
+ );
28
+ else if (parsed.error) {
29
+ console.warn(`chainHead follow failed on the ${currentSize} sub`);
30
+ forceDisconnect();
31
+ preOpId.set(id, msg);
32
+ send(msg);
33
+ return;
34
+ }
35
+ }
36
+ } else {
37
+ const { subscription, result: result2 } = parsed.params;
38
+ if (result2?.event === "stop") {
39
+ if (onGoing.has(subscription)) onGoing.delete(subscription);
40
+ else prematureStops.add(subscription);
41
+ }
42
+ }
43
+ onMsg(fromProvider);
44
+ });
45
+ return {
46
+ send(toProvider) {
47
+ const parsed = JSON.parse(toProvider);
48
+ const method = methods[parsed.method];
49
+ if (method === "follow") {
50
+ preOpId.set(parsed.id, toProvider);
51
+ } else if (method === "unfollow") {
52
+ onGoing.delete(parsed.params[0]);
53
+ }
54
+ send(toProvider);
55
+ },
56
+ disconnect
57
+ };
58
+ };
59
+ return Object.assign(result, {
60
+ cleanup: () => {
61
+ prematureStops.clear();
62
+ preOpId.clear();
63
+ onGoing.clear();
64
+ }
65
+ });
66
+ };
67
+
68
+ export { followEnhancer };
69
+ //# sourceMappingURL=follow-enhancer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follow-enhancer.mjs","sources":["../../../src/follow-enhancer.ts"],"sourcesContent":["import { JsonRpcProvider } from \"@polkadot-api/json-rpc-provider\"\n\nconst methods: Record<string, \"follow\" | \"unfollow\"> = {}\n;[\"v1\", \"unstable\"].forEach((version) => {\n methods[`chainHead_${version}_follow`] = \"follow\"\n methods[`chainHead_${version}_unfollow`] = \"unfollow\"\n})\n\nexport const followEnhancer: (\n input: JsonRpcProvider,\n forceDisconnect: () => void,\n) => JsonRpcProvider & {\n cleanup: () => void\n} = (base, forceDisconnect) => {\n const prematureStops = new Set<string>()\n const preOpId = new Map<string, string>()\n const onGoing = new Set<string>()\n\n const result: JsonRpcProvider = (onMsg) => {\n const { send, disconnect } = base((fromProvider) => {\n const parsed = JSON.parse(fromProvider)\n // it's a response\n if (\"id\" in parsed) {\n const { id, result } = parsed\n const msg = preOpId.get(id)\n if (msg) {\n preOpId.delete(id)\n if (prematureStops.has(result)) {\n prematureStops.delete(result)\n return\n }\n\n onGoing.add(result)\n const currentSize = onGoing.size + preOpId.size\n if (currentSize > 2)\n console.warn(\n `Too many chainHead follow subscriptions (${currentSize})`,\n )\n else if (parsed.error) {\n console.warn(`chainHead follow failed on the ${currentSize} sub`)\n forceDisconnect()\n preOpId.set(id, msg)\n send(msg)\n return\n }\n }\n } else {\n // it's a notifiaction\n const { subscription, result } = (parsed as any).params\n if (result?.event === \"stop\") {\n if (onGoing.has(subscription)) onGoing.delete(subscription)\n else prematureStops.add(subscription)\n }\n }\n onMsg(fromProvider)\n })\n\n return {\n send(toProvider) {\n const parsed = JSON.parse(toProvider)\n const method = methods[parsed.method]\n if (method === \"follow\") {\n preOpId.set(parsed.id, toProvider)\n } else if (method === \"unfollow\") {\n onGoing.delete(parsed.params[0])\n }\n send(toProvider)\n },\n disconnect,\n }\n }\n\n return Object.assign(result, {\n cleanup: () => {\n prematureStops.clear()\n preOpId.clear()\n onGoing.clear()\n },\n })\n}\n"],"names":["result"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { getSyncProvider } from '@polkadot-api/json-rpc-provider-proxy';
2
2
  import { WsEvent } from './types.mjs';
3
+ import { followEnhancer } from './follow-enhancer.mjs';
3
4
 
4
5
  const timeoutError = {
5
6
  type: WsEvent.ERROR,
@@ -33,109 +34,117 @@ const getInternalWsProvider = (WebsocketClass) => {
33
34
  let status;
34
35
  let switchTo = null;
35
36
  let disconnect = noop;
36
- const result = getSyncProvider(async () => {
37
- const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
38
- switchTo = null;
39
- const socket = new WebsocketClass(uri, protocols);
40
- const forceSocketClose = () => {
41
- try {
42
- socket.addEventListener("error", noop, { once: true });
43
- socket.close();
44
- } catch {
45
- }
46
- };
47
- onStatusChanged(
48
- status = {
49
- type: WsEvent.CONNECTING,
50
- uri,
51
- protocols
52
- }
53
- );
54
- await new Promise((resolve, reject) => {
55
- const onOpen = () => {
56
- initialCleanup();
57
- resolve();
37
+ let outerCleanup = noop;
38
+ const result = followEnhancer(
39
+ getSyncProvider(async () => {
40
+ const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
41
+ switchTo = null;
42
+ const socket = new WebsocketClass(uri, protocols);
43
+ const forceSocketClose = () => {
44
+ try {
45
+ socket.addEventListener("error", noop, { once: true });
46
+ socket.close();
47
+ } catch {
48
+ }
58
49
  };
59
- const onError = (e) => {
60
- initialCleanup();
61
- if (e == null) forceSocketClose();
62
- console.error(
63
- `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
64
- );
65
- onStatusChanged(
66
- status = {
67
- type: e ? WsEvent.ERROR : WsEvent.CLOSE,
68
- event: e
69
- }
70
- );
71
- setTimeout(reject, e ? 300 : 0, e);
50
+ onStatusChanged(
51
+ status = {
52
+ type: WsEvent.CONNECTING,
53
+ uri,
54
+ protocols
55
+ }
56
+ );
57
+ await new Promise((resolve, reject) => {
58
+ const onOpen = () => {
59
+ initialCleanup();
60
+ resolve();
61
+ };
62
+ const onError = (e) => {
63
+ initialCleanup();
64
+ if (e == null) forceSocketClose();
65
+ console.error(
66
+ `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
67
+ );
68
+ onStatusChanged(
69
+ status = {
70
+ type: e ? WsEvent.ERROR : WsEvent.CLOSE,
71
+ event: e
72
+ }
73
+ );
74
+ setTimeout(reject, e ? 300 : 0, e);
75
+ };
76
+ const timeoutToken = timeout !== Infinity ? setTimeout(() => {
77
+ initialCleanup();
78
+ forceSocketClose();
79
+ onStatusChanged(status = timeoutError);
80
+ reject(timeoutError.event);
81
+ }, timeout) : void 0;
82
+ const initialCleanup = () => {
83
+ clearTimeout(timeoutToken);
84
+ socket.removeEventListener("error", onError);
85
+ socket.removeEventListener("open", onOpen);
86
+ };
87
+ socket.addEventListener("open", onOpen);
88
+ socket.addEventListener("error", onError);
89
+ disconnect = () => {
90
+ onError(null);
91
+ };
92
+ });
93
+ onStatusChanged(
94
+ status = {
95
+ type: WsEvent.CONNECTED,
96
+ uri,
97
+ protocols
98
+ }
99
+ );
100
+ return (onMessage, onHalt) => {
101
+ const _onMessage = (e) => {
102
+ if (typeof e.data === "string") onMessage(e.data);
103
+ };
104
+ const innerHalt = (reason) => (e) => {
105
+ console.warn(`WS halt (${reason})`);
106
+ onStatusChanged(
107
+ status = {
108
+ type: reason,
109
+ event: e
110
+ }
111
+ );
112
+ onHalt();
113
+ };
114
+ const onError = innerHalt(WsEvent.ERROR);
115
+ const onClose = innerHalt(WsEvent.CLOSE);
116
+ socket.addEventListener("message", _onMessage);
117
+ socket.addEventListener("error", onError);
118
+ socket.addEventListener("close", onClose);
119
+ disconnect = (withHalt) => {
120
+ outerCleanup();
121
+ disconnect = noop;
122
+ socket.removeEventListener("message", _onMessage);
123
+ socket.removeEventListener("error", onError);
124
+ socket.removeEventListener("close", onClose);
125
+ forceSocketClose();
126
+ if (withHalt) onClose({});
127
+ };
128
+ return {
129
+ send: (msg) => {
130
+ socket.send(msg);
131
+ },
132
+ disconnect
133
+ };
72
134
  };
73
- const timeoutToken = timeout !== Infinity ? setTimeout(() => {
74
- initialCleanup();
75
- forceSocketClose();
76
- onStatusChanged(status = timeoutError);
77
- reject(timeoutError.event);
78
- }, timeout) : void 0;
79
- const initialCleanup = () => {
80
- clearTimeout(timeoutToken);
81
- socket.removeEventListener("error", onError);
82
- socket.removeEventListener("open", onOpen);
83
- };
84
- socket.addEventListener("open", onOpen);
85
- socket.addEventListener("error", onError);
86
- disconnect = () => {
87
- onError(null);
88
- };
89
- });
90
- onStatusChanged(
91
- status = {
92
- type: WsEvent.CONNECTED,
93
- uri,
94
- protocols
95
- }
96
- );
97
- return (onMessage, onHalt) => {
98
- const _onMessage = (e) => {
99
- if (typeof e.data === "string") onMessage(e.data);
100
- };
101
- const innerHalt = (reason) => (e) => {
102
- console.warn(`WS halt (${reason})`);
103
- onStatusChanged(
104
- status = {
105
- type: reason,
106
- event: e
107
- }
108
- );
109
- onHalt();
110
- };
111
- const onError = innerHalt(WsEvent.ERROR);
112
- const onClose = innerHalt(WsEvent.CLOSE);
113
- socket.addEventListener("message", _onMessage);
114
- socket.addEventListener("error", onError);
115
- socket.addEventListener("close", onClose);
116
- disconnect = (withHalt) => {
117
- disconnect = noop;
118
- socket.removeEventListener("message", _onMessage);
119
- socket.removeEventListener("error", onError);
120
- socket.removeEventListener("close", onClose);
121
- forceSocketClose();
122
- if (withHalt) onClose({});
123
- };
124
- return {
125
- send: (msg) => {
126
- socket.send(msg);
127
- },
128
- disconnect
129
- };
130
- };
131
- });
132
- result.getStatus = () => status;
133
- result.switch = (...args2) => {
135
+ }),
136
+ () => {
137
+ switchFn();
138
+ }
139
+ );
140
+ outerCleanup = result.cleanup;
141
+ delete result.cleanup;
142
+ const switchFn = (...args2) => {
134
143
  if (status.type === WsEvent.CLOSE) return;
135
144
  if (args2.length) switchTo = args2;
136
145
  if (status.type !== WsEvent.ERROR) disconnect(true);
137
146
  };
138
- return result;
147
+ return Object.assign(result, { switch: switchFn, getStatus: () => status });
139
148
  };
140
149
  };
141
150
 
@@ -1 +1 @@
1
- {"version":3,"file":"ws-provider.mjs","sources":["../../../src/ws-provider.ts"],"sourcesContent":["import { getSyncProvider } from \"@polkadot-api/json-rpc-provider-proxy\"\nimport {\n GetWsProviderInput,\n StatusChange,\n WsJsonRpcProvider,\n WsEvent,\n WsProviderConfig,\n} from \"./types\"\n\nconst timeoutError: StatusChange = {\n type: WsEvent.ERROR,\n event: { type: \"timeout\" },\n}\n\nconst noop = () => {}\n\nconst mapEndpoints = (\n endpoints: WsProviderConfig[\"endpoints\"],\n): Array<[string, string | string[]] | [string]> =>\n endpoints.map((x) => (typeof x === \"string\" ? [x] : [x.uri, x.protocol]))\n\nexport const getInternalWsProvider = (\n WebsocketClass: typeof WebSocket,\n): GetWsProviderInput => {\n return (...args): WsJsonRpcProvider => {\n let endpoints: Array<[string, string | string[]] | [string]> = []\n let onStatusChanged: (status: StatusChange) => void = noop\n let timeout = 3_500\n\n const [firstArg] = args\n if (\n args.length === 1 &&\n typeof firstArg === \"object\" &&\n !Array.isArray(firstArg)\n ) {\n endpoints = mapEndpoints(firstArg.endpoints)\n onStatusChanged = firstArg.onStatusChanged ?? noop\n timeout = firstArg.timeout ?? timeout\n } else {\n if (typeof args[1] === \"function\")\n onStatusChanged = args[1] as (status: StatusChange) => void\n if (Array.isArray(firstArg)) endpoints = mapEndpoints(firstArg)\n else {\n endpoints = [[firstArg as string]]\n if (args[1] && args[1] !== onStatusChanged)\n endpoints[0][1] = args[1] as any\n if (args[2]) onStatusChanged = args[2] as any\n }\n }\n\n let idx = 0\n let status: StatusChange\n let switchTo: [string] | [string, string | string[]] | null = null\n let disconnect: (withHalt?: boolean) => void = noop\n\n const result = getSyncProvider(async () => {\n const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length]\n switchTo = null\n const socket = new WebsocketClass(uri, protocols)\n const forceSocketClose = () => {\n try {\n socket.addEventListener(\"error\", noop, { once: true })\n socket.close()\n } catch {}\n }\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTING,\n uri,\n protocols,\n }),\n )\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n initialCleanup()\n resolve()\n }\n\n const onError = (e: Event | null) => {\n initialCleanup()\n if (e == null) forceSocketClose()\n console.error(\n `Unable to connect to ${uri}${\n protocols ? \", protocols: \" + protocols : \"\"\n }`,\n )\n onStatusChanged(\n (status = {\n type: e ? WsEvent.ERROR : WsEvent.CLOSE,\n event: e,\n }),\n )\n setTimeout(reject, e ? 300 : 0, e)\n }\n\n const timeoutToken =\n timeout !== Infinity\n ? setTimeout(() => {\n initialCleanup()\n forceSocketClose()\n onStatusChanged((status = timeoutError))\n reject(timeoutError.event)\n }, timeout)\n : undefined\n\n const initialCleanup = () => {\n clearTimeout(timeoutToken)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"open\", onOpen)\n }\n socket.addEventListener(\"open\", onOpen)\n socket.addEventListener(\"error\", onError)\n disconnect = () => {\n onError(null)\n }\n })\n\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTED,\n uri,\n protocols,\n }),\n )\n\n return (onMessage, onHalt) => {\n const _onMessage = (e: MessageEvent) => {\n if (typeof e.data === \"string\") onMessage(e.data)\n }\n const innerHalt =\n (reason: WsEvent.CLOSE | WsEvent.ERROR) => (e: any) => {\n console.warn(`WS halt (${reason})`)\n onStatusChanged(\n (status = {\n type: reason,\n event: e,\n }),\n )\n onHalt()\n }\n const onError = innerHalt(WsEvent.ERROR)\n const onClose = innerHalt(WsEvent.CLOSE)\n\n socket.addEventListener(\"message\", _onMessage)\n socket.addEventListener(\"error\", onError)\n socket.addEventListener(\"close\", onClose)\n disconnect = (withHalt) => {\n disconnect = noop\n socket.removeEventListener(\"message\", _onMessage)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"close\", onClose)\n forceSocketClose()\n if (withHalt) onClose({})\n }\n\n return {\n send: (msg) => {\n socket.send(msg)\n },\n disconnect,\n }\n }\n }) as WsJsonRpcProvider\n\n result.getStatus = () => status\n result.switch = (...args) => {\n if (status.type === WsEvent.CLOSE) return\n if (args.length) switchTo = args as any\n if (status.type !== WsEvent.ERROR) disconnect(true)\n }\n return result\n }\n}\n"],"names":["args"],"mappings":";;;AASA,MAAM,YAA6B,GAAA;AAAA,EACjC,MAAM,OAAQ,CAAA,KAAA;AAAA,EACd,KAAA,EAAO,EAAE,IAAA,EAAM,SAAU;AAC3B,CAAA;AAEA,MAAM,OAAO,MAAM;AAAC,CAAA;AAEpB,MAAM,eAAe,CACnB,SAAA,KAEA,UAAU,GAAI,CAAA,CAAC,MAAO,OAAO,CAAA,KAAM,QAAW,GAAA,CAAC,CAAC,CAAI,GAAA,CAAC,EAAE,GAAK,EAAA,CAAA,CAAE,QAAQ,CAAE,CAAA;AAE7D,MAAA,qBAAA,GAAwB,CACnC,cACuB,KAAA;AACvB,EAAA,OAAO,IAAI,IAA4B,KAAA;AACrC,IAAA,IAAI,YAA2D,EAAC;AAChE,IAAA,IAAI,eAAkD,GAAA,IAAA;AACtD,IAAA,IAAI,OAAU,GAAA,IAAA;AAEd,IAAM,MAAA,CAAC,QAAQ,CAAI,GAAA,IAAA;AACnB,IACE,IAAA,IAAA,CAAK,MAAW,KAAA,CAAA,IAChB,OAAO,QAAA,KAAa,YACpB,CAAC,KAAA,CAAM,OAAQ,CAAA,QAAQ,CACvB,EAAA;AACA,MAAY,SAAA,GAAA,YAAA,CAAa,SAAS,SAAS,CAAA;AAC3C,MAAA,eAAA,GAAkB,SAAS,eAAmB,IAAA,IAAA;AAC9C,MAAA,OAAA,GAAU,SAAS,OAAW,IAAA,OAAA;AAAA,KACzB,MAAA;AACL,MAAI,IAAA,OAAO,IAAK,CAAA,CAAC,CAAM,KAAA,UAAA;AACrB,QAAA,eAAA,GAAkB,KAAK,CAAC,CAAA;AAC1B,MAAA,IAAI,MAAM,OAAQ,CAAA,QAAQ,CAAG,EAAA,SAAA,GAAY,aAAa,QAAQ,CAAA;AAAA,WACzD;AACH,QAAY,SAAA,GAAA,CAAC,CAAC,QAAkB,CAAC,CAAA;AACjC,QAAA,IAAI,IAAK,CAAA,CAAC,CAAK,IAAA,IAAA,CAAK,CAAC,CAAM,KAAA,eAAA;AACzB,UAAA,SAAA,CAAU,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,KAAK,CAAC,CAAA;AAC1B,QAAA,IAAI,IAAK,CAAA,CAAC,CAAG,EAAA,eAAA,GAAkB,KAAK,CAAC,CAAA;AAAA;AACvC;AAGF,IAAA,IAAI,GAAM,GAAA,CAAA;AACV,IAAI,IAAA,MAAA;AACJ,IAAA,IAAI,QAA0D,GAAA,IAAA;AAC9D,IAAA,IAAI,UAA2C,GAAA,IAAA;AAE/C,IAAM,MAAA,MAAA,GAAS,gBAAgB,YAAY;AACzC,MAAM,MAAA,CAAC,KAAK,SAAS,CAAA,GAAI,YAAY,SAAU,CAAA,GAAA,EAAA,GAAQ,UAAU,MAAM,CAAA;AACvE,MAAW,QAAA,GAAA,IAAA;AACX,MAAA,MAAM,MAAS,GAAA,IAAI,cAAe,CAAA,GAAA,EAAK,SAAS,CAAA;AAChD,MAAA,MAAM,mBAAmB,MAAM;AAC7B,QAAI,IAAA;AACF,UAAA,MAAA,CAAO,iBAAiB,OAAS,EAAA,IAAA,EAAM,EAAE,IAAA,EAAM,MAAM,CAAA;AACrD,UAAA,MAAA,CAAO,KAAM,EAAA;AAAA,SACP,CAAA,MAAA;AAAA;AAAC,OACX;AACA,MAAA,eAAA;AAAA,QACG,MAAS,GAAA;AAAA,UACR,MAAM,OAAQ,CAAA,UAAA;AAAA,UACd,GAAA;AAAA,UACA;AAAA;AACF,OACF;AAEA,MAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAW,KAAA;AAC3C,QAAA,MAAM,SAAS,MAAM;AACnB,UAAe,cAAA,EAAA;AACf,UAAQ,OAAA,EAAA;AAAA,SACV;AAEA,QAAM,MAAA,OAAA,GAAU,CAAC,CAAoB,KAAA;AACnC,UAAe,cAAA,EAAA;AACf,UAAI,IAAA,CAAA,IAAK,MAAuB,gBAAA,EAAA;AAChC,UAAQ,OAAA,CAAA,KAAA;AAAA,YACN,wBAAwB,GAAG,CAAA,EACzB,SAAY,GAAA,eAAA,GAAkB,YAAY,EAC5C,CAAA;AAAA,WACF;AACA,UAAA,eAAA;AAAA,YACG,MAAS,GAAA;AAAA,cACR,IAAM,EAAA,CAAA,GAAI,OAAQ,CAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA;AAAA,cAClC,KAAO,EAAA;AAAA;AACT,WACF;AACA,UAAA,UAAA,CAAW,MAAQ,EAAA,CAAA,GAAI,GAAM,GAAA,CAAA,EAAG,CAAC,CAAA;AAAA,SACnC;AAEA,QAAA,MAAM,YACJ,GAAA,OAAA,KAAY,QACR,GAAA,UAAA,CAAW,MAAM;AACf,UAAe,cAAA,EAAA;AACf,UAAiB,gBAAA,EAAA;AACjB,UAAA,eAAA,CAAiB,SAAS,YAAa,CAAA;AACvC,UAAA,MAAA,CAAO,aAAa,KAAK,CAAA;AAAA,SAC3B,EAAG,OAAO,CACV,GAAA,KAAA,CAAA;AAEN,QAAA,MAAM,iBAAiB,MAAM;AAC3B,UAAA,YAAA,CAAa,YAAY,CAAA;AACzB,UAAO,MAAA,CAAA,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC3C,UAAO,MAAA,CAAA,mBAAA,CAAoB,QAAQ,MAAM,CAAA;AAAA,SAC3C;AACA,QAAO,MAAA,CAAA,gBAAA,CAAiB,QAAQ,MAAM,CAAA;AACtC,QAAO,MAAA,CAAA,gBAAA,CAAiB,SAAS,OAAO,CAAA;AACxC,QAAA,UAAA,GAAa,MAAM;AACjB,UAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,SACd;AAAA,OACD,CAAA;AAED,MAAA,eAAA;AAAA,QACG,MAAS,GAAA;AAAA,UACR,MAAM,OAAQ,CAAA,SAAA;AAAA,UACd,GAAA;AAAA,UACA;AAAA;AACF,OACF;AAEA,MAAO,OAAA,CAAC,WAAW,MAAW,KAAA;AAC5B,QAAM,MAAA,UAAA,GAAa,CAAC,CAAoB,KAAA;AACtC,UAAA,IAAI,OAAO,CAAE,CAAA,IAAA,KAAS,QAAU,EAAA,SAAA,CAAU,EAAE,IAAI,CAAA;AAAA,SAClD;AACA,QAAA,MAAM,SACJ,GAAA,CAAC,MAA0C,KAAA,CAAC,CAAW,KAAA;AACrD,UAAQ,OAAA,CAAA,IAAA,CAAK,CAAY,SAAA,EAAA,MAAM,CAAG,CAAA,CAAA,CAAA;AAClC,UAAA,eAAA;AAAA,YACG,MAAS,GAAA;AAAA,cACR,IAAM,EAAA,MAAA;AAAA,cACN,KAAO,EAAA;AAAA;AACT,WACF;AACA,UAAO,MAAA,EAAA;AAAA,SACT;AACF,QAAM,MAAA,OAAA,GAAU,SAAU,CAAA,OAAA,CAAQ,KAAK,CAAA;AACvC,QAAM,MAAA,OAAA,GAAU,SAAU,CAAA,OAAA,CAAQ,KAAK,CAAA;AAEvC,QAAO,MAAA,CAAA,gBAAA,CAAiB,WAAW,UAAU,CAAA;AAC7C,QAAO,MAAA,CAAA,gBAAA,CAAiB,SAAS,OAAO,CAAA;AACxC,QAAO,MAAA,CAAA,gBAAA,CAAiB,SAAS,OAAO,CAAA;AACxC,QAAA,UAAA,GAAa,CAAC,QAAa,KAAA;AACzB,UAAa,UAAA,GAAA,IAAA;AACb,UAAO,MAAA,CAAA,mBAAA,CAAoB,WAAW,UAAU,CAAA;AAChD,UAAO,MAAA,CAAA,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC3C,UAAO,MAAA,CAAA,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC3C,UAAiB,gBAAA,EAAA;AACjB,UAAI,IAAA,QAAA,EAAkB,OAAA,CAAA,EAAE,CAAA;AAAA,SAC1B;AAEA,QAAO,OAAA;AAAA,UACL,IAAA,EAAM,CAAC,GAAQ,KAAA;AACb,YAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AAAA,WACjB;AAAA,UACA;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAED,IAAA,MAAA,CAAO,YAAY,MAAM,MAAA;AACzB,IAAO,MAAA,CAAA,MAAA,GAAS,IAAIA,KAAS,KAAA;AAC3B,MAAI,IAAA,MAAA,CAAO,IAAS,KAAA,OAAA,CAAQ,KAAO,EAAA;AACnC,MAAIA,IAAAA,KAAAA,CAAK,QAAmBA,QAAAA,GAAAA,KAAAA;AAC5B,MAAA,IAAI,MAAO,CAAA,IAAA,KAAS,OAAQ,CAAA,KAAA,aAAkB,IAAI,CAAA;AAAA,KACpD;AACA,IAAO,OAAA,MAAA;AAAA,GACT;AACF;;;;"}
1
+ {"version":3,"file":"ws-provider.mjs","sources":["../../../src/ws-provider.ts"],"sourcesContent":["import { getSyncProvider } from \"@polkadot-api/json-rpc-provider-proxy\"\nimport {\n GetWsProviderInput,\n StatusChange,\n WsJsonRpcProvider,\n WsEvent,\n WsProviderConfig,\n} from \"./types\"\nimport { followEnhancer } from \"./follow-enhancer\"\n\nconst timeoutError: StatusChange = {\n type: WsEvent.ERROR,\n event: { type: \"timeout\" },\n}\n\nconst noop = () => {}\n\nconst mapEndpoints = (\n endpoints: WsProviderConfig[\"endpoints\"],\n): Array<[string, string | string[]] | [string]> =>\n endpoints.map((x) => (typeof x === \"string\" ? [x] : [x.uri, x.protocol]))\n\nexport const getInternalWsProvider = (\n WebsocketClass: typeof WebSocket,\n): GetWsProviderInput => {\n return (...args): WsJsonRpcProvider => {\n let endpoints: Array<[string, string | string[]] | [string]> = []\n let onStatusChanged: (status: StatusChange) => void = noop\n let timeout = 3_500\n\n const [firstArg] = args\n if (\n args.length === 1 &&\n typeof firstArg === \"object\" &&\n !Array.isArray(firstArg)\n ) {\n endpoints = mapEndpoints(firstArg.endpoints)\n onStatusChanged = firstArg.onStatusChanged ?? noop\n timeout = firstArg.timeout ?? timeout\n } else {\n if (typeof args[1] === \"function\")\n onStatusChanged = args[1] as (status: StatusChange) => void\n if (Array.isArray(firstArg)) endpoints = mapEndpoints(firstArg)\n else {\n endpoints = [[firstArg as string]]\n if (args[1] && args[1] !== onStatusChanged)\n endpoints[0][1] = args[1] as any\n if (args[2]) onStatusChanged = args[2] as any\n }\n }\n\n let idx = 0\n let status: StatusChange\n let switchTo: [string] | [string, string | string[]] | null = null\n let disconnect: (withHalt?: boolean) => void = noop\n\n let outerCleanup: () => void = noop\n const result = followEnhancer(\n getSyncProvider(async () => {\n const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length]\n switchTo = null\n const socket = new WebsocketClass(uri, protocols)\n const forceSocketClose = () => {\n try {\n socket.addEventListener(\"error\", noop, { once: true })\n socket.close()\n } catch {}\n }\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTING,\n uri,\n protocols,\n }),\n )\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n initialCleanup()\n resolve()\n }\n\n const onError = (e: Event | null) => {\n initialCleanup()\n if (e == null) forceSocketClose()\n console.error(\n `Unable to connect to ${uri}${\n protocols ? \", protocols: \" + protocols : \"\"\n }`,\n )\n onStatusChanged(\n (status = {\n type: e ? WsEvent.ERROR : WsEvent.CLOSE,\n event: e,\n }),\n )\n setTimeout(reject, e ? 300 : 0, e)\n }\n\n const timeoutToken =\n timeout !== Infinity\n ? setTimeout(() => {\n initialCleanup()\n forceSocketClose()\n onStatusChanged((status = timeoutError))\n reject(timeoutError.event)\n }, timeout)\n : undefined\n\n const initialCleanup = () => {\n clearTimeout(timeoutToken)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"open\", onOpen)\n }\n socket.addEventListener(\"open\", onOpen)\n socket.addEventListener(\"error\", onError)\n disconnect = () => {\n onError(null)\n }\n })\n\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTED,\n uri,\n protocols,\n }),\n )\n\n return (onMessage, onHalt) => {\n const _onMessage = (e: MessageEvent) => {\n if (typeof e.data === \"string\") onMessage(e.data)\n }\n const innerHalt =\n (reason: WsEvent.CLOSE | WsEvent.ERROR) => (e: any) => {\n console.warn(`WS halt (${reason})`)\n onStatusChanged(\n (status = {\n type: reason,\n event: e,\n }),\n )\n onHalt()\n }\n const onError = innerHalt(WsEvent.ERROR)\n const onClose = innerHalt(WsEvent.CLOSE)\n\n socket.addEventListener(\"message\", _onMessage)\n socket.addEventListener(\"error\", onError)\n socket.addEventListener(\"close\", onClose)\n disconnect = (withHalt) => {\n outerCleanup()\n disconnect = noop\n socket.removeEventListener(\"message\", _onMessage)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"close\", onClose)\n forceSocketClose()\n if (withHalt) onClose({})\n }\n\n return {\n send: (msg) => {\n socket.send(msg)\n },\n disconnect,\n }\n }\n }),\n () => {\n switchFn()\n },\n )\n outerCleanup = result.cleanup\n delete (result as any).cleanup\n\n const switchFn: WsJsonRpcProvider[\"switch\"] = (...args) => {\n if (status.type === WsEvent.CLOSE) return\n if (args.length) switchTo = args as any\n if (status.type !== WsEvent.ERROR) disconnect(true)\n }\n\n return Object.assign(result, { switch: switchFn, getStatus: () => status })\n }\n}\n"],"names":["args"],"mappings":"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"}
package/dist/node/node.js CHANGED
@@ -11,6 +11,73 @@ var WsEvent = /* @__PURE__ */ ((WsEvent2) => {
11
11
  return WsEvent2;
12
12
  })(WsEvent || {});
13
13
 
14
+ const methods = {};
15
+ ["v1", "unstable"].forEach((version) => {
16
+ methods[`chainHead_${version}_follow`] = "follow";
17
+ methods[`chainHead_${version}_unfollow`] = "unfollow";
18
+ });
19
+ const followEnhancer = (base, forceDisconnect) => {
20
+ const prematureStops = /* @__PURE__ */ new Set();
21
+ const preOpId = /* @__PURE__ */ new Map();
22
+ const onGoing = /* @__PURE__ */ new Set();
23
+ const result = (onMsg) => {
24
+ const { send, disconnect } = base((fromProvider) => {
25
+ const parsed = JSON.parse(fromProvider);
26
+ if ("id" in parsed) {
27
+ const { id, result: result2 } = parsed;
28
+ const msg = preOpId.get(id);
29
+ if (msg) {
30
+ preOpId.delete(id);
31
+ if (prematureStops.has(result2)) {
32
+ prematureStops.delete(result2);
33
+ return;
34
+ }
35
+ onGoing.add(result2);
36
+ const currentSize = onGoing.size + preOpId.size;
37
+ if (currentSize > 2)
38
+ console.warn(
39
+ `Too many chainHead follow subscriptions (${currentSize})`
40
+ );
41
+ else if (parsed.error) {
42
+ console.warn(`chainHead follow failed on the ${currentSize} sub`);
43
+ forceDisconnect();
44
+ preOpId.set(id, msg);
45
+ send(msg);
46
+ return;
47
+ }
48
+ }
49
+ } else {
50
+ const { subscription, result: result2 } = parsed.params;
51
+ if (result2?.event === "stop") {
52
+ if (onGoing.has(subscription)) onGoing.delete(subscription);
53
+ else prematureStops.add(subscription);
54
+ }
55
+ }
56
+ onMsg(fromProvider);
57
+ });
58
+ return {
59
+ send(toProvider) {
60
+ const parsed = JSON.parse(toProvider);
61
+ const method = methods[parsed.method];
62
+ if (method === "follow") {
63
+ preOpId.set(parsed.id, toProvider);
64
+ } else if (method === "unfollow") {
65
+ onGoing.delete(parsed.params[0]);
66
+ }
67
+ send(toProvider);
68
+ },
69
+ disconnect
70
+ };
71
+ };
72
+ return Object.assign(result, {
73
+ cleanup: () => {
74
+ prematureStops.clear();
75
+ preOpId.clear();
76
+ onGoing.clear();
77
+ }
78
+ });
79
+ };
80
+
14
81
  const timeoutError = {
15
82
  type: WsEvent.ERROR,
16
83
  event: { type: "timeout" }
@@ -43,109 +110,117 @@ const getInternalWsProvider = (WebsocketClass) => {
43
110
  let status;
44
111
  let switchTo = null;
45
112
  let disconnect = noop;
46
- const result = jsonRpcProviderProxy.getSyncProvider(async () => {
47
- const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
48
- switchTo = null;
49
- const socket = new WebsocketClass(uri, protocols);
50
- const forceSocketClose = () => {
51
- try {
52
- socket.addEventListener("error", noop, { once: true });
53
- socket.close();
54
- } catch {
55
- }
56
- };
57
- onStatusChanged(
58
- status = {
59
- type: WsEvent.CONNECTING,
60
- uri,
61
- protocols
62
- }
63
- );
64
- await new Promise((resolve, reject) => {
65
- const onOpen = () => {
66
- initialCleanup();
67
- resolve();
68
- };
69
- const onError = (e) => {
70
- initialCleanup();
71
- if (e == null) forceSocketClose();
72
- console.error(
73
- `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
74
- );
75
- onStatusChanged(
76
- status = {
77
- type: e ? WsEvent.ERROR : WsEvent.CLOSE,
78
- event: e
79
- }
80
- );
81
- setTimeout(reject, e ? 300 : 0, e);
82
- };
83
- const timeoutToken = timeout !== Infinity ? setTimeout(() => {
84
- initialCleanup();
85
- forceSocketClose();
86
- onStatusChanged(status = timeoutError);
87
- reject(timeoutError.event);
88
- }, timeout) : void 0;
89
- const initialCleanup = () => {
90
- clearTimeout(timeoutToken);
91
- socket.removeEventListener("error", onError);
92
- socket.removeEventListener("open", onOpen);
93
- };
94
- socket.addEventListener("open", onOpen);
95
- socket.addEventListener("error", onError);
96
- disconnect = () => {
97
- onError(null);
98
- };
99
- });
100
- onStatusChanged(
101
- status = {
102
- type: WsEvent.CONNECTED,
103
- uri,
104
- protocols
105
- }
106
- );
107
- return (onMessage, onHalt) => {
108
- const _onMessage = (e) => {
109
- if (typeof e.data === "string") onMessage(e.data);
110
- };
111
- const innerHalt = (reason) => (e) => {
112
- console.warn(`WS halt (${reason})`);
113
- onStatusChanged(
114
- status = {
115
- type: reason,
116
- event: e
117
- }
118
- );
119
- onHalt();
120
- };
121
- const onError = innerHalt(WsEvent.ERROR);
122
- const onClose = innerHalt(WsEvent.CLOSE);
123
- socket.addEventListener("message", _onMessage);
124
- socket.addEventListener("error", onError);
125
- socket.addEventListener("close", onClose);
126
- disconnect = (withHalt) => {
127
- disconnect = noop;
128
- socket.removeEventListener("message", _onMessage);
129
- socket.removeEventListener("error", onError);
130
- socket.removeEventListener("close", onClose);
131
- forceSocketClose();
132
- if (withHalt) onClose({});
113
+ let outerCleanup = noop;
114
+ const result = followEnhancer(
115
+ jsonRpcProviderProxy.getSyncProvider(async () => {
116
+ const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
117
+ switchTo = null;
118
+ const socket = new WebsocketClass(uri, protocols);
119
+ const forceSocketClose = () => {
120
+ try {
121
+ socket.addEventListener("error", noop, { once: true });
122
+ socket.close();
123
+ } catch {
124
+ }
133
125
  };
134
- return {
135
- send: (msg) => {
136
- socket.send(msg);
137
- },
138
- disconnect
126
+ onStatusChanged(
127
+ status = {
128
+ type: WsEvent.CONNECTING,
129
+ uri,
130
+ protocols
131
+ }
132
+ );
133
+ await new Promise((resolve, reject) => {
134
+ const onOpen = () => {
135
+ initialCleanup();
136
+ resolve();
137
+ };
138
+ const onError = (e) => {
139
+ initialCleanup();
140
+ if (e == null) forceSocketClose();
141
+ console.error(
142
+ `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
143
+ );
144
+ onStatusChanged(
145
+ status = {
146
+ type: e ? WsEvent.ERROR : WsEvent.CLOSE,
147
+ event: e
148
+ }
149
+ );
150
+ setTimeout(reject, e ? 300 : 0, e);
151
+ };
152
+ const timeoutToken = timeout !== Infinity ? setTimeout(() => {
153
+ initialCleanup();
154
+ forceSocketClose();
155
+ onStatusChanged(status = timeoutError);
156
+ reject(timeoutError.event);
157
+ }, timeout) : void 0;
158
+ const initialCleanup = () => {
159
+ clearTimeout(timeoutToken);
160
+ socket.removeEventListener("error", onError);
161
+ socket.removeEventListener("open", onOpen);
162
+ };
163
+ socket.addEventListener("open", onOpen);
164
+ socket.addEventListener("error", onError);
165
+ disconnect = () => {
166
+ onError(null);
167
+ };
168
+ });
169
+ onStatusChanged(
170
+ status = {
171
+ type: WsEvent.CONNECTED,
172
+ uri,
173
+ protocols
174
+ }
175
+ );
176
+ return (onMessage, onHalt) => {
177
+ const _onMessage = (e) => {
178
+ if (typeof e.data === "string") onMessage(e.data);
179
+ };
180
+ const innerHalt = (reason) => (e) => {
181
+ console.warn(`WS halt (${reason})`);
182
+ onStatusChanged(
183
+ status = {
184
+ type: reason,
185
+ event: e
186
+ }
187
+ );
188
+ onHalt();
189
+ };
190
+ const onError = innerHalt(WsEvent.ERROR);
191
+ const onClose = innerHalt(WsEvent.CLOSE);
192
+ socket.addEventListener("message", _onMessage);
193
+ socket.addEventListener("error", onError);
194
+ socket.addEventListener("close", onClose);
195
+ disconnect = (withHalt) => {
196
+ outerCleanup();
197
+ disconnect = noop;
198
+ socket.removeEventListener("message", _onMessage);
199
+ socket.removeEventListener("error", onError);
200
+ socket.removeEventListener("close", onClose);
201
+ forceSocketClose();
202
+ if (withHalt) onClose({});
203
+ };
204
+ return {
205
+ send: (msg) => {
206
+ socket.send(msg);
207
+ },
208
+ disconnect
209
+ };
139
210
  };
140
- };
141
- });
142
- result.getStatus = () => status;
143
- result.switch = (...args2) => {
211
+ }),
212
+ () => {
213
+ switchFn();
214
+ }
215
+ );
216
+ outerCleanup = result.cleanup;
217
+ delete result.cleanup;
218
+ const switchFn = (...args2) => {
144
219
  if (status.type === WsEvent.CLOSE) return;
145
220
  if (args2.length) switchTo = args2;
146
221
  if (status.type !== WsEvent.ERROR) disconnect(true);
147
222
  };
148
- return result;
223
+ return Object.assign(result, { switch: switchFn, getStatus: () => status });
149
224
  };
150
225
  };
151
226