Compare commits

..

7 Commits
4.7.3 ... 4.7.4

Author SHA1 Message Date
Damien Arrachequesne
6ab2509d52 chore(release): 4.7.4
Diff: https://github.com/socketio/socket.io/compare/4.7.3...4.7.4
2024-01-12 11:09:14 +01:00
Zachary Soare
d9fb2f64b6 chore(tests): add a test for noArgs in a namespace 2024-01-08 06:38:57 +01:00
Zachary Soare
2c0a81cd87 chore(tests): fix issues due to client#id type change 2024-01-08 06:38:57 +01:00
Zachary Soare
f8d2644921 chore(tests): add type defs for expectjs and fix invalid expectations 2024-01-08 06:38:57 +01:00
Zachary Soare
04640d68cf chore(tests): indicate a future ts error with version 2024-01-08 06:38:57 +01:00
Zachary Soare
cb6d2e02aa fix(typings): calling io.emit with no arguments incorrectly errored
Refs: #4914
2024-01-08 06:38:57 +01:00
Damien Arrachequesne
80b2c34478 chore: bump socket.io-client version 2024-01-03 21:37:25 +01:00
16 changed files with 327 additions and 24 deletions

View File

@@ -2,6 +2,7 @@
## 2024
- [4.7.4](#474-2024-01-12) (Jan 2024)
- [4.7.3](#473-2024-01-03) (Jan 2024)
## 2023
@@ -65,6 +66,21 @@
# Release notes
## [4.7.4](https://github.com/socketio/socket.io/compare/4.7.3...4.7.4) (2024-01-12)
### Bug Fixes
* **typings:** calling io.emit with no arguments incorrectly errored ([cb6d2e0](https://github.com/socketio/socket.io/commit/cb6d2e02aa7ec03c2de1817d35cffa1128b107ef)), closes [#4914](https://github.com/socketio/socket.io/issues/4914)
### Dependencies
- [`engine.io@~6.5.2`](https://github.com/socketio/engine.io/releases/tag/6.5.2) (no change)
- [`ws@~8.11.0`](https://github.com/websockets/ws/releases/tag/8.11.0) (no change)
## [4.7.3](https://github.com/socketio/socket.io/compare/4.7.2...4.7.3) (2024-01-03)

View File

@@ -1,5 +1,5 @@
/*!
* Socket.IO v4.7.3
* Socket.IO v4.7.4
* (c) 2014-2024 Guillermo Rauch
* Released under the MIT License.
*/

View File

@@ -1,5 +1,5 @@
/*!
* Socket.IO v4.7.3
* Socket.IO v4.7.4
* (c) 2014-2024 Guillermo Rauch
* Released under the MIT License.
*/

View File

@@ -1,5 +1,5 @@
/*!
* Socket.IO v4.7.3
* Socket.IO v4.7.4
* (c) 2014-2024 Guillermo Rauch
* Released under the MIT License.
*/

View File

@@ -1,5 +1,5 @@
/*!
* Socket.IO v4.7.3
* Socket.IO v4.7.4
* (c) 2014-2024 Guillermo Rauch
* Released under the MIT License.
*/

View File

@@ -52,9 +52,11 @@ export type EventNamesWithoutAck<
> = IfAny<
Last<Parameters<Map[K]>> | Map[K],
K,
K extends (
Last<Parameters<Map[K]>> extends (...args: any[]) => any ? never : K
)
K extends (Parameters<Map[K]> extends never[] ? K : never)
? K
: K extends (
Last<Parameters<Map[K]>> extends (...args: any[]) => any ? never : K
)
? K
: never
>;

18
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "socket.io",
"version": "4.7.2",
"version": "4.7.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "socket.io",
"version": "4.7.2",
"version": "4.7.3",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.4",
@@ -24,7 +24,7 @@
"nyc": "^15.1.0",
"prettier": "^2.3.2",
"rimraf": "^3.0.2",
"socket.io-client": "4.7.2",
"socket.io-client": "4.7.4",
"socket.io-client-v2": "npm:socket.io-client@^2.4.0",
"superagent": "^8.0.0",
"supertest": "^6.1.6",
@@ -3478,9 +3478,9 @@
}
},
"node_modules/socket.io-client": {
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz",
"integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==",
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
@@ -6942,9 +6942,9 @@
}
},
"socket.io-client": {
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz",
"integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==",
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
"dev": true,
"requires": {
"@socket.io/component-emitter": "~3.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io",
"version": "4.7.3",
"version": "4.7.4",
"description": "node.js realtime framework server",
"keywords": [
"realtime",
@@ -61,7 +61,7 @@
"nyc": "^15.1.0",
"prettier": "^2.3.2",
"rimraf": "^3.0.2",
"socket.io-client": "4.7.2",
"socket.io-client": "4.7.4",
"socket.io-client-v2": "npm:socket.io-client@^2.4.0",
"superagent": "^8.0.0",
"supertest": "^6.1.6",

View File

@@ -222,11 +222,11 @@ describe("connection state recovery", () => {
class DummyAdapter extends Adapter {
override persistSession(session) {
expect.fail();
expect().fail();
}
override restoreSession(pid, offset) {
expect.fail();
expect().fail();
return Promise.reject("should not happen");
}
}

View File

@@ -526,7 +526,7 @@ describe("messaging many", () => {
]).then(async () => {
try {
await io.timeout(200).emitWithAck("some event");
expect.fail();
expect().fail();
} catch (err) {
expect(err).to.be.an(Error);
// @ts-ignore

View File

@@ -6,6 +6,7 @@ import {
createClient,
successFn,
createPartialDone,
assert,
} from "./support/util";
describe("namespaces", () => {
@@ -417,6 +418,7 @@ describe("namespaces", () => {
socket1.on("a", successFn(done, io, socket1, socket2));
socket2.on("connect", () => {
assert(socket2.id);
io.except(socket2.id).emit("a");
});
});
@@ -435,6 +437,7 @@ describe("namespaces", () => {
socket1.on("a", successFn(done, io, socket1, socket2));
socket2.on("connect", () => {
assert(socket2.id);
nsp.except(socket2.id).emit("a");
});
});

View File

@@ -62,7 +62,7 @@ describe("timeout", () => {
io.on("connection", async (socket) => {
try {
await socket.timeout(50).emitWithAck("unknown");
expect.fail();
expect().fail();
} catch (err) {
expect(err).to.be.an(Error);
success(done, io, client);

View File

@@ -187,6 +187,7 @@ describe("server", () => {
Ev extends keyof Map = keyof Map
> = (ev: Ev, ...args: Parameters<Map[Ev]>) => ReturnType<Map[Ev]>;
interface ClientToServerEvents {
noArgs: () => void;
helloFromClient: (message: string) => void;
ackFromClient: (
a: string,
@@ -196,6 +197,7 @@ describe("server", () => {
}
interface ServerToClientEvents {
noArgs: () => void;
helloFromServer: (message: string, x: number) => void;
ackFromServer: (
a: boolean,
@@ -212,12 +214,14 @@ describe("server", () => {
// While these could be generated using the types from typed-events,
// it's likely better to just write them out, so that both the types and this are tested properly
interface ServerToClientEventsNoAck {
noArgs: () => void;
helloFromServer: (message: string, x: number) => void;
ackFromServer: never;
ackFromServerSingleArg: never;
onlyCallback: never;
}
interface ServerToClientEventsWithError {
noArgs: () => void;
helloFromServer: (message: string, x: number) => void;
ackFromServer: (
a: boolean,
@@ -233,6 +237,7 @@ describe("server", () => {
}
interface ServerToClientEventsWithMultiple {
noArgs: () => void;
helloFromServer: (message: string, x: number) => void;
ackFromServer: (a: boolean, b: string, ack: (c: boolean[]) => void) => void;
ackFromServerSingleArg: (
@@ -243,6 +248,7 @@ describe("server", () => {
onlyCallback: (a: () => void) => void;
}
interface ServerToClientEventsWithMultipleAndError {
noArgs: () => void;
helloFromServer: (message: string, x: number) => void;
ackFromServer: (
a: boolean,
@@ -279,7 +285,7 @@ describe("server", () => {
sio.send(1, "2", [3]);
// @ts-expect-error - ServerToClientEvents doesn't have a message event
nio.send(1, "2", [3]);
// This should likely be an error, but I don't know how to make it one
// This correctly becomes an error in TS 5.3.2, so when updating typescript, this should expect-error
sio.send();
nio.send();
});
@@ -383,6 +389,9 @@ describe("server", () => {
});
it("has the correct types for `emit`", () => {
const sio = new Server<ClientToServerEvents, ServerToClientEvents>();
expectType<ToEmit<ServerToClientEventsWithMultipleAndError, "noArgs">>(
sio.timeout(0).emit<"noArgs">
);
expectType<
ToEmit<ServerToClientEventsWithMultipleAndError, "helloFromServer">
>(sio.timeout(0).emit<"helloFromServer">);
@@ -406,6 +415,8 @@ describe("server", () => {
expectType<never>(
undefined as Parameters<typeof sansTimeout["emitWithAck"]>[0]
);
// @ts-expect-error - "noArgs" doesn't have a callback and is thus excluded
sio.timeout(0).emitWithAck("noArgs");
// @ts-expect-error - "helloFromServer" doesn't have a callback and is thus excluded
sio.timeout(0).emitWithAck("helloFromServer");
// @ts-expect-error - "onlyCallback" doesn't have a callback and is thus excluded
@@ -428,7 +439,12 @@ describe("server", () => {
it("Infers correct types", () => {
const sio = new Server<ClientToServerEvents, ServerToClientEvents>();
const nio = sio.of("/test");
expectType<ToEmit<ServerToClientEventsNoAck, "noArgs">>(
sio.emit<"noArgs">
);
expectType<ToEmit<ServerToClientEventsNoAck, "noArgs">>(
nio.emit<"noArgs">
);
expectType<ToEmit<ServerToClientEventsNoAck, "helloFromServer">>(
// These errors will dissapear once the TS version is updated from 4.7.4
// the TSD instance is using a newer version of TS than the workspace version
@@ -439,6 +455,7 @@ describe("server", () => {
nio.emit<"helloFromServer">
);
sio.on("connection", (s) => {
expectType<ToEmit<ServerToClientEvents, "noArgs">>(s.emit<"noArgs">);
expectType<ToEmit<ServerToClientEvents, "helloFromServer">>(
s.emit<"helloFromServer">
);
@@ -474,6 +491,8 @@ describe("server", () => {
it("Infers correct types", () => {
const sio = new Server<ClientToServerEvents, ServerToClientEvents>();
sio.on("connection", (s) => {
// @ts-expect-error - "noArgs" doesn't have a callback and is thus excluded
s.emitWithAck("noArgs");
// @ts-expect-error - "helloFromServer" doesn't have a callback and is thus excluded
s.emitWithAck("helloFromServer");
// @ts-expect-error - "onlyCallback" doesn't have a callback and is thus excluded
@@ -506,6 +525,10 @@ describe("server", () => {
srv.listen(() => {
sio.on("connection", (s) => {
expectType<Socket<ClientToServerEvents, ServerToClientEvents>>(s);
s.on("noArgs", (...args) => {
expectType<[]>(args);
done();
});
s.on("helloFromClient", (message) => {
expectType<string>(message);
done();
@@ -526,6 +549,10 @@ describe("server", () => {
const sio = new Server<ClientToServerEvents, ServerToClientEvents>(srv);
srv.listen(() => {
sio.on("connection", (s) => {
// @ts-expect-error - shouldn't accept emit events
s.on("noArgs", (message, number) => {
done();
});
// @ts-expect-error - shouldn't accept emit events
s.on("helloFromServer", (message, number) => {
done();
@@ -538,14 +565,17 @@ describe("server", () => {
describe("listen and emit event maps for the serverSideEmit method", () => {
interface ClientToServerEvents {
noArgs: () => void;
helloFromClient: (message: string) => void;
}
interface ServerToClientEvents {
noArgs: () => void;
helloFromServer: (message: string, x: number) => void;
}
interface InterServerEvents {
noArgs: () => void;
helloFromServerToServer: (message: string, x: number) => void;
ackFromServerToServer: (foo: string, cb: (bar: number) => void) => void;
}
@@ -563,20 +593,29 @@ describe("server", () => {
Server<ClientToServerEvents, ServerToClientEvents, InterServerEvents>
>(sio);
srv.listen(async () => {
sio.serverSideEmit("noArgs");
sio.serverSideEmit("helloFromServerToServer", "hello", 10);
sio
.of("/test")
.serverSideEmit("helloFromServerToServer", "hello", 10);
sio.on("noArgs", (...args) => {
expectType<[]>(args);
});
sio.on("helloFromServerToServer", (message, x) => {
expectType<string>(message);
expectType<number>(x);
});
sio.of("/test").on("noArgs", (...args) => {
expectType<[]>(args);
});
sio.of("/test").on("helloFromServerToServer", (message, x) => {
expectType<string>(message);
expectType<number>(x);
});
//@ts-expect-error - "helloFromServerToServer" does not have a callback
sio.serverSideEmitWithAck("noArgs");
//@ts-expect-error - "helloFromServerToServer" does not have a callback
sio.serverSideEmitWithAck("helloFromServerToServer", "hello");

221
test/support/expectjs.d.ts vendored Normal file
View File

@@ -0,0 +1,221 @@
declare function expect(target?: any): Expect.Root;
declare namespace Expect {
interface Assertion {
/**
* Check if the value is truthy
*/
ok(): void;
/**
* Creates an anonymous function which calls fn with arguments.
*/
withArgs(...args: any[]): Root;
/**
* Assert that the function throws.
*
* @param fn callback to match error string against
*/
throwError(fn?: (exception: any) => void): void;
/**
* Assert that the function throws.
*
* @param fn callback to match error string against
*/
throwException(fn?: (exception: any) => void): void;
/**
* Assert that the function throws.
*
* @param regexp regexp to match error string against
*/
throwError(regexp: RegExp): void;
/**
* Assert that the function throws.
*
* @param fn callback to match error string against
*/
throwException(regexp: RegExp): void;
/**
* Checks if the array is empty.
*/
empty(): Assertion;
/**
* Checks if the obj exactly equals another.
*/
equal(obj: any): Assertion;
/**
* Checks if the obj sortof equals another.
*/
eql(obj: any): Assertion;
/**
* Assert within start to finish (inclusive).
*
* @param start
* @param finish
*/
within(start: number, finish: number): Assertion;
/**
* Assert typeof.
*/
a(type: string): Assertion;
/**
* Assert instanceof.
*/
a(type: Function): Assertion;
/**
* Assert typeof / instanceof.
*/
an: An;
/**
* Assert numeric value above n.
*/
greaterThan(n: number): Assertion;
/**
* Assert numeric value above n.
*/
above(n: number): Assertion;
/**
* Assert numeric value below n.
*/
lessThan(n: number): Assertion;
/**
* Assert numeric value below n.
*/
below(n: number): Assertion;
/**
* Assert string value matches regexp.
*
* @param regexp
*/
match(regexp: RegExp): Assertion;
/**
* Assert property "length" exists and has value of n.
*
* @param n
*/
length(n: number): Assertion;
/**
* Assert property name exists, with optional val.
*
* @param name
* @param val
*/
property(name: string, val?: any): Assertion;
/**
* Assert that string contains str.
*/
contain(...strings: string[]): Assertion;
string(str: string): Assertion;
/**
* Assert that the array contains obj.
*/
contain(...objs: any[]): Assertion;
string(obj: any): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
key(keys: string[]): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
key(...keys: string[]): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
keys(keys: string[]): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
keys(...keys: string[]): Assertion;
/**
* Assert a failure.
*/
fail(message?: string): Assertion;
}
interface Root extends Assertion {
not: Not;
to: To;
only: Only;
have: Have;
be: Be;
}
interface Be extends Assertion {
/**
* Checks if the obj exactly equals another.
*/
(obj: any): Assertion;
an: An;
}
interface An extends Assertion {
/**
* Assert typeof.
*/
(type: string): Assertion;
/**
* Assert instanceof.
*/
(type: Function): Assertion;
}
interface Not extends Expect.NotBase {
to: Expect.ToBase;
}
interface NotBase extends Assertion {
be: Be;
have: Have;
include: Assertion;
only: Only;
}
interface To extends Expect.ToBase {
not: Expect.NotBase;
}
interface ToBase extends Assertion {
be: Be;
have: Have;
include: Assertion;
only: Only;
}
interface Only extends Assertion {
have: Have;
}
interface Have extends Assertion {
own: Assertion;
}
}
declare module "expect.js" {
//@ts-ignore
export = expect;
}

View File

@@ -1,3 +1,4 @@
/// <reference types="./expectjs" />
import type { Server } from "../..";
import {
io as ioc,
@@ -62,6 +63,16 @@ export function successFn(
return () => success(done, sio, ...clientSockets);
}
/**
* Asserts a condition so that typescript will recognize the assertion!
*
* Uses expect's `ok` check on condition
* @param condition
*/
export function assert(condition: any): asserts condition {
expect(condition).to.be.ok();
}
export function getPort(io: Server): number {
// @ts-ignore
return io.httpServer.address().port;

View File

@@ -7,6 +7,7 @@ import { Server } from "..";
import { io as ioc, Socket as ClientSocket } from "socket.io-client";
import request from "supertest";
import expect from "expect.js";
import { assert } from "./support/util";
const createPartialDone = (done: (err?: Error) => void, count: number) => {
let i = 0;
@@ -134,6 +135,8 @@ describe("socket.io with uWebSocket.js-based engine", () => {
clientWSOnly.on("hello", partialDone);
clientPollingOnly.on("hello", partialDone);
clientCustomNamespace.on("hello", shouldNotHappen(done));
assert(clientWSOnly.id);
assert(clientPollingOnly.id);
io.of("/").sockets.get(clientWSOnly.id)!.join("room1");
io.of("/").sockets.get(clientPollingOnly.id)!.join("room1");
@@ -148,6 +151,8 @@ describe("socket.io with uWebSocket.js-based engine", () => {
clientWSOnly.on("hello", partialDone);
clientPollingOnly.on("hello", partialDone);
clientCustomNamespace.on("hello", shouldNotHappen(done));
assert(clientWSOnly.id);
assert(clientPollingOnly.id);
io.of("/").sockets.get(clientWSOnly.id)!.join("room1");
io.of("/").sockets.get(clientPollingOnly.id)!.join("room2");
@@ -163,6 +168,8 @@ describe("socket.io with uWebSocket.js-based engine", () => {
clientPollingOnly.on("hello", shouldNotHappen(done));
clientCustomNamespace.on("hello", shouldNotHappen(done));
assert(clientWSOnly.id);
assert(clientPollingOnly.id);
io.of("/").sockets.get(clientWSOnly.id)!.join("room1");
io.of("/").sockets.get(clientPollingOnly.id)!.join("room2");
@@ -177,6 +184,9 @@ describe("socket.io with uWebSocket.js-based engine", () => {
clientPollingOnly.on("hello", partialDone);
clientCustomNamespace.on("hello", shouldNotHappen(done));
assert(client.id);
assert(clientWSOnly.id);
assert(clientPollingOnly.id);
io.of("/").sockets.get(client.id)!.join("room1");
io.of("/").sockets.get(clientPollingOnly.id)!.join("room1");
@@ -189,6 +199,7 @@ describe("socket.io with uWebSocket.js-based engine", () => {
it("should not crash when socket is disconnected before the upgrade", (done) => {
client.on("disconnect", () => done());
assert(client.id);
io.of("/").sockets.get(client.id)!.disconnect();
});