node-rtc-connection 1.0.18 → 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.
Files changed (65) hide show
  1. package/README.md +94 -85
  2. package/dist/index.cjs +20 -5421
  3. package/dist/index.mjs +25 -5413
  4. package/dist/types/crypto/der.d.ts +107 -0
  5. package/dist/types/crypto/x509.d.ts +56 -0
  6. package/dist/types/datachannel/RTCDataChannel.d.ts +179 -0
  7. package/dist/types/dtls/RTCCertificate.d.ts +163 -0
  8. package/dist/types/dtls/cipher.d.ts +81 -0
  9. package/dist/types/dtls/connection.d.ts +81 -0
  10. package/dist/types/dtls/prf.d.ts +29 -0
  11. package/dist/types/dtls/protocol.d.ts +127 -0
  12. package/dist/types/foundation/ByteBufferQueue.d.ts +71 -0
  13. package/dist/types/foundation/RTCError.d.ts +152 -0
  14. package/dist/types/ice/RTCIceCandidate.d.ts +161 -0
  15. package/dist/types/ice/ice-agent.d.ts +154 -0
  16. package/dist/types/ice/stun-message.d.ts +92 -0
  17. package/dist/types/index.d.ts +29 -0
  18. package/dist/types/peerconnection/RTCPeerConnection.d.ts +74 -0
  19. package/dist/types/sctp/association.d.ts +77 -0
  20. package/dist/types/sctp/chunks.d.ts +200 -0
  21. package/dist/types/sctp/crc32c.d.ts +24 -0
  22. package/dist/types/sctp/datachannel-manager.d.ts +51 -0
  23. package/dist/types/sctp/dcep.d.ts +56 -0
  24. package/dist/types/sdp/RTCSessionDescription.d.ts +73 -0
  25. package/dist/types/sdp/sdp-utils.d.ts +103 -0
  26. package/dist/types/stun/stun-client.d.ts +119 -0
  27. package/dist/types/transport-stack.d.ts +68 -0
  28. package/package.json +26 -21
  29. package/src/crypto/der.ts +205 -0
  30. package/src/crypto/x509.ts +146 -0
  31. package/src/datachannel/RTCDataChannel.ts +388 -0
  32. package/src/dtls/RTCCertificate.ts +396 -0
  33. package/src/dtls/cipher.ts +198 -0
  34. package/src/dtls/connection.ts +974 -0
  35. package/src/dtls/prf.ts +62 -0
  36. package/src/dtls/protocol.ts +204 -0
  37. package/src/foundation/{ByteBufferQueue.js → ByteBufferQueue.ts} +74 -72
  38. package/src/foundation/{RTCError.js → RTCError.ts} +110 -60
  39. package/src/ice/{RTCIceCandidate.js → RTCIceCandidate.ts} +140 -92
  40. package/src/ice/ice-agent.ts +609 -0
  41. package/src/ice/stun-message.ts +260 -0
  42. package/src/index.ts +72 -0
  43. package/src/peerconnection/RTCPeerConnection.ts +430 -0
  44. package/src/sctp/association.ts +523 -0
  45. package/src/sctp/chunks.ts +350 -0
  46. package/src/sctp/crc32c.ts +57 -0
  47. package/src/sctp/datachannel-manager.ts +187 -0
  48. package/src/sctp/dcep.ts +94 -0
  49. package/src/sdp/{RTCSessionDescription.js → RTCSessionDescription.ts} +42 -29
  50. package/src/sdp/sdp-utils.ts +229 -0
  51. package/src/stun/stun-client.ts +936 -0
  52. package/src/transport-stack.ts +165 -0
  53. package/dist/index.cjs.map +0 -1
  54. package/dist/index.mjs.map +0 -1
  55. package/src/datachannel/RTCDataChannel.js +0 -354
  56. package/src/dtls/RTCCertificate.js +0 -310
  57. package/src/dtls/RTCDtlsTransport.js +0 -247
  58. package/src/ice/RTCIceTransport.js +0 -998
  59. package/src/index.d.ts +0 -400
  60. package/src/index.js +0 -92
  61. package/src/network/network-transport.js +0 -478
  62. package/src/peerconnection/RTCPeerConnection.js +0 -851
  63. package/src/sctp/RTCSctpTransport.js +0 -253
  64. package/src/sdp/sdp-utils.js +0 -224
  65. package/src/stun/stun-client.js +0 -643
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @file prf.ts
3
+ * @description TLS 1.2 pseudo-random function (RFC 5246 §5) with SHA-256.
4
+ * @module dtls/prf
5
+ *
6
+ * The cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uses P_SHA256 for
7
+ * the PRF. This module also exposes the underlying HMAC-based P_hash.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ import * as crypto from 'crypto';
13
+
14
+ /**
15
+ * P_hash(secret, seed) expanded to `length` bytes (RFC 5246 §5).
16
+ * A(0) = seed
17
+ * A(i) = HMAC(secret, A(i-1))
18
+ * P_hash = HMAC(secret, A(1)+seed) | HMAC(secret, A(2)+seed) | ...
19
+ *
20
+ * @param hashAlg - Node hash name, e.g. 'sha256'.
21
+ * @param secret
22
+ * @param seed
23
+ * @param length
24
+ */
25
+ export function pHash(
26
+ hashAlg: string,
27
+ secret: Buffer,
28
+ seed: Buffer,
29
+ length: number
30
+ ): Buffer {
31
+ const out: Buffer[] = [];
32
+ let total = 0;
33
+ let a = seed; // A(0)
34
+ while (total < length) {
35
+ a = crypto.createHmac(hashAlg, secret).update(a).digest(); // A(i)
36
+ const chunk = crypto
37
+ .createHmac(hashAlg, secret)
38
+ .update(Buffer.concat([a, seed]))
39
+ .digest();
40
+ out.push(chunk);
41
+ total += chunk.length;
42
+ }
43
+ return Buffer.concat(out).slice(0, length);
44
+ }
45
+
46
+ /**
47
+ * TLS 1.2 PRF = P_SHA256(secret, label + seed).
48
+ *
49
+ * @param secret
50
+ * @param label - ASCII label, e.g. "master secret".
51
+ * @param seed
52
+ * @param length
53
+ */
54
+ export function prf(
55
+ secret: Buffer,
56
+ label: string,
57
+ seed: Buffer,
58
+ length: number
59
+ ): Buffer {
60
+ const labelAndSeed = Buffer.concat([Buffer.from(label, 'ascii'), seed]);
61
+ return pHash('sha256', secret, labelAndSeed, length);
62
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * @file protocol.ts
3
+ * @description DTLS 1.2 wire-format constants and TLV/vector encoders.
4
+ * @module dtls/protocol
5
+ *
6
+ * Covers exactly what WebRTC's data channel needs:
7
+ * cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xC02B)
8
+ * curve secp256r1, signature scheme ecdsa_secp256r1_sha256.
9
+ *
10
+ * References: RFC 6347 (DTLS 1.2), RFC 5246 (TLS 1.2), RFC 8422 (ECC).
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ // DTLS 1.2 on the wire is version 0xFEFD (i.e. ~1.2).
16
+ export const DTLS_1_2 = 0xfefd;
17
+
18
+ export const CONTENT_TYPE = Object.freeze({
19
+ CHANGE_CIPHER_SPEC: 20,
20
+ ALERT: 21,
21
+ HANDSHAKE: 22,
22
+ APPLICATION_DATA: 23,
23
+ });
24
+
25
+ export const HANDSHAKE_TYPE = Object.freeze({
26
+ HELLO_REQUEST: 0,
27
+ CLIENT_HELLO: 1,
28
+ SERVER_HELLO: 2,
29
+ HELLO_VERIFY_REQUEST: 3,
30
+ CERTIFICATE: 11,
31
+ SERVER_KEY_EXCHANGE: 12,
32
+ CERTIFICATE_REQUEST: 13,
33
+ SERVER_HELLO_DONE: 14,
34
+ CERTIFICATE_VERIFY: 15,
35
+ CLIENT_KEY_EXCHANGE: 16,
36
+ FINISHED: 20,
37
+ });
38
+
39
+ export const ALERT_LEVEL = Object.freeze({ WARNING: 1, FATAL: 2 });
40
+ export const ALERT_DESC = Object.freeze({
41
+ CLOSE_NOTIFY: 0,
42
+ HANDSHAKE_FAILURE: 40,
43
+ BAD_CERTIFICATE: 42,
44
+ DECRYPT_ERROR: 51,
45
+ INTERNAL_ERROR: 80,
46
+ });
47
+
48
+ // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
49
+ export const CIPHER_SUITE = 0xc02b;
50
+
51
+ export const NAMED_GROUP = Object.freeze({ secp256r1: 0x0017 });
52
+ export const EC_POINT_FORMAT = Object.freeze({ uncompressed: 0 });
53
+
54
+ // SignatureAndHashAlgorithm
55
+ export const HASH_ALG = Object.freeze({ sha256: 4, sha384: 5, sha512: 6 });
56
+ export const SIG_ALG = Object.freeze({ rsa: 1, ecdsa: 3 });
57
+
58
+ // ClientCertificateType
59
+ export const CERT_TYPE = Object.freeze({ ecdsa_sign: 64, rsa_sign: 1 });
60
+
61
+ export const EXTENSION = Object.freeze({
62
+ SUPPORTED_GROUPS: 10,
63
+ EC_POINT_FORMATS: 11,
64
+ SIGNATURE_ALGORITHMS: 13,
65
+ EXTENDED_MASTER_SECRET: 23,
66
+ RENEGOTIATION_INFO: 0xff01,
67
+ });
68
+
69
+ export const FINISHED_LABEL = Object.freeze({
70
+ CLIENT: 'client finished',
71
+ SERVER: 'server finished',
72
+ });
73
+
74
+ /** A parsed DTLS record from {@link parseRecords}. */
75
+ export interface Record {
76
+ type: number;
77
+ version: number;
78
+ epoch: number;
79
+ seq: number;
80
+ fragment: Buffer;
81
+ }
82
+
83
+ /** A parsed handshake message header from {@link parseHandshake}. */
84
+ export interface Handshake {
85
+ msgType: number;
86
+ length: number;
87
+ messageSeq: number;
88
+ fragmentOffset: number;
89
+ fragmentLength: number;
90
+ body: Buffer;
91
+ }
92
+
93
+ // ---- Vector / integer encoders -------------------------------------------
94
+
95
+ /** Encode a uint24 (3 bytes, big-endian). */
96
+ export function uint24(n: number): Buffer {
97
+ return Buffer.from([(n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff]);
98
+ }
99
+
100
+ /** Read a uint24 at offset. */
101
+ export function readUint24(buf: Buffer, off: number): number {
102
+ return (buf[off]! << 16) | (buf[off + 1]! << 8) | buf[off + 2]!;
103
+ }
104
+
105
+ /** Length-prefixed vector with a 1-byte length. */
106
+ export function vec8(body: Buffer): Buffer {
107
+ return Buffer.concat([Buffer.from([body.length]), body]);
108
+ }
109
+
110
+ /** Length-prefixed vector with a 2-byte length. */
111
+ export function vec16(body: Buffer): Buffer {
112
+ const len = Buffer.alloc(2);
113
+ len.writeUInt16BE(body.length, 0);
114
+ return Buffer.concat([len, body]);
115
+ }
116
+
117
+ /** Length-prefixed vector with a 3-byte length. */
118
+ export function vec24(body: Buffer): Buffer {
119
+ return Buffer.concat([uint24(body.length), body]);
120
+ }
121
+
122
+ // ---- Record layer ---------------------------------------------------------
123
+
124
+ /**
125
+ * Encode a DTLS record (13-byte header + fragment).
126
+ * @param type - CONTENT_TYPE
127
+ * @param epoch
128
+ * @param seq - 48-bit sequence number
129
+ * @param fragment
130
+ * @param version
131
+ */
132
+ export function encodeRecord(
133
+ type: number,
134
+ epoch: number,
135
+ seq: number,
136
+ fragment: Buffer,
137
+ version: number = DTLS_1_2
138
+ ): Buffer {
139
+ const header = Buffer.alloc(13);
140
+ header.writeUInt8(type, 0);
141
+ header.writeUInt16BE(version, 1);
142
+ header.writeUInt16BE(epoch, 3);
143
+ header.writeUIntBE(seq, 5, 6);
144
+ header.writeUInt16BE(fragment.length, 11);
145
+ return Buffer.concat([header, fragment]);
146
+ }
147
+
148
+ /**
149
+ * Parse one or more DTLS records from a datagram. Multiple records may be
150
+ * packed into a single UDP packet.
151
+ * @param packet
152
+ */
153
+ export function parseRecords(packet: Buffer): Record[] {
154
+ const records: Record[] = [];
155
+ let off = 0;
156
+ while (off + 13 <= packet.length) {
157
+ const type = packet.readUInt8(off);
158
+ const version = packet.readUInt16BE(off + 1);
159
+ const epoch = packet.readUInt16BE(off + 3);
160
+ const seq = packet.readUIntBE(off + 5, 6);
161
+ const length = packet.readUInt16BE(off + 11);
162
+ const start = off + 13;
163
+ if (start + length > packet.length) break;
164
+ records.push({ type, version, epoch, seq, fragment: packet.slice(start, start + length) });
165
+ off = start + length;
166
+ }
167
+ return records;
168
+ }
169
+
170
+ // ---- Handshake layer -------------------------------------------------------
171
+
172
+ /**
173
+ * Encode a DTLS handshake message header + body (unfragmented).
174
+ * @param msgType - HANDSHAKE_TYPE
175
+ * @param messageSeq
176
+ * @param body
177
+ */
178
+ export function encodeHandshake(
179
+ msgType: number,
180
+ messageSeq: number,
181
+ body: Buffer
182
+ ): Buffer {
183
+ const header = Buffer.alloc(12);
184
+ header.writeUInt8(msgType, 0);
185
+ uint24(body.length).copy(header, 1); // length
186
+ header.writeUInt16BE(messageSeq, 4); // message_seq
187
+ uint24(0).copy(header, 6); // fragment_offset
188
+ uint24(body.length).copy(header, 9); // fragment_length
189
+ return Buffer.concat([header, body]);
190
+ }
191
+
192
+ /**
193
+ * Parse a handshake message header.
194
+ * @param buf - starts at the handshake header
195
+ */
196
+ export function parseHandshake(buf: Buffer): Handshake {
197
+ const msgType = buf.readUInt8(0);
198
+ const length = readUint24(buf, 1);
199
+ const messageSeq = buf.readUInt16BE(4);
200
+ const fragmentOffset = readUint24(buf, 6);
201
+ const fragmentLength = readUint24(buf, 9);
202
+ const body = buf.slice(12, 12 + fragmentLength);
203
+ return { msgType, length, messageSeq, fragmentOffset, fragmentLength, body };
204
+ }
@@ -1,14 +1,11 @@
1
1
  /**
2
- * @fileoverview ByteBufferQueue - Efficient byte buffer with O(1) append and O(n) read.
3
- *
4
- * Ported from Chromium's WebRTC implementation:
5
- * chromium/src/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.{h,cc}
6
- *
2
+ * @file ByteBufferQueue - Efficient byte buffer with O(1) append and O(n) read.
3
+ *
7
4
  * This class provides efficient management of byte buffers with O(1) append operations
8
5
  * and O(n) read operations. Clients can append entire buffers then copy data out across
9
6
  * buffer boundaries.
10
- *
11
- * @license BSD-3-Clause
7
+ *
8
+ * @license MIT
12
9
  * @author nmhung1210
13
10
  */
14
11
 
@@ -16,7 +13,7 @@
16
13
 
17
14
  /**
18
15
  * A ByteBufferQueue manages a queue of byte buffers with efficient operations.
19
- *
16
+ *
20
17
  * Invariants maintained:
21
18
  * - size_ = sum of all buffer sizes - frontBufferOffset_
22
19
  * - No buffer in the queue is empty
@@ -24,52 +21,56 @@
24
21
  * - Otherwise, frontBufferOffset_ < front buffer size
25
22
  */
26
23
  class ByteBufferQueue {
24
+ /**
25
+ * Total number of bytes available to read.
26
+ * @private {number}
27
+ */
28
+ #size: number;
29
+
30
+ /**
31
+ * Double-ended queue of byte buffers.
32
+ * Append() pushes to the back, ReadInto() consumes from the front.
33
+ * @private {Buffer[]}
34
+ */
35
+ #buffers: Buffer[];
36
+
37
+ /**
38
+ * Offset from which to start reading the front buffer.
39
+ * @private {number}
40
+ */
41
+ #frontBufferOffset: number;
42
+
27
43
  constructor() {
28
- /**
29
- * Total number of bytes available to read.
30
- * @private {number}
31
- */
32
- this._size = 0;
33
-
34
- /**
35
- * Double-ended queue of byte buffers.
36
- * Append() pushes to the back, ReadInto() consumes from the front.
37
- * @private {Buffer[]}
38
- */
39
- this._buffers = [];
40
-
41
- /**
42
- * Offset from which to start reading the front buffer.
43
- * @private {number}
44
- */
45
- this._frontBufferOffset = 0;
44
+ this.#size = 0;
45
+ this.#buffers = [];
46
+ this.#frontBufferOffset = 0;
46
47
  }
47
48
 
48
49
  /**
49
50
  * Number of bytes that can be read.
50
51
  * @returns {number}
51
52
  */
52
- get size() {
53
- return this._size;
53
+ get size(): number {
54
+ return this.#size;
54
55
  }
55
56
 
56
57
  /**
57
58
  * Returns true if no bytes are available to read.
58
59
  * @returns {boolean}
59
60
  */
60
- get empty() {
61
- return this._size === 0;
61
+ get empty(): boolean {
62
+ return this.#size === 0;
62
63
  }
63
64
 
64
65
  /**
65
66
  * Copies data into the given buffer. Consumes bytes from the queue.
66
67
  * Returns the number of bytes written to bufferOut.
67
- *
68
+ *
68
69
  * @param {Buffer} bufferOut - Destination buffer to read into
69
70
  * @returns {number} Number of bytes actually read
70
71
  * @throws {TypeError} If bufferOut is not a Buffer
71
72
  */
72
- readInto(bufferOut) {
73
+ readInto(bufferOut: Buffer): number {
73
74
  if (!Buffer.isBuffer(bufferOut)) {
74
75
  throw new TypeError('bufferOut must be a Buffer');
75
76
  }
@@ -77,9 +78,9 @@ class ByteBufferQueue {
77
78
  let readAmount = 0;
78
79
  let outputOffset = 0;
79
80
 
80
- while (outputOffset < bufferOut.length && this._buffers.length > 0) {
81
- const frontBuffer = this._buffers[0];
82
- const availableInFront = frontBuffer.length - this._frontBufferOffset;
81
+ while (outputOffset < bufferOut.length && this.#buffers.length > 0) {
82
+ const frontBuffer = this.#buffers[0]!;
83
+ const availableInFront = frontBuffer.length - this.#frontBufferOffset;
83
84
  const remainingOutput = bufferOut.length - outputOffset;
84
85
  const toCopy = Math.min(availableInFront, remainingOutput);
85
86
 
@@ -87,8 +88,8 @@ class ByteBufferQueue {
87
88
  frontBuffer.copy(
88
89
  bufferOut,
89
90
  outputOffset,
90
- this._frontBufferOffset,
91
- this._frontBufferOffset + toCopy
91
+ this.#frontBufferOffset,
92
+ this.#frontBufferOffset + toCopy
92
93
  );
93
94
 
94
95
  readAmount += toCopy;
@@ -96,27 +97,27 @@ class ByteBufferQueue {
96
97
 
97
98
  if (toCopy < availableInFront) {
98
99
  // Partial read, update offset
99
- this._frontBufferOffset += toCopy;
100
+ this.#frontBufferOffset += toCopy;
100
101
  } else {
101
102
  // Consumed entire front buffer, remove it
102
- this._buffers.shift();
103
- this._frontBufferOffset = 0;
103
+ this.#buffers.shift();
104
+ this.#frontBufferOffset = 0;
104
105
  }
105
106
  }
106
107
 
107
- this._size -= readAmount;
108
- this._checkInvariants();
108
+ this.#size -= readAmount;
109
+ this.#checkInvariants();
109
110
  return readAmount;
110
111
  }
111
112
 
112
113
  /**
113
114
  * Appends a buffer to the queue. Takes ownership of the buffer.
114
115
  * Empty buffers are ignored.
115
- *
116
+ *
116
117
  * @param {Buffer} buffer - Buffer to append
117
118
  * @throws {TypeError} If buffer is not a Buffer
118
119
  */
119
- append(buffer) {
120
+ append(buffer: Buffer): void {
120
121
  if (!Buffer.isBuffer(buffer)) {
121
122
  throw new TypeError('buffer must be a Buffer');
122
123
  }
@@ -125,31 +126,31 @@ class ByteBufferQueue {
125
126
  return; // Ignore empty buffers
126
127
  }
127
128
 
128
- this._size += buffer.length;
129
- this._buffers.push(buffer);
130
- this._checkInvariants();
129
+ this.#size += buffer.length;
130
+ this.#buffers.push(buffer);
131
+ this.#checkInvariants();
131
132
  }
132
133
 
133
134
  /**
134
135
  * Clears all stored buffers.
135
136
  */
136
- clear() {
137
- this._buffers = [];
138
- this._frontBufferOffset = 0;
139
- this._size = 0;
140
- this._checkInvariants();
137
+ clear(): void {
138
+ this.#buffers = [];
139
+ this.#frontBufferOffset = 0;
140
+ this.#size = 0;
141
+ this.#checkInvariants();
141
142
  }
142
143
 
143
144
  /**
144
145
  * Reads and consumes exactly n bytes.
145
- *
146
+ *
146
147
  * @param {number} n - Number of bytes to read
147
148
  * @returns {Buffer} Buffer containing exactly n bytes
148
149
  * @throws {RangeError} If fewer than n bytes are available
149
150
  */
150
- read(n) {
151
- if (n > this._size) {
152
- throw new RangeError(`Cannot read ${n} bytes, only ${this._size} available`);
151
+ read(n: number): Buffer {
152
+ if (n > this.#size) {
153
+ throw new RangeError(`Cannot read ${n} bytes, only ${this.#size} available`);
153
154
  }
154
155
  if (n === 0) {
155
156
  return Buffer.allocUnsafe(0);
@@ -167,12 +168,12 @@ class ByteBufferQueue {
167
168
 
168
169
  /**
169
170
  * Peeks at data without consuming it.
170
- *
171
- * @param {number} [n=this._size] - Number of bytes to peek
171
+ *
172
+ * @param {number} [n=this.#size] - Number of bytes to peek
172
173
  * @returns {Buffer} Buffer containing up to n bytes (not consumed)
173
174
  */
174
- peek(n = this._size) {
175
- const peekAmount = Math.min(n, this._size);
175
+ peek(n: number = this.#size): Buffer {
176
+ const peekAmount = Math.min(n, this.#size);
176
177
  if (peekAmount === 0) {
177
178
  return Buffer.allocUnsafe(0);
178
179
  }
@@ -180,10 +181,10 @@ class ByteBufferQueue {
180
181
  const result = Buffer.allocUnsafe(peekAmount);
181
182
  let written = 0;
182
183
  let bufferIndex = 0;
183
- let offset = this._frontBufferOffset;
184
+ let offset = this.#frontBufferOffset;
184
185
 
185
- while (written < peekAmount && bufferIndex < this._buffers.length) {
186
- const buffer = this._buffers[bufferIndex];
186
+ while (written < peekAmount && bufferIndex < this.#buffers.length) {
187
+ const buffer = this.#buffers[bufferIndex]!;
187
188
  const available = buffer.length - offset;
188
189
  const toCopy = Math.min(available, peekAmount - written);
189
190
 
@@ -202,29 +203,29 @@ class ByteBufferQueue {
202
203
  * @private
203
204
  * @throws {Error} If invariants are violated
204
205
  */
205
- _checkInvariants() {
206
+ #checkInvariants(): void {
206
207
  if (process.env.NODE_ENV !== 'production') {
207
208
  let bufferSizeSum = 0;
208
- for (const buffer of this._buffers) {
209
+ for (const buffer of this.#buffers) {
209
210
  if (buffer.length === 0) {
210
211
  throw new Error('Invariant violation: empty buffer in queue');
211
212
  }
212
213
  bufferSizeSum += buffer.length;
213
214
  }
214
215
 
215
- const expectedSize = bufferSizeSum - this._frontBufferOffset;
216
- if (this._size !== expectedSize) {
216
+ const expectedSize = bufferSizeSum - this.#frontBufferOffset;
217
+ if (this.#size !== expectedSize) {
217
218
  throw new Error(
218
- `Invariant violation: size=${this._size}, expected=${expectedSize}`
219
+ `Invariant violation: size=${this.#size}, expected=${expectedSize}`
219
220
  );
220
221
  }
221
222
 
222
- if (this._buffers.length === 0) {
223
- if (this._frontBufferOffset !== 0) {
223
+ if (this.#buffers.length === 0) {
224
+ if (this.#frontBufferOffset !== 0) {
224
225
  throw new Error('Invariant violation: offset non-zero with empty queue');
225
226
  }
226
227
  } else {
227
- if (this._frontBufferOffset >= this._buffers[0].length) {
228
+ if (this.#frontBufferOffset >= this.#buffers[0]!.length) {
228
229
  throw new Error('Invariant violation: offset >= front buffer size');
229
230
  }
230
231
  }
@@ -232,4 +233,5 @@ class ByteBufferQueue {
232
233
  }
233
234
  }
234
235
 
235
- module.exports = ByteBufferQueue;
236
+ export default ByteBufferQueue;
237
+ export { ByteBufferQueue };