undici 6.19.7 → 7.0.0-alpha.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 (115) hide show
  1. package/README.md +5 -9
  2. package/docs/docs/api/Agent.md +0 -3
  3. package/docs/docs/api/Client.md +0 -2
  4. package/docs/docs/api/Dispatcher.md +204 -6
  5. package/docs/docs/api/EnvHttpProxyAgent.md +0 -1
  6. package/docs/docs/api/Fetch.md +1 -0
  7. package/docs/docs/api/Pool.md +0 -1
  8. package/docs/docs/api/RetryHandler.md +1 -1
  9. package/index.js +0 -4
  10. package/lib/api/api-connect.js +3 -1
  11. package/lib/api/api-pipeline.js +3 -4
  12. package/lib/api/api-request.js +29 -46
  13. package/lib/api/api-stream.js +36 -49
  14. package/lib/api/api-upgrade.js +5 -3
  15. package/lib/api/readable.js +71 -27
  16. package/lib/core/connect.js +39 -24
  17. package/lib/core/errors.js +17 -4
  18. package/lib/core/request.js +7 -5
  19. package/lib/core/symbols.js +0 -1
  20. package/lib/core/tree.js +6 -0
  21. package/lib/core/util.js +1 -11
  22. package/lib/dispatcher/agent.js +3 -17
  23. package/lib/dispatcher/balanced-pool.js +27 -11
  24. package/lib/dispatcher/client-h1.js +44 -39
  25. package/lib/dispatcher/client.js +3 -27
  26. package/lib/dispatcher/dispatcher-base.js +2 -34
  27. package/lib/dispatcher/dispatcher.js +3 -24
  28. package/lib/dispatcher/pool.js +3 -6
  29. package/lib/dispatcher/proxy-agent.js +3 -6
  30. package/lib/handler/decorator-handler.js +24 -0
  31. package/lib/handler/redirect-handler.js +9 -0
  32. package/lib/handler/retry-handler.js +22 -3
  33. package/lib/interceptor/dump.js +2 -2
  34. package/lib/interceptor/redirect.js +11 -14
  35. package/lib/interceptor/response-error.js +89 -0
  36. package/lib/llhttp/constants.d.ts +97 -0
  37. package/lib/llhttp/constants.js +412 -192
  38. package/lib/llhttp/constants.js.map +1 -0
  39. package/lib/llhttp/llhttp-wasm.js +11 -1
  40. package/lib/llhttp/llhttp_simd-wasm.js +11 -1
  41. package/lib/llhttp/utils.d.ts +2 -0
  42. package/lib/llhttp/utils.js +9 -9
  43. package/lib/llhttp/utils.js.map +1 -0
  44. package/lib/mock/mock-client.js +2 -2
  45. package/lib/mock/mock-pool.js +2 -2
  46. package/lib/mock/mock-symbols.js +1 -0
  47. package/lib/util/timers.js +324 -44
  48. package/lib/web/cookies/index.js +15 -13
  49. package/lib/web/cookies/parse.js +2 -2
  50. package/lib/web/eventsource/eventsource-stream.js +9 -8
  51. package/lib/web/eventsource/eventsource.js +10 -6
  52. package/lib/web/fetch/body.js +31 -11
  53. package/lib/web/fetch/data-url.js +1 -1
  54. package/lib/web/fetch/formdata-parser.js +1 -2
  55. package/lib/web/fetch/formdata.js +28 -37
  56. package/lib/web/fetch/headers.js +1 -1
  57. package/lib/web/fetch/index.js +7 -8
  58. package/lib/web/fetch/request.js +11 -28
  59. package/lib/web/fetch/response.js +13 -41
  60. package/lib/web/fetch/symbols.js +0 -1
  61. package/lib/web/fetch/util.js +3 -12
  62. package/lib/web/fetch/webidl.js +73 -62
  63. package/lib/web/websocket/connection.js +26 -174
  64. package/lib/web/websocket/constants.js +1 -1
  65. package/lib/web/websocket/frame.js +45 -3
  66. package/lib/web/websocket/receiver.js +28 -26
  67. package/lib/web/websocket/sender.js +18 -13
  68. package/lib/web/websocket/util.js +20 -74
  69. package/lib/web/websocket/websocket.js +294 -70
  70. package/package.json +16 -29
  71. package/scripts/strip-comments.js +3 -1
  72. package/types/agent.d.ts +7 -7
  73. package/types/api.d.ts +24 -24
  74. package/types/balanced-pool.d.ts +11 -11
  75. package/types/client.d.ts +11 -12
  76. package/types/diagnostics-channel.d.ts +10 -10
  77. package/types/dispatcher.d.ts +96 -97
  78. package/types/env-http-proxy-agent.d.ts +2 -2
  79. package/types/errors.d.ts +53 -47
  80. package/types/eventsource.d.ts +0 -2
  81. package/types/fetch.d.ts +8 -8
  82. package/types/formdata.d.ts +7 -7
  83. package/types/global-dispatcher.d.ts +4 -4
  84. package/types/global-origin.d.ts +5 -5
  85. package/types/handlers.d.ts +4 -4
  86. package/types/header.d.ts +157 -1
  87. package/types/index.d.ts +42 -46
  88. package/types/interceptors.d.ts +10 -8
  89. package/types/mock-agent.d.ts +18 -18
  90. package/types/mock-client.d.ts +4 -4
  91. package/types/mock-errors.d.ts +3 -3
  92. package/types/mock-interceptor.d.ts +19 -19
  93. package/types/mock-pool.d.ts +4 -4
  94. package/types/patch.d.ts +0 -42
  95. package/types/pool-stats.d.ts +8 -8
  96. package/types/pool.d.ts +12 -12
  97. package/types/proxy-agent.d.ts +4 -4
  98. package/types/readable.d.ts +14 -9
  99. package/types/retry-agent.d.ts +1 -1
  100. package/types/retry-handler.d.ts +8 -8
  101. package/types/util.d.ts +3 -3
  102. package/types/utility.d.ts +7 -0
  103. package/types/webidl.d.ts +22 -4
  104. package/types/websocket.d.ts +1 -3
  105. package/docs/docs/api/DispatchInterceptor.md +0 -60
  106. package/lib/interceptor/redirect-interceptor.js +0 -21
  107. package/lib/web/fetch/file.js +0 -126
  108. package/lib/web/fileapi/encoding.js +0 -290
  109. package/lib/web/fileapi/filereader.js +0 -344
  110. package/lib/web/fileapi/progressevent.js +0 -78
  111. package/lib/web/fileapi/symbols.js +0 -10
  112. package/lib/web/fileapi/util.js +0 -391
  113. package/lib/web/websocket/symbols.js +0 -12
  114. package/types/file.d.ts +0 -39
  115. package/types/filereader.d.ts +0 -54
