@seriousme/opifex 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/client/client.ts +5 -0
  2. package/connNext/baseConnNext.ts +123 -0
  3. package/deno/tlsServer.test.ts +1 -1
  4. package/deno/wsServer.ts +11 -3
  5. package/dev_utils/WebStreamEndpoint.ts +5 -0
  6. package/dev_utils/asyncStreamEndpoint.ts +5 -0
  7. package/dev_utils/asyncStreamPair.ts +4 -9
  8. package/dev_utils/asyncStreamPairToNext.ts +45 -0
  9. package/dev_utils/asyncStreamToNext.ts +30 -137
  10. package/dev_utils/connNextPair.test.ts +2 -2
  11. package/dev_utils/generateCert.ts +297 -77
  12. package/dev_utils/mockConn.ts +37 -93
  13. package/dev_utils/mockServer.ts +1 -1
  14. package/dev_utils/webStreamPair.ts +3 -7
  15. package/dev_utils/webStreamPairToNext.ts +48 -0
  16. package/dev_utils/webStreamToNext.ts +28 -161
  17. package/dist/client/client.d.ts +4 -0
  18. package/dist/client/client.d.ts.map +1 -1
  19. package/dist/client/client.js +3 -0
  20. package/dist/client/client.js.map +1 -1
  21. package/dist/connNext/baseConnNext.d.ts +20 -0
  22. package/dist/connNext/baseConnNext.d.ts.map +1 -0
  23. package/dist/connNext/baseConnNext.js +95 -0
  24. package/dist/connNext/baseConnNext.js.map +1 -0
  25. package/dist/dev_utils/generateCert.d.ts +5 -4
  26. package/dist/dev_utils/generateCert.d.ts.map +1 -1
  27. package/dist/dev_utils/generateCert.js +230 -65
  28. package/dist/dev_utils/generateCert.js.map +1 -1
  29. package/dist/examples/mqtt+mqtts.test.js +1 -1
  30. package/dist/examples/mqtt+mqtts.test.js.map +1 -1
  31. package/dist/examples/mqtts.test.js +1 -1
  32. package/dist/examples/mqtts.test.js.map +1 -1
  33. package/dist/node/nodeSocketToNext.d.ts +10 -13
  34. package/dist/node/nodeSocketToNext.d.ts.map +1 -1
  35. package/dist/node/nodeSocketToNext.js +75 -131
  36. package/dist/node/nodeSocketToNext.js.map +1 -1
  37. package/dist/web/webSocketToNext.d.ts +18 -1
  38. package/dist/web/webSocketToNext.d.ts.map +1 -1
  39. package/dist/web/webSocketToNext.js +92 -127
  40. package/dist/web/webSocketToNext.js.map +1 -1
  41. package/dist/web/wsClient.d.ts.map +1 -1
  42. package/dist/web/wsClient.js +4 -3
  43. package/dist/web/wsClient.js.map +1 -1
  44. package/examples/mqtt+mqtts.test.ts +1 -1
  45. package/examples/mqtts.test.ts +1 -1
  46. package/node/nodeSocketToNext.ts +85 -148
  47. package/node/tlsServer.test.ts +1 -1
  48. package/package.json +2 -4
  49. package/web/webSocketToNext.ts +108 -145
  50. package/web/wsClient.ts +10 -3
  51. package/dev_utils/webStreamPair.test.ts +0 -171
