@arcblock/ws 1.28.9 → 1.29.0

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,474 @@
1
+ import { __require } from "../_virtual/rolldown_runtime.mjs";
2
+ import logger_default from "../logger.mjs";
3
+ import EventEmitter from "node:events";
4
+ import WebSocket, { WebSocketServer } from "ws";
5
+ import cluster from "node:cluster";
6
+ import get from "lodash/get.js";
7
+
8
+ //#region src/server/index.ts
9
+ const eventHub = cluster.isMaster ? __require("@arcblock/event-hub/single").default : __require("@arcblock/event-hub").default;
10
+ const nanoid = (length = 16) => [...Array(length)].map(() => Math.random().toString(36)[2]).join("");
11
+ const sleep = (timeout) => new Promise((resolve) => {
12
+ setTimeout(resolve, timeout);
13
+ });
14
+ const reply = ({ socket, topic, event, data = {}, status = "ok", ref = "", joinRef = "" }) => {
15
+ if (socket.readyState === WebSocket.OPEN) {
16
+ const res = JSON.stringify([
17
+ joinRef,
18
+ ref,
19
+ topic,
20
+ event,
21
+ {
22
+ status,
23
+ response: data
24
+ }
25
+ ]);
26
+ socket.send(res);
27
+ }
28
+ };
29
+ const noop = () => {};
30
+ const defaultHooks = {
31
+ authenticateJoinChannel: noop,
32
+ preJoinChannel: noop,
33
+ postJoinChannel: noop,
34
+ preLeaveChannel: noop,
35
+ postLeaveChannel: noop,
36
+ postBroadcast: noop,
37
+ postSend: noop,
38
+ receiveMessage: noop
39
+ };
40
+ const refreshHeartbeat = (socket) => {
41
+ socket.heartbeatAt = Date.now();
42
+ };
43
+ const HEARTBEAT_TIMEOUT = 300 * 1e3;
44
+ /**
45
+ * Create a websocket server
46
+ *
47
+ * @param {Object} opts
48
+ * @param {String} opts.pathname - which path to mount the socket server
49
+ * @param {Object} opts.authenticate - authentication function to be called on connection
50
+ * @param {Object} opts.hooks - hooks to be called on events
51
+ * @param {Object} opts.logger - logger used to log messages
52
+ * @param {Object} opts.broadcastEventName - used in cluster mode, default is '@arcblock/ws:broadcast'
53
+ * @param {Object} opts.heartbeatTimeout - maximum non-response time of a connection socket
54
+ * @class WsServer
55
+ * @extends {EventEmitter}
56
+ */
57
+ var WsServer = class extends EventEmitter {
58
+ constructor(opts = {}) {
59
+ super();
60
+ this.pathname = opts.pathname;
61
+ this.authenticate = opts.authenticate;
62
+ this.hooks = Object.assign({}, defaultHooks, opts.hooks || {});
63
+ this.logger = opts.logger || logger_default("server", opts.silent);
64
+ this.skipLogOnHookError = opts.skipLogOnHookError || false;
65
+ this.heartbeatTimeout = opts.heartbeatTimeout || HEARTBEAT_TIMEOUT;
66
+ this.wss = new WebSocketServer({
67
+ noServer: true,
68
+ clientTracking: false
69
+ });
70
+ this.wss.on("connection", this.onWssConnection.bind(this));
71
+ this.wss.on("close", this.onWssClose.bind(this));
72
+ this.wss.on("error", this.onWssError.bind(this));
73
+ this.topics = {};
74
+ this.broadcastEventName = opts.broadcastEventName || "@arcblock/ws:broadcast";
75
+ eventHub.on(this.broadcastEventName, (data) => this._doBroadCast(data));
76
+ }
77
+ attach(server) {
78
+ server.on("upgrade", this.onConnect.bind(this));
79
+ return this;
80
+ }
81
+ onConnect(request, socket, head) {
82
+ const { pathname } = new URL(request.url, `http://${request.headers.host || "unknown"}`);
83
+ this.logger.debug("connect attempt", { pathname });
84
+ if (this.pathname && pathname !== this.pathname) {
85
+ socket.write("HTTP/1.1 404 Pathname mismatch\r\n\r\n");
86
+ socket.destroy();
87
+ return;
88
+ }
89
+ if (!this.authenticate) {
90
+ this.wss.handleUpgrade(request, socket, head, (ws) => {
91
+ this.wss.emit("connection", ws, request);
92
+ });
93
+ return;
94
+ }
95
+ this.authenticate(request, (err, authInfo) => {
96
+ if (err) {
97
+ socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
98
+ socket.destroy();
99
+ return;
100
+ }
101
+ this.wss.handleUpgrade(request, socket, head, (ws) => {
102
+ ws.authInfo = authInfo;
103
+ this.wss.emit("connection", ws, request);
104
+ });
105
+ });
106
+ }
107
+ /**
108
+ * Broadcast message to all subscribers of a topic, can be used as
109
+ * - broadcast(event, data) ==> broadcast(event, event, data)
110
+ * - broadcast(topic, event, data)
111
+ * - broadcast(topic, event, data, options)
112
+ */
113
+ async broadcast(...args) {
114
+ let topic;
115
+ let event;
116
+ let data;
117
+ let options = {};
118
+ let cb = () => {};
119
+ if (typeof args[args.length - 1] === "function") cb = args.pop();
120
+ if (args.length < 2) throw new Error("Broadcasting requires at least 2 arguments");
121
+ if (args.length === 2) {
122
+ [event, data] = args;
123
+ topic = event;
124
+ } else if (args.length === 3) [topic, event, data] = args;
125
+ else [topic, event, data, options] = args;
126
+ const enableLog = !!options.enableLog;
127
+ const { socketFilters, noCluster } = options;
128
+ const replyId = nanoid();
129
+ let count = 0;
130
+ if (noCluster) {
131
+ const { count: c } = this._doBroadCast({
132
+ topic,
133
+ event,
134
+ data,
135
+ enableLog,
136
+ socketFilters
137
+ });
138
+ count = c;
139
+ } else {
140
+ eventHub.on(replyId, ({ count: c } = {}) => {
141
+ if (c) count += c;
142
+ });
143
+ eventHub.broadcast(this.broadcastEventName, {
144
+ topic,
145
+ event,
146
+ data,
147
+ options,
148
+ enableLog,
149
+ replyId,
150
+ socketFilters
151
+ });
152
+ await sleep(600);
153
+ eventHub.off(replyId);
154
+ }
155
+ const opts = {
156
+ count,
157
+ topic,
158
+ event,
159
+ data,
160
+ options
161
+ };
162
+ cb(opts);
163
+ try {
164
+ await this.hooks.postBroadcast(opts);
165
+ } catch (error) {
166
+ if (!this.skipLogOnHookError) this.logger.error("postBroadcast error", { error });
167
+ }
168
+ }
169
+ _doBroadCast({ topic, event, data, enableLog, replyId, socketFilters } = {}) {
170
+ try {
171
+ let count = 0;
172
+ if (this.topics[topic]?.size) {
173
+ let conditions = null;
174
+ if (socketFilters && Object.keys(socketFilters).length) conditions = Object.entries(socketFilters);
175
+ this.topics[topic].forEach((socket) => {
176
+ const noHeartbeatTime = Date.now() - socket.heartbeatAt;
177
+ if (noHeartbeatTime > this.heartbeatTimeout) {
178
+ this.logger.error(`Socket has no heartbeat within ${Math.floor(noHeartbeatTime / 1e3)} seconds`, {
179
+ topic,
180
+ id: socket.id
181
+ });
182
+ this.topics[topic].delete(socket);
183
+ return;
184
+ }
185
+ if (conditions && !conditions.every(([key, value]) => get(socket, key) === value)) return;
186
+ count++;
187
+ if (enableLog) this.logger.info("broadcast message to", {
188
+ topic,
189
+ event,
190
+ id: socket.id
191
+ });
192
+ reply({
193
+ socket,
194
+ topic,
195
+ event,
196
+ data
197
+ });
198
+ });
199
+ }
200
+ if (count > 0 && replyId) eventHub.broadcast(replyId, { count });
201
+ return { count };
202
+ } catch (error) {
203
+ this.logger.error("_doBroadcast error", { error });
204
+ return {
205
+ count: 0,
206
+ error
207
+ };
208
+ }
209
+ }
210
+ /**
211
+ * Send message to 1 subscriber of a topic, can be used as
212
+ * - send(socket, event, data)
213
+ * - send(socket, topic, event, data)
214
+ * - send(socket, topic, event, data, options)
215
+ */
216
+ async send(...args) {
217
+ let socket;
218
+ let topic;
219
+ let event;
220
+ let data;
221
+ let options = {};
222
+ if (args.length < 3) throw new Error("send requires at least 3 arguments");
223
+ if (args.length === 3) {
224
+ [socket, event, data] = args;
225
+ topic = event;
226
+ } else if (args.length === 4) [socket, topic, event, data] = args;
227
+ else [socket, topic, event, data, options] = args;
228
+ const opts = {
229
+ enableLog: true,
230
+ ...options
231
+ };
232
+ if (!socket) {
233
+ this.logger.error("socket does not exist");
234
+ return;
235
+ }
236
+ if (opts.enableLog) this.logger.info("send message to", {
237
+ topic,
238
+ event,
239
+ id: socket.id
240
+ });
241
+ reply({
242
+ socket,
243
+ topic,
244
+ event,
245
+ data
246
+ });
247
+ try {
248
+ await this.hooks.postSend({
249
+ topic,
250
+ event,
251
+ data,
252
+ options
253
+ });
254
+ } catch (error) {
255
+ if (!this.skipLogOnHookError) this.logger.error("postSend error", { error });
256
+ }
257
+ }
258
+ /**
259
+ * private
260
+ */
261
+ async onWssConnection(socket) {
262
+ const wsSocket = socket;
263
+ wsSocket.id = nanoid();
264
+ wsSocket.channel = {};
265
+ refreshHeartbeat(wsSocket);
266
+ this.logger.debug("socket connected", { id: wsSocket.id });
267
+ wsSocket.on("message", async (msg) => {
268
+ this.logger.debug("socket onmessage", msg.toString());
269
+ let joinRef;
270
+ let ref;
271
+ let topic;
272
+ let event;
273
+ let payload;
274
+ try {
275
+ [joinRef, ref, topic, event, payload] = JSON.parse(msg.toString());
276
+ } catch (err) {
277
+ this.logger.error("parse socket message error", {
278
+ id: wsSocket.id,
279
+ error: err
280
+ });
281
+ return;
282
+ }
283
+ if (!topic || !event) {
284
+ this.logger.warn?.("Invalid message format, topic/event fields are required");
285
+ return;
286
+ }
287
+ if (topic === "phoenix" && event === "heartbeat") {
288
+ reply({
289
+ socket: wsSocket,
290
+ topic,
291
+ event,
292
+ ref
293
+ });
294
+ refreshHeartbeat(wsSocket);
295
+ return;
296
+ }
297
+ if (event === "phx_join") {
298
+ try {
299
+ const authInfo = await this.hooks.authenticateJoinChannel({
300
+ socket: wsSocket,
301
+ joinRef,
302
+ ref,
303
+ topic,
304
+ event,
305
+ payload
306
+ });
307
+ await this.hooks.preJoinChannel({
308
+ socket: wsSocket,
309
+ joinRef,
310
+ ref,
311
+ topic,
312
+ event,
313
+ payload
314
+ });
315
+ wsSocket.channel[topic] = { authInfo };
316
+ } catch (error) {
317
+ if (!this.skipLogOnHookError) this.logger.error("preJoinChannel error", { error });
318
+ reply({
319
+ socket: wsSocket,
320
+ topic,
321
+ event: `chan_reply_${ref}`,
322
+ data: { message: error.message },
323
+ status: "error",
324
+ ref,
325
+ joinRef
326
+ });
327
+ return;
328
+ }
329
+ if (!this.topics[topic]) this.topics[topic] = /* @__PURE__ */ new Set();
330
+ this.topics[topic].add(wsSocket);
331
+ reply({
332
+ socket: wsSocket,
333
+ topic,
334
+ event: `chan_reply_${ref}`,
335
+ ref,
336
+ joinRef
337
+ });
338
+ this.emit("channel.join", {
339
+ socket: wsSocket,
340
+ topic,
341
+ event,
342
+ payload
343
+ });
344
+ try {
345
+ await this.hooks.postJoinChannel({
346
+ socket: wsSocket,
347
+ joinRef,
348
+ ref,
349
+ topic,
350
+ event,
351
+ payload
352
+ });
353
+ } catch (error) {
354
+ if (!this.skipLogOnHookError) this.logger.error("postJoinChannel error", { error });
355
+ }
356
+ return;
357
+ }
358
+ if (event === "phx_leave") {
359
+ try {
360
+ await this.hooks.preLeaveChannel({
361
+ socket: wsSocket,
362
+ joinRef,
363
+ ref,
364
+ topic,
365
+ event,
366
+ payload
367
+ });
368
+ } catch (error) {
369
+ if (!this.skipLogOnHookError) this.logger.error("preLeaveChannel error", { error });
370
+ reply({
371
+ socket: wsSocket,
372
+ topic,
373
+ event: `chan_reply_${ref}`,
374
+ data: { message: error.message },
375
+ status: "error",
376
+ ref,
377
+ joinRef
378
+ });
379
+ return;
380
+ }
381
+ this._leaveChannel(wsSocket, topic);
382
+ reply({
383
+ socket: wsSocket,
384
+ topic,
385
+ event: `chan_reply_${ref}`,
386
+ ref,
387
+ joinRef
388
+ });
389
+ try {
390
+ await this.hooks.postLeaveChannel({
391
+ socket: wsSocket,
392
+ joinRef,
393
+ ref,
394
+ topic,
395
+ event,
396
+ payload
397
+ });
398
+ } catch (error) {
399
+ if (!this.skipLogOnHookError) this.logger.error("postLeaveChannel error", { error });
400
+ }
401
+ return;
402
+ }
403
+ try {
404
+ await this.hooks.receiveMessage({
405
+ socket: wsSocket,
406
+ joinRef,
407
+ ref,
408
+ topic,
409
+ event,
410
+ payload
411
+ });
412
+ } catch (error) {
413
+ if (!this.skipLogOnHookError) this.logger.error("receiveMessage error", { error });
414
+ reply({
415
+ socket: wsSocket,
416
+ topic,
417
+ event: `chan_reply_${ref}`,
418
+ data: { message: error.message },
419
+ status: "error",
420
+ ref,
421
+ joinRef
422
+ });
423
+ return;
424
+ }
425
+ reply({
426
+ socket: wsSocket,
427
+ topic,
428
+ event: `chan_reply_${ref}`,
429
+ ref,
430
+ joinRef
431
+ });
432
+ });
433
+ wsSocket.on("close", () => {
434
+ this.logger.debug("socket onclose", { id: wsSocket.id });
435
+ Object.keys(this.topics).forEach((topic) => this._leaveChannel(wsSocket, topic));
436
+ });
437
+ wsSocket.on("error", (err) => {
438
+ this.logger.error("socket onerror", {
439
+ id: wsSocket.id,
440
+ error: err
441
+ });
442
+ Object.keys(this.topics).forEach((topic) => this._leaveChannel(wsSocket, topic));
443
+ });
444
+ }
445
+ /**
446
+ * private
447
+ */
448
+ onWssClose() {
449
+ this.logger.debug("ws server onclose");
450
+ this.emit("close");
451
+ }
452
+ /**
453
+ * private
454
+ */
455
+ onWssError(error) {
456
+ this.logger.error("ws server error", { error });
457
+ this.emit("error", error);
458
+ }
459
+ _leaveChannel(socket, topic) {
460
+ if (this.topics[topic]) this.topics[topic].delete(socket);
461
+ this.emit("channel.leave", {
462
+ socket,
463
+ topic
464
+ });
465
+ if (!this.topics[topic] || !this.topics[topic].size) this.emit("channel.destroy", {
466
+ socket,
467
+ topic
468
+ });
469
+ }
470
+ };
471
+ var server_default = WsServer;
472
+
473
+ //#endregion
474
+ export { server_default as default };
@@ -0,0 +1,29 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+
27
+ //#endregion
28
+
29
+ exports.__toESM = __toESM;
@@ -0,0 +1,3 @@
1
+ const require_client_browser = require('./client/browser.cjs');
2
+
3
+ exports.WsClient = require_client_browser.default;
@@ -0,0 +1,2 @@
1
+ import _default from "./client/browser.cjs";
2
+ export { _default as WsClient };
@@ -0,0 +1,119 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+ const require_logger = require('../logger.cjs');
3
+
4
+ //#region src/client/base.ts
5
+ var base_default = (Socket, EventEmitter, transport) => {
6
+ return class WsClient extends Socket {
7
+ constructor(endpoint, opts = {}) {
8
+ super(endpoint, {
9
+ transport,
10
+ ...opts
11
+ });
12
+ this._logger = require_logger.default("client", opts.silent);
13
+ this.emitter = new EventEmitter();
14
+ this.onOpen(() => {
15
+ this._logger.debug("socket open", endpoint);
16
+ });
17
+ this.onClose(() => {
18
+ this._logger.debug("socket close", endpoint);
19
+ });
20
+ this.onError((err) => {
21
+ this._logger.error("socket error", err.error);
22
+ });
23
+ this.onMessage((message) => {
24
+ this._logger.debug("socket message", message);
25
+ });
26
+ }
27
+ on(event, handler, params = {}) {
28
+ this.ensureJoinChannel(event, params);
29
+ this.emitter.on(event, handler);
30
+ }
31
+ off(event, handler) {
32
+ if (handler) this.emitter.off(event, handler);
33
+ else this.emitter.removeAllListeners(event);
34
+ this.ensureLeaveChannel(event);
35
+ }
36
+ disconnect(callback, code, reason) {
37
+ this.emitter.eventNames().forEach((event) => {
38
+ this.emitter.removeAllListeners(event);
39
+ });
40
+ super.disconnect(callback, code, reason);
41
+ }
42
+ /**
43
+ * private
44
+ */
45
+ ensureJoinChannel(topic, params = {}) {
46
+ if (this.emitter.listenerCount(topic) > 0) return;
47
+ const channel = this.channel(topic, params);
48
+ channel.join().receive("ok", (message) => {
49
+ this._logger.debug("join success", {
50
+ topic,
51
+ message
52
+ });
53
+ }).receive("error", (error) => {
54
+ this._logger.error("join error", {
55
+ topic,
56
+ error
57
+ });
58
+ }).receive("timeout", () => {
59
+ this._logger.debug("join timeout", { topic });
60
+ });
61
+ channel.on(topic, ({ status, response: data }) => {
62
+ if (status === "ok") this.emitter.emit(topic, data);
63
+ else this._logger.debug("response error", {
64
+ topic,
65
+ status,
66
+ data
67
+ });
68
+ });
69
+ }
70
+ /**
71
+ * private
72
+ */
73
+ ensureLeaveChannel(topic) {
74
+ if (this.emitter.listenerCount(topic) > 0) return;
75
+ const channel = this.channels.find((c) => c.topic === topic);
76
+ if (!channel) return;
77
+ this.remove(channel);
78
+ channel.leave().receive("ok", (message) => {
79
+ this._logger.debug("leave success", {
80
+ topic,
81
+ message
82
+ });
83
+ }).receive("error", (err) => {
84
+ this._logger.error("leave error", {
85
+ topic,
86
+ err
87
+ });
88
+ }).receive("timeout", () => {
89
+ this._logger.debug("leave timeout", { topic });
90
+ });
91
+ channel.off(topic);
92
+ }
93
+ subscribe(topic, params = {}) {
94
+ let channel = this.channels.find((c) => c.topic === topic);
95
+ if (channel) return channel;
96
+ channel = this.channel(topic, params);
97
+ channel.join().receive("ok", (message) => {
98
+ this._logger.debug("join success", {
99
+ topic,
100
+ message
101
+ });
102
+ }).receive("error", (error) => {
103
+ this._logger.error("join error", {
104
+ topic,
105
+ error
106
+ });
107
+ }).receive("timeout", () => {
108
+ this._logger.debug("join timeout", { topic });
109
+ });
110
+ return channel;
111
+ }
112
+ unsubscribe(topic) {
113
+ this.ensureLeaveChannel(topic);
114
+ }
115
+ };
116
+ };
117
+
118
+ //#endregion
119
+ exports.default = base_default;
@@ -0,0 +1,80 @@
1
+ import _default$1 from "../logger.cjs";
2
+
3
+ //#region src/client/base.d.ts
4
+ interface SocketConstructor {
5
+ new (endpoint: string, opts: object): SocketInstance;
6
+ }
7
+ interface SocketInstance {
8
+ channels: Channel[];
9
+ connect(): void;
10
+ disconnect(callback?: () => void, code?: number, reason?: string): void;
11
+ isConnected(): boolean;
12
+ onOpen(cb: () => void): void;
13
+ onClose(cb: () => void): void;
14
+ onError(cb: (err: {
15
+ error: Error;
16
+ }) => void): void;
17
+ onMessage(cb: (message: unknown) => void): void;
18
+ channel(topic: string, params?: object | (() => object)): Channel;
19
+ remove(channel: Channel): void;
20
+ }
21
+ interface Channel {
22
+ topic: string;
23
+ join(): ChannelPush;
24
+ leave(): ChannelPush;
25
+ on(event: string, callback: (data: {
26
+ status: string;
27
+ response: unknown;
28
+ }) => void): void;
29
+ off(event: string): void;
30
+ }
31
+ interface ChannelPush {
32
+ receive(status: string, callback: (data: unknown) => void): ChannelPush;
33
+ }
34
+ interface EventEmitterConstructor {
35
+ new (): EventEmitterInstance;
36
+ }
37
+ interface EventEmitterInstance {
38
+ on(event: string, handler: (data: unknown) => void): void;
39
+ off(event: string, handler?: (data: unknown) => void): void;
40
+ emit(event: string, data: unknown): void;
41
+ removeAllListeners(event: string): void;
42
+ listenerCount(event: string): number;
43
+ eventNames(): (string | symbol)[];
44
+ }
45
+ interface WsClientOptions {
46
+ silent?: boolean;
47
+ [key: string]: unknown;
48
+ }
49
+ declare const _default: (Socket: SocketConstructor, EventEmitter: EventEmitterConstructor, transport?: unknown) => {
50
+ new (endpoint: string, opts?: WsClientOptions): {
51
+ _logger: ReturnType<typeof _default$1>;
52
+ emitter: EventEmitterInstance;
53
+ on(event: string, handler: (data: unknown) => void, params?: object): void;
54
+ off(event: string, handler?: (data: unknown) => void): void;
55
+ disconnect(callback?: () => void, code?: number, reason?: string): void;
56
+ /**
57
+ * private
58
+ */
59
+ ensureJoinChannel(topic: string, params?: object): void;
60
+ /**
61
+ * private
62
+ */
63
+ ensureLeaveChannel(topic: string): void;
64
+ subscribe(topic: string, params?: object): Channel;
65
+ unsubscribe(topic: string): void;
66
+ channels: Channel[];
67
+ connect(): void;
68
+ isConnected(): boolean;
69
+ onOpen(cb: () => void): void;
70
+ onClose(cb: () => void): void;
71
+ onError(cb: (err: {
72
+ error: Error;
73
+ }) => void): void;
74
+ onMessage(cb: (message: unknown) => void): void;
75
+ channel(topic: string, params?: object | (() => object)): Channel;
76
+ remove(channel: Channel): void;
77
+ };
78
+ };
79
+ //#endregion
80
+ export { Channel, ChannelPush, EventEmitterConstructor, EventEmitterInstance, SocketConstructor, SocketInstance, WsClientOptions, _default as default };