Compare commits

..

2 Commits

Author SHA1 Message Date
Damien Arrachequesne
2a2b44f20d test: add test 2025-12-22 10:24:29 +01:00
Suraj Rana
e1ad89a708 Drain queue before emitting connect event 2025-12-22 09:58:31 +01:00
56 changed files with 402 additions and 728 deletions

View File

@@ -20,9 +20,9 @@ jobs:
fail-fast: false
matrix:
node-version:
- 18
- 20
- 22
- 24
- 22.17.1 # experimental TS type striping in 22.18.0 breaks the build
services:
redis:

View File

@@ -19,10 +19,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Use Node.js 24
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 24
node-version: 20
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies

26
package-lock.json generated
View File

@@ -77,7 +77,7 @@
"tsd": "^0.31.1",
"tsx": "~4.20.6",
"typescript": "^5.5.3",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.56.0",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.48.0",
"wdio-geckodriver-service": "^5.0.2"
}
},
@@ -2277,27 +2277,25 @@
}
},
"node_modules/@fails-components/webtransport": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@fails-components/webtransport/-/webtransport-1.5.1.tgz",
"integrity": "sha512-WB6ZnnunU+pzkl7MtguVCf5K6h7nE7ulHpQMQM+sjZoE77GEtjUfBKSwH0z30fN+H+7caMbXSmPyAOD/WA0QAQ==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@fails-components/webtransport/-/webtransport-1.1.4.tgz",
"integrity": "sha512-cFc9XhEREi+afRRl9S9c/xNQ3KVi9dZkaIRVq3xPGwjjezgX5QMQ1pJKG6iZffSwboOOjk1VrDwlvPjuVwtGwQ==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@types/debug": "^4.1.7",
"bindings": "^1.5.0",
"debug": "^4.3.4"
},
"engines": {
"node": ">=20"
"node": ">=16.5"
}
},
"node_modules/@fails-components/webtransport-transport-http3-quiche": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@fails-components/webtransport-transport-http3-quiche/-/webtransport-transport-http3-quiche-1.5.1.tgz",
"integrity": "sha512-70FoQURf5KxByC7reVjgGDbRUqbMaFhqkvUc1LisLXw+PD6fIcE7Ua3eAnfsXG3izpV+YNMvucDM2qnCMn8dFg==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@fails-components/webtransport-transport-http3-quiche/-/webtransport-transport-http3-quiche-1.1.4.tgz",
"integrity": "sha512-/tkuAJMSU641c+LrOmHpw8ZtZOQjrHX9O/kg/8iIhnqycNPyFBlzW8EWrmUfSTOran6QmTtQHRks+A1BqMEZeQ==",
"dev": true,
"hasInstallScript": true,
"license": "BSD-3-Clause",
"dependencies": {
"@types/debug": "^4.1.7",
"bindings": "^1.5.0",
@@ -2307,7 +2305,7 @@
"prebuild-install": "^7.1.1"
},
"engines": {
"node": ">=20"
"node": ">=16.5"
}
},
"node_modules/@ioredis/commands": {
@@ -15159,8 +15157,8 @@
}
},
"node_modules/uWebSockets.js": {
"version": "20.56.0",
"resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#d04e707a1292928d50163ff7545e45c3e84c5ec3",
"version": "20.48.0",
"resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#51ae1d1fd92dff77cbbdc7c431021f85578da1a6",
"dev": true,
"license": "Apache-2.0"
},
@@ -16185,7 +16183,7 @@
},
"packages/socket.io-redis-streams-emitter": {
"name": "@socket.io/redis-streams-emitter",
"version": "0.1.1",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"@msgpack/msgpack": "~2.8.0",

View File

@@ -78,7 +78,7 @@
"tsd": "^0.31.1",
"tsx": "~4.20.6",
"typescript": "^5.5.3",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.56.0",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.48.0",
"wdio-geckodriver-service": "^5.0.2"
}
}

View File

