Previously, getting disconnected while waiting for an acknowledgement
would create a memory leak, as the acknowledgement was never received
and the handler would stay in memory forever.
This commit fixes the issue:
- handlers that do accept an error as first argument, such as:
* `socket.emit("test", (err, value) => { ... })` with `ackTimeout` option
* `socket.timeout(5000).emit("test", (err, value) => { ... })`
* `const value = await socket.emitWithAck("test")`
will now properly resolve with an error and get discarded.
- handlers that don't like `socket.emit("test", (value) => { ... });`
will simply be discarded upon disconnection
Note: the structure of the 'acks' attribute has been left untouched, in
order to prevent any breaking change.
Related:
- https://github.com/socketio/socket.io-client/issues/1546
- https://github.com/socketio/socket.io/issues/4964
The packet ID cannot be used for deduplication, because it's only
unique for the given session. If you reconnect on another server and
try to resend a packet, then the server won't be able to know whether
the packet has already been processed or not.
In the previous implementation added in [1], the socket would try to
send the packet even if it was disconnected, which would needlessly
exhaust the number of retries.
[1]: 655dce9755
Syntax:
```js
const socket = io({
retries: 3,
ackTimeout: 10000
});
// "my-event" will be sent up to 4 times (1 + 3), until the server sends an acknowledgement
socket.emit("my-event", (err) => {});
```
Notes:
- the order of the packets is guaranteed, as we send packets one by one
- the same packet id is reused for consecutive retries, in order to
allow deduplication on the server side
This commit adds some syntactic sugar around acknowledgements:
```js
// without timeout
const response = await socket.emitWithAck("hello", "world");
// with a specific timeout
try {
const response = await socket.timeout(1000).emitWithAck("hello", "world");
} catch (err) {
// the server did not acknowledge the event in the given delay
}
```
Note: enviroments that do not support Promises ([1]) will need to add a
polyfill in order to use this feature
See also: 184f3cf7af
[1]: https://caniuse.com/promises
Connection state recovery allows a client to reconnect after a
temporary disconnection and restore its state:
- id
- rooms
- data
- missed packets
See also: 54d5ee05a6
For some reason, the lockfile was not in sync anymore with the
package.json file:
> `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync.
That may be linked to a new version of Node.js (v16.15.1).
This is similar to `onAny()`, but for outgoing packets.
Syntax:
```js
socket.onAnyOutgoing((event, ...args) => {
console.log(event);
});
```
Related: 531104d332
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
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 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
The meaning is not modified: this packet type is still used by the
server when the connection to a namespace is refused.
Breaking change: the Socket instance will now emit a "connect_error"
event instead of "error" (which is not a reserved event anymore)
```js
// before
socket.on("error", () => {});
// after
socket.on("connect_error", () => {});
```
Inspired from EventEmitter2 [1]
The API is similar to the one on the server-side:
```js
socket.onAny((event, ...args) => {});
socket.prependAny((event, ...args) => {});
socket.offAny(); // remove all listeners
socket.offAny(listener);
const listeners = socket.listenersAny();
```
[1]: https://github.com/EventEmitter2/EventEmitter2
A volatile packet will be dropped if:
- the socket is not connected
- the low-level transport is not ready (for example, a HTTP POST request is already pending)
Syntax:
```js
socket.volatile.emit("volatile event", "might or might not be sent");
```
This event was added in 41956806a7
But it does not convey the information that the Socket is actually
sending a CONNECT packet to the server. It should maybe be moved to the
Socket#onopen() method, but let's remove it for now as it is not
documented anywhere.
These events cannot be used by the end users, because they are part of
the Socket.IO public API, so using them will now throw an error
explicitly.
Related: f7ed81e5d2