A "new_namespace" event will be emitted when a new namespace is created:
```js
io.on("new_namespace", (namespace) => {
// ...
});
```
This could be used for example for registering the same middleware for
each namespace.
See https://github.com/socketio/socket.io/issues/3851
Syntax:
```js
// server A
io.serverSideEmit("hello", "world");
// server B
io.on("hello", (arg) => {
console.log(arg); // prints "world"
});
```
With acknowledgements:
```js
// server A
io.serverSideEmit("hello", "world", (err, responses) => {
console.log(responses); // prints ["hi"]
});
// server B
io.on("hello", (arg, callback) => {
callback("hi");
});
```
This feature replaces the customHook/customRequest API from the Redis
adapter: https://github.com/socketio/socket.io-redis/issues/370
Packets that are sent to multiple clients will now be pre-encoded for
the WebSocket transport (which means simply prepending "4" - which is
the "message" packet type in Engine.IO).
Note: buffers are not pre-encoded, since they are sent without
modification over the WebSocket connection
See also: 7706b123df
engine.io diff: https://github.com/socketio/engine.io/compare/5.0.0...5.1.0
Before this change, `require("socket.io").Socket` would return
"undefined".
Note: having access to the Socket class allows users to modify its
prototype.
Related: https://github.com/socketio/socket.io/issues/3726
Syntax:
```ts
interface ClientToServerEvents {
"my-event": (a: number, b: string, c: number[]) => void;
}
interface ServerToClientEvents {
hello: (message: string) => void;
}
const io = new Server<ClientToServerEvents, ServerToClientEvents>(httpServer);
io.emit("hello", "world");
io.on("connection", (socket) => {
socket.on("my-event", (a, b, c) => {
// ...
});
socket.emit("hello", "again");
});
```
The events are not typed by default (inferred as any), so this change
is backward compatible.
Note: we could also have reused the method here ([1]) to add types to
the EventEmitter, instead of creating a StrictEventEmitter class.
Related: https://github.com/socketio/socket.io/issues/3742
[1]: https://github.com/binier/tiny-typed-emitter
This commit adds the following methods:
- fetchSockets: returns the matching socket instances
Syntax:
```js
// return all Socket instances
const sockets = await io.fetchSockets();
// return all Socket instances of the "admin" namespace in the "room1" room
const sockets = await io.of("/admin").in("room1").fetchSockets();
```
- socketsJoin: makes the matching socket instances join the specified rooms
Syntax:
```js
// make all Socket instances join the "room1" room
io.socketsJoin("room1");
// make all Socket instances of the "admin" namespace in the "room1" room join the "room2" room
io.of("/admin").in("room1").socketsJoin("room2");
```
- socketsLeave: makes the matching socket instances leave the specified rooms
Syntax:
```js
// make all Socket instances leave the "room1" room
io.socketsLeave("room1");
// make all Socket instances of the "admin" namespace in the "room1" room leave the "room2" room
io.of("/admin").in("room1").socketsLeave("room2");
```
- disconnectSockets: makes the matching socket instances disconnect
Syntax:
```js
// make all Socket instances disconnect
io.disconnectSockets();
// make all Socket instances of the "admin" namespace in the "room1" room disconnect
io.of("/admin").in("room1").disconnectSockets();
```
Those methods share the same semantics as broadcasting. They will also
work with multiple Socket.IO servers when using the Redis adapter. In
that case, the fetchSockets() method will return a list of RemoteSocket
instances, which expose a subset of the methods and attributes of the
Socket class (the "request" attribute cannot be mocked, for example).
Related:
- https://github.com/socketio/socket.io/issues/3042
- https://github.com/socketio/socket.io/issues/3418
- https://github.com/socketio/socket.io/issues/3570
- https://github.com/socketio/socket.io-redis/issues/283
In some cases it is necessary to pass an array of rooms instead of a single room.
New syntax:
```
io.to(["room1", "room2"]).except(["room3"]).emit(...);
socket.to(["room1", "room2"]).except(["room3"]).emit(...);
```
Related: https://github.com/socketio/socket.io/issues/3048
Previously, broadcasting to a given room (by calling `io.to()`) would
mutate the io instance, which could lead to surprising behaviors, like:
```js
io.to("room1");
io.to("room2").emit(...); // also sent to room1
// or with async/await
io.to("room3").emit("details", await fetchDetails()); // random behavior: maybe in room3, maybe to all clients
```
Calling `io.to()` (or any other broadcast modifier) will now return an
immutable instance.
Related:
- https://github.com/socketio/socket.io/issues/3431
- https://github.com/socketio/socket.io/issues/3444
In Socket.IO v2, the Socket query option was appended to the namespace
in the CONNECT packet:
{
type: 0,
nsp: "/my-namespace?abc=123"
}
Note: the "query" option on the client-side (v2) will be found in the
"auth" attribute on the server-side:
```
// client-side
const socket = io("/nsp1", {
query: {
abc: 123
}
});
socket.query = { abc: 456 };
// server-side
const io = require("socket.io")(httpServer, {
allowEIO3: true // enable compatibility mode
});
io.of("/nsp1").on("connection", (socket) => {
console.log(socket.handshake.auth); // { abc: 456 } (the Socket query)
console.log(socket.handshake.query.abc); // 123 (the Manager query)
});
More information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/#Add-a-clear-distinction-between-the-Manager-query-option-and-the-Socket-query-option
Related: https://github.com/socketio/socket.io/issues/3791
When handling compression at the proxy server level, the client receives a weak ETag.
Weak ETags are prefixed with `W/`, e.g. `W/"2.2.0"`.
Upon cache validation we should take care of these too.
Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
In order to ease the migration to Socket.IO v3, the Socket.IO server
can now communicate with v2 clients.
```js
const io = require("socket.io")({
allowEIO3: true
});
```
This feature is disabled by default.