@@ -1,8 +1,7 @@
# Changelog
# History
| Version | Release date | Bundle size (UMD min+gzip) |
|-------------------------------------------------------------------------------------------------------------|----------------|----------------------------|
| [6.6.4](#664-2025-12-23) | December 2025 | `8.7 KB` |
| [6.6.3](#663-2025-01-23) | January 2025 | `8.7 KB` |
| [6.6.2](#662-2024-10-23) | October 2024 | `8.7 KB` |
| [6.6.1](#661-2024-09-21) | September 2024 | `8.7 KB` |
@@ -40,24 +39,7 @@
| [4.1.1](#411-2021-02-02) | February 2021 | `9.1 KB` |
| [4.1.0](#410-2021-01-14) | January 2021 | `9.1 KB` |
## [6.6.4](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.3...engine.io-client@6.6.4) (2025-12-23)
This release contains a bump of:
- `ws` from `~8.17.1` to `~8.18.3`
- `debug` from `~4.3.1` to `~4.4.1`
### Bug Fixes
* properly handle port option ([#5241](https://github.com/socketio/socket.io/issues/5241)) ([1da9cdd](https://github.com/socketio/socket.io/commit/1da9cddeab0bf5ce41890d156d73af8194cef656))
### Dependencies
- [`ws@~8.18.3`](https://github.com/websockets/ws/releases/tag/8.18.3) ([diff](https://github.com/websockets/ws/compare/8.17.1...8.18.3))
# Release notes
## [6.6.3](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.2...engine.io-client@6.6.3) (2025-01-23)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
/*!
* Engine.IO v6.6.4
* Engine.IO v6.6.3
* (c) 2014-2025 Guillermo Rauch
* Released under the MIT License.
*/
@@ -35,54 +35,6 @@
writable: !1
}), e;
}
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
t && (r = t);
var n = 0,
F = function () {};
return {
s: F,
n: function () {
return n >= r.length ? {
done: !0
} : {
done: !1,
value: r[n++]
};
},
e: function (r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = !0,
u = !1;
return {
s: function () {
t = t.call(r);
},
n: function () {
var r = t.next();
return a = r.done, r;
},
e: function (r) {
u = !0, o = r;
},
f: function () {
try {
a || null == t.return || t.return();
} finally {
if (u) throw o;
}
}
};
}
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function (n) {
for (var e = 1; e < arguments.length; e++) {
@@ -1097,65 +1049,21 @@
createDebug.namespaces = namespaces;
createDebug.names = [];
createDebug.skips = [];
var split = (typeof namespaces === 'string' ? namespaces : '').trim().replace(/\s+/g, ',').split(',').filter(Boolean);
var _iterator = _createForOfIteratorHelper(split),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var ns = _step.value;
if (ns[0] === '-') {
createDebug.skips.push(ns.slice(1));
} else {
createDebug.names.push(ns);
}
var i;
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
var len = split.length;
for (i = 0; i < len; i++) {
if (!split[i]) {
// ignore empty strings
continue;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
/**
* Checks if the given string matches a namespace template, honoring
* asterisks as wildcards.
*
* @param {String} search
* @param {String} template
* @return {Boolean}
*/
function matchesTemplate(search, template) {
var searchIndex = 0;
var templateIndex = 0;
var starIndex = -1;
var matchIndex = 0;
while (searchIndex < search.length) {
if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
// Match character or proceed with wildcard
if (template[templateIndex] === '*') {
starIndex = templateIndex;
matchIndex = searchIndex;
templateIndex++; // Skip the '*'
} else {
searchIndex++;
templateIndex++;
}
} else if (starIndex !== -1) {
// eslint-disable-line no-negated-condition
// Backtrack to the last '*' and try to match more characters
templateIndex = starIndex + 1;
matchIndex++;
searchIndex = matchIndex;
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
} else {
return false; // No match
createDebug.names.push(new RegExp('^' + namespaces + '$'));
}
}
// Handle trailing '*' in template
while (templateIndex < template.length && template[templateIndex] === '*') {
templateIndex++;
}
return templateIndex === template.length;
}
/**
@@ -1165,7 +1073,7 @@
* @api public
*/
function disable() {
var namespaces = [].concat(_toConsumableArray(createDebug.names), _toConsumableArray(createDebug.skips.map(function (namespace) {
var namespaces = [].concat(_toConsumableArray(createDebug.names.map(toNamespace)), _toConsumableArray(createDebug.skips.map(toNamespace).map(function (namespace) {
return '-' + namespace;
}))).join(',');
createDebug.enable('');
@@ -1180,37 +1088,35 @@
* @api public
*/
function enabled(name) {
var _iterator2 = _createForOfIteratorHelper(createDebug.skips),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var skip = _step2.value;
if (matchesTemplate(name, skip)) {
return false;
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
if (name[name.length - 1] === '*') {
return true;
}
var _iterator3 = _createForOfIteratorHelper(createDebug.names),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var ns = _step3.value;
if (matchesTemplate(name, ns)) {
return true;
}
var i;
var len;
for (i = 0, len = createDebug.skips.length; i < len; i++) {
if (createDebug.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = createDebug.names.length; i < len; i++) {
if (createDebug.names[i].test(name)) {
return true;
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return false;
}
/**
* Convert regexp to namespace
*
* @param {RegExp} regxep
* @return {String} namespace
* @api private
*/
function toNamespace(regexp) {
return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\.\*\?$/, '*');
}
/**
* Coerce `val`.
*
@@ -1286,17 +1192,15 @@
if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
return false;
}
var m;
// Is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
// eslint-disable-next-line no-return-assign
return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance ||
// Is firebug? http://stackoverflow.com/a/398120/376773
typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) ||
// Is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31 ||
typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 ||
// Double check webkit in userAgent just in case we are in a worker
typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
}
@@ -1372,7 +1276,7 @@
function load() {
var r;
try {
r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG');
r = exports.storage.getItem('debug');
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
@@ -1553,7 +1457,7 @@
return hostname.indexOf(":") === -1 ? hostname : "[" + hostname + "]";
};
_proto._port = function _port() {
if (this.opts.port && (this.opts.secure && Number(this.opts.port) !== 443 || !this.opts.secure && Number(this.opts.port) !== 80)) {
if (this.opts.port && (this.opts.secure && Number(this.opts.port !== 443) || !this.opts.secure && Number(this.opts.port) !== 80)) {
return ":" + this.opts.port;
} else {
return "";

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
"name": "engine.io-client",
"description": "Client for the realtime Engine",
"license": "MIT",
"version": "6.6.4",
"version": "6.6.3",
"main": "./build/cjs/index.js",
"module": "./build/esm/index.js",
"exports": {

View File

@@ -53,26 +53,6 @@ async function setup(opts, cb) {
cb({ engine, h3Server, certificate });
}
function createHttpServer(port) {
const httpServer = createServer();
let retryCount = 0;
return new Promise((resolve, reject) => {
httpServer.listen(port, () => resolve(httpServer));
httpServer.on("error", (e) => {
if (e.code === "EADDRINUSE" && ++retryCount <= 3) {
console.warn("port already in use, retrying...");
setTimeout(() => {
httpServer.listen(port, () => resolve(httpServer));
}, 100);
}
reject(e);
});
});
}
function success(engine, h3server, done) {
engine.close();
h3server.stopServer();
@@ -118,9 +98,10 @@ describe("WebTransport", () => {
{
transports: ["polling", "webtransport"],
},
async ({ engine, h3Server, certificate }) => {
const httpServer = await createHttpServer(h3Server.port);
({ engine, h3Server, certificate }) => {
const httpServer = createServer();
engine.attach(httpServer);
httpServer.listen(h3Server.port);
const socket = createSocket(h3Server.port, certificate, {
transports: ["polling", "webtransport"],
@@ -139,9 +120,10 @@ describe("WebTransport", () => {
{
transports: ["polling", "websocket", "webtransport"],
},
async ({ engine, h3Server, certificate }) => {
const httpServer = await createHttpServer(h3Server.port);
({ engine, h3Server, certificate }) => {
const httpServer = createServer();
engine.attach(httpServer);
httpServer.listen(h3Server.port);
const socket = createSocket(h3Server.port, certificate, {
transports: ["polling", "websocket", "webtransport"],

View File

@@ -13,7 +13,7 @@
"scripts": {
"compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
"test": "npm run format:check && npm run compile && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
"test:node": "nyc mocha --import=tsx test/index.ts",
"test:node": "nyc mocha -r ts-node/register test/index.ts",
"test:browser": "zuul test/index.ts --no-coverage",
"format:check": "prettier --check 'lib/**/*.ts' 'test/**/*.ts'",
"format:fix": "prettier --write 'lib/**/*.ts' 'test/**/*.ts'",

View File

@@ -0,0 +1,12 @@
const parser = require('.');
parser.encodePayload([
{
type: 'message',
data: '€',
},
{
type: 'message',
data: Buffer.from([1, 2, 3, 4]),
},
], true, console.log);

View File

@@ -0,0 +1,44 @@
"use strict";
const browsers = require("socket.io-browsers");
const zuulConfig = (module.exports = {
ui: "mocha-bdd",
// test on localhost by default
local: true,
open: true,
concurrency: 2, // ngrok only accepts two tunnels by default
// if browser does not sends output in 120s since last output:
// stop testing, something is wrong
browser_output_timeout: 120 * 1000,
browser_open_timeout: 60 * 4 * 1000,
// we want to be notified something is wrong asap, so no retry
browser_retries: 1,
browserify: [
{
plugin: ["tsify", {
target: "es5"
}],
transform: {
name: "babelify",
presets: ["@babel/preset-env"]
}
}
]
});
if (process.env.CI === "true") {
zuulConfig.local = false;
zuulConfig.tunnel = {
type: "ngrok",
bind_tls: true
};
}
const isPullRequest =
process.env.TRAVIS_PULL_REQUEST &&
process.env.TRAVIS_PULL_REQUEST !== "false";
zuulConfig.browsers = isPullRequest ? browsers.pullRequest : browsers.all;

View File

@@ -1,8 +1,7 @@
# Changelog
# History
| Version | Release date |
|------------------------------------------------------------------------------------------------------|----------------|
| [6.6.5](#665-2025-12-22) | December 2025 |
| [6.6.4](#664-2025-01-28) | January 2025 |
| [6.6.3](#663-2025-01-23) | January 2025 |
| [6.6.2](#662-2024-10-09) | October 2024 |
@@ -48,16 +47,7 @@
| [3.4.1](#341-2020-04-17) | April 2020 |
## [6.6.5](https://github.com/socketio/socket.io/compare/engine.io@6.6.4...engine.io@6.6.5) (2025-12-22)
The `url.parse()` function is now deprecated and has been replaced by `new URL()` (see [e08293b](https://github.com/socketio/socket.io/commit/e08293bc3735de5b824b347383e86e0b8ab9fbd5)).
### Dependencies
- [`ws@~8.18.3`](https://github.com/websockets/ws/releases/tag/8.18.3) ([diff](https://github.com/websockets/ws/compare/8.17.1...8.18.3))
# Release notes
## [6.6.4](https://github.com/socketio/socket.io/compare/engine.io@6.6.3...engine.io@6.6.4) (2025-01-28)

View File

@@ -1,3 +1,5 @@
import * as qs from "querystring";
import { parse } from "url";
import * as base64id from "base64id";
import transports from "./transports";
import { EventEmitter } from "events";
@@ -734,8 +736,9 @@ export class Server extends BaseServer {
private prepare(req: EngineRequest) {
// try to leverage pre-existing `req._query` (e.g: from connect)
if (!req._query) {
const url = new URL(req.url, "https://socket.io");
req._query = Object.fromEntries(url.searchParams.entries());
req._query = (
~req.url.indexOf("?") ? qs.parse(parse(req.url).query) : {}
) as Record<string, string>;
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "engine.io",
"version": "6.6.5",
"version": "6.6.4",
"description": "The realtime engine behind Socket.IO. Provides the foundation of a bidirectional connection between client and server",
"type": "commonjs",
"main": "./build/engine.io.js",

View File

@@ -1,6 +1,5 @@
if (process.env.EIO_CLIENT === "3") {
// we need the WebSocket object provided by the "ws" library to test the SSL certs and HTTP headers so we hide the now built-in WebSocket constructor
// ref: https://nodejs.org/api/globals.html#class-websocket
if (process.env.EIO_CLIENT === "3" && process.versions.node.startsWith("22")) {
// FIXME WebSocket error with engine.io-client@3
global.WebSocket = null;
}

View File

@@ -99,26 +99,6 @@ function setup(opts, cb) {
});
}
function createHttpServer(port) {
const httpServer = createServer();
let retryCount = 0;
return new Promise((resolve, reject) => {
httpServer.listen(port, () => resolve(httpServer));
httpServer.on("error", (e) => {
if (e.code === "EADDRINUSE" && ++retryCount <= 3) {
console.warn("port already in use, retrying...");
setTimeout(() => {
httpServer.listen(port, () => resolve(httpServer));
}, 100);
}
reject(e);
});
});
}
describe("WebTransport", () => {
it("should allow to connect with WebTransport directly", (done) => {
setupServer({}, async ({ engine, h3Server, certificate }) => {
@@ -174,8 +154,9 @@ describe("WebTransport", () => {
transports: ["polling", "websocket", "webtransport"],
},
async ({ engine, h3Server, certificate }) => {
const httpServer = await createHttpServer(h3Server.port);
const httpServer = createServer();
engine.attach(httpServer);
httpServer.listen(h3Server.port);
const partialDone = createPartialDone(() => {
httpServer.close();

View File

@@ -1,35 +1,26 @@
# Changelog
# History
| Version | Release date |
|------------------------------|----------------|
| [2.5.6](#256-2025-12-23) | December 2025 |
| [2.5.5](#255-2024-06-18) | June 2024 |
| [2.5.4](#254-2024-02-22) | February 2024 |
| [2.5.3](#253-2024-02-21) | February 2024 |
| [2.5.2](#252-2023-01-12) | January 2023 |
| [2.5.1](#251-2023-01-06) | January 2023 |
| [2.5.0](#250-2023-01-06) | January 2023 |
| [2.4.0](#240-2022-03-30) | March 2022 |
| [2.3.3](#233-2021-11-16) | November 2021 |
| [2.3.2](#232-2021-08-28) | August 2021 |
| [2.3.1](#231-2021-05-19) | May 2021 |
| [2.3.0](#230-2021-05-10) | May 2021 |
| [2.2.0](#220-2021-02-27) | February 2021 |
| [2.1.0](#210-2021-01-15) | January 2021 |
| [2.0.3](#203-2020-11-05) | November 2020 |
| [2.0.2](#202-2020-09-28) | September 2020 |
| [2.0.1](#201-2020-09-28) | September 2020 |
| [**2.0.0**](#200-2020-09-25) | September 2020 |
- [2.5.5](#255-2024-06-18) (Jun 2024)
- [2.5.4](#254-2024-02-22) (Feb 2024)
- [2.5.3](#253-2024-02-21) (Feb 2024)
- [2.5.2](#252-2023-01-12) (Jan 2023)
- [2.5.1](#251-2023-01-06) (Jan 2023)
- [2.5.0](#250-2023-01-06) (Jan 2023)
- [2.4.0](#240-2022-03-30) (Mar 2022)
- [2.3.3](#233-2021-11-16) (Nov 2021)
- [2.3.2](#232-2021-08-28) (Aug 2021)
- [2.3.1](#231-2021-05-19) (May 2021)
- [2.3.0](#230-2021-05-10) (May 2021)
- [2.2.0](#220-2021-02-27) (Feb 2021)
- [2.1.0](#210-2021-01-15) (Jan 2021)
- [2.0.3](#203-2020-11-05) (Nov 2020)
- [2.0.2](#202-2020-09-28) (Sep 2020)
- [2.0.1](#201-2020-09-28) (Sep 2020)
- [**2.0.0**](#200-2020-09-25) (Sep 2020)
## [2.5.6](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.5...socket.io-adapter@2.5.6) (2025-12-23)
This release contains a bump of:
- `ws` from `~8.17.1` to `~8.18.3`
- `debug` from `~4.3.1` to `~4.4.1`
# Release notes
## [2.5.5](https://github.com/socketio/socket.io-adapter/compare/2.5.4...2.5.5) (2024-06-18)

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io-adapter",
"version": "2.5.6",
"version": "2.5.5",
"license": "MIT",
"homepage": "https://github.com/socketio/socket.io/tree/main/packages/socket.io-adapter#readme",
"repository": {
@@ -22,7 +22,7 @@
},
"scripts": {
"compile": "rimraf ./dist && tsc",
"test": "npm run format:check && npm run compile && nyc mocha --import=tsx test/*.ts",
"test": "npm run format:check && npm run compile && nyc mocha --require ts-node/register test/*.ts",
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
"prepack": "npm run compile"

View File

@@ -1,9 +1,7 @@
# Changelog
# History
| Version | Release date | Bundle size (UMD min+gzip) |
|-------------------------------------------------------------------------------------------------------------|----------------|----------------------------|
| [4.8.3](#483-2025-12-23) | December 2025 | `14.4 KB` |
| [4.8.2](#482-2025-12-22) | December 2025 | `14.4 KB` |
| [4.8.1](#481-2024-10-25) | October 2024 | `14.4 KB` |
| [4.8.0](#480-2024-09-21) | September 2024 | `14.4 KB` |
| [4.7.5](#475-2024-03-14) | March 2024 | `14.6 KB` |
@@ -52,33 +50,7 @@
| [2.1.0](#210-2018-03-29) | March 2018 | `18.7 KB` |
## [4.8.3](https://github.com/socketio/socket.io/compare/socket.io-client@4.8.2...socket.io-client@4.8.3) (2025-12-23)
There were some minor bug fixes on the server side, which mandate a client bump.
### Dependencies
- [`engine.io-client@~6.6.1`](https://github.com/socketio/engine.io-client/releases/tag/6.5.2) (no change)
- [`ws@~8.18.3`](https://github.com/websockets/ws/releases/tag/8.18.3) ([diff](https://github.com/websockets/ws/compare/8.17.1...8.18.3))
## [4.8.2](https://github.com/socketio/socket.io/compare/socket.io-client@4.8.1...socket.io-client@4.8.2) (2025-12-22)
### Bug Fixes
* **bundle** do not mangle the "_placeholder" attribute (bis) ([cdae019](https://github.com/socketio/socket.io/commit/cdae01983a8ae840fc9812875a8b88166b377c11))
* drain queue before emitting "connect" ([#5259](https://github.com/socketio/socket.io/issues/5259)) ([d19928e](https://github.com/socketio/socket.io/commit/d19928e8d8b325310274031ed7de2ddc93ebb589)
### Dependencies
- [`engine.io-client@~6.6.1`](https://github.com/socketio/engine.io-client/releases/tag/6.5.2) (no change)
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
# Release notes
## [4.8.1](https://github.com/socketio/socket.io/compare/socket.io-client@4.8.0...socket.io-client@4.8.1) (2024-10-25)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Socket.IO v4.8.3
* (c) 2014-2025 Guillermo Rauch
* Socket.IO v4.8.1
* (c) 2014-2024 Guillermo Rauch
* Released under the MIT License.
*/
(function (global, factory) {
@@ -899,7 +899,7 @@
return hostname.indexOf(":") === -1 ? hostname : "[" + hostname + "]";
};
_proto._port = function _port() {
if (this.opts.port && (this.opts.secure && Number(this.opts.port) !== 443 || !this.opts.secure && Number(this.opts.port) !== 80)) {
if (this.opts.port && (this.opts.secure && Number(this.opts.port !== 443) || !this.opts.secure && Number(this.opts.port) !== 80)) {
return ":" + this.opts.port;
} else {
return "";
@@ -2669,65 +2669,21 @@
createDebug.namespaces = namespaces;
createDebug.names = [];
createDebug.skips = [];
var split = (typeof namespaces === 'string' ? namespaces : '').trim().replace(/\s+/g, ',').split(',').filter(Boolean);
var _iterator = _createForOfIteratorHelper(split),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var ns = _step.value;
if (ns[0] === '-') {
createDebug.skips.push(ns.slice(1));
} else {
createDebug.names.push(ns);
}
var i;
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
var len = split.length;
for (i = 0; i < len; i++) {
if (!split[i]) {
// ignore empty strings
continue;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
/**
* Checks if the given string matches a namespace template, honoring
* asterisks as wildcards.
*
* @param {String} search
* @param {String} template
* @return {Boolean}
*/
function matchesTemplate(search, template) {
var searchIndex = 0;
var templateIndex = 0;
var starIndex = -1;
var matchIndex = 0;
while (searchIndex < search.length) {
if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
// Match character or proceed with wildcard
if (template[templateIndex] === '*') {
starIndex = templateIndex;
matchIndex = searchIndex;
templateIndex++; // Skip the '*'
} else {
searchIndex++;
templateIndex++;
}
} else if (starIndex !== -1) {
// eslint-disable-line no-negated-condition
// Backtrack to the last '*' and try to match more characters
templateIndex = starIndex + 1;
matchIndex++;
searchIndex = matchIndex;
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
} else {
return false; // No match
createDebug.names.push(new RegExp('^' + namespaces + '$'));
}
}
// Handle trailing '*' in template
while (templateIndex < template.length && template[templateIndex] === '*') {
templateIndex++;
}
return templateIndex === template.length;
}
/**
@@ -2737,7 +2693,7 @@
* @api public
*/
function disable() {
var namespaces = [].concat(_toConsumableArray(createDebug.names), _toConsumableArray(createDebug.skips.map(function (namespace) {
var namespaces = [].concat(_toConsumableArray(createDebug.names.map(toNamespace)), _toConsumableArray(createDebug.skips.map(toNamespace).map(function (namespace) {
return '-' + namespace;
}))).join(',');
createDebug.enable('');
@@ -2752,37 +2708,35 @@
* @api public
*/
function enabled(name) {
var _iterator2 = _createForOfIteratorHelper(createDebug.skips),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var skip = _step2.value;
if (matchesTemplate(name, skip)) {
return false;
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
if (name[name.length - 1] === '*') {
return true;
}
var _iterator3 = _createForOfIteratorHelper(createDebug.names),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var ns = _step3.value;
if (matchesTemplate(name, ns)) {
return true;
}
var i;
var len;
for (i = 0, len = createDebug.skips.length; i < len; i++) {
if (createDebug.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = createDebug.names.length; i < len; i++) {
if (createDebug.names[i].test(name)) {
return true;
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return false;
}
/**
* Convert regexp to namespace
*
* @param {RegExp} regxep
* @return {String} namespace
* @api private
*/
function toNamespace(regexp) {
return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\.\*\?$/, '*');
}
/**
* Coerce `val`.
*
@@ -2858,17 +2812,15 @@
if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
return false;
}
var m;
// Is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
// eslint-disable-next-line no-return-assign
return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance ||
// Is firebug? http://stackoverflow.com/a/398120/376773
typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) ||
// Is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31 ||
typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 ||
// Double check webkit in userAgent just in case we are in a worker
typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
}
@@ -2944,7 +2896,7 @@
function load() {
var r;
try {
r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG');
r = exports.storage.getItem('debug');
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
@@ -3876,7 +3828,8 @@
};
args.push(function (err) {
if (packet !== _this4._queue[0]) {
return debug$2("packet [%d] already acknowledged", packet.id);
// the packet has already been acknowledged
return;
}
var hasError = err !== null;
if (hasError) {
@@ -4147,8 +4100,8 @@
this._pid = pid; // defined only if connection state recovery is enabled
this.connected = true;
this.emitBuffered();
this._drainQueue(true);
this.emitReserved("connect");
this._drainQueue(true);
}
/**
* Emit buffered events (received and emitted).

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io-client",
"version": "4.8.3",
"version": "4.8.1",
"description": "Realtime application framework client",
"keywords": [
"realtime",
@@ -53,7 +53,7 @@
"scripts": {
"compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
"test": "npm run format:check && npm run compile && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
"test:node": "mocha --import=tsx --require test/support/hooks.ts --exit test/index.ts",
"test:node": "mocha --require ts-node/register --require test/support/hooks.ts --exit test/index.ts",
"test:browser": "ts-node test/browser-runner.ts",
"test:types": "tsd",
"build": "rollup -c support/rollup.config.umd.js && rollup -c support/rollup.config.esm.js && rollup -c support/rollup.config.umd.msgpack.js",

View File

@@ -1,5 +1,5 @@
{
"name": "socket.io-client",
"version": "4.8.3",
"version": "4.7.5",
"type": "module"
}

View File

@@ -111,7 +111,7 @@ describe("retry", () => {
});
});
it("should not emit a packet twice in the 'connect' handler", () => {
it.only("should not emit a packet twice in the 'connect' handler", () => {
return wrap((done) => {
const socket = io(BASE_URL, {
forceNew: true,

View File

@@ -26,7 +26,7 @@
"scripts": {
"compile": "rimraf ./dist && tsc",
"test": "npm run format:check && npm run compile && npm run test:unit",
"test:unit": "mocha --import=tsx test/*.ts",
"test:unit": "mocha --require ts-node/register test/*.ts",
"format:check": "prettier --check \"lib/**/*.ts\" \"test/**/*.ts\"",
"format:fix": "prettier --write \"lib/**/*.ts\" \"test/**/*.ts\"",
"prepack": "npm run compile"

View File

@@ -1,8 +1,7 @@
# Changelog
# History
| Version | Release date |
|-------------------------------------------------------------------------------------------------------------|----------------|
| [4.2.5](#425-2025-12-23) | December 2025 |
| [3.3.4](#334-2024-07-22) (from the [3.3.x](https://github.com/socketio/socket.io-parser/tree/3.3.x) branch) | July 2024 |
| [4.2.4](#424-2023-05-31) | May 2023 |
| [3.4.3](#343-2023-05-22) (from the [3.4.x](https://github.com/socketio/socket.io-parser/tree/3.4.x) branch) | May 2023 |
@@ -34,11 +33,7 @@
| [3.3.0](#330-2018-11-07) | November 2018 |
## [4.2.5](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.4...socket.io-parser@4.2.5) (2025-12-23)
This release contains a bump of `debug` from `~4.3.1` to `~4.4.1`.
# Release notes
## [3.3.4](https://github.com/Automattic/socket.io-parser/compare/3.3.3...3.3.4) (2024-07-22)

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io-parser",
"version": "4.2.5",
"version": "4.2.4",
"description": "socket.io protocol parser",
"homepage": "https://github.com/socketio/socket.io/tree/main/packages/socket.io-client#readme",
"repository": {

View File

@@ -15,7 +15,7 @@
"types": "./dist/index.d.ts",
"scripts": {
"compile": "rimraf ./dist && tsc",
"test": "npm run format:check && npm run compile && nyc mocha --import=tsx --timeout 5000 test/index.ts",
"test": "npm run format:check && npm run compile && nyc mocha --require ts-node/register --timeout 5000 test/index.ts",
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
"prepack": "npm run compile"

View File

@@ -19,11 +19,11 @@
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
"prepack": "npm run compile",
"test": "npm run format:check && npm run compile && npm run test:redis-standalone && npm run test:ioredis-standalone",
"test:redis-standalone": "tsx --test",
"test:redis-cluster": "REDIS_CLUSTER=1 npm run test:redis-standalone",
"test:ioredis-standalone": "REDIS_LIB=ioredis npm run test:redis-standalone",
"test:ioredis-cluster": "REDIS_LIB=ioredis REDIS_CLUSTER=1 npm run test:redis-standalone",
"test:valkey-standalone": "VALKEY=1 npm run test:redis-standalone"
"test:redis-standalone": "nyc mocha --import=tsx test/**/*.ts",
"test:redis-cluster": "REDIS_CLUSTER=1 mocha --import=tsx test/**/*.ts",
"test:ioredis-standalone": "REDIS_LIB=ioredis mocha --import=tsx test/**/*.ts",
"test:ioredis-cluster": "REDIS_LIB=ioredis REDIS_CLUSTER=1 mocha --import=tsx test/**/*.ts",
"test:valkey-standalone": "VALKEY=1 mocha --import=tsx test/**/*.ts"
},
"dependencies": {
"@msgpack/msgpack": "~2.8.0",

View File

@@ -1,16 +1,15 @@
import { describe, it, beforeEach, afterEach } from "node:test";
import * as assert from "node:assert";
import { type Server, type Socket as ServerSocket } from "socket.io";
import { type Socket as ClientSocket } from "socket.io-client";
import expect = require("expect.js");
import { times, sleep, setup, initRedisClient } from "./util";
import { Emitter } from "../lib";
const PROPAGATION_DELAY_IN_MS = 100;
describe("@socket.io/redis-streams-emitter", () => {
let servers: [Server, Server, Server],
serverSockets: [ServerSocket, ServerSocket, ServerSocket],
clientSockets: [ClientSocket, ClientSocket, ClientSocket],
let servers: Server[],
serverSockets: ServerSocket[],
clientSockets: ClientSocket[],
cleanup: () => void,
emitter: Emitter;
@@ -31,88 +30,80 @@ describe("@socket.io/redis-streams-emitter", () => {
afterEach(() => cleanup());
describe("broadcast", function () {
it("broadcasts to all clients", () => {
return new Promise<void>((resolve) => {
const partialResolve = times(3, resolve);
it("broadcasts to all clients", (done) => {
const partialDone = times(3, done);
clientSockets.forEach((clientSocket) => {
clientSocket.on("test", (arg1, arg2, arg3) => {
assert.equal(arg1, 1);
assert.equal(arg2, "2");
assert.ok(Buffer.isBuffer(arg3));
partialResolve();
});
clientSockets.forEach((clientSocket) => {
clientSocket.on("test", (arg1, arg2, arg3) => {
expect(arg1).to.eql(1);
expect(arg2).to.eql("2");
expect(Buffer.isBuffer(arg3)).to.be(true);
partialDone();
});
emitter.emit("test", 1, "2", Buffer.from([3, 4]));
});
emitter.emit("test", 1, "2", Buffer.from([3, 4]));
});
it("broadcasts to all clients in a namespace", () => {
return new Promise<void>((resolve) => {
const partialResolve = times(3, () => {
servers.forEach((server) => server.of("/custom").adapter.close());
resolve();
});
it("broadcasts to all clients in a namespace", (done) => {
const partialDone = times(3, () => {
servers.forEach((server) => server.of("/custom").adapter.close());
done();
});
servers.forEach((server) => server.of("/custom"));
servers.forEach((server) => server.of("/custom"));
const onConnect = times(3, async () => {
await sleep(PROPAGATION_DELAY_IN_MS);
const onConnect = times(3, async () => {
await sleep(PROPAGATION_DELAY_IN_MS);
emitter.of("/custom").emit("test");
});
emitter.of("/custom").emit("test");
});
clientSockets.forEach((clientSocket) => {
const socket = clientSocket.io.socket("/custom");
socket.on("connect", onConnect);
socket.on("test", () => {
socket.disconnect();
partialResolve();
});
clientSockets.forEach((clientSocket) => {
const socket = clientSocket.io.socket("/custom");
socket.on("connect", onConnect);
socket.on("test", () => {
socket.disconnect();
partialDone();
});
});
});
it("broadcasts to all clients in a room", () => {
return new Promise<void>((resolve, reject) => {
serverSockets[1].join("room1");
it("broadcasts to all clients in a room", (done) => {
serverSockets[1].join("room1");
clientSockets[0].on("test", () => {
reject("should not happen");
});
clientSockets[1].on("test", () => {
resolve();
});
clientSockets[2].on("test", () => {
reject("should not happen");
});
emitter.to("room1").emit("test");
clientSockets[0].on("test", () => {
done(new Error("should not happen"));
});
clientSockets[1].on("test", () => {
done();
});
clientSockets[2].on("test", () => {
done(new Error("should not happen"));
});
emitter.to("room1").emit("test");
});
it("broadcasts to all clients except in room", () => {
return new Promise<void>((resolve, reject) => {
const partialResolve = times(2, resolve);
serverSockets[1].join("room1");
it("broadcasts to all clients except in room", (done) => {
const partialDone = times(2, done);
serverSockets[1].join("room1");
clientSockets[0].on("test", () => {
partialResolve();
});
clientSockets[1].on("test", () => {
reject("should not happen");
});
clientSockets[2].on("test", () => {
partialResolve();
});
emitter.of("/").except("room1").emit("test");
clientSockets[0].on("test", () => {
partialDone();
});
clientSockets[1].on("test", () => {
done(new Error("should not happen"));
});
clientSockets[2].on("test", () => {
partialDone();
});
emitter.of("/").except("room1").emit("test");
});
});
@@ -122,9 +113,9 @@ describe("@socket.io/redis-streams-emitter", () => {
await sleep(PROPAGATION_DELAY_IN_MS);
assert.ok(serverSockets[0].rooms.has("room1"));
assert.ok(serverSockets[1].rooms.has("room1"));
assert.ok(serverSockets[2].rooms.has("room1"));
expect(serverSockets[0].rooms.has("room1")).to.be(true);
expect(serverSockets[1].rooms.has("room1")).to.be(true);
expect(serverSockets[2].rooms.has("room1")).to.be(true);
});
it("makes the matching socket instances join the specified room", async () => {
@@ -135,9 +126,9 @@ describe("@socket.io/redis-streams-emitter", () => {
await sleep(PROPAGATION_DELAY_IN_MS);
assert.ok(serverSockets[0].rooms.has("room2"));
assert.ok(serverSockets[1].rooms.has("room2") === false);
assert.ok(serverSockets[2].rooms.has("room2"));
expect(serverSockets[0].rooms.has("room2")).to.be(true);
expect(serverSockets[1].rooms.has("room2")).to.be(false);
expect(serverSockets[2].rooms.has("room2")).to.be(true);
});
it("makes the given socket instance join the specified room", async () => {
@@ -145,9 +136,9 @@ describe("@socket.io/redis-streams-emitter", () => {
await sleep(PROPAGATION_DELAY_IN_MS);
assert.ok(serverSockets[0].rooms.has("room3") === false);
assert.ok(serverSockets[1].rooms.has("room3"));
assert.ok(serverSockets[2].rooms.has("room3") === false);
expect(serverSockets[0].rooms.has("room3")).to.be(false);
expect(serverSockets[1].rooms.has("room3")).to.be(true);
expect(serverSockets[2].rooms.has("room3")).to.be(false);
});
});
@@ -160,9 +151,9 @@ describe("@socket.io/redis-streams-emitter", () => {
await sleep(PROPAGATION_DELAY_IN_MS);
assert.ok(serverSockets[0].rooms.has("room1") === false);
assert.ok(serverSockets[1].rooms.has("room1") === false);
assert.ok(serverSockets[2].rooms.has("room1") === false);
expect(serverSockets[0].rooms.has("room1")).to.be(false);
expect(serverSockets[1].rooms.has("room1")).to.be(false);
expect(serverSockets[2].rooms.has("room1")).to.be(false);
});
it("makes the matching socket instances leave the specified room", async () => {
@@ -174,9 +165,9 @@ describe("@socket.io/redis-streams-emitter", () => {
await sleep(PROPAGATION_DELAY_IN_MS);
assert.ok(serverSockets[0].rooms.has("room2") === false);
assert.ok(serverSockets[1].rooms.has("room2") === false);
assert.ok(serverSockets[2].rooms.has("room2"));
expect(serverSockets[0].rooms.has("room2")).to.be(false);
expect(serverSockets[1].rooms.has("room2")).to.be(false);
expect(serverSockets[2].rooms.has("room2")).to.be(true);
});
it("makes the given socket instance leave the specified room", async () => {
@@ -188,50 +179,46 @@ describe("@socket.io/redis-streams-emitter", () => {
await sleep(PROPAGATION_DELAY_IN_MS);
assert.ok(serverSockets[0].rooms.has("room3"));
assert.ok(serverSockets[1].rooms.has("room1") === false);
assert.ok(serverSockets[2].rooms.has("room3"));
expect(serverSockets[0].rooms.has("room3")).to.be(true);
expect(serverSockets[1].rooms.has("room3")).to.be(false);
expect(serverSockets[2].rooms.has("room3")).to.be(true);
});
});
describe("disconnectSockets", () => {
it("makes all socket instances disconnect", () => {
return new Promise<void>((resolve) => {
const partialResolve = times(3, resolve);
it("makes all socket instances disconnect", (done) => {
const partialDone = times(3, done);
clientSockets.forEach((clientSocket) => {
clientSocket.on("disconnect", (reason) => {
assert.equal(reason, "io server disconnect");
partialResolve();
});
clientSockets.forEach((clientSocket) => {
clientSocket.on("disconnect", (reason) => {
expect(reason).to.eql("io server disconnect");
partialDone();
});
emitter.disconnectSockets();
});
emitter.disconnectSockets();
});
});
describe("serverSideEmit", () => {
it("sends an event to other server instances", () => {
return new Promise<void>((resolve) => {
const partialResolve = times(3, resolve);
it("sends an event to other server instances", (done) => {
const partialDone = times(3, done);
emitter.serverSideEmit("hello", "world", 1, "2");
emitter.serverSideEmit("hello", "world", 1, "2");
servers[0].on("hello", (arg1, arg2, arg3) => {
assert.equal(arg1, "world");
assert.equal(arg2, 1);
assert.equal(arg3, "2");
partialResolve();
});
servers[0].on("hello", (arg1, arg2, arg3) => {
expect(arg1).to.eql("world");
expect(arg2).to.eql(1);
expect(arg3).to.eql("2");
partialDone();
});
servers[1].on("hello", (arg1, arg2, arg3) => {
partialResolve();
});
servers[1].on("hello", (arg1, arg2, arg3) => {
partialDone();
});
servers[2].of("/").on("hello", () => {
partialResolve();
});
servers[2].of("/").on("hello", () => {
partialDone();
});
});
});

View File

@@ -138,17 +138,9 @@ async function init() {
export async function setup() {
const results = await Promise.all([init(), init(), init()]);
const servers = results.map(({ io }) => io) as [Server, Server, Server];
const serverSockets = results.map(({ socket }) => socket) as [
ServerSocket,
ServerSocket,
ServerSocket,
];
const clientSockets = results.map(({ clientSocket }) => clientSocket) as [
ClientSocket,
ClientSocket,
ClientSocket,
];
const servers = results.map(({ io }) => io);
const serverSockets = results.map(({ socket }) => socket);
const clientSockets = results.map(({ clientSocket }) => clientSocket);
const cleanupMethods = results.map(({ cleanup }) => cleanup);
return {

View File

@@ -1,9 +1,7 @@
# Changelog
# History
| Version | Release date |
|--------------------------------------------------------------------------------------------------|----------------|
| [4.8.3](#483-2025-12-23) | December 2025 |
| [4.8.2](#482-2025-12-22) | December 2025 |
| [4.8.1](#481-2024-10-25) | October 2024 |
| [4.8.0](#480-2024-09-21) | September 2024 |
| [4.7.5](#475-2024-03-14) | March 2024 |
@@ -51,37 +49,7 @@
| [2.1.0](#210-2018-03-29) | March 2018 |
## [4.8.3](https://github.com/socketio/socket.io/compare/socket.io@4.8.2...socket.io@4.8.3) (2025-12-23)
### Bug Fixes
* do not throw when calling io.close() on a stopped server ([9581f9b](https://github.com/socketio/socket.io/commit/9581f9bcfd0c0fa8cb16eae1604c6a727af21efa))
### Dependencies
- [`engine.io@~6.6.0`](https://github.com/socketio/engine.io/releases/tag/6.6.0) (no change)
- [`ws@~8.18.3`](https://github.com/websockets/ws/releases/tag/8.18.3) (no change)
## [4.8.2](https://github.com/socketio/socket.io/compare/socket.io@4.8.1...socket.io@4.8.2) (2025-12-22)
The `url.parse()` function is now deprecated and has been replaced by `new URL()` (see [8af7019](https://github.com/socketio/socket.io/commit/8af70195bb8c5bc3efe9685997ab6373fb8b1ca9)).
### Bug Fixes
* call adapter.init() when creating each namespace ([f3e1f5e](https://github.com/socketio/socket.io/commit/f3e1f5ebdf59158d0c8d1e20f8230275617fb355))
* improve `io.close()` function ([#5344](https://github.com/socketio/socket.io/issues/5344)) ([bb0b480](https://github.com/socketio/socket.io/commit/bb0b480d2ab3108a8ae255b539015da451fdb249))
### Dependencies
- [`engine.io@~6.6.0`](https://github.com/socketio/engine.io/releases/tag/6.6.0) (no change)
- [`ws@~8.18.3`](https://github.com/websockets/ws/releases/tag/8.18.3) ([diff](https://github.com/websockets/ws/compare/8.17.1...8.18.3))
# Release notes
## [4.8.1](https://github.com/socketio/socket.io/compare/socket.io@4.8.0...socket.io@4.8.1) (2024-10-25)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Socket.IO v4.8.3
* (c) 2014-2025 Guillermo Rauch
* Socket.IO v4.8.1
* (c) 2014-2024 Guillermo Rauch
* Released under the MIT License.
*/
(function (global, factory) {
@@ -899,7 +899,7 @@
return hostname.indexOf(":") === -1 ? hostname : "[" + hostname + "]";
};
_proto._port = function _port() {
if (this.opts.port && (this.opts.secure && Number(this.opts.port) !== 443 || !this.opts.secure && Number(this.opts.port) !== 80)) {
if (this.opts.port && (this.opts.secure && Number(this.opts.port !== 443) || !this.opts.secure && Number(this.opts.port) !== 80)) {
return ":" + this.opts.port;
} else {
return "";
@@ -2669,65 +2669,21 @@
createDebug.namespaces = namespaces;
createDebug.names = [];
createDebug.skips = [];
var split = (typeof namespaces === 'string' ? namespaces : '').trim().replace(/\s+/g, ',').split(',').filter(Boolean);
var _iterator = _createForOfIteratorHelper(split),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var ns = _step.value;
if (ns[0] === '-') {
createDebug.skips.push(ns.slice(1));
} else {
createDebug.names.push(ns);
}
var i;
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
var len = split.length;
for (i = 0; i < len; i++) {
if (!split[i]) {
// ignore empty strings
continue;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
/**
* Checks if the given string matches a namespace template, honoring
* asterisks as wildcards.
*
* @param {String} search
* @param {String} template
* @return {Boolean}
*/
function matchesTemplate(search, template) {
var searchIndex = 0;
var templateIndex = 0;
var starIndex = -1;
var matchIndex = 0;
while (searchIndex < search.length) {
if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
// Match character or proceed with wildcard
if (template[templateIndex] === '*') {
starIndex = templateIndex;
matchIndex = searchIndex;
templateIndex++; // Skip the '*'
} else {
searchIndex++;
templateIndex++;
}
} else if (starIndex !== -1) {
// eslint-disable-line no-negated-condition
// Backtrack to the last '*' and try to match more characters
templateIndex = starIndex + 1;
matchIndex++;
searchIndex = matchIndex;
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
} else {
return false; // No match
createDebug.names.push(new RegExp('^' + namespaces + '$'));
}
}
// Handle trailing '*' in template
while (templateIndex < template.length && template[templateIndex] === '*') {
templateIndex++;
}
return templateIndex === template.length;
}
/**
@@ -2737,7 +2693,7 @@
* @api public
*/
function disable() {
var namespaces = [].concat(_toConsumableArray(createDebug.names), _toConsumableArray(createDebug.skips.map(function (namespace) {
var namespaces = [].concat(_toConsumableArray(createDebug.names.map(toNamespace)), _toConsumableArray(createDebug.skips.map(toNamespace).map(function (namespace) {
return '-' + namespace;
}))).join(',');
createDebug.enable('');
@@ -2752,37 +2708,35 @@
* @api public
*/
function enabled(name) {
var _iterator2 = _createForOfIteratorHelper(createDebug.skips),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var skip = _step2.value;
if (matchesTemplate(name, skip)) {
return false;
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
if (name[name.length - 1] === '*') {
return true;
}
var _iterator3 = _createForOfIteratorHelper(createDebug.names),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var ns = _step3.value;
if (matchesTemplate(name, ns)) {
return true;
}
var i;
var len;
for (i = 0, len = createDebug.skips.length; i < len; i++) {
if (createDebug.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = createDebug.names.length; i < len; i++) {
if (createDebug.names[i].test(name)) {
return true;
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return false;
}
/**
* Convert regexp to namespace
*
* @param {RegExp} regxep
* @return {String} namespace
* @api private
*/
function toNamespace(regexp) {
return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\.\*\?$/, '*');
}
/**
* Coerce `val`.
*
@@ -2858,17 +2812,15 @@
if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
return false;
}
var m;
// Is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
// eslint-disable-next-line no-return-assign
return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance ||
// Is firebug? http://stackoverflow.com/a/398120/376773
typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) ||
// Is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31 ||
typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 ||
// Double check webkit in userAgent just in case we are in a worker
typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
}
@@ -2944,7 +2896,7 @@
function load() {
var r;
try {
r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG');
r = exports.storage.getItem('debug');
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
@@ -3876,7 +3828,8 @@
};
args.push(function (err) {
if (packet !== _this4._queue[0]) {
return debug$2("packet [%d] already acknowledged", packet.id);
// the packet has already been acknowledged
return;
}
var hasError = err !== null;
if (hasError) {
@@ -4147,8 +4100,8 @@
this._pid = pid; // defined only if connection state recovery is enabled
this.connected = true;
this.emitBuffered();
this._drainQueue(true);
this.emitReserved("connect");
this._drainQueue(true);
}
/**
* Emit buffered events (received and emitted).

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -831,15 +831,7 @@ export class Server<
restoreAdapter();
if (this.httpServer) {
return new Promise<void>((resolve) => {
this.httpServer.close((err) => {
fn && fn(err);
if (err) {
debug("server was not running");
}
resolve();
});
});
this.httpServer.close(fn);
} else {
fn && fn();
}

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io",
"version": "4.8.3",
"version": "4.8.1",
"description": "node.js realtime framework server",
"keywords": [
"realtime",
@@ -26,12 +26,9 @@
"type": "commonjs",
"main": "./dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./wrapper.mjs",
"require": "./dist/index.js"
},
"./package.json": "./package.json"
"types": "./dist/index.d.ts",
"import": "./wrapper.mjs",
"require": "./dist/index.js"
},
"types": "./dist/index.d.ts",
"license": "MIT",
@@ -47,7 +44,7 @@
"compile": "rimraf ./dist && tsc",
"test": "npm run format:check && npm run compile && npm run test:types && npm run test:unit",
"test:types": "tsd",
"test:unit": "nyc mocha --import=tsx --reporter spec --slow 200 --bail --timeout 10000 test/index.ts",
"test:unit": "nyc mocha --require ts-node/register --reporter spec --slow 200 --bail --timeout 10000 test/index.ts",
"format:check": "prettier --check \"lib/**/*.ts\" \"test/**/*.ts\"",
"format:fix": "prettier --write \"lib/**/*.ts\" \"test/**/*.ts\"",
"prepack": "npm run compile"

View File

@@ -70,27 +70,6 @@ describe("close", () => {
});
});
it("should not throw when the underlying HTTP server is not running (callback)", (done) => {
const httpServer = createServer();
const io = new Server(httpServer);
io.close((err) => {
expect((err as Error & { code: string }).code).to.eql(
"ERR_SERVER_NOT_RUNNING",
);
done();
});
});
it("should not throw when the underlying HTTP server is not running (Promise)", (done) => {
const httpServer = createServer();
const io = new Server(httpServer);
io.close()
.then(() => done())
.catch((e) => done(e));
});
describe("graceful close", () => {
function fixture(filename) {
return (

View File

@@ -6,7 +6,7 @@ import { getPort, successFn } from "./support/util";
describe("server attachment", () => {
describe("http.Server", () => {
const clientVersion = require("../package.json").version;
const clientVersion = require("socket.io-client/package.json").version;
const testSource = (filename) => (done) => {
const srv = createServer();

View File

@@ -229,7 +229,7 @@ describe("socket.io with uWebSocket.js-based engine", () => {
});
it("should serve static files", (done) => {
const clientVersion = require("../package.json").version;
const clientVersion = require("socket.io-client/package.json").version;
request(`http://localhost:${port}`)
.get("/socket.io/socket.io.js")