bare-ws 2.0.2 → 2.0.4

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/lib/errors.d.ts CHANGED
@@ -1,28 +1,23 @@
1
1
  declare class WebSocketError extends Error {
2
- constructor(
3
- msg: string,
4
- code: string,
5
- status: number,
6
- fn?: WebSocketError,
7
- cause?: unknown
8
- )
2
+ constructor(msg: string, code: string, status: number, fn?: WebSocketError, cause?: unknown)
9
3
 
10
4
  static NETWORK_ERROR(msg: string, cause?: unknown): WebSocketError
11
- static NOT_CONNECTED(msg?: string, cause?: unknown): WebSocketError
12
- static UNEXPECTED_RSV1(msg?: string, cause?: unknown): WebSocketError
13
- static UNEXPECTED_RSV2(msg?: string, cause?: unknown): WebSocketError
14
- static UNEXPECTED_RSV3(msg?: string, cause?: unknown): WebSocketError
15
- static EXPECTED_MASK(msg?: string, cause?: unknown): WebSocketError
16
- static EXPECTED_CONTINUATION(msg?: string, cause?: unknown): WebSocketError
17
- static UNEXPECTED_CONTINUATION(msg?: string, cause?: unknown): WebSocketError
18
- static UNEXPECTED_CONTROL(msg?: string, cause?: unknown): WebSocketError
19
- static INVALID_ENCODING(msg?: string, cause?: unknown): WebSocketError
20
- static INVALID_UPGRADE_HEADER(msg?: string, cause?: unknown): WebSocketError
21
- static INVALID_VERSION_HEADER(msg?: string, cause?: unknown): WebSocketError
22
- static INVALID_KEY_HEADER(msg?: string, cause?: unknown): WebSocketError
23
- static INVALID_ACCEPT_HEADER(msg?: string, cause?: unknown): WebSocketError
24
- static INVALID_OPCODE(msg?: string, cause?: unknown): WebSocketError
25
- static INVALID_PAYLOAD_LENGTH(msg?: string, cause?: unknown): WebSocketError
5
+ static NOT_CONNECTED(msg?: string): WebSocketError
6
+ static UNEXPECTED_RSV1(msg?: string): WebSocketError
7
+ static UNEXPECTED_RSV2(msg?: string): WebSocketError
8
+ static UNEXPECTED_RSV3(msg?: string): WebSocketError
9
+ static EXPECTED_MASK(msg?: string): WebSocketError
10
+ static EXPECTED_CONTINUATION(msg?: string): WebSocketError
11
+ static UNEXPECTED_CONTINUATION(msg?: string): WebSocketError
12
+ static UNEXPECTED_CONTROL(msg?: string): WebSocketError
13
+ static INVALID_ENCODING(msg?: string): WebSocketError
14
+ static INVALID_UPGRADE_HEADER(msg?: string): WebSocketError
15
+ static INVALID_VERSION_HEADER(msg?: string): WebSocketError
16
+ static INVALID_KEY_HEADER(msg?: string): WebSocketError
17
+ static INVALID_ACCEPT_HEADER(msg?: string): WebSocketError
18
+ static INVALID_OPCODE(msg?: string): WebSocketError
19
+ static INVALID_PAYLOAD_LENGTH(msg?: string): WebSocketError
20
+ static INCOMPLETE_FRAME(msg?: string, length?: number): WebSocketError
26
21
  }
27
22
 
28
23
  export = WebSocketError
package/lib/errors.js CHANGED
@@ -16,22 +16,11 @@ module.exports = class WebSocketError extends Error {
16
16
  }
17
17
 
18
18
  static NETWORK_ERROR(msg, cause) {
19
- return new WebSocketError(
20
- msg,
21
- 'NETWORK_ERROR',
22
- 0,
23
- WebSocketError.NETWORK_ERROR,
24
- cause
25
- )
19
+ return new WebSocketError(msg, 'NETWORK_ERROR', 0, WebSocketError.NETWORK_ERROR, cause)
26
20
  }
27
21
 
28
22
  static NOT_CONNECTED(msg = 'Socket is not connected') {
29
- return new WebSocketError(
30
- msg,
31
- 'NOT_CONNECTED',
32
- 0,
33
- WebSocketError.NOT_CONNECTED
34
- )
23
+ return new WebSocketError(msg, 'NOT_CONNECTED', 0, WebSocketError.NOT_CONNECTED)
35
24
  }