@@ -13,7 +13,7 @@ test("Test pubSub using TLS client and server and sqlitePersistence", async func
13
13
  // the localhost certs generate here are great for testing but lack securiity
14
14
  // use something like LetsEncrypt for any serious server
15
15
  // generateLocalhostCerts is a dev tool and relies on node-forge as a (dev)dependency
16
- const { key, cert, caCert } = generateLocalhostCerts();
16
+ const { key, cert, caCert } = await generateLocalhostCerts();
17
17
  const dbFile = ":memory:";
18
18
  // .start() combines instance creation and async initialization
19
19
  const persistence = await SqlitePersistence.start(dbFile);
@@ -1,187 +1,124 @@
1
1
  import type { Socket } from "node:net";
2
- import type { ConnAddr, ConnNext } from "../connNext/connNext.ts"; // Custom types
3
-
4
- /** wrapper class */
5
- export class NodeSocketConnNextWrapper {
6
- private endPoint: Socket;
7
- private closed: boolean;
8
- private leftover: Uint8Array = new Uint8Array(0);
9
-
10
- // Store bound event listeners so we can cleanly remove them later
11
- private onClose = () => {
12
- this.closed = true;
13
- };
14
- private onError = () => {
15
- this.closed = true;
16
- };
17
-
18
- /** Create a new ConnNext object from a Webstream */
19
- constructor(endPoint: Socket) {
20
- this.endPoint = endPoint;
21
- this.closed = false;
22
- this.endPoint;
23
- }
24
-
25
- async read(length?: number): Promise<Uint8Array | null> {
26
- if (this.closed || (length ?? 0) < 0) {
27
- return null;
28
- }
2
+ import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
3
+ import { BaseConnNext } from "../connNext/baseConnNext.ts";
29
4
 
30
- // If no specific byte length is requested, read whatever is available
31
- if (length === undefined) {
32
- const chunk = this.endPoint.read();
33
- return chunk
34
- ? Promise.resolve(
35
- new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength),
36
- )
37
- : Promise.resolve(null);
38
- }
5
+ export class NodeSocketConnNext extends BaseConnNext {
6
+ private socket: Socket;
39
7
 
40
- if (length === 0) {
41
- return new Uint8Array(0);
42
- }
8
+ constructor(socket: Socket) {
9
+ super();
10
+ this.socket = socket;
43
11
 
44
- const result = new Uint8Array(length);
45
- let bytesAccumulated = 0;
12
+ const markClosed = () => {
13
+ this.closed = true;
14
+ };
46
15
 
47
- // 1. Process leftover data from the previous read operation
48
- if (this.leftover.byteLength > 0) {
49
- const take = Math.min(this.leftover.byteLength, length);
50
- result.set(this.leftover.subarray(0, take), bytesAccumulated);
51
- bytesAccumulated += take;
52
- this.leftover = this.leftover.subarray(take);
53
- }
16
+ this.socket.on("end", markClosed);
17
+ this.socket.on("close", markClosed);
18
+ this.socket.on("error", markClosed);
19
+ }
54
20
 
55
- // 2. Loop until the requested number of bytes is accumulated
56
- while (bytesAccumulated < length) {
57
- if (this.closed || !this.endPoint.readable) {
58
- break;
21
+ get localAddr(): ConnAddr | undefined {
22
+ return this.socket.localAddress
23
+ ? {
24
+ transport: "tcp",
25
+ hostname: this.socket.localAddress,
26
+ port: this.socket.localPort ?? 0,
59
27
  }
28
+ : undefined;
29
+ }
60
30
 
61
- const chunk = this.endPoint.read();
62
- if (chunk === null) {
63
- await new Promise<void>((resolve) => {
64
- const cleanup = () => {
65
- this.endPoint.off("readable", onEvent);
66
- this.endPoint.off("end", onEvent);
67
- this.endPoint.off("error", onEvent);
68
- this.endPoint.off("close", onEvent);
69
- };
70
- const onEvent = () => {
71
- cleanup();
72
- resolve();
73
- };
74
-
75
- this.endPoint.on("readable", onEvent);
76
- this.endPoint.on("end", onEvent);
77
- this.endPoint.on("error", onEvent);
78
- this.endPoint.on("close", onEvent);
79
- });
80
-
81
- continue;
31
+ get remoteAddr(): ConnAddr | undefined {
32
+ return this.socket.remoteAddress
33
+ ? {
34
+ transport: "tcp",
35
+ hostname: this.socket.remoteAddress,
36
+ port: this.socket.remotePort ?? 0,
82
37
  }
38
+ : undefined;
39
+ }
83
40
 
84
- // 3. Process the retrieved chunk
85
- const chunkLength = chunk.byteLength;
86
- const needed = length - bytesAccumulated;
87
-
88
- if (chunkLength <= needed) {
89
- result.set(chunk, bytesAccumulated);
90
- bytesAccumulated += chunkLength;
91
- } else {
92
- result.set(chunk.subarray(0, needed), bytesAccumulated);
93
- bytesAccumulated += needed;
94
- this.leftover = chunk.subarray(needed);
95
- }
41
+ /**
42
+ * Haalt direct op verzoek een chunk op via Node's ingebouwde socket.read() mechanisme.
43
+ */
44
+ protected pullNextChunk(): Promise<Uint8Array | null> {
45
+ if (this.closed || !this.socket.readable) {
46
+ return Promise.resolve(null);
96
47
  }
97
48
 
98
- if (bytesAccumulated < length) {
99
- return null;
49
+ // Vraag direct om data uit de Node socket buffer
50
+ const chunk = this.socket.read();
51
+
52
+ if (chunk !== null) {
53
+ return Promise.resolve(
54
+ new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength),
55
+ );
100
56
  }
101
57
 
102
- return result;
58
+ // Als er nog geen data is ('null'), wachten we op het 'readable' (of 'end'/'close') event van Node
59
+ return new Promise<Uint8Array | null>((resolve) => {
60
+ const cleanup = () => {
61
+ this.socket.off("readable", onReadable);
62
+ this.socket.off("end", onEnd);
63
+ this.socket.off("error", onClose);
64
+ this.socket.off("close", onClose);
65
+ };
66
+
67
+ const onReadable = () => {
68
+ cleanup();
69
+ // Roep zichzelf direct weer aan om de data op te halen
70
+ resolve(this.pullNextChunk());
71
+ };
72
+
73
+ const onEnd = () => {
74
+ cleanup();
75
+ this.closed = true;
76
+ resolve(null);
77
+ };
78
+
79
+ const onClose = () => {
80
+ cleanup();
81
+ this.closed = true;
82
+ resolve(null);
83
+ };
84
+
85
+ this.socket.on("readable", onReadable);
86
+ this.socket.on("end", onEnd);
87
+ this.socket.on("error", onClose);
88
+ this.socket.on("close", onClose);
89
+ });
103
90
  }
104
91
 
105
92
  write(data: Uint8Array): Promise<void> {
106
- if (this.closed || !this.endPoint.writable) {
107
- return Promise.reject(new Error("Stream is closed or not writable"));
93
+ if (this.isClosed() || !this.socket.writable) {
94
+ return Promise.reject(new Error("Socket is closed or not writable"));
108
95
  }
109
96
 
110
97
  return new Promise((resolve, reject) => {
111
- // 1. Fire the write command and catch any immediate/async errors via the callback
112
- const canWriteMore = this.endPoint.write(data, (err) => {
113
- if (err) {
114
- reject(err);
115
- }
98
+ const canWriteMore = this.socket.write(data, (err) => {
99
+ if (err) reject(err);
116
100
  });
117
101
 
118
- // 2. Determine when to resolve based on the return value of write()
119
102
  if (canWriteMore) {
120
- // If the buffer is not full, we can resolve immediately
121
103
  resolve();
122
104
  } else {
123
- // If backpressure is triggered, we must wait for the 'drain' event
124
- this.endPoint.once("drain", () => {
125
- resolve();
126
- });
105
+ this.socket.once("drain", resolve);
127
106
  }
128
107
  });
129
108
  }
130
109
 
131
- close() {
110
+ close(): void {
132
111
  if (!this.closed) {
133
112
  this.closed = true;
134
-
135
- // Clean up permanent event listeners to prevent memory leaks
136
- this.endPoint.off("close", this.onClose);
137
- this.endPoint.off("error", this.onError);
138
-
139
- // Safely destroy the stream first, then trigger the closer callback
140
113
  try {
141
- this.endPoint.destroy();
142
- // deno-coverage-ignore
143
- } catch (_) {
144
- // Suppress stream destruction errors
145
- // deno-coverage-ignore
114
+ this.socket.destroy();
115
+ } catch {
116
+ /* swallow */
146
117
  }
147
118
  }
148
119
  }
149
-
150
- async *[Symbol.asyncIterator]() {
151
- while (true) {
152
- const chunk = await this.read();
153
- if (chunk === null) {
154
- break;
155
- }
156
- yield chunk;
157
- }
158
- }
159
-
160
- // Convert addresses to custom ConnAddr format
161
- get localAddr(): ConnAddr | undefined {
162
- if (this.endPoint.localAddress) {
163
- return {
164
- transport: "tcp",
165
- hostname: this.endPoint.localAddress,
166
- port: this.endPoint.localPort ?? 0,
167
- };
168
- }
169
- return undefined;
170
- }
171
-
172
- get remoteAddr(): ConnAddr | undefined {
173
- if (this.endPoint.remoteAddress) {
174
- return {
175
- transport: "tcp",
176
- hostname: this.endPoint.remoteAddress,
177
- port: this.endPoint.remotePort ?? 0,
178
- };
179
- }
180
- return undefined;
181
- }
182
120
  }
183
121
 
184
122
  export function nodeSocketToNext(socket: Socket): ConnNext {
185
- const connNext = new NodeSocketConnNextWrapper(socket);
186
- return connNext;
123
+ return new NodeSocketConnNext(socket);
187
124
  }
@@ -9,7 +9,7 @@ import { MqttServer } from "../server/mod.ts";
9
9
 
10
10
  logger.level(LogLevel.info);
11
11
 
12
- const { key, cert, caCert } = generateLocalhostCerts();
12
+ const { key, cert, caCert } = await generateLocalhostCerts();
13
13
 
14
14
  test("Test pubSub using client and server", async () => {
15
15
  const server = new TlsServer({ port: 0, key, cert }, {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seriousme/opifex",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "MQTT client & server for Deno & NodeJS and Bun",
5
5
  "author": "Hans Klunder",
6
6
  "license": "MIT",
@@ -100,8 +100,6 @@
100
100
  }
101
101
  },
102
102
  "devDependencies": {
103
- "@types/node": "^26.6.2",
104
- "@types/node-forge": "^1.3.14",
105
- "node-forge": "^1.4.0"
103
+ "@types/node": "^26.6.5"
106
104
  }
107
105
  }
@@ -1,28 +1,77 @@
1
1
  import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
2
+ import { BaseConnNext } from "../connNext/baseConnNext.ts";
3
+ import { delay } from "../utils/utils.ts";
4
+
5
+ export class WebSocketConnNext extends BaseConnNext {
6
+ localAddr = undefined;
7
+ remoteAddr?: ConnAddr;
8
+
9
+ private ws: WebSocket;
10
+ private messageQueue: Uint8Array[] = [];
11
+ private maxBufferSize: number;
12
+ private currentBufferSize = 0;
13
+ private readResolvers: Array<() => void> = [];
14
+
15
+ constructor(
16
+ ws: WebSocket,
17
+ remoteAddr?: ConnAddr,
18
+ maxBufferSize = 1 * 1024 * 1024,
19
+ ) {
20
+ super();
21
+ this.ws = ws;
22
+ this.remoteAddr = remoteAddr;
23
+ this.maxBufferSize = maxBufferSize;
24
+ this.ws.binaryType = "arraybuffer";
25
+
26
+ this.ws.addEventListener("message", (event: MessageEvent) => {
27
+ let chunk: Uint8Array;
28
+ if (typeof event.data === "string") {
29
+ chunk = new TextEncoder().encode(event.data);
30
+ } else if (event.data instanceof ArrayBuffer) {
31
+ chunk = new Uint8Array(event.data);
32
+ } else {
33
+ return;
34
+ }
2
35
 
3
- export async function webSocketToNext(
4
- ws: WebSocket,
5
- remoteAddr?: ConnAddr,
6
- ): Promise<ConnNext> {
7
- ws.binaryType = "arraybuffer";
36
+ // Check the bufferlimit (Throttling / Overflow protection)
37
+ if (this.currentBufferSize + chunk.byteLength > this.maxBufferSize) {
38
+ this.close();
39
+ throw new Error(
40
+ "WebSocket buffer overflow: Too much unread data from push source",
41
+ );
42
+ }
8
43
 
9
- const messageQueue: Uint8Array[] = [];
10
- let queueOffset = 0;
11
- const readResolvers: Array<() => void> = [];
44
+ this.messageQueue.push(chunk);
45
+ this.currentBufferSize += chunk.byteLength;
46
+ this.notifyWaiters();
47
+ });
12
48
 
13
- const notifyWaiters = () => {
14
- while (readResolvers.length > 0) {
15
- const resolve = readResolvers.shift();
49
+ const onClose = () => {
50
+ this.closed = true;
51
+ this.notifyWaiters();
52
+ };
53
+ this.ws.addEventListener("close", onClose);
54
+ this.ws.addEventListener("error", onClose);
55
+ }
56
+
57
+ private notifyWaiters() {
58
+ while (this.readResolvers.length > 0) {
59
+ const resolve = this.readResolvers.shift();
16
60
  resolve?.();
17
61
  }
18
- };
62
+ }
63
+
64
+ private waitForData(): Promise<void> {
65
+ return new Promise<void>((resolve) => {
66
+ this.readResolvers.push(resolve);
67
+ });
68
+ }
19
69
 
20
- // helper to check if websocket is Open
21
- const ensureOpen = (): Promise<void> => {
22
- if (ws.readyState === WebSocket.OPEN) {
70
+ ensureOpen(): Promise<void> {
71
+ if (this.ws.readyState === WebSocket.OPEN) {
23
72
  return Promise.resolve();
24
73
  }
25
- if (ws.readyState >= WebSocket.CLOSING) {
74
+ if (this.ws.readyState >= WebSocket.CLOSING) {
26
75
  return Promise.reject(new Error("WebSocket is closing or closed"));
27
76
  }
28
77
  return new Promise((resolve, reject) => {
@@ -39,145 +88,59 @@ export async function webSocketToNext(
39
88
  reject(new Error("WebSocket closed before opening"));
40
89
  };
41
90
  const cleanup = () => {
42
- ws.removeEventListener("open", onOpen);
43
- ws.removeEventListener("error", onError);
44
- ws.removeEventListener("close", onClose);
91
+ this.ws.removeEventListener("open", onOpen);
92
+ this.ws.removeEventListener("error", onError);
93
+ this.ws.removeEventListener("close", onClose);
45
94
  };
46
95
 
47
- ws.addEventListener("open", onOpen);
48
- ws.addEventListener("error", onError);
49
- ws.addEventListener("close", onClose);
96
+ this.ws.addEventListener("open", onOpen);
97
+ this.ws.addEventListener("error", onError);
98
+ this.ws.addEventListener("close", onClose);
50
99
  });
51
- };
52
-
53
- ws.addEventListener("message", (event: MessageEvent) => {
54
- let chunk: Uint8Array;
55
- if (typeof event.data === "string") {
56
- chunk = new TextEncoder().encode(event.data);
57
- } else if (event.data instanceof ArrayBuffer) {
58
- chunk = new Uint8Array(event.data);
59
- } else {
60
- return;
100
+ }
101
+
102
+ protected async pullNextChunk(): Promise<Uint8Array | null> {
103
+ if (this.messageQueue.length === 0) {
104
+ await this.waitForData();
61
105
  }
62
- messageQueue.push(chunk);
63
- notifyWaiters();
64
- });
65
-
66
- ws.addEventListener("close", notifyWaiters);
67
- ws.addEventListener("error", notifyWaiters);
68
-
69
- const getBufferedBytes = (): number => {
70
- let total = 0;
71
- for (let i = 0; i < messageQueue.length; i++) {
72
- total += i === 0
73
- ? messageQueue[i]!.byteLength - queueOffset
74
- : messageQueue[i]!.byteLength;
106
+ if (this.closed) {
107
+ return null;
75
108
  }
76
- return total;
77
- };
78
-
79
- const waitForData = (): Promise<void> => {
80
- return new Promise<void>((resolve) => {
81
- readResolvers.push(resolve);
82
- });
83
- };
84
-
85
- const connNext = {
86
- remoteAddr,
87
- localAddr: undefined,
88
-
89
- async read(length?: number): Promise<Uint8Array | null> {
90
- try {
91
- await ensureOpen();
92
- } catch {
93
- return null;
94
- }
95
-
96
- if (getBufferedBytes() === 0 && ws.readyState >= WebSocket.CLOSING) {
97
- return null;
98
- }
99
-
100
- while (getBufferedBytes() === 0) {
101
- if (ws.readyState >= WebSocket.CLOSING) return null;
102
- await waitForData();
103
- }
104
-
105
- if (length === undefined) {
106
- const firstChunk = messageQueue.shift()!;
107
- const result = firstChunk.subarray(queueOffset);
108
- queueOffset = 0;
109
- return result;
110
- }
111
-
112
- while (getBufferedBytes() < length) {
113
- if (ws.readyState >= WebSocket.CLOSING) {
114
- return null;
115
- }
116
- await waitForData();
117
- }
118
-
119
- const result = new Uint8Array(length);
120
- let bytesCopied = 0;
121
-
122
- while (bytesCopied < length && messageQueue.length > 0) {
123
- const currentChunk = messageQueue[0]!;
124
- const bytesNeeded = length - bytesCopied;
125
- const bytesAvailable = currentChunk.byteLength - queueOffset;
126
-
127
- if (bytesAvailable <= bytesNeeded) {
128
- result.set(currentChunk.subarray(queueOffset), bytesCopied);
129
- bytesCopied += bytesAvailable;
130
- messageQueue.shift();
131
- queueOffset = 0;
132
- } else {
133
- result.set(
134
- currentChunk.subarray(queueOffset, queueOffset + bytesNeeded),
135
- bytesCopied,
136
- );
137
- bytesCopied += bytesNeeded;
138
- queueOffset += bytesNeeded;
139
- }
140
- }
141
-
142
- return result;
143
- },
144
-
145
- async write(data: Uint8Array): Promise<void> {
146
- await ensureOpen();
147
-
148
- if (data instanceof Uint8Array) {
149
- ws.send(data.buffer as ArrayBuffer);
150
- } else {
151
- ws.send(data);
152
- }
153
-
154
- const HIGH_WATER_MARK = 64 * 1024;
155
- while (ws.bufferedAmount > HIGH_WATER_MARK) {
156
- if (ws.readyState >= WebSocket.CLOSING) {
157
- throw new Error("WebSocket closed while writing");
158
- }
159
- await new Promise((resolve) => setTimeout(resolve, 10));
160
- }
161
- },
109
+ const chunk = this.messageQueue.shift()!;
110
+ this.currentBufferSize -= chunk.byteLength;
111
+ return chunk;
112
+ }
113
+
114
+ async write(data: Uint8Array): Promise<void> {
115
+ if (this.isClosed()) throw new Error("WebSocket is closed");
116
+ this.ws.send(data.buffer as ArrayBuffer);
117
+
118
+ // Check WebSocket bufferedAmount for write-backpressure
119
+ const HIGH_WATER_MARK = 64 * 1024;
120
+ while (this.ws.bufferedAmount > HIGH_WATER_MARK) {
121
+ if (this.isClosed()) throw new Error("WebSocket closed while writing");
122
+ await delay(10);
123
+ }
124
+ }
162
125
 
163
- close(): void {
126
+ close(): void {
127
+ if (!this.closed) {
128
+ this.closed = true;
164
129
  try {
165
- ws.close();
130
+ this.ws.close();
166
131
  } catch {
167
132
  /* swallow */
168
133
  }
169
- notifyWaiters();
170
- },
171
-
172
- async *[Symbol.asyncIterator]() {
173
- while (true) {
174
- const chunk = await this.read();
175
- if (chunk === null) break;
176
- yield chunk;
177
- }
178
- },
179
- };
134
+ }
135
+ }
136
+ }
180
137
 
181
- await ensureOpen();
138
+ export async function webSocketToNext(
139
+ ws: WebSocket,
140
+ remoteAddr?: ConnAddr,
141
+ maxBufferSize?: number,
142
+ ): Promise<ConnNext> {
143
+ const connNext = new WebSocketConnNext(ws, remoteAddr, maxBufferSize);
144
+ await connNext.ensureOpen();
182
145
  return connNext;
183
146
  }
package/web/wsClient.ts CHANGED
@@ -16,7 +16,10 @@ import { webSocketToNext } from "./webSocketToNext.ts";
16
16
  */
17
17
  export class WsClient extends Client {
18
18
  /** create a websocket and wrap it in a ConnNext */
19
- private async establishSocket(url: string): Promise<ConnNext> {
19
+ private async establishSocket(
20
+ url: string,
21
+ maxBufferSize?: number,
22
+ ): Promise<ConnNext> {
20
23
  try {
21
24
  const urlObj = new URL(url);
22
25
  const remoteAddr: NetAddr = {
@@ -25,7 +28,7 @@ export class WsClient extends Client {
25
28
  port: Number(urlObj.port || 0),
26
29
  };
27
30
  const ws = new WebSocket(url);
28
- const connNext = await webSocketToNext(ws, remoteAddr);
31
+ const connNext = await webSocketToNext(ws, remoteAddr, maxBufferSize);
29
32
  return connNext;
30
33
  } catch (error) {
31
34
  const message = error instanceof ErrorEvent
@@ -40,10 +43,14 @@ export class WsClient extends Client {
40
43
  const { protocol, hostname, port: portStr, pathname } = this.connectUrl;
41
44
  const port = portStr ? Number(portStr) : (protocol === "wss:" ? 443 : 80);
42
45
  const path = pathname || "/mqtt";
46
+ const maxBufferSize = this.maxBufferSize;
43
47
 
44
48
  logger.debug({ hostname, port, path });
45
49
  if (protocol === "ws:" || protocol === "wss:") {
46
- return this.establishSocket(`${protocol}//${hostname}:${port}${path}`);
50
+ return this.establishSocket(
51
+ `${protocol}//${hostname}:${port}${path}`,
52
+ maxBufferSize,
53
+ );
47
54
  }
48
55
  throw new Error(`Unsupported protocol: ${protocol}`);
49
56
  }