This should fix the following error:
> TypeError: Cannot read property 'writeHead' of undefined
This bug was introduced by [1], because the `if (res !== undefined) { ... }`
check was removed.
But `res` is indeed undefined when the client connects with WebSocket
directly, in that case we need to manually write the response content
(in the abortUpgrade method).
Please note that the previous behavior was invalid too, since the
WebSocket connection was left open when an error occurred during the
handshake.
[1]: 7096e98a02
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
A few notes:
- only the first element is pre-encoded, because the other elements are
buffers and will be sent as is over the WebSocket connection
- using `socket.packet()` was unexpectedly working, we will now use
`socket.client.writeToEngine()` (see [1])
See also: 7706b123df
[1]: https://github.com/socketio/socket.io/issues/3775
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
Before this change, `require("socket.io-client").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
Before this commit, an event sent in the "connect" handler could be
sent before the events that were buffered while disconnected.
```js
socket.on("connect", () => {
socket.emit("bar");
});
socket.emit("foo"); // buffered while disconnected
```
In the example above, the "bar" event was sent first, which is not
correct.
Related: https://github.com/socketio/socket.io-client/issues/1458
When passing the same `options` argument for two distinct Socket
instances, a new Manager was created:
```js
const opts = {};
const socket1 = io("/foo", opts);
const socket2 = io("/bar", opts);
console.log(socket1.io === socket2.io); // false
```
This bug was introduced by [1].
Note: the `options` argument is modified at the `socket.io-client`
level (path, query) and at the `engine.io-client` level (host, port),
which may not be optimal.
[1]: 7a0c2b504f
Related: https://github.com/socketio/socket.io/issues/3898
Since [1], the socket is now closed when receiving the "beforeunload"
event in the browser.
This change was meant to fix a discrepancy between Chrome and Firefox
when the user reloads/closes a browser tab: Firefox would close the
connection (and emit a "disconnect" event, at the Socket.IO level), but
not Chrome (see [2]).
But it also closes the connection when there is another "beforeunload"
handler, for example when the user is prompted "are you sure you want
to leave this page?".
Note: calling "stopImmediatePropagation()" was a possible workaround:
```js
window.addEventListener('beforeunload', (event) => {
event.preventDefault();
event.stopImmediatePropagation();
event.returnValue = 'are you sure you want to leave this page?';
});
```
This commit adds a "closeOnBeforeunload" option, which controls whether
a handler is registered for the "beforeunload" event.
Syntax:
```js
const socket = require('engine.io-client')('ws://localhost', {
closeOnBeforeunload: false // defaults to true
});
```
[1]: ed48b5dc34
[2]: https://github.com/socketio/socket.io/issues/3639
Related:
- https://github.com/socketio/engine.io-client/issues/661
- https://github.com/socketio/engine.io-client/issues/658
- https://github.com/socketio/socket.io-client/issues/1451
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
This option will be used when broadcasting a packet to multiple clients,
in order to only encode the packet once.
Usage:
```js
socket.write("test", {
wsPreEncoded: "4test"
});
```
Note: pre-encoding the content with HTTP long-polling is a bit harder,
since the concatenation of the packets is specific to each client.
This change should reduce memory usage when many packets are emitted to
many clients in a burst.
Co-authored-by: Branislav Katreniak <bkatreniak@slido.com>
Those events will be emitted before the response headers are written to
the socket:
- "initial_headers": on the first request of the connection
- "headers": on all requests (HTTP long-polling and WebSocket upgrade)
Syntax:
```js
server.on("initial_headers", (headers, req) => {
headers["test"] = "123";
headers["set-cookie"] = "mycookie=456";
});
server.on("headers", (headers, req) => {
headers["test"] = "789";
});
```
Related:
- https://github.com/socketio/engine.io/issues/557
- https://github.com/socketio/socket.io/issues/3630
The "connection_error" event will be emitted when one of the following
errors occurs:
- Transport unknown
- Session ID unknown
- Bad handshake method
- Bad request
- Forbidden
- Unsupported protocol version
Syntax:
```js
server.on("connection_error", (err) => {
console.log(err.req); // the request object
console.log(err.code); // the error code, for example 1
console.log(err.message); // the error message, for example "Session ID unknown"
console.log(err.context); // some additional error context
});
```
Related:
- https://github.com/socketio/socket.io/issues/3819
- https://github.com/socketio/engine.io/issues/576
In some cases, a "Transport not open" error could be thrown when the
transport was silently closed in the onbeforeunload event (added in
[1]).
To reproduce:
```js
window.addEventListener("unload", () => {
socket.write("...");
});
```
[1]: ed48b5dc34
Related: https://github.com/socketio/socket.io/issues/3838