stelar-time-real 3.2.0 → 3.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["websocket.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,eAAO,MAAM,yBAAyB,QAAmB,CAAC;AAE1D,eAAO,MAAM,eAAe,IAAM,CAAC;AACnC,eAAO,MAAM,OAAO,IAAQ,CAAC;AAC7B,eAAO,MAAM,SAAS,IAAM,CAAC;AAC7B,eAAO,MAAM,QAAQ,IAAO,CAAC;AAC7B,eAAO,MAAM,OAAO,IAAQ,CAAC;AAC7B,eAAO,MAAM,OAAO,KAAQ,CAAC;AAE7B,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,oBAAoB,OAAO,CAAC;AACzC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,qBAAa,cAAe,SAAQ,KAAK;IAChC,IAAI,EAAE,MAAM,CAAC;gBACR,OAAO,EAAE,MAAM,EAAE,IAAI,SAAuB;CAKzD;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAe1F;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIlD;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,SAA4B,GAAG;IACnF,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CA8DP;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAuB9E;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAgCpF;AAID,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAe,EAAE,MAAM,SAAK,GAAG,MAAM,CAK3E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAID,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,SAAe,EAAE,MAAM,SAAK,GAAG,MAAM,CAKjF;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,6FAA6F;AAC7F,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,kBAAkB,CAAK;gBAEnB,YAAY,SAA4B;IAIpD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE;IAyC7B,KAAK,IAAI,IAAI;IAKb,gBAAgB,IAAI,MAAM;CAG3B"}
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["websocket.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,eAAO,MAAM,yBAAyB,QAAmB,CAAC;AAE1D,eAAO,MAAM,eAAe,IAAM,EAAE,OAAO,IAAM,EAAE,SAAS,IAAM,EAChE,QAAQ,IAAM,EAAE,OAAO,IAAM,EAAE,OAAO,KAAM,CAAC;AAE/C,eAAO,MAAM,YAAY,OAAO,EAAE,gBAAgB,OAAO,EAAE,oBAAoB,OAAO,EACpF,iBAAiB,OAAO,EAAE,qBAAqB,OAAO,EAAE,sBAAsB,OAAO,EACrF,qBAAqB,OAAO,EAAE,oBAAoB,OAAO,CAAC;AAE5D,qBAAa,cAAe,SAAQ,KAAK;IACvC,IAAI,EAAE,MAAM,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,IAAI,SAAuB;CACzD;AAED,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,WAA+D,CAAC;AAC5G,eAAO,MAAM,aAAa,cAA2C,CAAC;AACtE,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,KAAG,OAA8E,CAAC;AAE3H,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAK1F;AAED,MAAM,WAAW,OAAO;IAAG,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;CAAE;AAE5F,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAA4B,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAetH;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,UAAQ,GAAG,MAAM,CAkB9F;AAGD,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,4BAAgC,CAAC;AAC9E,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,4BAAmC,CAAC;AACpF,eAAO,MAAM,kBAAkB,GAAI,aAAmB,EAAE,eAAW,4BAElE,CAAC;AACF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,4BAAoD,CAAC;AACpG,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,4BAAoD,CAAC;AAGpG,eAAO,MAAM,uBAAuB,GAAI,KAAK,MAAM,4BAAsC,CAAC;AAC1F,eAAO,MAAM,yBAAyB,GAAI,MAAM,MAAM,4BAAyC,CAAC;AAChG,eAAO,MAAM,wBAAwB,GAAI,aAAmB,EAAE,eAAW,4BAExE,CAAC;AACF,eAAO,MAAM,uBAAuB,+BAAsD,CAAC;AAC3F,eAAO,MAAM,uBAAuB,+BAAsD,CAAC;AAE3F,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAmB;IAC9B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,QAAQ,CAAK;gBAET,GAAG,SAA4B;IAE3C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE;IAgB7B,KAAK;IACL,gBAAgB;CACjB"}
package/src/websocket.js CHANGED
@@ -1,260 +1,150 @@
1
1
  /**
2
- * @stelar-time-real WebSocket Protocol (RFC 6455)
3
- *
4
- * Hand-crafted implementation with no external dependencies.
5
- * Uses Node.js built-in crypto for handshake and frame masking.
2
+ * @stelar-time-real WebSocket (RFC 6455)
6
3
  */
7
4
  import { createHash, randomBytes } from 'crypto';
8
5
  const WS_MAGIC = '258EAFA5-E914-47DA-95CA-5AB5A7E3A741';
9
6
  export const DEFAULT_MAX_WS_FRAME_SIZE = 10 * 1024 * 1024;