36
25
 
37
26
  static UNEXPECTED_RSV1(msg = 'RSV1 must be unset') {
@@ -168,4 +157,8 @@ module.exports = class WebSocketError extends Error {
168
157
  WebSocketError.INVALID_PAYLOAD_LENGTH
169
158
  )
170
159
  }
160
+
161
+ static INCOMPLETE_FRAME(msg = 'Incomplete frame', length = -1) {
162
+ return new WebSocketError(msg, 'INCOMPLETE_FRAME', length, WebSocketError.INCOMPLETE_FRAME)
163
+ }
171
164
  }
package/lib/frame.js CHANGED
@@ -19,13 +19,7 @@ module.exports = exports = class Frame {
19
19
  payload = EMPTY
20
20
  }
21
21
 
22
- const {
23
- fin = true,
24
- rsv1 = false,
25
- rsv2 = false,
26
- rsv3 = false,
27
- mask = null
28
- } = opts
22
+ const { fin = true, rsv1 = false, rsv2 = false, rsv3 = false, mask = null } = opts
29
23
 
30
24
  this.fin = fin
31
25
  this.rsv1 = rsv1
@@ -136,12 +130,13 @@ exports.encode = function encode(state, f) {
136
130
  }
137
131
 
138
132
  exports.decode = function decode(state) {
133
+ const s = state.start
139
134
  const b = state.buffer
140
135
 
141
- let i = state.start
142
- let n = b.length
136
+ let i = s
137
+ let n = b.byteLength
143
138
 
144
- if (n < 2) return null
139
+ if (n < 2) throw errors.INCOMPLETE_FRAME()
145
140
 
146
141
  const view = new DataView(b.buffer, b.byteOffset, b.byteLength)
147
142
 
@@ -164,14 +159,14 @@ exports.decode = function decode(state) {
164
159
  n--
165
160
 
166
161
  if (length === 0x7e) {
167
- if (n < 2) return null
162
+ if (n < 2) throw errors.INCOMPLETE_FRAME()
168
163
 
169
164
  length = view.getUint16(i, false)
170
165
 
171
166
  i += 2
172
167
  n -= 2
173
168
  } else if (length === 0x7f) {
174
- if (n < 8) return null
169
+ if (n < 8) throw errors.INCOMPLETE_FRAME()
175
170
 
176
171
  const high = view.getUint32(i, false)
177
172
 
@@ -191,7 +186,7 @@ exports.decode = function decode(state) {
191
186
  let mask = null
192
187
 
193
188
  if (masked) {
194
- if (n < 4) return null
189
+ if (n < 4) throw errors.INCOMPLETE_FRAME()
195
190
 
196
191
  mask = b.subarray(i, i + 4)
197
192
 
@@ -199,7 +194,9 @@ exports.decode = function decode(state) {
199
194
  n -= 4
200
195
  }
201
196
 
202
- if (n < length) return null
197
+ if (n < length) {
198
+ throw errors.INCOMPLETE_FRAME('Incomplete frame', i - s + length)
199
+ }
203
200
 
204
201
  const payload = b.subarray(i, i + length)
205
202
 
package/lib/server.d.ts CHANGED
@@ -7,9 +7,7 @@ import Buffer from 'bare-buffer'
7
7
  import WebSocket from './socket'
8
8
  import WebSocketError from './errors'
9
9
 
10
- interface WebSocketServerOptions
11
- extends HTTPServerConnectionOptions,
12
- HTTPSServerConnectionOptions {
10
+ interface WebSocketServerOptions extends HTTPServerConnectionOptions, HTTPSServerConnectionOptions {
13
11
  secure?: boolean
14
12
  }
15
13
 
@@ -18,15 +16,14 @@ interface WebSocketServerEvents extends DuplexEvents {
18
16
  listening: []
19
17
  }
20
18
 
21
- interface WebSocketServer<
22
- M extends WebSocketServerEvents = WebSocketServerEvents
23
- > extends EventEmitter<M> {
19
+ interface WebSocketServer<M extends WebSocketServerEvents = WebSocketServerEvents>
20
+ extends EventEmitter<M> {
24
21
  readonly listening: boolean
25
22
 
26
23
  address(): TCPSocketAddress
27
- close(cb?: (err: WebSocketError | null) => void): void
28
- ref(): void
29
- unref(): void
24
+ close(cb?: (err?: Error | null) => void): this
25
+ ref(): this
26
+ unref(): this
30
27
  }
31
28
 
32
29
  declare class WebSocketServer {
@@ -41,10 +38,7 @@ declare class WebSocketServer {
41
38
  declare namespace WebSocketServer {
42
39
  export { type WebSocketServerOptions, type WebSocketServerEvents }
43
40
 
44
- export function handshake(
45
- req: HTTPClientRequest,
46
- cb: (err: WebSocketError | null) => void
47
- ): void
41
+ export function handshake(req: HTTPClientRequest, cb: (err: WebSocketError | null) => void): void
48
42
 
49
43
  export function handshake(
50
44
  req: HTTPClientRequest,
package/lib/server.js CHANGED
@@ -44,15 +44,21 @@ module.exports = exports = class WebSocketServer extends EventEmitter {
44
44
  }
45
45
 
46
46
  close(cb) {
47
- return this._server.close(cb)
47
+ this._server.close(cb)
48
+
49
+ return this
48
50
  }
49
51
 
50
52
  ref() {
51
53
  this._server.ref()
54
+
55
+ return this
52
56
  }
53
57
 
54
58
  unref() {
55
59
  this._server.unref()
60
+
61
+ return this
56
62
  }
57
63
 
58
64
  _onlistening() {
@@ -80,12 +86,7 @@ module.exports = exports = class WebSocketServer extends EventEmitter {
80
86
  }
81
87
 
82
88
  // https://datatracker.ietf.org/doc/html/rfc6455#section-4.2
83
- exports.handshake = function handshake(
84
- req,
85
- socket = req.socket,
86
- head = EMPTY,
87
- cb
88
- ) {
89
+ exports.handshake = function handshake(req, socket = req.socket, head = EMPTY, cb) {
89
90
  if (typeof socket === 'function') {
90
91
  cb = socket
91
92
  socket = req.socket
@@ -111,11 +112,7 @@ exports.handshake = function handshake(
111
112
  return cb(errors.INVALID_KEY_HEADER())
112
113
  }
113
114
 
114
- const digest = crypto
115
- .createHash('sha1')
116
- .update(key)
117
- .update(GUID)
118
- .digest('base64')
115
+ const digest = crypto.createHash('sha1').update(key).update(GUID).digest('base64')
119
116
 
120
117
  socket.write(
121
118
  'HTTP/1.1 101 Web Socket Protocol Handshake' +
package/lib/socket.d.ts CHANGED
@@ -18,8 +18,7 @@ interface WebSocketEvents extends DuplexEvents {
18
18
  pong: [payload: unknown]
19
19
  }
20
20
 
21
- interface WebSocket<M extends WebSocketEvents = WebSocketEvents>
22
- extends Duplex<M> {
21
+ interface WebSocket<M extends WebSocketEvents = WebSocketEvents> extends Duplex<M> {
23
22
  ping(data: unknown): void
24
23
  pong(data: unknown): void
25
24
  }
package/lib/socket.js CHANGED
@@ -24,8 +24,7 @@ module.exports = exports = class WebSocket extends Duplex {
24
24
 
25
25
  // For Node.js compatibility
26
26
  opts.host = opts.hostname || opts.host
27
- opts.port =
28
- typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
27
+ opts.port = typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
29
28
  }
30
29
 
31
30
  const { isServer = false, socket = null } = opts
@@ -40,7 +39,9 @@ module.exports = exports = class WebSocket extends Duplex {
40
39
  this._pendingOpen = null
41
40
  this._pendingWrite = null
42
41
 
43
- this._buffer = null
42
+ this._buffer = []
43
+ this._buffered = 0
44
+ this._frame = -1
44
45
 
45
46
  if (socket !== null) this._attach(socket)
46
47
  else this._connect(opts)
@@ -51,9 +52,7 @@ module.exports = exports = class WebSocket extends Duplex {
51
52
 
52
53
  if (typeof data === 'string') data = Buffer.from(data)
53
54
 
54
- this._socket.write(
55
- new Frame(opcode.PING, data, { mask: this._mask }).toBuffer()
56
- )
55
+ this._socket.write(new Frame(opcode.PING, data, { mask: this._mask }).toBuffer())
57
56
  }
58
57
 
59
58
  pong(data) {
@@ -61,9 +60,7 @@ module.exports = exports = class WebSocket extends Duplex {
61
60
 
62
61
  if (typeof data === 'string') data = Buffer.from(data)
63
62
 
64
- this._socket.write(
65
- new Frame(opcode.PONG, data, { mask: this._mask }).toBuffer()
66
- )
63
+ this._socket.write(new Frame(opcode.PONG, data, { mask: this._mask }).toBuffer())
67
64
  }
68
65
 
69
66
  _attach(socket) {
@@ -101,29 +98,27 @@ module.exports = exports = class WebSocket extends Duplex {
101
98
  }
102
99
 
103
100
  _ondata(data) {
104
- if (this._buffer === null) this._buffer = data
105
- else this._buffer = Buffer.concat([this._buffer, data])
101
+ this._buffer.push(data)
102
+ this._buffered += data.byteLength
106
103
 
107
- while (this._buffer !== null) {
108
- const state = { start: 0, end: this._buffer.length, buffer: this._buffer }
104
+ while (this._frame === -1 || this._frame <= this._buffered) {
105
+ const buffer = this._buffer.length === 1 ? this._buffer[0] : Buffer.concat(this._buffer)
109
106
 
110
- let frame
111
- try {
112
- frame = Frame.decode(state)
113
- } catch (err) {
114
- return this.destroy(err)
115
- }
116
-
117
- if (frame === null) return
107
+ this._buffer = [buffer]
118
108
 
119
- this._buffer =
120
- state.start === state.end ? null : this._buffer.subarray(state.start)
109
+ const state = { start: 0, end: buffer.length, buffer }
121
110
 
122
111
  try {
123
- this._onframe(frame)
112
+ this._onframe(Frame.decode(state))
124
113
  } catch (err) {
125
- return this.destroy(err)
114
+ if (err.code === 'INCOMPLETE_FRAME') this._frame = err.status
115
+ else this.destroy(err)
116
+ return
126
117
  }
118
+
119
+ this._buffered -= state.start
120
+ this._buffer = this._buffered > 0 ? [buffer.subarray(state.start)] : []
121
+ this._frame = -1
127
122
  }
128
123
  }
129
124
 
@@ -222,11 +217,9 @@ module.exports = exports = class WebSocket extends Duplex {
222
217
  return cb(errors.INVALID_ENCODING())
223
218
  }
224
219
 
225
- const frame = new Frame(
226
- encoding === 'buffer' ? opcode.BINARY : opcode.TEXT,
227
- data,
228
- { mask: this._mask }
229
- )
220
+ const frame = new Frame(encoding === 'buffer' ? opcode.BINARY : opcode.TEXT, data, {
221
+ mask: this._mask
222
+ })
230
223
 
231
224
  if (this._socket.write(frame.toBuffer())) cb(null)
232
225
  else this._pendingWrite = cb
@@ -260,11 +253,7 @@ exports.handshake = function handshake(req, cb) {
260
253
  return cb(errors.INVALID_UPGRADE_HEADER())
261
254
  }
262
255
 
263
- const digest = crypto
264
- .createHash('sha1')
265
- .update(key)
266
- .update(GUID)
267
- .digest('base64')
256
+ const digest = crypto.createHash('sha1').update(key).update(GUID).digest('base64')
268
257
 
269
258
  if (res.headers['sec-websocket-accept'] !== digest) {
270
259
  return cb(errors.INVALID_ACCEPT_HEADER())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-ws",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "WebSocket library for JavaScript",
5
5
  "exports": {
6
6
  ".": {
@@ -48,7 +48,7 @@
48
48
  "bare-url": "^2.1.3",
49
49
  "brittle": "^3.3.0",
50
50
  "prettier": "^3.4.1",
51
- "prettier-config-standard": "^7.0.0"
51
+ "prettier-config-holepunch": "^2.0.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "bare-buffer": "*",