@@ -3,7 +3,6 @@
3
3
  const { Writable } = require('node:stream')
4
4
  const assert = require('node:assert')
5
5
  const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
6
- const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols')
7
6
  const { channels } = require('../../core/diagnostics')
8
7
  const {
9
8
  isValidStatusCode,
@@ -37,10 +36,13 @@ class ByteParser extends Writable {
37
36
  /** @type {Map<string, PerMessageDeflate>} */
38
37
  #extensions
39
38
 
40
- constructor (ws, extensions) {
39
+ /** @type {import('./websocket').Handler} */
40
+ #handler
41
+
42
+ constructor (handler, extensions) {
41
43
  super()
42
44
 
43
- this.ws = ws
45
+ this.#handler = handler
44
46
  this.#extensions = extensions == null ? new Map() : extensions
45
47
 
46
48
  if (this.#extensions.has('permessage-deflate')) {
@@ -86,12 +88,12 @@ class ByteParser extends Writable {
86
88
  const rsv3 = buffer[0] & 0x10
87
89
 
88
90
  if (!isValidOpcode(opcode)) {
89
- failWebsocketConnection(this.ws, 'Invalid opcode received')
91
+ failWebsocketConnection(this.#handler, 'Invalid opcode received')
90
92
  return callback()
91
93
  }
92
94
 
93
95
  if (masked) {
94
- failWebsocketConnection(this.ws, 'Frame cannot be masked')
96
+ failWebsocketConnection(this.#handler, 'Frame cannot be masked')
95
97
  return callback()
96
98
  }
97
99
 
@@ -105,43 +107,43 @@ class ByteParser extends Writable {
105
107
  // WebSocket connection where a PMCE is in use, this bit indicates
106
108
  // whether a message is compressed or not.
107
109
  if (rsv1 !== 0 && !this.#extensions.has('permessage-deflate')) {
108
- failWebsocketConnection(this.ws, 'Expected RSV1 to be clear.')
110
+ failWebsocketConnection(this.#handler, 'Expected RSV1 to be clear.')
109
111
  return
110
112
  }
111
113
 
112
114
  if (rsv2 !== 0 || rsv3 !== 0) {
113
- failWebsocketConnection(this.ws, 'RSV1, RSV2, RSV3 must be clear')
115
+ failWebsocketConnection(this.#handler, 'RSV1, RSV2, RSV3 must be clear')
114
116
  return
115
117
  }
116
118
 
117
119
  if (fragmented && !isTextBinaryFrame(opcode)) {
118
120
  // Only text and binary frames can be fragmented
119
- failWebsocketConnection(this.ws, 'Invalid frame type was fragmented.')
121
+ failWebsocketConnection(this.#handler, 'Invalid frame type was fragmented.')
120
122
  return
121
123
  }
122
124
 
123
125
  // If we are already parsing a text/binary frame and do not receive either
124
126
  // a continuation frame or close frame, fail the connection.
125
127
  if (isTextBinaryFrame(opcode) && this.#fragments.length > 0) {
126
- failWebsocketConnection(this.ws, 'Expected continuation frame')
128
+ failWebsocketConnection(this.#handler, 'Expected continuation frame')
127
129
  return
128
130
  }
129
131
 
130
132
  if (this.#info.fragmented && fragmented) {
131
133
  // A fragmented frame can't be fragmented itself
132
- failWebsocketConnection(this.ws, 'Fragmented frame exceeded 125 bytes.')
134
+ failWebsocketConnection(this.#handler, 'Fragmented frame exceeded 125 bytes.')
133
135
  return
134
136
  }
135
137
 
136
138
  // "All control frames MUST have a payload length of 125 bytes or less
137
139
  // and MUST NOT be fragmented."
138
140
  if ((payloadLength > 125 || fragmented) && isControlFrame(opcode)) {
139
- failWebsocketConnection(this.ws, 'Control frame either too large or fragmented')
141
+ failWebsocketConnection(this.#handler, 'Control frame either too large or fragmented')
140
142
  return
141
143
  }
142
144
 
143
145
  if (isContinuationFrame(opcode) && this.#fragments.length === 0 && !this.#info.compressed) {
144
- failWebsocketConnection(this.ws, 'Unexpected continuation frame')
146
+ failWebsocketConnection(this.#handler, 'Unexpected continuation frame')
145
147
  return
146
148
  }
147
149
 
@@ -187,7 +189,7 @@ class ByteParser extends Writable {
187
189
  // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275
188
190
  // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e
189
191
  if (upper > 2 ** 31 - 1) {
190
- failWebsocketConnection(this.ws, 'Received payload length > 2^31 bytes.')
192
+ failWebsocketConnection(this.#handler, 'Received payload length > 2^31 bytes.')
191
193
  return
192
194
  }
193
195
 
@@ -215,7 +217,7 @@ class ByteParser extends Writable {
215
217
  // parsing continuation frames, not here.
216
218
  if (!this.#info.fragmented && this.#info.fin) {
217
219
  const fullMessage = Buffer.concat(this.#fragments)
218
- websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage)
220
+ websocketMessageReceived(this.#handler, this.#info.binaryType, fullMessage)
219
221
  this.#fragments.length = 0
220
222
  }
221
223
 
@@ -223,7 +225,7 @@ class ByteParser extends Writable {
223
225
  } else {
224
226
  this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => {
225
227
  if (error) {
226
- closeWebSocketConnection(this.ws, 1007, error.message, error.message.length)
228
+ closeWebSocketConnection(this.#handler, 1007, error.message, error.message.length)
227
229
  return
228
230
  }
229
231
 
@@ -236,7 +238,7 @@ class ByteParser extends Writable {
236
238
  return
237
239
  }
238
240
 
239
- websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments))
241
+ websocketMessageReceived(this.#handler, this.#info.binaryType, Buffer.concat(this.#fragments))
240
242
 
241
243
  this.#loop = true
242
244
  this.#state = parserStates.INFO
@@ -339,7 +341,7 @@ class ByteParser extends Writable {
339
341
 
340
342
  if (opcode === opcodes.CLOSE) {
341
343
  if (payloadLength === 1) {
342
- failWebsocketConnection(this.ws, 'Received close frame with a 1-byte body.')
344
+ failWebsocketConnection(this.#handler, 'Received close frame with a 1-byte body.')
343
345
  return false
344
346
  }
345
347
 
@@ -348,12 +350,12 @@ class ByteParser extends Writable {
348
350
  if (this.#info.closeInfo.error) {
349
351
  const { code, reason } = this.#info.closeInfo
350
352
 
351
- closeWebSocketConnection(this.ws, code, reason, reason.length)
352
- failWebsocketConnection(this.ws, reason)
353
+ closeWebSocketConnection(this.#handler, code, reason, reason.length)
354
+ failWebsocketConnection(this.#handler, reason)
353
355
  return false
354
356
  }
355
357
 
356
- if (this.ws[kSentClose] !== sentCloseFrameState.SENT) {
358
+ if (this.#handler.closeState !== sentCloseFrameState.SENT) {
357
359
  // If an endpoint receives a Close frame and did not previously send a
358
360
  // Close frame, the endpoint MUST send a Close frame in response. (When
359
361
  // sending a Close frame in response, the endpoint typically echos the
@@ -365,11 +367,11 @@ class ByteParser extends Writable {
365
367
  }
366
368
  const closeFrame = new WebsocketFrameSend(body)
367
369
 
368
- this.ws[kResponse].socket.write(
370
+ this.#handler.socket.write(
369
371
  closeFrame.createFrame(opcodes.CLOSE),
370
372
  (err) => {
371
373
  if (!err) {
372
- this.ws[kSentClose] = sentCloseFrameState.SENT
374
+ this.#handler.closeState = sentCloseFrameState.SENT
373
375
  }
374
376
  }
375
377
  )
@@ -378,8 +380,8 @@ class ByteParser extends Writable {
378
380
  // Upon either sending or receiving a Close control frame, it is said
379
381
  // that _The WebSocket Closing Handshake is Started_ and that the
380
382
  // WebSocket connection is in the CLOSING state.
381
- this.ws[kReadyState] = states.CLOSING
382
- this.ws[kReceivedClose] = true
383
+ this.#handler.readyState = states.CLOSING
384
+ this.#handler.receivedClose = true
383
385
 
384
386
  return false
385
387
  } else if (opcode === opcodes.PING) {
@@ -388,10 +390,10 @@ class ByteParser extends Writable {
388
390
  // A Pong frame sent in response to a Ping frame must have identical
389
391
  // "Application data"
390
392
 
391
- if (!this.ws[kReceivedClose]) {
393
+ if (!this.#handler.receivedClose) {
392
394
  const frame = new WebsocketFrameSend(body)
393
395
 
394
- this.ws[kResponse].socket.write(frame.createFrame(opcodes.PONG))
396
+ this.#handler.socket.write(frame.createFrame(opcodes.PONG))
395
397
 
396
398
  if (channels.ping.hasSubscribers) {
397
399
  channels.ping.publish({
@@ -4,9 +4,6 @@ const { WebsocketFrameSend } = require('./frame')
4
4
  const { opcodes, sendHints } = require('./constants')
5
5
  const FixedQueue = require('../../dispatcher/fixed-queue')
6
6
 
7
- /** @type {typeof Uint8Array} */
8
- const FastBuffer = Buffer[Symbol.species]
9
-
10
7
  /**
11
8
  * @typedef {object} SendQueueNode
12
9
  * @property {Promise<void> | null} promise
@@ -34,16 +31,25 @@ class SendQueue {
34
31
 
35
32
  add (item, cb, hint) {
36
33
  if (hint !== sendHints.blob) {
37
- const frame = createFrame(item, hint)
38
34
  if (!this.#running) {
39
- // fast-path
40
- this.#socket.write(frame, cb)
35
+ // TODO(@tsctx): support fast-path for string on running
36
+ if (hint === sendHints.text) {
37
+ // special fast-path for string
38
+ const { 0: head, 1: body } = WebsocketFrameSend.createFastTextFrame(item)
39
+ this.#socket.cork()
40
+ this.#socket.write(head)
41
+ this.#socket.write(body, cb)
42
+ this.#socket.uncork()
43
+ } else {
44
+ // direct writing
45
+ this.#socket.write(createFrame(item, hint), cb)
46
+ }
41
47
  } else {
42
48
  /** @type {SendQueueNode} */
43
49
  const node = {
44
50
  promise: null,
45
51
  callback: cb,
46
- frame
52
+ frame: createFrame(item, hint)
47
53
  }
48
54
  this.#queue.push(node)
49
55
  }
@@ -86,18 +92,17 @@ class SendQueue {
86
92
  }
87
93
 
88
94
  function createFrame (data, hint) {
89
- return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.string ? opcodes.TEXT : opcodes.BINARY)
95
+ return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.text ? opcodes.TEXT : opcodes.BINARY)
90
96
  }
91
97
 
92
98
  function toBuffer (data, hint) {
93
99
  switch (hint) {
94
- case sendHints.string:
95
- return Buffer.from(data)
100
+ case sendHints.text:
101
+ case sendHints.typedArray:
102
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
96
103
  case sendHints.arrayBuffer:
97
104
  case sendHints.blob:
98
- return new FastBuffer(data)
99
- case sendHints.typedArray:
100
- return new FastBuffer(data.buffer, data.byteOffset, data.byteLength)
105
+ return new Uint8Array(data)
101
106
  }
102
107
  }
103
108
 
@@ -1,51 +1,47 @@
1
1
  'use strict'
2
2
 
3
- const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require('./symbols')
4
3
  const { states, opcodes } = require('./constants')
5
- const { ErrorEvent, createFastMessageEvent } = require('./events')
6
4
  const { isUtf8 } = require('node:buffer')
7
5
  const { collectASequenceOfCodePointsFast, removeHTTPWhitespace } = require('../fetch/data-url')
8
6
 
9
- /* globals Blob */
10
-
11
7
  /**
12
- * @param {import('./websocket').WebSocket} ws
8
+ * @param {number} readyState
13
9
  * @returns {boolean}
14
10
  */
15
- function isConnecting (ws) {
11
+ function isConnecting (readyState) {
16
12
  // If the WebSocket connection is not yet established, and the connection
17
13
  // is not yet closed, then the WebSocket connection is in the CONNECTING state.
18
- return ws[kReadyState] === states.CONNECTING
14
+ return readyState === states.CONNECTING
19
15
  }
20
16
 
21
17
  /**
22
- * @param {import('./websocket').WebSocket} ws
18
+ * @param {number} readyState
23
19
  * @returns {boolean}
24
20
  */
25
- function isEstablished (ws) {
21
+ function isEstablished (readyState) {
26
22
  // If the server's response is validated as provided for above, it is
27
23
  // said that _The WebSocket Connection is Established_ and that the
28
24
  // WebSocket Connection is in the OPEN state.
29
- return ws[kReadyState] === states.OPEN
25
+ return readyState === states.OPEN
30
26
  }
31
27
 
32
28
  /**
33
- * @param {import('./websocket').WebSocket} ws
29
+ * @param {number} readyState
34
30
  * @returns {boolean}
35
31
  */
36
- function isClosing (ws) {
32
+ function isClosing (readyState) {
37
33
  // Upon either sending or receiving a Close control frame, it is said
38
34
  // that _The WebSocket Closing Handshake is Started_ and that the
39
35
  // WebSocket connection is in the CLOSING state.
40
- return ws[kReadyState] === states.CLOSING
36
+ return readyState === states.CLOSING
41
37
  }
42
38
 
43
39
  /**
44
- * @param {import('./websocket').WebSocket} ws
40
+ * @param {number} readyState
45
41
  * @returns {boolean}
46
42
  */
47
- function isClosed (ws) {
48
- return ws[kReadyState] === states.CLOSED
43
+ function isClosed (readyState) {
44
+ return readyState === states.CLOSED
49
45
  }
50
46
 
51
47
  /**
@@ -73,49 +69,12 @@ function fireEvent (e, target, eventFactory = (type, init) => new Event(type, in
73
69
 
74
70
  /**
75
71
  * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
76
- * @param {import('./websocket').WebSocket} ws
72
+ * @param {import('./websocket').Handler} handler
77
73
  * @param {number} type Opcode
78
74
  * @param {Buffer} data application data
79
75
  */
80
- function websocketMessageReceived (ws, type, data) {
81
- // 1. If ready state is not OPEN (1), then return.
82
- if (ws[kReadyState] !== states.OPEN) {
83
- return
84
- }
85
-
86
- // 2. Let dataForEvent be determined by switching on type and binary type:
87
- let dataForEvent
88
-
89
- if (type === opcodes.TEXT) {
90
- // -> type indicates that the data is Text
91
- // a new DOMString containing data
92
- try {
93
- dataForEvent = utf8Decode(data)
94
- } catch {
95
- failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.')
96
- return
97
- }
98
- } else if (type === opcodes.BINARY) {
99
- if (ws[kBinaryType] === 'blob') {
100
- // -> type indicates that the data is Binary and binary type is "blob"
101
- // a new Blob object, created in the relevant Realm of the WebSocket
102
- // object, that represents data as its raw data
103
- dataForEvent = new Blob([data])
104
- } else {
105
- // -> type indicates that the data is Binary and binary type is "arraybuffer"
106
- // a new ArrayBuffer object, created in the relevant Realm of the
107
- // WebSocket object, whose contents are data
108
- dataForEvent = toArrayBuffer(data)
109
- }
110
- }
111
-
112
- // 3. Fire an event named message at the WebSocket object, using MessageEvent,
113
- // with the origin attribute initialized to the serialization of the WebSocket
114
- // object’s url's origin, and the data attribute initialized to dataForEvent.
115
- fireEvent('message', ws, createFastMessageEvent, {
116
- origin: ws[kWebSocketURL].origin,
117
- data: dataForEvent
118
- })
76
+ function websocketMessageReceived (handler, type, data) {
77
+ handler.onMessage(type, data)
119
78
  }
120
79
 
121
80
  function toArrayBuffer (buffer) {
@@ -190,25 +149,11 @@ function isValidStatusCode (code) {
190
149
  }
191
150
 
192
151
  /**
193
- * @param {import('./websocket').WebSocket} ws
152
+ * @param {import('./websocket').Handler} handler
194
153
  * @param {string|undefined} reason
195
154
  */
196
- function failWebsocketConnection (ws, reason) {
197
- const { [kController]: controller, [kResponse]: response } = ws
198
-
199
- controller.abort()
200
-
201
- if (response?.socket && !response.socket.destroyed) {
202
- response.socket.destroy()
203
- }
204
-
205
- if (reason) {
206
- // TODO: process.nextTick
207
- fireEvent('error', ws, (type, init) => new ErrorEvent(type, init), {
208
- error: new Error(reason),
209
- message: reason
210
- })
211
- }
155
+ function failWebsocketConnection (handler, reason) {
156
+ handler.onFail(reason)
212
157
  }
213
158
 
214
159
  /**
@@ -310,5 +255,6 @@ module.exports = {
310
255
  isTextBinaryFrame,
311
256
  isValidOpcode,
312
257
  parseExtensions,
313
- isValidClientWindowBits
258
+ isValidClientWindowBits,
259
+ toArrayBuffer
314
260
  }