10
- export const OP_CONTINUATION = 0x0;
11
- export const OP_TEXT = 0x1;
12
- export const OP_BINARY = 0x2;
13
- export const OP_CLOSE = 0x8;
14
- export const OP_PING = 0x9;
15
- export const OP_PONG = 0xA;
16
- export const CLOSE_NORMAL = 1000;
17
- export const CLOSE_GOING_AWAY = 1001;
18
- export const CLOSE_PROTOCOL_ERROR = 1002;
19
- export const CLOSE_UNSUPPORTED = 1003;
20
- export const CLOSE_INVALID_PAYLOAD = 1007;
21
- export const CLOSE_POLICY_VIOLATION = 1008;
22
- export const CLOSE_MESSAGE_TOO_BIG = 1009;
23
- export const CLOSE_INTERNAL_ERROR = 1011;
7
+ export const OP_CONTINUATION = 0x0, OP_TEXT = 0x1, OP_BINARY = 0x2, OP_CLOSE = 0x8, OP_PING = 0x9, OP_PONG = 0xA;
8
+ export const CLOSE_NORMAL = 1000, CLOSE_GOING_AWAY = 1001, CLOSE_PROTOCOL_ERROR = 1002, CLOSE_UNSUPPORTED = 1003, CLOSE_INVALID_PAYLOAD = 1007, CLOSE_POLICY_VIOLATION = 1008, CLOSE_MESSAGE_TOO_BIG = 1009, CLOSE_INTERNAL_ERROR = 1011;
24
9
  export class WebSocketError extends Error {
25
- constructor(message, code = CLOSE_INTERNAL_ERROR) {
26
- super(message);
27
- this.name = 'WebSocketError';
28
- this.code = code;
29
- }
30
- }
31
- /** Compute Sec-WebSocket-Accept from client key per RFC 6455 Section 4.2.2 */
32
- export function computeAcceptKey(key) {
33
- return createHash('sha1').update(key + WS_MAGIC).digest('base64');
34
- }
35
- export function generateWSKey() {
36
- return randomBytes(16).toString('base64');
10
+ constructor(message, code = CLOSE_INTERNAL_ERROR) { super(message); this.name = 'WebSocketError'; this.code = code; }
37
11
  }
12
+ export const computeAcceptKey = (key) => createHash('sha1').update(key + WS_MAGIC).digest('base64');
13
+ export const generateWSKey = () => randomBytes(16).toString('base64');
14
+ export const validateWSKey = (key) => typeof key === 'string' && Buffer.from(key, 'base64').length === 16;
38
15
  export function buildUpgradeResponse(key, headers) {
39
- const accept = computeAcceptKey(key);
40
- const lines = [
41
- 'HTTP/1.1 101 Switching Protocols',
42
- 'Upgrade: websocket',
43
- 'Connection: Upgrade',
44
- `Sec-WebSocket-Accept: ${accept}`,
45
- ];
46
- if (headers) {
47
- for (const [k, v] of Object.entries(headers)) {
16
+ const lines = ['HTTP/1.1 101 Switching Protocols', 'Upgrade: websocket', 'Connection: Upgrade', `Sec-WebSocket-Accept: ${computeAcceptKey(key)}`];
17
+ if (headers)
18
+ for (const [k, v] of Object.entries(headers))
48
19
  lines.push(`${k}: ${v}`);
49
- }
50
- }
51
20
  lines.push('', '');
52
21
  return lines.join('\r\n');
53
22
  }
