Details:
- engine.io-client sets clearTimeoutFn and setTimeoutFn function
depending on settings passed to manager
- socker.io-client is using manager.setTimeoutFn to start connection
monitoring timer, but is using regular clearTimeout function to
stop it when connection is established
- in some setups it is causing timer fail to stop and it will break
connection every _timeout_ milliseconds (which is 20000 by default)
In some specific cases (Node.js client with WebSocket only), the reason
attached to the "connect_error" event was "websocket error" instead of
"timeout".
Related: https://github.com/socketio/socket.io/issues/4062
This bug was introduced in [1]: a multiplexed socket could in some
cases send multiple CONNECT packets, resulting in duplicate connections
on the server side.
A cached socket will now be reopened only if it was inactive, that is,
if one had explicitly called socket.disconnect() before.
Related: https://github.com/socketio/socket.io-client/issues/1460
[1]: b7dd891e89
This commit allows to:
- provide an ESM version of those modules ([1])
- reduce the attack surface in case of supply chain attacks
- reduce the size of the bundle with tree-shaking
As a downside, we won't receive security updates for those modules
anymore.
[1]: socketio/socket.io-client#1536
Related: df32277c3f
The "disconnect" event will now include additional details to help
debugging if anything has gone wrong.
Example when a payload is over the maxHttpBufferSize value in HTTP
long-polling mode:
```js
socket.on("disconnect", (reason, details) => {
console.log(reason); // "transport error"
// in that case, details is an error object
console.log(details.message); "xhr post error"
console.log(details.description); // 413 (the HTTP status of the response)
// details.context refers to the XMLHttpRequest object
console.log(details.context.status); // 413
console.log(details.context.responseText); // ""
});
```
Related: b9252e2074
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.
Here's what happened:
> socket.disconnect()
- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)
> socket.connect()
- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine
And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.
Related: https://github.com/socketio/socket.io-client/issues/1014
This allows to control the behavior of mocked timers (@sinonjs/fake-timers),
depending on the value of the "useNativeTimers" option:
- true: use native setTimeout function
- false (default): use classic timers, that may be mocked
Related: 5d1d5bea11
With autoUnref set to true (default: false), the Socket.IO client will
allow the program to exit if there is no other active timer/socket in
the event system.
```js
const socket = io({
autoUnref: true
});
```
Note: this option only applies to Node.js clients.
Related: https://github.com/socketio/socket.io-client/issues/1446
Having type `Object` it was not possible to set values, e.g.:
```ts
if (!this.socket.io.opts.query) {
this.socket.io.opts.query = {};
}
this.socket.io.opts.query.token = 'abc123';
```
Results in error:
> Element implicitly has an 'any' type because expression of type '"token"' can't be used to index type 'Object'.
When a given socket was disconnected, either by the server-side or by the client-side, the manager was closed too, regardless of the other connected sockets.
```js
const socket1 = io({
autoConnect: false
});
const socket2 = io("/test");
socket1.disconnect(); // also disconnect socket2
```
This bug was introduced in [1].
[1]: b60e909039
- rename "connect_error" to "error"
- remove "reconnecting" (duplicate of "reconnect_attempt")
The updated list of events emitted by the Manager:
- open: successful (re)connection
- error: (re)connection failure (previously: "connect_error") or error after a successful connection
- close: disconnection
- ping: ping packet
- packet: data packet
- reconnect_attempt: reconnection attempt (previously: "reconnect_attempt" & "reconnecting")
- reconnect: successful reconnection
- reconnect_error: reconnection failure
- reconnect_failed: reconnection failure after all attempts
For reference, the Socket instance emits the following events:
- connect: successful connection to a Namespace
- connect_error: connection failure
- disconnect: disconnection
Previously, most of the events emitted by the Manager were also emitted
by the Socket instances, but it was somehow misleading for the end
users because they don't have the same meaning:
- Manager: the state of the low-level connection (with connection and reconnection events)
- Socket: the state of the connection to the Namespace (only 'connect', 'disconnect' and 'error')
For example, the `reconnect` event:
```js
socket.on("reconnect", () => {
console.log(socket.connected); // might be false, which is a bit surprising
});
```
Breaking change: the Socket instance will no longer forward the events
of its Manager
Those events can still be accessed on the Manager instance though:
```js
socket.io.on("reconnect", () => {
// ...
});
```