socket.io
Advanced tools
Comparing version 3.0.0-rc2 to 3.0.0-rc3
@@ -0,1 +1,35 @@ | ||
# [3.0.0-rc3](https://github.com/socketio/socket.io/compare/3.0.0-rc2...3.0.0-rc3) (2020-10-26) | ||
### Features | ||
* add support for catch-all listeners ([5c73733](https://github.com/socketio/socket.io/commit/5c737339858d59eab4b5ee2dd6feff0e82c4fe5a)) | ||
* make Socket#join() and Socket#leave() synchronous ([129c641](https://github.com/socketio/socket.io/commit/129c6417bd818bc8b4e1b831644323876e627c13)) | ||
* remove prod dependency to socket.io-client ([7603da7](https://github.com/socketio/socket.io/commit/7603da71a535481e3fc60e38b013abf78516d322)) | ||
### BREAKING CHANGES | ||
* the Socket#use() method is removed (see [5c73733](https://github.com/socketio/socket.io/commit/5c737339858d59eab4b5ee2dd6feff0e82c4fe5a)) | ||
* Socket#join() and Socket#leave() do not accept a callback argument anymore. | ||
Before: | ||
```js | ||
socket.join("room1", () => { | ||
io.to("room1").emit("hello"); | ||
}); | ||
``` | ||
After: | ||
```js | ||
socket.join("room1"); | ||
io.to("room1").emit("hello"); | ||
// or await socket.join("room1"); for custom adapters | ||
``` | ||
# [3.0.0-rc2](https://github.com/socketio/socket.io/compare/3.0.0-rc1...3.0.0-rc2) (2020-10-15) | ||
@@ -2,0 +36,0 @@ |
@@ -78,3 +78,3 @@ "use strict"; | ||
this._packet({ | ||
type: socket_io_parser_1.PacketType.ERROR, | ||
type: socket_io_parser_1.PacketType.CONNECT_ERROR, | ||
nsp: name, | ||
@@ -81,0 +81,0 @@ data: "Invalid namespace" |
@@ -142,2 +142,3 @@ /// <reference types="node" /> | ||
private _path; | ||
private clientPathRegex; | ||
/** | ||
@@ -238,3 +239,3 @@ * @private | ||
/** | ||
* Handles a request serving `/socket.io.js` | ||
* Handles a request serving of client source and map | ||
* | ||
@@ -247,9 +248,8 @@ * @param {http.IncomingMessage} req | ||
/** | ||
* Handles a request serving `/socket.io.js.map` | ||
* | ||
* @param {http.IncomingMessage} req | ||
* @param {http.ServerResponse} res | ||
* @param filename | ||
* @param req | ||
* @param res | ||
* @private | ||
*/ | ||
private serveMap; | ||
private static sendFile; | ||
/** | ||
@@ -354,2 +354,2 @@ * Binds socket.io to an engine.io instance. | ||
} | ||
export {}; | ||
export { Socket }; |
@@ -25,5 +25,8 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Server = void 0; | ||
exports.Socket = exports.Server = void 0; | ||
const http_1 = __importDefault(require("http")); | ||
const fs_1 = require("fs"); | ||
const zlib_1 = require("zlib"); | ||
const accepts = require("accepts"); | ||
const stream_1 = require("stream"); | ||
const path_1 = __importDefault(require("path")); | ||
@@ -38,9 +41,7 @@ const engine_io_1 = __importDefault(require("engine.io")); | ||
const debug_1 = __importDefault(require("debug")); | ||
const socket_1 = require("./socket"); | ||
Object.defineProperty(exports, "Socket", { enumerable: true, get: function () { return socket_1.Socket; } }); | ||
const debug = debug_1.default("socket.io:server"); | ||
const clientVersion = require("socket.io-client/package.json").version; | ||
/** | ||
* Socket.IO client source. | ||
*/ | ||
let clientSource = undefined; | ||
let clientSourceMap = undefined; | ||
const clientVersion = require("../package.json").version; | ||
const dotMapRegex = /\.map/; | ||
class Server extends events_1.EventEmitter { | ||
@@ -72,18 +73,2 @@ constructor(srv, opts = {}) { | ||
this._serveClient = v; | ||
const resolvePath = function (file) { | ||
const filepath = path_1.default.resolve(__dirname, "./../../", file); | ||
if (fs_1.existsSync(filepath)) { | ||
return filepath; | ||
} | ||
return require.resolve(file); | ||
}; | ||
if (v && !clientSource) { | ||
clientSource = fs_1.readFileSync(resolvePath("socket.io-client/dist/socket.io.js"), "utf-8"); | ||
try { | ||
clientSourceMap = fs_1.readFileSync(resolvePath("socket.io-client/dist/socket.io.js.map"), "utf-8"); | ||
} | ||
catch (err) { | ||
debug("could not load sourcemap file"); | ||
} | ||
} | ||
return this; | ||
@@ -124,2 +109,4 @@ } | ||
this._path = v.replace(/\/$/, ""); | ||
const escapedPath = this._path.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); | ||
this.clientPathRegex = new RegExp("^" + escapedPath + "/socket\\.io(\\.min)?\\.js(\\.map)?$"); | ||
return this; | ||
@@ -196,14 +183,8 @@ } | ||
debug("attaching client serving req handler"); | ||
const url = this._path + "/socket.io.js"; | ||
const urlMap = this._path + "/socket.io.js.map"; | ||
const evs = srv.listeners("request").slice(0); | ||
const self = this; | ||
srv.removeAllListeners("request"); | ||
srv.on("request", function (req, res) { | ||
if (0 === req.url.indexOf(urlMap)) { | ||
self.serveMap(req, res); | ||
srv.on("request", (req, res) => { | ||
if (this.clientPathRegex.test(req.url)) { | ||
this.serve(req, res); | ||
} | ||
else if (0 === req.url.indexOf(url)) { | ||
self.serve(req, res); | ||
} | ||
else { | ||
@@ -217,3 +198,3 @@ for (let i = 0; i < evs.length; i++) { | ||
/** | ||
* Handles a request serving `/socket.io.js` | ||
* Handles a request serving of client source and map | ||
* | ||
@@ -225,2 +206,5 @@ * @param {http.IncomingMessage} req | ||
serve(req, res) { | ||
const filename = req.url.replace(this._path, ""); | ||
const isMap = dotMapRegex.test(filename); | ||
const type = isMap ? "map" : "source"; | ||
// Per the standard, ETags must be quoted: | ||
@@ -232,3 +216,3 @@ // https://tools.ietf.org/html/rfc7232#section-2.3 | ||
if (expectedEtag == etag) { | ||
debug("serve client 304"); | ||
debug("serve client %s 304", type); | ||
res.writeHead(304); | ||
@@ -239,34 +223,43 @@ res.end(); | ||
} | ||
debug("serve client source"); | ||
debug("serve client %s", type); | ||
res.setHeader("Cache-Control", "public, max-age=0"); | ||
res.setHeader("Content-Type", "application/javascript"); | ||
res.setHeader("Content-Type", "application/" + (isMap ? "json" : "javascript")); | ||
res.setHeader("ETag", expectedEtag); | ||
res.writeHead(200); | ||
res.end(clientSource); | ||
if (!isMap) { | ||
res.setHeader("X-SourceMap", filename.substring(1) + ".map"); | ||
} | ||
Server.sendFile(filename, req, res); | ||
} | ||
/** | ||
* Handles a request serving `/socket.io.js.map` | ||
* | ||
* @param {http.IncomingMessage} req | ||
* @param {http.ServerResponse} res | ||
* @param filename | ||
* @param req | ||
* @param res | ||
* @private | ||
*/ | ||
serveMap(req, res) { | ||
// Per the standard, ETags must be quoted: | ||
// https://tools.ietf.org/html/rfc7232#section-2.3 | ||
const expectedEtag = '"' + clientVersion + '"'; | ||
const etag = req.headers["if-none-match"]; | ||
if (etag) { | ||
if (expectedEtag == etag) { | ||
debug("serve client 304"); | ||
res.writeHead(304); | ||
static sendFile(filename, req, res) { | ||
const readStream = fs_1.createReadStream(path_1.default.join(__dirname, "../client-dist/", filename)); | ||
const encoding = accepts(req).encodings(["br", "gzip", "deflate"]); | ||
const onError = err => { | ||
if (err) { | ||
res.end(); | ||
return; | ||
} | ||
}; | ||
switch (encoding) { | ||
case "br": | ||
res.writeHead(200, { "content-encoding": "br" }); | ||
readStream.pipe(zlib_1.createBrotliCompress()).pipe(res); | ||
stream_1.pipeline(readStream, zlib_1.createBrotliCompress(), res, onError); | ||
break; | ||
case "gzip": | ||
res.writeHead(200, { "content-encoding": "gzip" }); | ||
stream_1.pipeline(readStream, zlib_1.createGzip(), res, onError); | ||
break; | ||
case "deflate": | ||
res.writeHead(200, { "content-encoding": "deflate" }); | ||
stream_1.pipeline(readStream, zlib_1.createDeflate(), res, onError); | ||
break; | ||
default: | ||
res.writeHead(200); | ||
stream_1.pipeline(readStream, res, onError); | ||
} | ||
debug("serve client sourcemap"); | ||
res.setHeader("Content-Type", "application/json"); | ||
res.setHeader("ETag", expectedEtag); | ||
res.writeHead(200); | ||
res.end(clientSourceMap); | ||
} | ||
@@ -273,0 +266,0 @@ /** |
@@ -62,2 +62,3 @@ /// <reference types="node" /> | ||
private _rooms; | ||
private _anyListeners; | ||
/** | ||
@@ -127,7 +128,6 @@ * Interface to a `Client` for a given `Namespace`. | ||
* @param {String|Array} rooms - room or array of rooms | ||
* @param {Function} fn - optional, callback | ||
* @return {Socket} self | ||
* @return a Promise or nothing, depending on the adapter | ||
* @public | ||
*/ | ||
join(rooms: Room | Array<Room>, fn?: (err: Error) => void): Socket; | ||
join(rooms: Room | Array<Room>): Promise<void> | void; | ||
/** | ||
@@ -137,7 +137,6 @@ * Leaves a room. | ||
* @param {String} room | ||
* @param {Function} fn - optional, callback | ||
* @return {Socket} self | ||
* @return a Promise or nothing, depending on the adapter | ||
* @public | ||
*/ | ||
leave(room: string, fn?: (err: Error) => void): Socket; | ||
leave(room: string): Promise<void> | void; | ||
/** | ||
@@ -256,40 +255,47 @@ * Leave all rooms. | ||
/** | ||
* Dispatch incoming event to socket listeners. | ||
* A reference to the request that originated the underlying Engine.IO Socket. | ||
* | ||
* @param {Array} event - event that will get emitted | ||
* @private | ||
* @public | ||
*/ | ||
private dispatch; | ||
get request(): IncomingMessage; | ||
/** | ||
* Sets up socket middleware. | ||
* A reference to the underlying Client transport connection (Engine.IO Socket object). | ||
* | ||
* @param {Function} fn - middleware function (event, next) | ||
* @return {Socket} self | ||
* @public | ||
*/ | ||
use(fn: (event: Array<any>, next: (err: Error) => void) => void): Socket; | ||
get conn(): any; | ||
/** | ||
* Executes the middleware for an incoming event. | ||
* @public | ||
*/ | ||
get rooms(): Set<Room>; | ||
/** | ||
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | ||
* callback. | ||
* | ||
* @param {Array} event - event that will get emitted | ||
* @param {Function} fn - last fn call in the middleware | ||
* @private | ||
* @param listener | ||
* @public | ||
*/ | ||
private run; | ||
onAny(listener: (...args: any[]) => void): Socket; | ||
/** | ||
* A reference to the request that originated the underlying Engine.IO Socket. | ||
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | ||
* callback. The listener is added to the beginning of the listeners array. | ||
* | ||
* @param listener | ||
* @public | ||
*/ | ||
get request(): IncomingMessage; | ||
prependAny(listener: (...args: any[]) => void): Socket; | ||
/** | ||
* A reference to the underlying Client transport connection (Engine.IO Socket object). | ||
* Removes the listener that will be fired when any event is emitted. | ||
* | ||
* @param listener | ||
* @public | ||
*/ | ||
get conn(): any; | ||
offAny(listener?: (...args: any[]) => void): Socket; | ||
/** | ||
* Returns an array of listeners that are listening for any event that is specified. This array can be manipulated, | ||
* e.g. to remove listeners. | ||
* | ||
* @public | ||
*/ | ||
get rooms(): Set<Room>; | ||
listenersAny(): ((...args: any[]) => void)[]; | ||
} |
@@ -14,4 +14,4 @@ "use strict"; | ||
exports.RESERVED_EVENTS = new Set([ | ||
"error", | ||
"connect", | ||
"connect_error", | ||
"disconnect", | ||
@@ -169,12 +169,8 @@ "disconnecting", | ||
* @param {String|Array} rooms - room or array of rooms | ||
* @param {Function} fn - optional, callback | ||
* @return {Socket} self | ||
* @return a Promise or nothing, depending on the adapter | ||
* @public | ||
*/ | ||
join(rooms, fn) { | ||
debug("joining room %s", rooms); | ||
this.adapter.addAll(this.id, new Set(Array.isArray(rooms) ? rooms : [rooms])); | ||
debug("joined room %s", rooms); | ||
fn && fn(null); | ||
return this; | ||
join(rooms) { | ||
debug("join room %s", rooms); | ||
return this.adapter.addAll(this.id, new Set(Array.isArray(rooms) ? rooms : [rooms])); | ||
} | ||
@@ -185,12 +181,8 @@ /** | ||
* @param {String} room | ||
* @param {Function} fn - optional, callback | ||
* @return {Socket} self | ||
* @return a Promise or nothing, depending on the adapter | ||
* @public | ||
*/ | ||
leave(room, fn) { | ||
leave(room) { | ||
debug("leave room %s", room); | ||
this.adapter.del(this.id, room); | ||
debug("left room %s", room); | ||
fn && fn(null); | ||
return this; | ||
return this.adapter.del(this.id, room); | ||
} | ||
@@ -242,3 +234,3 @@ /** | ||
break; | ||
case socket_io_parser_1.PacketType.ERROR: | ||
case socket_io_parser_1.PacketType.CONNECT_ERROR: | ||
this._onerror(new Error(packet.data)); | ||
@@ -260,3 +252,9 @@ } | ||
} | ||
this.dispatch(args); | ||
if (this._anyListeners && this._anyListeners.length) { | ||
const listeners = this._anyListeners.slice(); | ||
for (const listener of listeners) { | ||
listener.apply(this, args); | ||
} | ||
} | ||
super.emit.apply(this, args); | ||
} | ||
@@ -353,3 +351,3 @@ /** | ||
_error(err) { | ||
this.packet({ type: socket_io_parser_1.PacketType.ERROR, data: err }); | ||
this.packet({ type: socket_io_parser_1.PacketType.CONNECT_ERROR, data: err }); | ||
} | ||
@@ -421,77 +419,81 @@ /** | ||
/** | ||
* Dispatch incoming event to socket listeners. | ||
* A reference to the request that originated the underlying Engine.IO Socket. | ||
* | ||
* @param {Array} event - event that will get emitted | ||
* @private | ||
* @public | ||
*/ | ||
dispatch(event) { | ||
debug("dispatching an event %j", event); | ||
this.run(event, err => { | ||
process.nextTick(() => { | ||
if (err) { | ||
return this._error(err.message); | ||
} | ||
super.emit.apply(this, event); | ||
}); | ||
}); | ||
get request() { | ||
return this.client.request; | ||
} | ||
/** | ||
* Sets up socket middleware. | ||
* A reference to the underlying Client transport connection (Engine.IO Socket object). | ||
* | ||
* @param {Function} fn - middleware function (event, next) | ||
* @return {Socket} self | ||
* @public | ||
*/ | ||
use(fn) { | ||
this.fns.push(fn); | ||
return this; | ||
get conn() { | ||
return this.client.conn; | ||
} | ||
/** | ||
* Executes the middleware for an incoming event. | ||
* @public | ||
*/ | ||
get rooms() { | ||
return this.adapter.socketRooms(this.id) || new Set(); | ||
} | ||
/** | ||
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | ||
* callback. | ||
* | ||
* @param {Array} event - event that will get emitted | ||
* @param {Function} fn - last fn call in the middleware | ||
* @private | ||
* @param listener | ||
* @public | ||
*/ | ||
run(event, fn) { | ||
const fns = this.fns.slice(0); | ||
if (!fns.length) | ||
return fn(null); | ||
function run(i) { | ||
fns[i](event, function (err) { | ||
// upon error, short-circuit | ||
if (err) | ||
return fn(err); | ||
// if no middleware left, summon callback | ||
if (!fns[i + 1]) | ||
return fn(null); | ||
// go on to next | ||
run(i + 1); | ||
}); | ||
} | ||
run(0); | ||
onAny(listener) { | ||
this._anyListeners = this._anyListeners || []; | ||
this._anyListeners.push(listener); | ||
return this; | ||
} | ||
/** | ||
* A reference to the request that originated the underlying Engine.IO Socket. | ||
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | ||
* callback. The listener is added to the beginning of the listeners array. | ||
* | ||
* @param listener | ||
* @public | ||
*/ | ||
get request() { | ||
return this.client.request; | ||
prependAny(listener) { | ||
this._anyListeners = this._anyListeners || []; | ||
this._anyListeners.unshift(listener); | ||
return this; | ||
} | ||
/** | ||
* A reference to the underlying Client transport connection (Engine.IO Socket object). | ||
* Removes the listener that will be fired when any event is emitted. | ||
* | ||
* @param listener | ||
* @public | ||
*/ | ||
get conn() { | ||
return this.client.conn; | ||
offAny(listener) { | ||
if (!this._anyListeners) { | ||
return this; | ||
} | ||
if (listener) { | ||
const listeners = this._anyListeners; | ||
for (let i = 0; i < listeners.length; i++) { | ||
if (listener === listeners[i]) { | ||
listeners.splice(i, 1); | ||
return this; | ||
} | ||
} | ||
} | ||
else { | ||
this._anyListeners = []; | ||
} | ||
return this; | ||
} | ||
/** | ||
* Returns an array of listeners that are listening for any event that is specified. This array can be manipulated, | ||
* e.g. to remove listeners. | ||
* | ||
* @public | ||
*/ | ||
get rooms() { | ||
return this.adapter.socketRooms(this.id) || new Set(); | ||
listenersAny() { | ||
return this._anyListeners || []; | ||
} | ||
} | ||
exports.Socket = Socket; |
{ | ||
"name": "socket.io", | ||
"version": "3.0.0-rc2", | ||
"version": "3.0.0-rc3", | ||
"description": "node.js realtime framework server", | ||
@@ -37,8 +37,8 @@ "keywords": [ | ||
"dependencies": { | ||
"accepts": "~1.3.4", | ||
"base64id": "~2.0.0", | ||
"debug": "~4.1.0", | ||
"engine.io": "~4.0.0", | ||
"socket.io-adapter": "2.0.3-rc1", | ||
"socket.io-client": "3.0.0-rc2", | ||
"socket.io-parser": "4.0.1-rc2" | ||
"socket.io-adapter": "2.0.3-rc2", | ||
"socket.io-parser": "4.0.1-rc3" | ||
}, | ||
@@ -57,2 +57,3 @@ "devDependencies": { | ||
"prettier": "^1.19.1", | ||
"socket.io-client": "3.0.0-rc3", | ||
"superagent": "^3.8.2", | ||
@@ -59,0 +60,0 @@ "supertest": "^3.0.0", |
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
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
90817
2371
1
16
+ Addedaccepts@~1.3.4
+ Addedsocket.io-adapter@2.0.3-rc2(transitive)
+ Addedsocket.io-parser@4.0.1-rc3(transitive)
- Removedsocket.io-client@3.0.0-rc2
- Removed@types/component-emitter@1.2.14(transitive)
- Removedbacko2@1.0.2(transitive)
- Removedcomponent-bind@1.0.0(transitive)
- Removedengine.io-client@4.0.6(transitive)
- Removedhas-cors@1.1.0(transitive)
- Removedparseqs@0.0.6(transitive)
- Removedparseuri@0.0.6(transitive)
- Removedsocket.io-adapter@2.0.3-rc1(transitive)
- Removedsocket.io-client@3.0.0-rc2(transitive)
- Removedsocket.io-parser@4.0.1-rc2(transitive)
- Removedxmlhttprequest-ssl@1.5.5(transitive)
- Removedyeast@0.1.2(transitive)
Updatedsocket.io-adapter@2.0.3-rc2
Updatedsocket.io-parser@4.0.1-rc3