54
- /** Validate Sec-WebSocket-Key: must be 16 bytes base64 encoded */
55
- export function validateWSKey(key) {
56
- if (typeof key !== 'string')
57
- return false;
58
- const decoded = Buffer.from(key, 'base64');
59
- return decoded.length === 16;
60
- }
61
- /** Parse a single WebSocket frame from buffer. Returns null if incomplete. */
62
- export function parseWSFrame(buf, maxFrameSize = DEFAULT_MAX_WS_FRAME_SIZE) {
23
+ export function parseWSFrame(buf, max = DEFAULT_MAX_WS_FRAME_SIZE) {
63
24
  if (buf.length < 2)
64
25
  return null;
65
- const firstByte = buf[0];
66
- const secondByte = buf[1];
67
- const fin = (firstByte & 0x80) !== 0;
68
- const rsv1 = (firstByte & 0x40) !== 0;
69
- const rsv2 = (firstByte & 0x20) !== 0;
70
- const rsv3 = (firstByte & 0x10) !== 0;
71
- const opcode = firstByte & 0x0F;
72
- const masked = (secondByte & 0x80) !== 0;
73
- let payloadLen = secondByte & 0x7F;
74
- if (rsv1 || rsv2 || rsv3) {
75
- throw new WebSocketError('RSV bits set without extension negotiation', CLOSE_PROTOCOL_ERROR);
76
- }
77
- let offset = 2;
78
- if (payloadLen === 126) {
26
+ const b0 = buf[0], b1 = buf[1];
27
+ const fin = !!(b0 & 0x80), rsv = b0 & 0x70, opcode = b0 & 0x0F, masked = !!(b1 & 0x80);
28
+ let len = b1 & 0x7F, off = 2;
29
+ if (rsv)
30
+ throw new WebSocketError('RSV bits set', CLOSE_PROTOCOL_ERROR);
31
+ if (len === 126) {
79
32
  if (buf.length < 4)
80
33
  return null;
81
- payloadLen = buf.readUInt16BE(2);
82
- offset = 4;
34
+ len = buf.readUInt16BE(2);
35
+ off = 4;
83
36
  }
84
- else if (payloadLen === 127) {
37
+ else if (len === 127) {
85
38
  if (buf.length < 10)
86
39
  return null;
87
- const high = buf.readUInt32BE(2);
88
- const low = buf.readUInt32BE(6);
89
- payloadLen = high * 0x100000000 + low;
90
- if (payloadLen > Number.MAX_SAFE_INTEGER) {
91
- throw new WebSocketError('Frame payload too large for JavaScript', CLOSE_MESSAGE_TOO_BIG);
92
- }
93
- offset = 10;
94
- }
95
- if (payloadLen > maxFrameSize) {
96
- throw new WebSocketError(`Frame payload exceeds max size (${maxFrameSize} bytes)`, CLOSE_MESSAGE_TOO_BIG);
40
+ len = buf.readUInt32BE(2) * 0x100000000 + buf.readUInt32BE(6);
41
+ off = 10;
97
42
  }
98
- let maskKey;
43
+ if (len > max)
44
+ throw new WebSocketError(`Frame exceeds max (${max})`, CLOSE_MESSAGE_TOO_BIG);
45
+ let mk;
99
46
  if (masked) {
100
- if (buf.length < offset + 4)
47
+ if (buf.length < off + 4)
101
48
  return null;
102
- maskKey = buf.subarray(offset, offset + 4);
103
- offset += 4;
49
+ mk = buf.subarray(off, off + 4);
50
+ off += 4;
104
51
  }
105
- if (buf.length < offset + payloadLen)
52
+ if (buf.length < off + len)
106
53
  return null;
107
- let payload = Buffer.from(buf.subarray(offset, offset + payloadLen));
108
- if (masked && maskKey) {
109
- for (let i = 0; i < payloadLen; i++) {
110
- payload[i] ^= maskKey[i & 3];
111
- }
112
- }
113
- return {
114
- frame: { fin, opcode, payload, masked },
115
- consumed: offset + payloadLen,
116
- };
117
- }
118
- /** Create an unmasked WS frame (server-to-client per RFC 6455 Section 5.3) */
119
- export function createWSFrame(opcode, payload) {
120
- const data = typeof payload === 'string' ? Buffer.from(payload, 'utf8') : payload;
121
- let header;
122
- if (data.length < 126) {
123
- header = Buffer.alloc(2);
124
- header[0] = 0x80 | opcode;
125
- header[1] = data.length;
126
- }
127
- else if (data.length < 65536) {
128
- header = Buffer.alloc(4);
129
- header[0] = 0x80 | opcode;
130
- header[1] = 126;
131
- header.writeUInt16BE(data.length, 2);
132
- }
133
- else {
134
- header = Buffer.alloc(10);
135
- header[0] = 0x80 | opcode;
136
- header[1] = 127;
137
- header.writeUInt32BE(Math.floor(data.length / 0x100000000), 2);
138
- header.writeUInt32BE(data.length & 0xFFFFFFFF, 6);
139
- }
140
- return Buffer.concat([header, data]);
141
- }
142
- /** Create a masked WS frame (client-to-server per RFC 6455 Section 5.3) */
143
- export function createWSFrameMasked(opcode, payload) {
144
- const data = typeof payload === 'string' ? Buffer.from(payload, 'utf8') : payload;
145
- const maskKey = randomBytes(4);
146
- let header;
147
- if (data.length < 126) {
148
- header = Buffer.alloc(6);
149
- header[0] = 0x80 | opcode;
150
- header[1] = 0x80 | data.length;
151
- maskKey.copy(header, 2);
152
- }
153
- else if (data.length < 65536) {
154
- header = Buffer.alloc(8);
155
- header[0] = 0x80 | opcode;
156
- header[1] = 0x80 | 126;
157
- header.writeUInt16BE(data.length, 2);
158
- maskKey.copy(header, 4);
54
+ const payload = Buffer.from(buf.subarray(off, off + len));
55
+ if (masked && mk)
56
+ for (let i = 0; i < len; i++)
57
+ payload[i] ^= mk[i & 3];
58
+ return { frame: { fin, opcode, payload, masked }, consumed: off + len };
59
+ }
60
+ export function createWSFrame(opcode, payload, masked = false) {
61
+ const d = typeof payload === 'string' ? Buffer.from(payload, 'utf8') : payload;
62
+ const mk = masked ? randomBytes(4) : undefined;
63
+ const base = masked ? 0x80 : 0;
64
+ let h;
65
+ if (d.length < 126) {
66
+ h = Buffer.alloc(masked ? 6 : 2);
67
+ h[0] = 0x80 | opcode;
68
+ h[1] = base | d.length;
69
+ if (mk)
70
+ mk.copy(h, 2);
71
+ }
72
+ else if (d.length < 65536) {
73
+ h = Buffer.alloc(masked ? 8 : 4);
74
+ h[0] = 0x80 | opcode;
75
+ h[1] = base | 126;
76
+ h.writeUInt16BE(d.length, 2);
77
+ if (mk)
78
+ mk.copy(h, 4);
159
79
  }
160
80
  else {
161
- header = Buffer.alloc(14);
162
- header[0] = 0x80 | opcode;
163
- header[1] = 0x80 | 127;
164
- header.writeUInt32BE(Math.floor(data.length / 0x100000000), 2);
165
- header.writeUInt32BE(data.length & 0xFFFFFFFF, 6);
166
- maskKey.copy(header, 10);
167
- }
168
- const outData = Buffer.from(data);
169
- for (let i = 0; i < outData.length; i++) {
170
- outData[i] ^= maskKey[i & 3];
171
- }
172
- return Buffer.concat([header, outData]);
173
- }
174
- /* Server-to-client frame helpers (unmasked) */
175
- export function createWSTextFrame(message) {
176
- return createWSFrame(OP_TEXT, message);
177
- }
178
- export function createWSBinaryFrame(data) {
179
- return createWSFrame(OP_BINARY, data);
180
- }
181
- export function createWSCloseFrame(code = CLOSE_NORMAL, reason = '') {
182
- const buf = Buffer.alloc(2 + Buffer.byteLength(reason));
183
- buf.writeUInt16BE(code, 0);
184
- if (reason.length > 0)
185
- buf.write(reason, 2, 'utf8');
186
- return createWSFrame(OP_CLOSE, buf);
187
- }
188
- export function createWSPingFrame(data) {
189
- return createWSFrame(OP_PING, data || Buffer.alloc(0));
190
- }
191
- export function createWSPongFrame(data) {
192
- return createWSFrame(OP_PONG, data || Buffer.alloc(0));
193
- }
194
- /* Client-to-server frame helpers (masked) */
195
- export function createWSTextFrameMasked(message) {
196
- return createWSFrameMasked(OP_TEXT, message);
197
- }
198
- export function createWSBinaryFrameMasked(data) {
199
- return createWSFrameMasked(OP_BINARY, data);
200
- }
201
- export function createWSCloseFrameMasked(code = CLOSE_NORMAL, reason = '') {
202
- const buf = Buffer.alloc(2 + Buffer.byteLength(reason));
203
- buf.writeUInt16BE(code, 0);
204
- if (reason.length > 0)
205
- buf.write(reason, 2, 'utf8');
206
- return createWSFrameMasked(OP_CLOSE, buf);
207
- }
208
- export function createWSPingFrameMasked() {
209
- return createWSFrameMasked(OP_PING, Buffer.alloc(0));
210
- }
211
- export function createWSPongFrameMasked() {
212
- return createWSFrameMasked(OP_PONG, Buffer.alloc(0));
213
- }
214
- /** Streaming parser for WebSocket frames. Buffers partial data and emits complete frames. */
81
+ h = Buffer.alloc(masked ? 14 : 10);
82
+ h[0] = 0x80 | opcode;
83
+ h[1] = base | 127;
84
+ h.writeUInt32BE(Math.floor(d.length / 0x100000000), 2);
85
+ h.writeUInt32BE(d.length & 0xFFFFFFFF, 6);
86
+ if (mk)
87
+ mk.copy(h, 10);
88
+ }
89
+ if (mk)
90
+ for (let i = 0; i < d.length; i++)
91
+ d[i] ^= mk[i & 3];
92
+ return Buffer.concat([h, d]);
93
+ }
94
+ /* Server (unmasked) */
95
+ export const createWSTextFrame = (msg) => createWSFrame(OP_TEXT, msg);
96
+ export const createWSBinaryFrame = (data) => createWSFrame(OP_BINARY, data);
97
+ export const createWSCloseFrame = (code = CLOSE_NORMAL, reason = '') => {
98
+ const b = Buffer.alloc(2 + Buffer.byteLength(reason));
99
+ b.writeUInt16BE(code, 0);
100
+ if (reason)
101
+ b.write(reason, 2, 'utf8');
102
+ return createWSFrame(OP_CLOSE, b);
103
+ };
104
+ export const createWSPingFrame = (data) => createWSFrame(OP_PING, data || Buffer.alloc(0));
105
+ export const createWSPongFrame = (data) => createWSFrame(OP_PONG, data || Buffer.alloc(0));
106
+ /* Client (masked) */
107
+ export const createWSTextFrameMasked = (msg) => createWSFrame(OP_TEXT, msg, true);
108
+ export const createWSBinaryFrameMasked = (data) => createWSFrame(OP_BINARY, data, true);
109
+ export const createWSCloseFrameMasked = (code = CLOSE_NORMAL, reason = '') => {
110
+ const b = Buffer.alloc(2 + Buffer.byteLength(reason));
111
+ b.writeUInt16BE(code, 0);
112
+ if (reason)
113
+ b.write(reason, 2, 'utf8');
114
+ return createWSFrame(OP_CLOSE, b, true);
115
+ };
116
+ export const createWSPingFrameMasked = () => createWSFrame(OP_PING, Buffer.alloc(0), true);
117
+ export const createWSPongFrameMasked = () => createWSFrame(OP_PONG, Buffer.alloc(0), true);
215
118
  export class WSFrameParser {
216
- constructor(maxFrameSize = DEFAULT_MAX_WS_FRAME_SIZE) {
119
+ constructor(max = DEFAULT_MAX_WS_FRAME_SIZE) {
217
120
  this.buf = Buffer.alloc(0);
218
- this.totalBytesReceived = 0;
219
- this.maxFrameSize = maxFrameSize;
121
+ this.received = 0;
122
+ this.max = max;
220
123
  }
221
124
  feed(data) {
222
- this.totalBytesReceived += data.length;
125
+ this.received += data.length;
223
126
  this.buf = Buffer.concat([this.buf, data]);
224
- if (this.buf.length > this.maxFrameSize * 2) {
127
+ if (this.buf.length > this.max * 2) {
225
128
  this.buf = Buffer.alloc(0);
226
- throw new WebSocketError(`Input buffer exceeded limit`, CLOSE_POLICY_VIOLATION);
129
+ throw new WebSocketError('Buffer overflow', CLOSE_POLICY_VIOLATION);
227
130
  }
228
131
  const frames = [];
229
132
  while (this.buf.length > 0) {
230
133
  try {
231
- const result = parseWSFrame(this.buf, this.maxFrameSize);
232
- if (!result)
134
+ const r = parseWSFrame(this.buf, this.max);
135
+ if (!r)
233
136
  break;
234
- const { frame, consumed } = result;
235
- if (frame.opcode === OP_CONTINUATION) {
236
- this.buf = consumed < this.buf.length
237
- ? Buffer.from(this.buf.subarray(consumed))
238
- : Buffer.alloc(0);
239
- continue;
240
- }
241
- frames.push(frame);
242
- this.buf = consumed < this.buf.length
243
- ? Buffer.from(this.buf.subarray(consumed))
244
- : Buffer.alloc(0);
137
+ this.buf = r.consumed < this.buf.length ? Buffer.from(this.buf.subarray(r.consumed)) : Buffer.alloc(0);
138
+ if (r.frame.opcode !== OP_CONTINUATION)
139
+ frames.push(r.frame);
245
140
  }
246
- catch (err) {
141
+ catch (e) {
247
142
  this.buf = Buffer.alloc(0);
248
- throw err;
143
+ throw e;
249
144
  }
250
145
  }
251
146
  return frames;
252
147
  }
253
- reset() {
254
- this.buf = Buffer.alloc(0);
255
- this.totalBytesReceived = 0;
256
- }
257
- getBytesReceived() {
258
- return this.totalBytesReceived;
259
- }
148
+ reset() { this.buf = Buffer.alloc(0); this.received = 0; }
149
+ getBytesReceived() { return this.received; }
260
150
  }