@nmtjs/ws-client 0.8.1 → 0.10.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.
package/dist/index.js CHANGED
@@ -1,53 +1,57 @@
1
- import { EventEmitter } from "@nmtjs/protocol/client";
2
- import { concat, decodeNumber, encodeNumber, ServerMessageType } from "@nmtjs/protocol/common";
3
- export class WebSocketClientTransport extends EventEmitter {
4
- #webSocket = null;
5
- #connecting = null;
6
- constructor(options) {
1
+ import { ClientMessageType, concat, encodeNumber } from "@nmtjs/protocol";
2
+ import { ProtocolTransport } from "@nmtjs/protocol/client";
3
+ export class WebSocketClientTransport extends ProtocolTransport {
4
+ webSocket = null;
5
+ connecting = null;
6
+ constructor(protocol, options) {
7
7
  super();
8
+ this.protocol = protocol;
8
9
  this.options = options;
9
10
  }
10
- connect(auth = undefined, contentType) {
11
- const wsUrl = new URL(this.options.origin);
12
- wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
13
- wsUrl.pathname = "/api";
14
- wsUrl.searchParams.set("content-type", contentType);
15
- wsUrl.searchParams.set("accept", contentType);
11
+ connect(auth, transformer) {
12
+ const wsUrl = new URL("/api", this.options.origin);
13
+ if (this.protocol.contentType) {
14
+ wsUrl.searchParams.set("content-type", this.protocol.contentType);
15
+ wsUrl.searchParams.set("accept", this.protocol.contentType);
16
+ }
16
17
  if (auth) wsUrl.searchParams.set("auth", auth);
17
18
  const ws = this.options.wsFactory?.(wsUrl) ?? new WebSocket(wsUrl.toString());
18
19
  ws.binaryType = "arraybuffer";
19
20
  ws.addEventListener("message", ({ data }) => {
20
- const buffer = data;
21
- const type = decodeNumber(buffer, "Uint8");
22
- if (type in ServerMessageType) {
23
- this.emit(`${type}`, buffer.slice(Uint8Array.BYTES_PER_ELEMENT));
24
- }
21
+ this.protocol.handleServerMessage(data, this, transformer);
25
22
  });
26
- this.#webSocket = ws;
27
- this.#connecting = new Promise((resolve, reject) => {
23
+ this.webSocket = ws;
24
+ this.connecting = new Promise((resolve, reject) => {
28
25
  ws.addEventListener("open", () => {
29
- this.emit("connected");
26
+ this.protocol.emit("connected");
30
27
  resolve();
31
28
  }, { once: true });
32
- ws.addEventListener("error", (event) => reject(new Error("WebSocket error", { cause: event })), { once: true });
29
+ ws.addEventListener("error", (event) => {
30
+ reject(new Error("WebSocket error", { cause: event }));
31
+ }, { once: true });
33
32
  ws.addEventListener("close", (event) => {
34
- this.emit("disconnected");
35
- this.#webSocket = null;
33
+ this.protocol.emit("disconnected");
34
+ this.webSocket = null;
36
35
  if (this.options.autoreconnect === true) {
37
- setTimeout(() => this.connect(auth, contentType), 1e3);
36
+ setTimeout(this.connect.bind(this), 1e3);
38
37
  }
39
38
  }, { once: true });
40
39
  });
41
- return this.#connecting;
40
+ return this.connecting;
42
41
  }
43
42
  async disconnect() {
44
- if (this.#webSocket === null) return;
45
- this.#webSocket.close();
46
- return _once(this.#webSocket, "close");
43
+ if (this.webSocket === null) return;
44
+ this.webSocket.close();
45
+ return _once(this.webSocket, "close");
46
+ }
47
+ async call(namespace, procedure, payload, options, transformer) {
48
+ const { call, buffer } = this.protocol.createRpc(namespace, procedure, payload, options, transformer);
49
+ await this.send(ClientMessageType.Rpc, buffer);
50
+ return call;
47
51
  }
48
52
  async send(messageType, buffer) {
49
- if (this.#connecting) await this.#connecting;
50
- this.#webSocket.send(concat(encodeNumber(messageType, "Uint8"), buffer));
53
+ if (this.connecting) await this.connecting;
54
+ this.webSocket.send(concat(encodeNumber(messageType, "Uint8"), buffer));
51
55
  }
52
56
  }
53
57
  function _once(target, event) {
@@ -55,3 +59,5 @@ function _once(target, event) {
55
59
  target.addEventListener(event, () => resolve(), { once: true });
56
60
  });
57
61
  }
62
+
63
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"AAAA,SAEE,oBAGK,wBAAwB;AAC/B,SAEE,QACA,cACA,cACA,yBACK,wBAAwB;AAsB/B,OAAO,MAAM,iCACH,aAEV;CACE,aAA+B;CAC/B,cAAoC;CAEpC,YAA6BA,SAA0C;AACrE,SAAO;OADoB;CAE5B;CAED,QACEC,OAA2B,WAC3BC,aACe;EACf,MAAM,QAAQ,IAAI,IAAI,KAAK,QAAQ;AACnC,QAAM,WAAW,MAAM,aAAa,WAAW,SAAS;AACxD,QAAM,WAAW;AACjB,QAAM,aAAa,IAAI,gBAAgB,YAAY;AACnD,QAAM,aAAa,IAAI,UAAU,YAAY;AAC7C,MAAI,KAAM,OAAM,aAAa,IAAI,QAAQ,KAAK;EAE9C,MAAM,KACJ,KAAK,QAAQ,YAAY,MAAM,IAAI,IAAI,UAAU,MAAM,UAAU;AAEnE,KAAG,aAAa;AAEhB,KAAG,iBAAiB,WAAW,CAAC,EAAE,MAAM,KAAK;GAC3C,MAAMC,SAAsB;GAC5B,MAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,OAAI,QAAQ,mBAAmB;AAC7B,SAAK,MAAM,EAAE,KAAK,GAAG,OAAO,MAAM,WAAW,kBAAkB,CAAC;GACjE;EACF,EAAC;AAEF,OAAKC,aAAa;AAElB,OAAKC,cAAc,IAAI,QAAQ,CAAC,SAAS,WAAW;AAClD,MAAG,iBACD,QACA,MAAM;AACJ,SAAK,KAAK,YAAY;AACtB,aAAS;GACV,GACD,EAAE,MAAM,KAAM,EACf;AAED,MAAG,iBACD,SACA,CAAC,UAAU,OAAO,IAAI,MAAM,mBAAmB,EAAE,OAAO,MAAO,GAAE,EACjE,EAAE,MAAM,KAAM,EACf;AAED,MAAG,iBACD,SACA,CAAC,UAAU;AACT,SAAK,KAAK,eAAe;AACzB,SAAKD,aAAa;AAClB,QAAI,KAAK,QAAQ,kBAAkB,MAAM;AACvC,gBAAW,MAAM,KAAK,QAAQ,MAAM,YAAY,EAAE,IAAK;IACxD;GACF,GACD,EAAE,MAAM,KAAM,EACf;EACF;AAED,SAAO,KAAKC;CACb;CAED,MAAM,aAA4B;AAChC,MAAI,KAAKD,eAAe,KAAM;AAC9B,OAAKA,WAAY,OAAO;AACxB,SAAO,MAAM,KAAKA,YAAY,QAAQ;CACvC;CAED,MAAM,KACJE,aACAH,QACe;AACf,MAAI,KAAKE,YAAa,OAAM,KAAKA;AACjC,OAAKD,WAAY,KAAK,OAAO,aAAa,aAAa,QAAQ,EAAE,OAAO,CAAC;CAC1E;AACF;AAED,SAAS,MAAMG,QAAqBC,OAAe;AACjD,QAAO,IAAI,QAAc,CAAC,YAAY;AACpC,SAAO,iBAAiB,OAAO,MAAM,SAAS,EAAE,EAAE,MAAM,KAAM,EAAC;CAChE;AACF","names":["options: WebSocketClientTransportOptions","auth: string | undefined","contentType: BaseClientFormat['contentType']","buffer: ArrayBuffer","#webSocket","#connecting","messageType: ClientMessageType","target: EventTarget","event: string"],"sources":["src/index.ts"],"sourcesContent":["import {\n type BaseClientFormat,\n EventEmitter,\n type ProtocolTransport,\n type ProtocolTransportEventMap,\n} from '@nmtjs/protocol/client'\nimport {\n type ClientMessageType,\n concat,\n decodeNumber,\n encodeNumber,\n ServerMessageType,\n} from '@nmtjs/protocol/common'\n\nexport type WebSocketClientTransportOptions = {\n /**\n * The origin of the server\n * @example 'http://localhost:3000'\n */\n origin: string\n /**\n * Whether to autoreconnect on close\n * @default true\n */\n autoreconnect?: boolean\n /**\n * Custom WebSocket class\n * @default globalThis.WebSocket\n */\n wsFactory?: (url: URL) => WebSocket\n\n debug?: boolean\n}\n\nexport class WebSocketClientTransport\n extends EventEmitter<ProtocolTransportEventMap>\n implements ProtocolTransport\n{\n #webSocket: WebSocket | null = null\n #connecting: Promise<void> | null = null\n\n constructor(private readonly options: WebSocketClientTransportOptions) {\n super()\n }\n\n connect(\n auth: string | undefined = undefined,\n contentType: BaseClientFormat['contentType'],\n ): Promise<void> {\n const wsUrl = new URL(this.options.origin)\n wsUrl.protocol = wsUrl.protocol === 'https:' ? 'wss:' : 'ws:'\n wsUrl.pathname = '/api'\n wsUrl.searchParams.set('content-type', contentType)\n wsUrl.searchParams.set('accept', contentType)\n if (auth) wsUrl.searchParams.set('auth', auth)\n\n const ws =\n this.options.wsFactory?.(wsUrl) ?? new WebSocket(wsUrl.toString())\n\n ws.binaryType = 'arraybuffer'\n\n ws.addEventListener('message', ({ data }) => {\n const buffer: ArrayBuffer = data\n const type = decodeNumber(buffer, 'Uint8')\n if (type in ServerMessageType) {\n this.emit(`${type}`, buffer.slice(Uint8Array.BYTES_PER_ELEMENT))\n }\n })\n\n this.#webSocket = ws\n\n this.#connecting = new Promise((resolve, reject) => {\n ws.addEventListener(\n 'open',\n () => {\n this.emit('connected')\n resolve()\n },\n { once: true },\n )\n\n ws.addEventListener(\n 'error',\n (event) => reject(new Error('WebSocket error', { cause: event })),\n { once: true },\n )\n\n ws.addEventListener(\n 'close',\n (event) => {\n this.emit('disconnected')\n this.#webSocket = null\n if (this.options.autoreconnect === true) {\n setTimeout(() => this.connect(auth, contentType), 1000)\n }\n },\n { once: true },\n )\n })\n\n return this.#connecting\n }\n\n async disconnect(): Promise<void> {\n if (this.#webSocket === null) return\n this.#webSocket!.close()\n return _once(this.#webSocket, 'close')\n }\n\n async send(\n messageType: ClientMessageType,\n buffer: ArrayBuffer,\n ): Promise<void> {\n if (this.#connecting) await this.#connecting\n this.#webSocket!.send(concat(encodeNumber(messageType, 'Uint8'), buffer))\n }\n}\n\nfunction _once(target: EventTarget, event: string) {\n return new Promise<void>((resolve) => {\n target.addEventListener(event, () => resolve(), { once: true })\n })\n}\n"],"version":3}
1
+ {"mappings":"AAAA,SAAS,mBAAmB,QAAQ,oBAAoB,iBAAiB;AACzE,SAIE,yBACK,wBAAwB;AAsB/B,OAAO,MAAM,iCAAiC,kBAAkB;CAC9D,AAAU,YAA8B;CACxC,AAAU,aAAmC;CAE7C,YACqBA,UACAC,SACnB;AACA,SAAO;OAHY;OACA;CAGpB;CAED,QAAQC,MAAWC,aAAqD;EACtE,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAK,QAAQ;AAC3C,MAAI,KAAK,SAAS,aAAa;AAC7B,SAAM,aAAa,IAAI,gBAAgB,KAAK,SAAS,YAAY;AACjE,SAAM,aAAa,IAAI,UAAU,KAAK,SAAS,YAAY;EAC5D;AACD,MAAI,KAAM,OAAM,aAAa,IAAI,QAAQ,KAAK;EAE9C,MAAM,KACJ,KAAK,QAAQ,YAAY,MAAM,IAAI,IAAI,UAAU,MAAM,UAAU;AAEnE,KAAG,aAAa;AAEhB,KAAG,iBAAiB,WAAW,CAAC,EAAE,MAAM,KAAK;AAC3C,QAAK,SAAS,oBAAoB,MAAqB,MAAM,YAAY;EAC1E,EAAC;AAEF,OAAK,YAAY;AAEjB,OAAK,aAAa,IAAI,QAAQ,CAAC,SAAS,WAAW;AACjD,MAAG,iBACD,QACA,MAAM;AACJ,SAAK,SAAS,KAAK,YAAY;AAC/B,aAAS;GACV,GACD,EAAE,MAAM,KAAM,EACf;AAED,MAAG,iBACD,SACA,CAAC,UAAU;AACT,WAAO,IAAI,MAAM,mBAAmB,EAAE,OAAO,MAAO,GAAE;GACvD,GACD,EAAE,MAAM,KAAM,EACf;AAED,MAAG,iBACD,SACA,CAAC,UAAU;AACT,SAAK,SAAS,KAAK,eAAe;AAClC,SAAK,YAAY;AACjB,QAAI,KAAK,QAAQ,kBAAkB,MAAM;AACvC,gBAAW,KAAK,QAAQ,KAAK,KAAK,EAAE,IAAK;IAC1C;GACF,GACD,EAAE,MAAM,KAAM,EACf;EACF;AAED,SAAO,KAAK;CACb;CAED,MAAM,aAA4B;AAChC,MAAI,KAAK,cAAc,KAAM;AAC7B,OAAK,UAAW,OAAO;AACvB,SAAO,MAAM,KAAK,WAAW,QAAQ;CACtC;CAED,MAAM,KACJC,WACAC,WACAC,SACAC,SACAJ,aACA;EACA,MAAM,EAAE,MAAM,QAAQ,GAAG,KAAK,SAAS,UACrC,WACA,WACA,SACA,SACA,YACD;AACD,QAAM,KAAK,KAAK,kBAAkB,KAAK,OAAO;AAC9C,SAAO;CACR;CAED,MAAM,KACJK,aACAC,QACe;AACf,MAAI,KAAK,WAAY,OAAM,KAAK;AAChC,OAAK,UAAW,KAAK,OAAO,aAAa,aAAa,QAAQ,EAAE,OAAO,CAAC;CACzE;AACF;AAED,SAAS,MAAMC,QAAqBC,OAAe;AACjD,QAAO,IAAI,QAAc,CAAC,YAAY;AACpC,SAAO,iBAAiB,OAAO,MAAM,SAAS,EAAE,EAAE,MAAM,KAAM,EAAC;CAChE;AACF","names":["protocol: Protocol","options: WebSocketClientTransportOptions","auth: any","transformer: ProtocolBaseTransformer","namespace: string","procedure: string","payload: any","options: ProtocolBaseClientCallOptions","messageType: ClientMessageType","buffer: ArrayBuffer","target: EventTarget","event: string"],"sources":["../src/index.ts"],"sourcesContent":["import { ClientMessageType, concat, encodeNumber } from '@nmtjs/protocol'\nimport {\n type Protocol,\n type ProtocolBaseClientCallOptions,\n type ProtocolBaseTransformer,\n ProtocolTransport,\n} from '@nmtjs/protocol/client'\n\nexport type WebSocketClientTransportOptions = {\n /**\n * The origin of the server\n * @example 'http://localhost:3000'\n */\n origin: string\n /**\n * Whether to autoreconnect on close\n * @default true\n */\n autoreconnect?: boolean\n /**\n * Custom WebSocket class\n * @default globalThis.WebSocket\n */\n wsFactory?: (url: URL) => WebSocket\n\n debug?: boolean\n}\n\nexport class WebSocketClientTransport extends ProtocolTransport {\n protected webSocket: WebSocket | null = null\n protected connecting: Promise<void> | null = null\n\n constructor(\n protected readonly protocol: Protocol,\n protected readonly options: WebSocketClientTransportOptions,\n ) {\n super()\n }\n\n connect(auth: any, transformer: ProtocolBaseTransformer): Promise<void> {\n const wsUrl = new URL('/api', this.options.origin)\n if (this.protocol.contentType) {\n wsUrl.searchParams.set('content-type', this.protocol.contentType)\n wsUrl.searchParams.set('accept', this.protocol.contentType)\n }\n if (auth) wsUrl.searchParams.set('auth', auth)\n\n const ws =\n this.options.wsFactory?.(wsUrl) ?? new WebSocket(wsUrl.toString())\n\n ws.binaryType = 'arraybuffer'\n\n ws.addEventListener('message', ({ data }) => {\n this.protocol.handleServerMessage(data as ArrayBuffer, this, transformer)\n })\n\n this.webSocket = ws\n\n this.connecting = new Promise((resolve, reject) => {\n ws.addEventListener(\n 'open',\n () => {\n this.protocol.emit('connected')\n resolve()\n },\n { once: true },\n )\n\n ws.addEventListener(\n 'error',\n (event) => {\n reject(new Error('WebSocket error', { cause: event }))\n },\n { once: true },\n )\n\n ws.addEventListener(\n 'close',\n (event) => {\n this.protocol.emit('disconnected')\n this.webSocket = null\n if (this.options.autoreconnect === true) {\n setTimeout(this.connect.bind(this), 1000)\n }\n },\n { once: true },\n )\n })\n\n return this.connecting\n }\n\n async disconnect(): Promise<void> {\n if (this.webSocket === null) return\n this.webSocket!.close()\n return _once(this.webSocket, 'close')\n }\n\n async call(\n namespace: string,\n procedure: string,\n payload: any,\n options: ProtocolBaseClientCallOptions,\n transformer: ProtocolBaseTransformer,\n ) {\n const { call, buffer } = this.protocol.createRpc(\n namespace,\n procedure,\n payload,\n options,\n transformer,\n )\n await this.send(ClientMessageType.Rpc, buffer)\n return call\n }\n\n async send(\n messageType: ClientMessageType,\n buffer: ArrayBuffer,\n ): Promise<void> {\n if (this.connecting) await this.connecting\n this.webSocket!.send(concat(encodeNumber(messageType, 'Uint8'), buffer))\n }\n}\n\nfunction _once(target: EventTarget, event: string) {\n return new Promise<void>((resolve) => {\n target.addEventListener(event, () => resolve(), { once: true })\n })\n}\n"],"version":3,"file":"index.js"}
package/package.json CHANGED
@@ -8,14 +8,14 @@
8
8
  }
9
9
  },
10
10
  "dependencies": {
11
- "@nmtjs/client": "0.8.1",
12
- "@nmtjs/protocol": "0.8.1",
13
- "@nmtjs/common": "0.8.1"
11
+ "@nmtjs/client": "0.10.0",
12
+ "@nmtjs/protocol": "0.10.0",
13
+ "@nmtjs/common": "0.10.0"
14
14
  },
15
15
  "peerDependencies": {
16
- "@nmtjs/client": "0.8.1",
17
- "@nmtjs/common": "0.8.1",
18
- "@nmtjs/protocol": "0.8.1"
16
+ "@nmtjs/client": "0.10.0",
17
+ "@nmtjs/common": "0.10.0",
18
+ "@nmtjs/protocol": "0.10.0"
19
19
  },
20
20
  "files": [
21
21
  "src",
@@ -23,7 +23,7 @@
23
23
  "LICENSE.md",
24
24
  "README.md"
25
25
  ],
26
- "version": "0.8.1",
26
+ "version": "0.10.0",
27
27
  "scripts": {
28
28
  "build": "neemata-build --root=./src './*.ts'",
29
29
  "type-check": "tsc --noEmit"
package/src/index.ts CHANGED
@@ -1,16 +1,10 @@
1
+ import { ClientMessageType, concat, encodeNumber } from '@nmtjs/protocol'
1
2
  import {
2
- type BaseClientFormat,
3
- EventEmitter,
4
- type ProtocolTransport,
5
- type ProtocolTransportEventMap,
3
+ type Protocol,
4
+ type ProtocolBaseClientCallOptions,
5
+ type ProtocolBaseTransformer,
6
+ ProtocolTransport,
6
7
  } from '@nmtjs/protocol/client'
7
- import {
8
- type ClientMessageType,
9
- concat,
10
- decodeNumber,
11
- encodeNumber,
12
- ServerMessageType,
13
- } from '@nmtjs/protocol/common'
14
8
 
15
9
  export type WebSocketClientTransportOptions = {
16
10
  /**
@@ -32,26 +26,23 @@ export type WebSocketClientTransportOptions = {
32
26
  debug?: boolean
33
27
  }
34
28
 
35
- export class WebSocketClientTransport
36
- extends EventEmitter<ProtocolTransportEventMap>
37
- implements ProtocolTransport
38
- {
39
- #webSocket: WebSocket | null = null
40
- #connecting: Promise<void> | null = null
29
+ export class WebSocketClientTransport extends ProtocolTransport {
30
+ protected webSocket: WebSocket | null = null
31
+ protected connecting: Promise<void> | null = null
41
32
 
42
- constructor(private readonly options: WebSocketClientTransportOptions) {
33
+ constructor(
34
+ protected readonly protocol: Protocol,
35
+ protected readonly options: WebSocketClientTransportOptions,
36
+ ) {
43
37
  super()
44
38
  }
45
39
 
46
- connect(
47
- auth: string | undefined = undefined,
48
- contentType: BaseClientFormat['contentType'],
49
- ): Promise<void> {
50
- const wsUrl = new URL(this.options.origin)
51
- wsUrl.protocol = wsUrl.protocol === 'https:' ? 'wss:' : 'ws:'
52
- wsUrl.pathname = '/api'
53
- wsUrl.searchParams.set('content-type', contentType)
54
- wsUrl.searchParams.set('accept', contentType)
40
+ connect(auth: any, transformer: ProtocolBaseTransformer): Promise<void> {
41
+ const wsUrl = new URL('/api', this.options.origin)
42
+ if (this.protocol.contentType) {
43
+ wsUrl.searchParams.set('content-type', this.protocol.contentType)
44
+ wsUrl.searchParams.set('accept', this.protocol.contentType)
45
+ }
55
46
  if (auth) wsUrl.searchParams.set('auth', auth)
56
47
 
57
48
  const ws =
@@ -60,20 +51,16 @@ export class WebSocketClientTransport
60
51
  ws.binaryType = 'arraybuffer'
61
52
 
62
53
  ws.addEventListener('message', ({ data }) => {
63
- const buffer: ArrayBuffer = data
64
- const type = decodeNumber(buffer, 'Uint8')
65
- if (type in ServerMessageType) {
66
- this.emit(`${type}`, buffer.slice(Uint8Array.BYTES_PER_ELEMENT))
67
- }
54
+ this.protocol.handleServerMessage(data as ArrayBuffer, this, transformer)
68
55
  })
69
56
 
70
- this.#webSocket = ws
57
+ this.webSocket = ws
71
58
 
72
- this.#connecting = new Promise((resolve, reject) => {
59
+ this.connecting = new Promise((resolve, reject) => {
73
60
  ws.addEventListener(
74
61
  'open',
75
62
  () => {
76
- this.emit('connected')
63
+ this.protocol.emit('connected')
77
64
  resolve()
78
65
  },
79
66
  { once: true },
@@ -81,38 +68,58 @@ export class WebSocketClientTransport
81
68
 
82
69
  ws.addEventListener(
83
70
  'error',
84
- (event) => reject(new Error('WebSocket error', { cause: event })),
71
+ (event) => {
72
+ reject(new Error('WebSocket error', { cause: event }))
73
+ },
85
74
  { once: true },
86
75
  )
87
76
 
88
77
  ws.addEventListener(
89
78
  'close',
90
79
  (event) => {
91
- this.emit('disconnected')
92
- this.#webSocket = null
80
+ this.protocol.emit('disconnected')
81
+ this.webSocket = null
93
82
  if (this.options.autoreconnect === true) {
94
- setTimeout(() => this.connect(auth, contentType), 1000)
83
+ setTimeout(this.connect.bind(this), 1000)
95
84
  }
96
85
  },
97
86
  { once: true },
98
87
  )
99
88
  })
100
89
 
101
- return this.#connecting
90
+ return this.connecting
102
91
  }
103
92
 
104
93
  async disconnect(): Promise<void> {
105
- if (this.#webSocket === null) return
106
- this.#webSocket!.close()
107
- return _once(this.#webSocket, 'close')
94
+ if (this.webSocket === null) return
95
+ this.webSocket!.close()
96
+ return _once(this.webSocket, 'close')
97
+ }
98
+
99
+ async call(
100
+ namespace: string,
101
+ procedure: string,
102
+ payload: any,
103
+ options: ProtocolBaseClientCallOptions,
104
+ transformer: ProtocolBaseTransformer,
105
+ ) {
106
+ const { call, buffer } = this.protocol.createRpc(
107
+ namespace,
108
+ procedure,
109
+ payload,
110
+ options,
111
+ transformer,
112
+ )
113
+ await this.send(ClientMessageType.Rpc, buffer)
114
+ return call
108
115
  }
109
116
 
110
117
  async send(
111
118
  messageType: ClientMessageType,
112
119
  buffer: ArrayBuffer,
113
120
  ): Promise<void> {
114
- if (this.#connecting) await this.#connecting
115
- this.#webSocket!.send(concat(encodeNumber(messageType, 'Uint8'), buffer))
121
+ if (this.connecting) await this.connecting
122
+ this.webSocket!.send(concat(encodeNumber(messageType, 'Uint8'), buffer))
116
123
  }
117
124
  }
118
125