websocket13
Advanced tools
Comparing version 1.1.2 to 1.2.0-beta1
@@ -7,3 +7,3 @@ /** | ||
var socket = new WS13.WebSocket('ws://echo.websocket.org', { | ||
var socket = new WS13.WebSocket('ws://127.0.0.1:8080', { | ||
"protocols": ["foo", "bar"] // supported subprotocols | ||
@@ -70,1 +70,3 @@ }); | ||
}); | ||
socket.on('debug', console.log); |
392
lib/base.js
var WS13 = require('./index.js'); | ||
var Extensions = require('websocket-extensions'); | ||
var StreamedOutgoingMessage = require('./StreamedOutgoingMessage.js'); | ||
@@ -13,3 +14,4 @@ var StreamedIncomingMessage = require('./StreamedIncomingMessage.js'); | ||
this.state = WS13.State.Closed; | ||
this.extensions = []; | ||
this.extensions = new Extensions(); | ||
this.extensions.add(require('permessage-deflate')); | ||
this.protocol = null; | ||
@@ -27,2 +29,3 @@ | ||
this._incomingStream = null; // StreamedIncomingMessage object for the current message | ||
this._extensionProcessingOutgoingFrameId = 0; | ||
@@ -53,2 +56,3 @@ this.on('connected', () => { | ||
this._sendControl(WS13.FrameType.Control.Close, buf.flip().toBuffer()); | ||
this._outgoingFrames = []; // empty the queue; we can't send any more data now | ||
this.state = WS13.State.Closing; | ||
@@ -58,3 +62,5 @@ | ||
if (this.state != WS13.State.Closed) { | ||
this._socket.end(); | ||
this._closeExtensions(() => { | ||
this._socket.end(); | ||
}); | ||
} | ||
@@ -114,3 +120,3 @@ }, 5000); | ||
if (this.state == WS13.State.ClosingError) { | ||
this.state = WS13.State.Closing; | ||
this.state = WS13.State.Closed; | ||
return; | ||
@@ -127,2 +133,3 @@ } | ||
this.emit('disconnected', WS13.StatusCode.AbnormalTermination, "Socket closed", state == WS13.State.Closing); | ||
this._closeExtensions(); | ||
}); | ||
@@ -133,2 +140,3 @@ | ||
this.state = WS13.State.ClosingError; | ||
this._closeExtensions(); | ||
this.emit('error', err); | ||
@@ -243,18 +251,14 @@ }); | ||
// We don't have any extensions, so all the RSV bits must be 0 or else we have to bail | ||
if (frame.RSV1 || frame.RSV2 || frame.RSV3) { | ||
var bit = (frame.RSV1 ? 'RSV1' : (frame.RSV2 ? 'RSV2' : 'RSV3')); | ||
this._terminateError(WS13.StatusCode.ProtocolError, "Unexpected reserved bit " + bit + "set"); | ||
return; | ||
var debugMsg = "Got frame " + frame.opcode.toString(16).toUpperCase() + ", " + (frame.FIN ? "FIN, " : ""); | ||
for (var i = 1; i <= 3; i++) { | ||
if (frame['RSV' + i]) { | ||
debugMsg += "RSV" + i + ", "; | ||
} | ||
} | ||
this.emit('debug', "Got frame " + frame.opcode.toString(16).toUpperCase() + ", " + (frame.FIN ? "FIN, " : "") + | ||
(frame.maskKey ? "MASK, " : "") + "payload " + frame.payload.length + " bytes"); | ||
debugMsg += (frame.maskKey ? "MASK, " : "") + "payload " + frame.payload.length + " bytes"; | ||
if ( | ||
this.state != WS13.State.Connected && !( | ||
(this.state == WS13.State.ClosingError || this.state == WS13.State.Closing) && | ||
frame.opcode == WS13.FrameType.Control.Close | ||
) | ||
) { | ||
this.emit('debug', debugMsg); | ||
if (this.state != WS13.State.Connected && !((this.state == WS13.State.ClosingError || this.state == WS13.State.Closing) && frame.opcode == WS13.FrameType.Control.Close)) { | ||
this.emit('debug', "Got frame " + frame.opcode.toString(16) + " while in state " + this.state); | ||
@@ -269,2 +273,8 @@ return; | ||
// Check to make sure RSV bits are valid | ||
if (this.extensions && !this.extensions.validFrameRsv(getExtensionFrame(frame))) { | ||
this._terminateError(WS13.StatusCode.ProtocolError, "Unexpected reserved bit set"); | ||
return; | ||
} | ||
var payload; | ||
@@ -285,54 +295,72 @@ | ||
switch (frame.opcode) { | ||
case WS13.FrameType.Control.Close: | ||
var code = WS13.StatusCode.NoStatusCode; | ||
var reason = ""; | ||
// Run it through extensions | ||
this.extensions.processIncomingMessage(getExtensionMessage(frame), (err, msg) => { | ||
if (err) { | ||
this._terminateError(WS13.StatusCode.ProtocolError, err.message || err); | ||
return; | ||
} | ||
if (frame.payload && frame.payload.length >= 2) { | ||
code = frame.payload.readUInt16BE(0); | ||
frame = fromExtensionMessage(msg); | ||
if (frame.payload.length > 2) { | ||
reason = frame.payload.toString('utf8', 2); | ||
switch (frame.opcode) { | ||
case WS13.FrameType.Control.Close: | ||
var code = WS13.StatusCode.NoStatusCode; | ||
var reason = ""; | ||
if (frame.payload && frame.payload.length >= 2) { | ||
code = frame.payload.readUInt16BE(0); | ||
if (frame.payload.length > 2) { | ||
reason = frame.payload.toString('utf8', 2); | ||
} | ||
} | ||
} | ||
var state = this.state; | ||
var state = this.state; | ||
if (state == WS13.State.Closing || state == WS13.State.ClosingError) { | ||
this._socket.end(); | ||
// We're all done here | ||
} else { | ||
if (code != WS13.StatusCode.NoStatusCode) { | ||
payload = new ByteBuffer(2 + reason.length, ByteBuffer.BIG_ENDIAN); | ||
payload.writeUint16(code); | ||
payload.writeString(reason || ""); | ||
if (state == WS13.State.Closing || state == WS13.State.ClosingError) { | ||
this._closeExtensions(() => { | ||
this._socket.end(); | ||
}); | ||
// We're all done here | ||
} else { | ||
payload = new ByteBuffer(0, ByteBuffer.BIG_ENDIAN); // don't send anything back | ||
if (code != WS13.StatusCode.NoStatusCode) { | ||
payload = new ByteBuffer(2 + reason.length, ByteBuffer.BIG_ENDIAN); | ||
payload.writeUint16(code); | ||
payload.writeString(reason || ""); | ||
} else { | ||
payload = new ByteBuffer(0, ByteBuffer.BIG_ENDIAN); // don't send anything back | ||
} | ||
this._sendControl(WS13.FrameType.Control.Close, payload.flip().toBuffer()); | ||
this._closeExtensions(() => { | ||
this._socket.end(); | ||
}); | ||
} | ||
this._sendControl(WS13.FrameType.Control.Close, payload.flip().toBuffer()); | ||
this._socket.end(); | ||
} | ||
this.state = WS13.State.Closed; | ||
this.state = WS13.State.Closed; | ||
this.emit('disconnected', code, reason, state == WS13.State.Closing); | ||
if (state != WS13.State.ClosingError) { | ||
this.emit('disconnected', code, reason, state == WS13.State.Closing); | ||
} | ||
break; | ||
break; | ||
case WS13.FrameType.Control.Ping: | ||
this._sendControl(WS13.FrameType.Control.Pong, frame.payload); | ||
break; | ||
case WS13.FrameType.Control.Ping: | ||
this._sendControl(WS13.FrameType.Control.Pong, frame.payload); | ||
break; | ||
case WS13.FrameType.Control.Pong: | ||
if (frame.payload && frame.payload.length == 4 && frame.payload.readUInt32BE(0) == this._pingValue) { | ||
this.emit('latency', Date.now() - this._pingTime); | ||
this._pingFailures = 0; | ||
this._queuePing(); | ||
} | ||
case WS13.FrameType.Control.Pong: | ||
if (frame.payload && frame.payload.length == 4 && frame.payload.readUInt32BE(0) == this._pingValue) { | ||
this.emit('latency', Date.now() - this._pingTime); | ||
this._pingFailures = 0; | ||
this._queuePing(); | ||
} | ||
break; | ||
break; | ||
default: | ||
this._terminateError(WS13.StatusCode.UnacceptableDataType, "Unknown control frame type " + frame.opcode.toString(16).toUpperCase()); | ||
} | ||
default: | ||
this._terminateError(WS13.StatusCode.UnacceptableDataType, "Unknown control frame type " + frame.opcode.toString(16).toUpperCase()); | ||
} | ||
}); | ||
@@ -355,3 +383,3 @@ return; | ||
var dispatch = this.listenerCount('streamedMessage') >= 1; | ||
var dispatch = this.listenerCount('streamedMessage') >= 1 && !frame.RSV1 && !frame.RSV2 && !frame.RSV3; | ||
this._incomingStream = new StreamedIncomingMessage(frame, dispatch); | ||
@@ -393,23 +421,32 @@ | ||
WebSocketBase.prototype._dispatchDataFrame = function(frame) { | ||
switch (frame.opcode) { | ||
case WS13.FrameType.Data.Text: | ||
var utf8 = frame.payload.toString('utf8'); | ||
this.extensions.processIncomingMessage(getExtensionMessage(frame), (err, msg) => { | ||
if (err) { | ||
this._terminateError(WS13.StatusCode.ProtocolError, err.message || err); | ||
return; | ||
} | ||
// Check that the UTF-8 is valid | ||
if (Buffer.compare(new Buffer(utf8, 'utf8'), frame.payload) !== 0) { | ||
// This is invalid. We must tear down the connection. | ||
this._terminateError(WS13.StatusCode.InconsistentData, "Received invalid UTF-8 data in a text frame."); | ||
return; | ||
} | ||
frame = fromExtensionMessage(msg); | ||
this.emit('message', WS13.FrameType.Data.Text, utf8); | ||
break; | ||
switch (frame.opcode) { | ||
case WS13.FrameType.Data.Text: | ||
var utf8 = frame.payload.toString('utf8'); | ||
case WS13.FrameType.Data.Binary: | ||
this.emit('message', WS13.FrameType.Data.Binary, frame.payload); | ||
break; | ||
// Check that the UTF-8 is valid | ||
if (Buffer.compare(new Buffer(utf8, 'utf8'), frame.payload) !== 0) { | ||
// This is invalid. We must tear down the connection. | ||
this._terminateError(WS13.StatusCode.InconsistentData, "Received invalid UTF-8 data in a text frame."); | ||
return; | ||
} | ||
default: | ||
this._terminateError(WS13.StatusCode.UnacceptableDataType, "Unknown data frame type " + frame.opcode.toString(16).toUpperCase()); | ||
} | ||
this.emit('message', WS13.FrameType.Data.Text, utf8); | ||
break; | ||
case WS13.FrameType.Data.Binary: | ||
this.emit('message', WS13.FrameType.Data.Binary, frame.payload); | ||
break; | ||
default: | ||
this._terminateError(WS13.StatusCode.UnacceptableDataType, "Unknown data frame type " + frame.opcode.toString(16).toUpperCase()); | ||
} | ||
}); | ||
}; | ||
@@ -429,2 +466,6 @@ | ||
if (isControl) { | ||
if (frame.payload && frame.payload.length > 125) { | ||
throw new Error("Cannot send control frame " + frame.opcode.toString(16).toUpperCase() + " with " + frame.payload.length + " bytes of payload data. Payload must be 125 bytes or fewer."); | ||
} | ||
bypassQueue = true; // we can send control messages whenever | ||
@@ -434,88 +475,139 @@ } | ||
frame.payload = frame.payload || new Buffer(0); | ||
var maskKey = frame.maskKey; | ||
var fin = frame.FIN; | ||
if (frame.payload.length == 0) { | ||
frame.maskKey = null; | ||
frame.maskKey = maskKey = null; | ||
} | ||
this.emit('debug', (bypassQueue ? "Sending" : "Queueing") + " frame " + frame.opcode.toString(16).toUpperCase() + ", " + (frame.FIN ? "FIN, " : "") + | ||
(frame.maskKey ? "MASK, " : "") + "payload " + frame.payload.length + " bytes"); | ||
if (isControl || !frame.FIN || frame.opcode == 0) { | ||
// https://github.com/faye/permessage-deflate-node/issues/6 | ||
onExtensionsProcessed.call(this, frame); | ||
} else { | ||
if (!bypassQueue) { | ||
var queueId = ++this._extensionProcessingOutgoingFrameId; | ||
this._outgoingFrames.push(queueId); | ||
var size = 0; | ||
size += 1; // FIN, RSV1, RSV2, RSV3, opcode | ||
size += 1; // MASK, payload length | ||
if (queueId >= 4294967295) { | ||
// just for fun. this is unlikely to ever really happen. 4294967295 is max uint32 and is totally arbitrary, we can go up to 2^53 | ||
this._extensionProcessingOutgoingFrameId = 0; | ||
} | ||
} | ||
if (frame.payload.length >= 126 && frame.payload.length <= 65535) { | ||
size += 2; // 16-bit payload length | ||
} else if (frame.payload.length > 65535) { | ||
size += 8; // 64-bit payload length | ||
} | ||
this.extensions.processOutgoingMessage(getExtensionMessage(frame), (err, msg) => { | ||
if (err) { | ||
this._terminateError(WS13.StatusCode.ProtocolError, err.message || err); | ||
return; | ||
} | ||
if (frame.maskKey) { | ||
size += 4; | ||
frame = fromExtensionMessage(msg); | ||
frame.maskKey = maskKey; | ||
frame.FIN = fin; | ||
onExtensionsProcessed.call(this, frame); | ||
}); | ||
} | ||
size += frame.payload.length; | ||
function onExtensionsProcessed(frame) { | ||
var debugMsg = (bypassQueue ? "Sending" : "Queueing") + " frame " + frame.opcode.toString(16).toUpperCase() + ", " + (frame.FIN ? "FIN, " : ""); | ||
for (var i = 1; i <= 3; i++) { | ||
if (frame['RSV' + i]) { | ||
debugMsg += "RSV" + i + ", "; | ||
} | ||
} | ||
var buf = new ByteBuffer(size, ByteBuffer.BIG_ENDIAN); | ||
var byte = 0; | ||
debugMsg += (frame.maskKey ? "MASK, " : "") + "payload " + frame.payload.length + " bytes"; | ||
this.emit('debug', debugMsg); | ||
byte |= (frame.FIN ? 1 : 0) << 7; | ||
byte |= (frame.RSV1 ? 1 : 0) << 6; | ||
byte |= (frame.RSV2 ? 1 : 0) << 5; | ||
byte |= (frame.RSV3 ? 1 : 0) << 4; | ||
byte |= frame.opcode & 0x0F; | ||
buf.writeUint8(byte); | ||
var size = 0; | ||
size += 1; // FIN, RSV1, RSV2, RSV3, opcode | ||
size += 1; // MASK, payload length | ||
byte = 0; | ||
byte |= (frame.maskKey ? 1 : 0) << 7; | ||
if (frame.payload.length >= 126 && frame.payload.length <= 65535) { | ||
size += 2; // 16-bit payload length | ||
} else if (frame.payload.length > 65535) { | ||
size += 8; // 64-bit payload length | ||
} | ||
if (frame.payload.length <= 125) { | ||
byte |= frame.payload.length; | ||
if (frame.maskKey) { | ||
size += 4; | ||
} | ||
size += frame.payload.length; | ||
var buf = new ByteBuffer(size, ByteBuffer.BIG_ENDIAN); | ||
var byte = 0; | ||
byte |= (frame.FIN ? 1 : 0) << 7; | ||
byte |= (frame.RSV1 ? 1 : 0) << 6; | ||
byte |= (frame.RSV2 ? 1 : 0) << 5; | ||
byte |= (frame.RSV3 ? 1 : 0) << 4; | ||
byte |= frame.opcode & 0x0F; | ||
buf.writeUint8(byte); | ||
} else if (frame.payload.length <= 65535) { | ||
byte |= 126; | ||
buf.writeUint8(byte); | ||
buf.writeUint16(frame.payload.length); | ||
} else { | ||
byte |= 127; | ||
buf.writeUint8(byte); | ||
buf.writeUint64(frame.payload.length); | ||
} | ||
if (frame.maskKey) { | ||
buf.writeUint32(frame.maskKey); | ||
buf.append(maskOrUnmask(frame.payload, frame.maskKey)); | ||
} else { | ||
buf.append(frame.payload); | ||
} | ||
byte = 0; | ||
byte |= (frame.maskKey ? 1 : 0) << 7; | ||
if (bypassQueue) { | ||
this._socket.write(buf.flip().toBuffer()); | ||
} else { | ||
this._outgoingFrames.push(buf.flip().toBuffer()); | ||
if (frame.payload.length <= 125) { | ||
byte |= frame.payload.length; | ||
buf.writeUint8(byte); | ||
} else if (frame.payload.length <= 65535) { | ||
byte |= 126; | ||
buf.writeUint8(byte); | ||
buf.writeUint16(frame.payload.length); | ||
} else { | ||
byte |= 127; | ||
buf.writeUint8(byte); | ||
buf.writeUint64(frame.payload.length); | ||
} | ||
if (frame.maskKey) { | ||
buf.writeUint32(frame.maskKey); | ||
buf.append(maskOrUnmask(frame.payload, frame.maskKey)); | ||
} else { | ||
buf.append(frame.payload); | ||
} | ||
if (bypassQueue) { | ||
this._socket.write(buf.flip().toBuffer()); | ||
} else if (queueId) { | ||
// This already has a placeholder in the queue | ||
var idx = this._outgoingFrames.indexOf(queueId); | ||
if (idx == -1) { | ||
this._outgoingFrames.push(buf.flip().toBuffer()); | ||
} else { | ||
this._outgoingFrames[idx] = buf.flip().toBuffer(); | ||
} | ||
} else { | ||
// No queue placeholder, just stick it in | ||
this._outgoingFrames.push(buf.flip().toBuffer()); | ||
} | ||
this._processQueue(); | ||
} | ||
this._processQueue(); | ||
}; | ||
WebSocketBase.prototype._processQueue = function() { | ||
var frame; | ||
var frames = this._outgoingFrames.slice(0); | ||
while (frames.length > 0) { | ||
frame = frames.splice(0, 1)[0]; | ||
if (typeof frames[0] === 'number') { | ||
// This is a placeholder, so we're done | ||
console.log("Abandonining queue as we hit " + frames[0]); | ||
break; | ||
} | ||
if (frame instanceof StreamedOutgoingMessage) { | ||
if (!frame.started) { | ||
if (frames[0] instanceof StreamedOutgoingMessage) { | ||
if (!frames[0].started) { | ||
this.emit('debug', "Starting StreamedOutgoingMessage"); | ||
frame._start(); | ||
frames[0]._start(); | ||
} | ||
if (frame.finished) { | ||
if (frames[0].finished) { | ||
frames.splice(0, 1); | ||
continue; | ||
} | ||
return; | ||
break; | ||
} | ||
this._socket.write(frame); | ||
this._socket.write(frames.splice(0, 1)[0]); | ||
} | ||
@@ -545,2 +637,3 @@ | ||
this.state = WS13.State.Closed; | ||
this._closeExtensions(); | ||
@@ -564,5 +657,14 @@ if (this._socket) { | ||
err.code = code; | ||
this.state = WS13.State.ClosingError; | ||
this.emit('error', err); | ||
}; | ||
WebSocketBase.prototype._closeExtensions = function(callback) { | ||
try { | ||
this.extensions.close(callback); | ||
} catch (ex) { | ||
callback(); | ||
} | ||
}; | ||
// Util | ||
@@ -578,2 +680,36 @@ function maskOrUnmask(data, maskKey) { | ||
return data; | ||
} | ||
} | ||
function getExtensionFrame(frame) { | ||
return { | ||
"final": frame.FIN, | ||
"rsv1": frame.RSV1, | ||
"rsv2": frame.RSV2, | ||
"rsv3": frame.RSV3, | ||
"opcode": frame.opcode, | ||
"masked": !!frame.maskKey, | ||
"maskingKey": frame.maskKey, | ||
"payload": frame.payload | ||
}; | ||
} | ||
function getExtensionMessage(frame) { | ||
return { | ||
"rsv1": frame.RSV1, | ||
"rsv2": frame.RSV2, | ||
"rsv3": frame.RSV3, | ||
"opcode": frame.opcode, | ||
"data": frame.payload | ||
}; | ||
} | ||
function fromExtensionMessage(msg) { | ||
return { | ||
"FIN": true, | ||
"RSV1": msg.rsv1, | ||
"RSV2": msg.rsv2, | ||
"RSV3": msg.rsv3, | ||
"opcode": msg.opcode, | ||
"payload": msg.data | ||
}; | ||
} |
@@ -67,2 +67,11 @@ var WS13 = require('./index.js'); | ||
if (this.options.extensions) { | ||
this.extensions = this.options.extensions; | ||
} | ||
var extOffer = this.extensions.generateOffer(); | ||
if (extOffer) { | ||
this.headers['sec-websocket-extensions'] = extOffer; | ||
} | ||
if (this.options.protocols) { | ||
@@ -163,14 +172,2 @@ this.options.protocols = this.options.protocols.map(protocol => protocol.trim().toLowerCase()); | ||
if (headers['sec-websocket-extensions']) { | ||
var extensions = headers['sec-websocket-extensions'].split(',').map(item => item.trim().toLowerCase()); | ||
var unsupported = extensions.filter(extension => this.extensions.indexOf(extension) == -1); | ||
if (unsupported.length > 0) { | ||
err.message = "Server is using unsupported extension" + (unsupported.length > 1 ? "s" : "") + unsupported.join(', '); | ||
this._closeError(err); | ||
return; | ||
} | ||
this.extensions = extensions; | ||
} | ||
if (headers['sec-websocket-protocol']) { | ||
@@ -187,2 +184,10 @@ var protocol = headers['sec-websocket-protocol'].toLowerCase(); | ||
try { | ||
this.extensions.activate(headers['sec-websocket-extensions']); | ||
} catch (ex) { | ||
err.message = ex.message; | ||
this._closeError(err); | ||
return; | ||
} | ||
this._socket = socket; | ||
@@ -189,0 +194,0 @@ this._prepSocketEvents(); |
var WS13 = require('./index.js'); | ||
var Extensions = require('websocket-extensions'); | ||
var WebSocketBase = require('./base.js'); | ||
@@ -79,2 +80,6 @@ var HTTPStatusCodes = require('../resources/HTTPStatusCodes.json'); | ||
var extensions = new Extensions(); | ||
extensions.add(require('permessage-deflate')); | ||
var selectedExtensions = extensions.generateResponse(req.headers['sec-websocket-extensions']); | ||
var handshakeData = { | ||
@@ -86,4 +91,5 @@ "path": uri.pathname, | ||
"origin": req.headers.origin || null, | ||
"extensions": [], | ||
"selectedExtensions": [], | ||
"extensions": req.headers['sec-websocket-extensions'], | ||
"extensionsHandler": extensions, | ||
"selectedExtensions": selectedExtensions, | ||
"protocols": protocols || [], | ||
@@ -129,2 +135,9 @@ "selectedProtocol": selectedProtocol || null, | ||
var options = { | ||
"pingInterval": this.options.pingInterval, | ||
"pingTimeout": this.options.pingTimeout, | ||
"pingFailures": this.options.pingFailures, | ||
"extensions": extensions | ||
}; | ||
headers.Upgrade = "websocket"; | ||
@@ -139,2 +152,11 @@ headers.Connection = "Upgrade"; | ||
if (response.extensions) { | ||
options.extensions = extensions = response.extensions; | ||
selectedExtensions = extensions.generateResponse(req.headers['sec-websocket-extensions']); | ||
} | ||
if (selectedExtensions) { | ||
headers['Sec-WebSocket-Extensions'] = selectedExtensions; | ||
} | ||
if (handshakeData.selectedProtocol) { | ||
@@ -146,8 +168,2 @@ headers['Sec-WebSocket-Protocol'] = handshakeData.selectedProtocol; | ||
var options = { | ||
"pingInterval": this.options.pingInterval, | ||
"pingTimeout": this.options.pingTimeout, | ||
"pingFailures": this.options.pingFailures | ||
}; | ||
response.options = response.options || {}; | ||
@@ -217,3 +233,3 @@ for (var i in response.options) { | ||
this.handshakeData = handshakeData; | ||
this.extensions = handshakeData.selectedExtensions || []; | ||
this.extensions = options.extensions; | ||
this.protocol = handshakeData.selectedProtocol || null; | ||
@@ -220,0 +236,0 @@ |
{ | ||
"name": "websocket13", | ||
"version": "1.1.2", | ||
"version": "1.2.0-beta1", | ||
"description": "Simple WebSocket protocol 13 client with no native or heavy dependencies", | ||
@@ -28,3 +28,5 @@ "author": "Alexander Corn <mckay@doctormckay.com>", | ||
"dependencies": { | ||
"bytebuffer": "^5.0.0" | ||
"bytebuffer": "^5.0.0", | ||
"websocket-extensions": "^0.1.1", | ||
"permessage-deflate": "^0.1.5" | ||
}, | ||
@@ -31,0 +33,0 @@ "engines": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
96732
1276
3
1
+ Addedpermessage-deflate@^0.1.5
+ Addedwebsocket-extensions@^0.1.1
+ Addedpermessage-deflate@0.1.7(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedwebsocket-extensions@0.1.4(transitive)