mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-12 08:27:57 -05:00
Compare commits
67 Commits
@socket.io
...
engine.io@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72d61dab82 | ||
|
|
5a31aaf917 | ||
|
|
62e4da125e | ||
|
|
bfa6eab195 | ||
|
|
7fcddcb3bb | ||
|
|
7427109658 | ||
|
|
91e1c8b358 | ||
|
|
8d5528aa2a | ||
|
|
71387e5294 | ||
|
|
aead83560d | ||
|
|
029e010901 | ||
|
|
4ca6ddb3a2 | ||
|
|
ca9e994815 | ||
|
|
4865f2e62e | ||
|
|
d4b3ddedff | ||
|
|
3b68658201 | ||
|
|
175a2c58c1 | ||
|
|
9b80ab42d6 | ||
|
|
a5d2368512 | ||
|
|
88efd446f1 | ||
|
|
d0fc720420 | ||
|
|
4a0555c671 | ||
|
|
2b60df18a8 | ||
|
|
d4cb375856 | ||
|
|
c251ae7ba7 | ||
|
|
8a2f5a3da0 | ||
|
|
b04fa64365 | ||
|
|
7085f0e3e4 | ||
|
|
4f66708210 | ||
|
|
1a95db2145 | ||
|
|
282ae922a4 | ||
|
|
93010ca3c4 | ||
|
|
132d05fc0b | ||
|
|
d5095fe98c | ||
|
|
da613810fd | ||
|
|
19c48a44e6 | ||
|
|
9b3c9abeca | ||
|
|
043b55c418 | ||
|
|
32c761f02f | ||
|
|
1f54ee08c6 | ||
|
|
923a12e2de | ||
|
|
13c6d2e89d | ||
|
|
8adcfbfde5 | ||
|
|
7a23dde6ef | ||
|
|
60c757f718 | ||
|
|
04c8dd979c | ||
|
|
2194264820 | ||
|
|
09f573cad8 | ||
|
|
fcbecd4f46 | ||
|
|
fd99f2e15f | ||
|
|
02d59a0e99 | ||
|
|
7160eb7eb0 | ||
|
|
a1ccba3a77 | ||
|
|
e347a3c24e | ||
|
|
b5ccfd4838 | ||
|
|
5d9a2d5544 | ||
|
|
d5b22f5a76 | ||
|
|
582655f679 | ||
|
|
b79d80aa59 | ||
|
|
7fd75e6aac | ||
|
|
b7577556e3 | ||
|
|
6e9bff4fcf | ||
|
|
8b0a40fd4a | ||
|
|
1f09a3e979 | ||
|
|
0af50758f6 | ||
|
|
b9b16132c2 | ||
|
|
be1e4cb24d |
2
.github/workflows/build-examples.yml
vendored
2
.github/workflows/build-examples.yml
vendored
@@ -19,6 +19,8 @@ jobs:
|
||||
- custom-parsers
|
||||
- typescript-example/cjs
|
||||
- typescript-example/esm
|
||||
- typescript-client-example/cjs
|
||||
- typescript-client-example/esm
|
||||
- webpack-build
|
||||
- webpack-build-server
|
||||
- basic-crud-application/angular-client
|
||||
|
||||
4
.github/workflows/ci-browser.yml
vendored
4
.github/workflows/ci-browser.yml
vendored
@@ -2,6 +2,8 @@ name: CI (browser)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
paths:
|
||||
- 'packages/engine.io-parser/**'
|
||||
- 'packages/engine.io-client/**'
|
||||
@@ -14,7 +16,7 @@ permissions:
|
||||
jobs:
|
||||
test-browser:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -2,6 +2,8 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
@@ -20,6 +22,7 @@ jobs:
|
||||
node-version:
|
||||
- 18
|
||||
- 20
|
||||
- 22
|
||||
|
||||
services:
|
||||
redis:
|
||||
@@ -44,13 +47,20 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# in order to test our compliance with TypeScript v4.2 (older versions are not tested)
|
||||
- name: Install TypeScript 4.2
|
||||
run: npm i typescript@4.2
|
||||
if: ${{ matrix.node-version == '16' }}
|
||||
|
||||
- name: Compile each package
|
||||
run: npm run compile --workspaces --if-present
|
||||
|
||||
- name: Run tests
|
||||
run: npm test --workspaces
|
||||
|
||||
- name: Run tests with uws (engine.io)
|
||||
run: npm run test:uws --workspace=engine.io
|
||||
if: ${{ matrix.node-version == '18' }}
|
||||
|
||||
- name: Run tests with fetch instead of XHR (engine.io-client)
|
||||
run: npm run test:node-fetch --workspace=engine.io-client
|
||||
if: ${{ matrix.node-version == '18' }}
|
||||
|
||||
- name: Run tests with Node.js native WebSocket (engine.io-client)
|
||||
run: npm run test:node-builtin-ws --workspace=engine.io-client
|
||||
if: ${{ matrix.node-version == '22' }}
|
||||
|
||||
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
push:
|
||||
tags:
|
||||
# expected format: <package>@<version> (example: socket.io@1.2.3)
|
||||
- '*@*'
|
||||
- '**@*'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@@ -28,6 +28,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Compile each package
|
||||
run: npm run compile --workspaces --if-present
|
||||
|
||||
- name: Publish package
|
||||
run: npm publish --workspace=${GITHUB_REF_NAME%@*} --provenance --access public
|
||||
env:
|
||||
|
||||
@@ -150,3 +150,18 @@ For a specific workspace:
|
||||
```bash
|
||||
npm test --workspace=socket.io
|
||||
```
|
||||
|
||||
### Generate the changelog
|
||||
|
||||
Install the [`conventional-changelog-cli`](https://www.npmjs.com/package/conventional-changelog-cli) package:
|
||||
|
||||
```bash
|
||||
npm i -g conventional-changelog-cli
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
cd packages/engine.io-client
|
||||
conventional-changelog -p angular --tag-prefix "engine.io-client@" --commit-path .
|
||||
```
|
||||
|
||||
19
examples/cluster-engine-node-cluster/README.md
Normal file
19
examples/cluster-engine-node-cluster/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Example with `@socket.io/cluster-engine` and Node.js cluster
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
# run the server
|
||||
$ node server.js
|
||||
|
||||
# run the client
|
||||
$ node client.js
|
||||
```
|
||||
|
||||
## Explanation
|
||||
|
||||
The `server.js` script will create one Socket.IO server per core, each listening on the same port (`3000`).
|
||||
|
||||
With the default engine (provided by the `engine.io` package), sticky sessions would be required, so that each HTTP request of the same Engine.IO session reaches the same worker.
|
||||
|
||||
The `NodeClusterEngine` is a custom engine which takes care of the synchronization between the servers by using [the IPC channel](https://nodejs.org/api/cluster.html#workersendmessage-sendhandle-options-callback) and removes the need for sticky sessions when scaling horizontally.
|
||||
26
examples/cluster-engine-node-cluster/client.js
Normal file
26
examples/cluster-engine-node-cluster/client.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const CLIENTS_COUNT = 3;
|
||||
|
||||
for (let i = 0; i < CLIENTS_COUNT; i++) {
|
||||
const socket = io("ws://localhost:3000/", {
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connected as ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (socketId, workerId) => {
|
||||
console.log(`received "hello" from ${socketId} (worker: ${workerId})`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.emit("hello");
|
||||
}, 2000);
|
||||
}
|
||||
12
examples/cluster-engine-node-cluster/package.json
Normal file
12
examples/cluster-engine-node-cluster/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "cluster-engine-node-cluster",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@socket.io/cluster-adapter": "^0.2.2",
|
||||
"@socket.io/cluster-engine": "^0.1.0",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5"
|
||||
}
|
||||
}
|
||||
63
examples/cluster-engine-node-cluster/server.js
Normal file
63
examples/cluster-engine-node-cluster/server.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import cluster from "node:cluster";
|
||||
import process from "node:process";
|
||||
import { availableParallelism } from "node:os";
|
||||
import {
|
||||
setupPrimary as setupPrimaryEngine,
|
||||
NodeClusterEngine,
|
||||
} from "@socket.io/cluster-engine";
|
||||
import {
|
||||
setupPrimary as setupPrimaryAdapter,
|
||||
createAdapter,
|
||||
} from "@socket.io/cluster-adapter";
|
||||
import { createServer } from "node:http";
|
||||
import { Server } from "socket.io";
|
||||
|
||||
if (cluster.isPrimary) {
|
||||
console.log(`Primary ${process.pid} is running`);
|
||||
|
||||
const numCPUs = availableParallelism();
|
||||
|
||||
// fork workers
|
||||
for (let i = 0; i < numCPUs; i++) {
|
||||
cluster.fork();
|
||||
}
|
||||
|
||||
setupPrimaryEngine();
|
||||
setupPrimaryAdapter();
|
||||
|
||||
// needed for packets containing Buffer objects (you can ignore it if you only send plaintext objects)
|
||||
cluster.setupPrimary({
|
||||
serialization: "advanced",
|
||||
});
|
||||
|
||||
cluster.on("exit", (worker, code, signal) => {
|
||||
console.log(`worker ${worker.process.pid} died`);
|
||||
});
|
||||
} else {
|
||||
const httpServer = createServer((req, res) => {
|
||||
res.writeHead(404).end();
|
||||
});
|
||||
|
||||
const engine = new NodeClusterEngine();
|
||||
|
||||
engine.attach(httpServer, {
|
||||
path: "/socket.io/",
|
||||
});
|
||||
|
||||
const io = new Server({
|
||||
adapter: createAdapter(),
|
||||
});
|
||||
|
||||
io.bind(engine);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.on("hello", () => {
|
||||
socket.broadcast.emit("hello", socket.id, process.pid);
|
||||
});
|
||||
});
|
||||
|
||||
// workers will share the same port
|
||||
httpServer.listen(3000);
|
||||
|
||||
console.log(`Worker ${process.pid} started`);
|
||||
}
|
||||
22
examples/cluster-engine-redis/README.md
Normal file
22
examples/cluster-engine-redis/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Example with `@socket.io/cluster-engine` and Redis
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
# start the redis server
|
||||
$ docker compose up -d
|
||||
|
||||
# run the server
|
||||
$ node server.js
|
||||
|
||||
# run the client
|
||||
$ node client.js
|
||||
```
|
||||
|
||||
## Explanation
|
||||
|
||||
The `server.js` script will create 3 Socket.IO servers, each listening on a distinct port (`3001`, `3002` and `3003`), and a proxy server listening on port `3000` which randomly redirects to one of those servers.
|
||||
|
||||
With the default engine (provided by the `engine.io` package), sticky sessions would be required, so that each HTTP request of the same Engine.IO session reaches the same server.
|
||||
|
||||
The `RedisEngine` is a custom engine which takes care of the synchronization between the servers by using [Redis pub/sub](https://redis.io/docs/latest/develop/interact/pubsub/) and removes the need for sticky sessions when scaling horizontally.
|
||||
26
examples/cluster-engine-redis/client.js
Normal file
26
examples/cluster-engine-redis/client.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const CLIENTS_COUNT = 3;
|
||||
|
||||
for (let i = 0; i < CLIENTS_COUNT; i++) {
|
||||
const socket = io("ws://localhost:3000/", {
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connected as ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (socketId, workerId) => {
|
||||
console.log(`received "hello" from ${socketId} (worker: ${workerId})`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.emit("hello");
|
||||
}, 2000);
|
||||
}
|
||||
5
examples/cluster-engine-redis/compose.yaml
Normal file
5
examples/cluster-engine-redis/compose.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
services:
|
||||
redis:
|
||||
image: redis:7
|
||||
ports:
|
||||
- "6379:6379"
|
||||
14
examples/cluster-engine-redis/package.json
Normal file
14
examples/cluster-engine-redis/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "cluster-engine-redis",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@socket.io/cluster-engine": "^0.1.0",
|
||||
"@socket.io/redis-adapter": "^8.3.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"redis": "^4.6.15",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5"
|
||||
}
|
||||
}
|
||||
65
examples/cluster-engine-redis/server.js
Normal file
65
examples/cluster-engine-redis/server.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { RedisEngine } from "@socket.io/cluster-engine";
|
||||
import { createServer } from "node:http";
|
||||
import { createClient } from "redis";
|
||||
import { Server } from "socket.io";
|
||||
import { createAdapter } from "@socket.io/redis-adapter";
|
||||
import proxyModule from "http-proxy";
|
||||
|
||||
const { createProxyServer } = proxyModule;
|
||||
|
||||
async function initServer(port) {
|
||||
const httpServer = createServer((req, res) => {
|
||||
res.writeHead(404).end();
|
||||
});
|
||||
|
||||
const pubClient = createClient();
|
||||
const subClient = pubClient.duplicate();
|
||||
|
||||
await Promise.all([pubClient.connect(), subClient.connect()]);
|
||||
|
||||
const engine = new RedisEngine(pubClient, subClient);
|
||||
|
||||
engine.attach(httpServer, {
|
||||
path: "/socket.io/",
|
||||
});
|
||||
|
||||
const io = new Server({
|
||||
adapter: createAdapter(pubClient, subClient),
|
||||
});
|
||||
|
||||
io.bind(engine);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.on("hello", () => {
|
||||
socket.broadcast.emit("hello", socket.id, port);
|
||||
});
|
||||
});
|
||||
|
||||
httpServer.listen(port);
|
||||
}
|
||||
|
||||
function initProxy() {
|
||||
const proxy = createProxyServer();
|
||||
|
||||
function randomTarget() {
|
||||
return [
|
||||
"http://localhost:3001",
|
||||
"http://localhost:3002",
|
||||
"http://localhost:3003",
|
||||
][Math.floor(Math.random() * 3)];
|
||||
}
|
||||
|
||||
const httpServer = createServer((req, res) => {
|
||||
proxy.web(req, res, { target: randomTarget() });
|
||||
});
|
||||
|
||||
httpServer.on("upgrade", function (req, socket, head) {
|
||||
proxy.ws(req, socket, head, { target: randomTarget() });
|
||||
});
|
||||
|
||||
httpServer.listen(3000);
|
||||
}
|
||||
|
||||
await Promise.all([initServer(3001), initServer(3002), initServer(3003)]);
|
||||
|
||||
initProxy();
|
||||
25
examples/nestjs-example/.eslintrc.js
Normal file
25
examples/nestjs-example/.eslintrc.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
56
examples/nestjs-example/.gitignore
vendored
Normal file
56
examples/nestjs-example/.gitignore
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
/build
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# temp directory
|
||||
.temp
|
||||
.tmp
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
4
examples/nestjs-example/.prettierrc
Normal file
4
examples/nestjs-example/.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
73
examples/nestjs-example/README.md
Normal file
73
examples/nestjs-example/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
## Running the app
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](LICENSE).
|
||||
8
examples/nestjs-example/nest-cli.json
Normal file
8
examples/nestjs-example/nest-cli.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
72
examples/nestjs-example/package.json
Normal file
72
examples/nestjs-example/package.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "nestjs-example",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/platform-socket.io": "^10.3.10",
|
||||
"@nestjs/websockets": "^10.3.10",
|
||||
"hbs": "^4.2.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
22
examples/nestjs-example/src/app.controller.spec.ts
Normal file
22
examples/nestjs-example/src/app.controller.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
||||
13
examples/nestjs-example/src/app.controller.ts
Normal file
13
examples/nestjs-example/src/app.controller.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Controller, Get, Render } from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
@Render('index')
|
||||
root() {
|
||||
return { message: 'Hello world2!' };
|
||||
}
|
||||
}
|
||||
11
examples/nestjs-example/src/app.module.ts
Normal file
11
examples/nestjs-example/src/app.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { EventsModule } from './events/events.module';
|
||||
|
||||
@Module({
|
||||
imports: [EventsModule],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
8
examples/nestjs-example/src/app.service.ts
Normal file
8
examples/nestjs-example/src/app.service.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getHello(): string {
|
||||
return 'Hello World!';
|
||||
}
|
||||
}
|
||||
18
examples/nestjs-example/src/events/events.gateway.ts
Normal file
18
examples/nestjs-example/src/events/events.gateway.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {
|
||||
MessageBody,
|
||||
SubscribeMessage,
|
||||
WebSocketGateway,
|
||||
WebSocketServer,
|
||||
} from '@nestjs/websockets';
|
||||
import { Server } from 'socket.io';
|
||||
|
||||
@WebSocketGateway({})
|
||||
export class EventsGateway {
|
||||
@WebSocketServer()
|
||||
io: Server;
|
||||
|
||||
@SubscribeMessage('hello')
|
||||
handleEvent(@MessageBody() data: string): string {
|
||||
return data.split('').reverse().join('');
|
||||
}
|
||||
}
|
||||
7
examples/nestjs-example/src/events/events.module.ts
Normal file
7
examples/nestjs-example/src/events/events.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { EventsGateway } from './events.gateway';
|
||||
|
||||
@Module({
|
||||
providers: [EventsGateway],
|
||||
})
|
||||
export class EventsModule {}
|
||||
15
examples/nestjs-example/src/main.ts
Normal file
15
examples/nestjs-example/src/main.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { join } from 'node:path';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
|
||||
app.setBaseViewsDir(join(__dirname, '..', 'views'));
|
||||
app.setViewEngine('hbs');
|
||||
|
||||
await app.listen(3000);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
24
examples/nestjs-example/test/app.e2e-spec.ts
Normal file
24
examples/nestjs-example/test/app.e2e-spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from './../src/app.module';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
});
|
||||
9
examples/nestjs-example/test/jest-e2e.json
Normal file
9
examples/nestjs-example/test/jest-e2e.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".e2e-spec.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
4
examples/nestjs-example/tsconfig.build.json
Normal file
4
examples/nestjs-example/tsconfig.build.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
21
examples/nestjs-example/tsconfig.json
Normal file
21
examples/nestjs-example/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
47
examples/nestjs-example/views/index.hbs
Normal file
47
examples/nestjs-example/views/index.hbs
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>App</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Status: <span id="status"></span></p>
|
||||
<p>Transport: <span id="transport"></span></p>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script>
|
||||
const statusSpan = document.getElementById("status");
|
||||
const transportSpan = document.getElementById("transport");
|
||||
const socket = io({
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
statusSpan.innerText = "Disconnected";
|
||||
transportSpan.innerText = "N/A";
|
||||
|
||||
socket.on("connect", () => {
|
||||
statusSpan.innerText = "Connected";
|
||||
transportSpan.innerText = socket.io.engine.transport.name;
|
||||
socket.io.engine.on("upgrade", (transport) => {
|
||||
transportSpan.innerText = transport.name;
|
||||
});
|
||||
console.log(`connect ${socket.id}`);
|
||||
|
||||
socket.emit("hello", "world", (val) => {
|
||||
console.log(`got ${val}`);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
console.log(`connect_error due to ${err.message}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
statusSpan.innerText = "Disconnected";
|
||||
transportSpan.innerText = "N/A";
|
||||
console.log(`disconnect due to ${reason}`);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -20,17 +20,18 @@ export default defineNitroPlugin((nitroApp: NitroApp) => {
|
||||
},
|
||||
websocket: {
|
||||
open(peer) {
|
||||
const nodeContext = peer.ctx.node;
|
||||
const req = nodeContext.req;
|
||||
// crossws >= 0.3.0
|
||||
// @ts-expect-error private method and property
|
||||
engine.prepare(peer._internal.nodeReq);
|
||||
// @ts-expect-error private method and property
|
||||
engine.onWebSocket(peer._internal.nodeReq, peer._internal.nodeReq.socket, peer.websocket);
|
||||
|
||||
// @ts-expect-error private method
|
||||
engine.prepare(req);
|
||||
|
||||
const rawSocket = nodeContext.req.socket;
|
||||
const websocket = nodeContext.ws;
|
||||
|
||||
// @ts-expect-error private method
|
||||
engine.onWebSocket(req, rawSocket, websocket);
|
||||
// crossws < 0.3.0
|
||||
// const context = peer.ctx.node;
|
||||
// // @ts-expect-error private method
|
||||
// engine.prepare(context.req);
|
||||
// // @ts-expect-error private method
|
||||
// engine.onWebSocket(context.req, context.req.socket, context.ws);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
25
examples/postgres-adapter-example/README.md
Normal file
25
examples/postgres-adapter-example/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Example with `@socket.io/postgres-adapter`
|
||||
|
||||
**Table of contents**
|
||||
|
||||
<!-- TOC -->
|
||||
* [How to use](#how-to-use)
|
||||
* [Documentation](#documentation)
|
||||
<!-- TOC -->
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
# start the postgres server
|
||||
$ docker compose up -d
|
||||
|
||||
# run the cluster
|
||||
$ node cluster.js
|
||||
|
||||
# run the client
|
||||
$ node client.js
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation can be found here: https://socket.io/docs/v4/postgres-adapter/
|
||||
31
examples/postgres-adapter-example/client.js
Normal file
31
examples/postgres-adapter-example/client.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const CLIENTS_COUNT = 3;
|
||||
const PORTS = [3000, 3001, 3002];
|
||||
|
||||
for (let i = 0; i < CLIENTS_COUNT; i++) {
|
||||
const socket = io(`ws://localhost:${PORTS[i % 3]}`, {
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connected as ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("connect_error", () => {
|
||||
console.log(`connect_error`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (socketId, pid) => {
|
||||
console.log(`received "hello" from ${socketId} (process: ${pid})`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.emit("hello");
|
||||
}, 2000);
|
||||
}
|
||||
13
examples/postgres-adapter-example/cluster.js
Normal file
13
examples/postgres-adapter-example/cluster.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import cluster from 'node:cluster';
|
||||
|
||||
const SERVERS_COUNT = 3;
|
||||
|
||||
cluster.setupPrimary({
|
||||
exec: 'server.js',
|
||||
});
|
||||
|
||||
for (let i = 0; i < SERVERS_COUNT; i++) {
|
||||
cluster.fork({
|
||||
PORT: 3000 + i
|
||||
});
|
||||
}
|
||||
7
examples/postgres-adapter-example/compose.yaml
Normal file
7
examples/postgres-adapter-example/compose.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:14
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_PASSWORD: "changeit"
|
||||
12
examples/postgres-adapter-example/package.json
Normal file
12
examples/postgres-adapter-example/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "postgres-adapter-example",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@socket.io/postgres-adapter": "^0.4.0",
|
||||
"pg": "^8.12.0",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5"
|
||||
}
|
||||
}
|
||||
40
examples/postgres-adapter-example/server.js
Normal file
40
examples/postgres-adapter-example/server.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Server } from "socket.io";
|
||||
import { createAdapter } from "@socket.io/postgres-adapter";
|
||||
import pg from "pg";
|
||||
import process from "node:process";
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
const pool = new pg.Pool({
|
||||
user: "postgres",
|
||||
host: "localhost",
|
||||
database: "postgres",
|
||||
password: "changeit",
|
||||
port: 5432,
|
||||
});
|
||||
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS socket_io_attachments (
|
||||
id bigserial UNIQUE,
|
||||
created_at timestamptz DEFAULT NOW(),
|
||||
payload bytea
|
||||
);
|
||||
`);
|
||||
|
||||
pool.on("error", (err) => {
|
||||
console.error("Postgres error", err);
|
||||
});
|
||||
|
||||
const io = new Server({
|
||||
adapter: createAdapter(pool)
|
||||
});
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.on("hello", () => {
|
||||
// send to anyone except the sender
|
||||
socket.broadcast.emit("hello", socket.id, process.pid);
|
||||
});
|
||||
});
|
||||
|
||||
io.listen(PORT);
|
||||
console.log(`server listening on port ${PORT}`);
|
||||
30
examples/typescript-client-example/cjs/client.ts
Normal file
30
examples/typescript-client-example/cjs/client.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { io, type Socket } from "socket.io-client";
|
||||
|
||||
interface ServerToClientEvents {
|
||||
hello: (val: string) => void;
|
||||
}
|
||||
|
||||
interface ClientToServerEvents {
|
||||
ping: (cb: () => void) => void;
|
||||
}
|
||||
|
||||
const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io("ws://localhost:8080/");
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connect ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (val) => {
|
||||
console.log(`got ${val}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log(`disconnect`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
const start = Date.now();
|
||||
socket.emit("ping", () => {
|
||||
console.log(`pong (latency: ${Date.now() - start} ms)`);
|
||||
});
|
||||
}, 1000);
|
||||
17
examples/typescript-client-example/cjs/package.json
Normal file
17
examples/typescript-client-example/cjs/package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "typescript-client-example-cjs",
|
||||
"version": "0.0.1",
|
||||
"description": "An example with TypeScript",
|
||||
"type": "commonjs",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "ts-node client.ts"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"socket.io-client": "^4.8.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
9
examples/typescript-client-example/cjs/tsconfig.json
Normal file
9
examples/typescript-client-example/cjs/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"target": "es2022",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
30
examples/typescript-client-example/esm/client.ts
Normal file
30
examples/typescript-client-example/esm/client.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { io, type Socket } from "socket.io-client";
|
||||
|
||||
interface ServerToClientEvents {
|
||||
hello: (val: string) => void;
|
||||
}
|
||||
|
||||
interface ClientToServerEvents {
|
||||
ping: (cb: () => void) => void;
|
||||
}
|
||||
|
||||
const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io("ws://localhost:8080/");
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connect ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (val) => {
|
||||
console.log(`got ${val}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log(`disconnect`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
const start = Date.now();
|
||||
socket.emit("ping", () => {
|
||||
console.log(`pong (latency: ${Date.now() - start} ms)`);
|
||||
});
|
||||
}, 1000);
|
||||
17
examples/typescript-client-example/esm/package.json
Normal file
17
examples/typescript-client-example/esm/package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "typescript-client-example-esm",
|
||||
"version": "0.0.1",
|
||||
"description": "An example with TypeScript",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node --no-warnings=ExperimentalWarning --loader ts-node/esm client.ts"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"socket.io-client": "^4.8.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
9
examples/typescript-client-example/esm/tsconfig.json
Normal file
9
examples/typescript-client-example/esm/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"target": "es2022",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
497
package-lock.json
generated
497
package-lock.json
generated
@@ -4,6 +4,7 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "socket.io",
|
||||
"workspaces": [
|
||||
"packages/socket.io-component-emitter",
|
||||
"packages/engine.io-parser",
|
||||
@@ -20,7 +21,8 @@
|
||||
"@babel/plugin-transform-object-assign": "^7.24.7",
|
||||
"@babel/preset-env": "^7.24.7",
|
||||
"@babel/register": "^7.24.6",
|
||||
"@fails-components/webtransport": "^0.1.7",
|
||||
"@fails-components/webtransport": "^1.1.4",
|
||||
"@fails-components/webtransport-transport-http3-quiche": "^1.1.4",
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^26.0.1",
|
||||
@@ -40,6 +42,7 @@
|
||||
"base64-arraybuffer": "^1.0.2",
|
||||
"benchmark": "^2.1.4",
|
||||
"blob": "^0.1.0",
|
||||
"cookie": "~0.7.2",
|
||||
"eiows": "^7.1.0",
|
||||
"engine.io-client-v3": "npm:engine.io-client@^3.5.2",
|
||||
"expect.js": "^0.3.1",
|
||||
@@ -51,7 +54,7 @@
|
||||
"mocha": "^10.6.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"nyc": "^17.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.3.2",
|
||||
"redis": "^4.6.15",
|
||||
"rimraf": "^6.0.0",
|
||||
"rollup": "^2.79.1",
|
||||
@@ -66,7 +69,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"tsd": "^0.31.1",
|
||||
"typescript": "^5.5.3",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.30.0",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.48.0",
|
||||
"wdio-geckodriver-service": "^5.0.2"
|
||||
}
|
||||
},
|
||||
@@ -1835,18 +1838,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@fails-components/webtransport": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@fails-components/webtransport/-/webtransport-0.1.7.tgz",
|
||||
"integrity": "sha512-RD8kGxFVSBElx7Y/ApskD1/t8kXF4GNtvveJnnMET8TAd6FfcEmtETvzJax5o7KyvGONsoVlCtLRY6s12ncn4w==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@fails-components/webtransport/-/webtransport-1.1.4.tgz",
|
||||
"integrity": "sha512-cFc9XhEREi+afRRl9S9c/xNQ3KVi9dZkaIRVq3xPGwjjezgX5QMQ1pJKG6iZffSwboOOjk1VrDwlvPjuVwtGwQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/debug": "^4.1.7",
|
||||
"bindings": "^1.5.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@fails-components/webtransport-transport-http3-quiche": {
|
||||
"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,
|
||||
"dependencies": {
|
||||
"@types/debug": "^4.1.7",
|
||||
"bindings": "^1.5.0",
|
||||
"node-addon-api": "^4.3.0",
|
||||
"cmake-js": "^7.2.1",
|
||||
"debug": "^4.3.4",
|
||||
"node-addon-api": "^7.0.0",
|
||||
"prebuild-install": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=16.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@ioredis/commands": {
|
||||
@@ -2804,11 +2824,6 @@
|
||||
"@types/responselike": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||
@@ -4148,6 +4163,12 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/archiver": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
|
||||
@@ -4405,6 +4426,34 @@
|
||||
"integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/are-we-there-yet": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
|
||||
"integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
|
||||
"deprecated": "This package is no longer supported.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"delegates": "^1.0.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/are-we-there-yet/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
@@ -4495,6 +4544,17 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
|
||||
@@ -5444,6 +5504,45 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cmake-js": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-7.3.0.tgz",
|
||||
"integrity": "sha512-dXs2zq9WxrV87bpJ+WbnGKv8WUBXDw8blNiwNHoRe/it+ptscxhQHKB1SJXa1w+kocLMeP28Tk4/eTCezg4o+w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"axios": "^1.6.5",
|
||||
"debug": "^4",
|
||||
"fs-extra": "^11.2.0",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"memory-stream": "^1.0.0",
|
||||
"node-api-headers": "^1.1.0",
|
||||
"npmlog": "^6.0.2",
|
||||
"rc": "^1.2.7",
|
||||
"semver": "^7.5.4",
|
||||
"tar": "^6.2.0",
|
||||
"url-join": "^4.0.1",
|
||||
"which": "^2.0.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"cmake-js": "bin/cmake-js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cmake-js/node_modules/semver": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
@@ -5459,6 +5558,15 @@
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@@ -5604,6 +5712,12 @@
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/constant-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
|
||||
@@ -5643,9 +5757,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -6070,6 +6184,12 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||
@@ -7504,6 +7624,26 @@
|
||||
"integrity": "sha512-3VELfuWCLVzt5d2Gblk8qcqFro6nuwvxwMzHaENVDHI7rxcBRtMCwTk/E9FXcgh+82DSpavPNDueA9+RxXJoFg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
|
||||
@@ -7624,6 +7764,36 @@
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass/node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@@ -7653,6 +7823,26 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
|
||||
"integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
|
||||
"deprecated": "This package is no longer supported.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.3",
|
||||
"console-control-strings": "^1.1.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"signal-exit": "^3.0.7",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wide-align": "^1.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gaze": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
|
||||
@@ -8107,6 +8297,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
@@ -9641,6 +9837,12 @@
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.pickby": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz",
|
||||
@@ -9848,6 +10050,29 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/memory-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-stream/-/memory-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/memory-stream/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/meow": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
|
||||
@@ -10040,6 +10265,37 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib/node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mitt": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
|
||||
@@ -10260,9 +10516,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.65.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
|
||||
"integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
|
||||
"version": "3.71.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.71.0.tgz",
|
||||
"integrity": "sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
@@ -10272,9 +10528,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi/node_modules/semver": {
|
||||
"version": "7.6.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
||||
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
@@ -10284,9 +10540,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
|
||||
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-api-headers": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.3.0.tgz",
|
||||
"integrity": "sha512-8Bviwtw4jNhv0B2qDjj4M5e6GyAuGtxsmZTrFJu3S3Z0+oHwIgSUdIKkKJmZd+EbMo7g3v4PLBbrjxwmZOqMBg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
@@ -10434,6 +10696,22 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/npmlog": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz",
|
||||
"integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==",
|
||||
"deprecated": "This package is no longer supported.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"are-we-there-yet": "^3.0.0",
|
||||
"console-control-strings": "^1.1.0",
|
||||
"gauge": "^4.0.3",
|
||||
"set-blocking": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nyc": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nyc/-/nyc-17.0.0.tgz",
|
||||
@@ -11320,15 +11598,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
@@ -13442,6 +13720,23 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^5.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
|
||||
@@ -13512,6 +13807,42 @@
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/minipass": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.31.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz",
|
||||
@@ -14172,6 +14503,12 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/url-join": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/userhome": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/userhome/-/userhome-1.0.0.tgz",
|
||||
@@ -14206,9 +14543,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/uWebSockets.js": {
|
||||
"version": "20.30.0",
|
||||
"resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#d39d4181daf5b670d44cbc1b18f8c28c85fd4142",
|
||||
"dev": true
|
||||
"version": "20.48.0",
|
||||
"resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#51ae1d1fd92dff77cbbdc7c431021f85578da1a6",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
@@ -14800,6 +15138,15 @@
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/workerpool": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
|
||||
@@ -14945,14 +15292,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
@@ -15168,15 +15507,14 @@
|
||||
}
|
||||
},
|
||||
"packages/engine.io": {
|
||||
"version": "6.6.0",
|
||||
"version": "6.6.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cookie": "~0.7.2",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
@@ -15187,41 +15525,31 @@
|
||||
}
|
||||
},
|
||||
"packages/engine.io-client": {
|
||||
"version": "6.6.0",
|
||||
"version": "6.6.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"packages/engine.io-client/node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz",
|
||||
"integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"packages/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"prettier": "^3.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"packages/engine.io-parser/node_modules/prettier": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"packages/engine.io/node_modules/debug": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
@@ -15239,14 +15567,14 @@
|
||||
}
|
||||
},
|
||||
"packages/socket.io": {
|
||||
"version": "4.7.5",
|
||||
"version": "4.8.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.5.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
@@ -15263,12 +15591,12 @@
|
||||
}
|
||||
},
|
||||
"packages/socket.io-client": {
|
||||
"version": "4.7.5",
|
||||
"version": "4.8.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.5.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -15291,19 +15619,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/socket.io-client/node_modules/engine.io-client": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
|
||||
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"packages/socket.io-cluster-engine": {
|
||||
"name": "@socket.io/cluster-engine",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -15359,26 +15676,6 @@
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/socket.io/node_modules/engine.io": {
|
||||
"version": "6.5.5",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
|
||||
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/socket.io-component-emitter",
|
||||
@@ -21,7 +22,8 @@
|
||||
"@babel/plugin-transform-object-assign": "^7.24.7",
|
||||
"@babel/preset-env": "^7.24.7",
|
||||
"@babel/register": "^7.24.6",
|
||||
"@fails-components/webtransport": "^0.1.7",
|
||||
"@fails-components/webtransport": "^1.1.4",
|
||||
"@fails-components/webtransport-transport-http3-quiche": "^1.1.4",
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^26.0.1",
|
||||
@@ -41,6 +43,7 @@
|
||||
"base64-arraybuffer": "^1.0.2",
|
||||
"benchmark": "^2.1.4",
|
||||
"blob": "^0.1.0",
|
||||
"cookie": "~0.7.2",
|
||||
"eiows": "^7.1.0",
|
||||
"engine.io-client-v3": "npm:engine.io-client@^3.5.2",
|
||||
"expect.js": "^0.3.1",
|
||||
@@ -52,7 +55,7 @@
|
||||
"mocha": "^10.6.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"nyc": "^17.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.3.2",
|
||||
"redis": "^4.6.15",
|
||||
"rimraf": "^6.0.0",
|
||||
"rollup": "^2.79.1",
|
||||
@@ -67,7 +70,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"tsd": "^0.31.1",
|
||||
"typescript": "^5.5.3",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.30.0",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.48.0",
|
||||
"wdio-geckodriver-service": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
| Version | Release date | Bundle size (UMD min+gzip) |
|
||||
|-------------------------------------------------------------------------------------------------------------|----------------|----------------------------|
|
||||
| [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` |
|
||||
| [6.6.0](#660-2024-06-21) | June 2024 | `8.6 KB` |
|
||||
| [6.5.4](#654-2024-06-18) (from the [6.5.x](https://github.com/socketio/engine.io-client/tree/6.5.x) branch) | June 2024 | `8.8 KB` |
|
||||
| [3.5.4](#354-2024-06-18) (from the [3.5.x](https://github.com/socketio/engine.io-client/tree/3.5.x) branch) | June 2024 | `-` |
|
||||
@@ -38,6 +41,56 @@
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correctly consume the `ws` package ([#5220](https://github.com/socketio/socket.io/issues/5220)) ([7fcddcb](https://github.com/socketio/socket.io/commit/7fcddcb3bbd236b46aa8fee6f4ce6c45afb7b03a))
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.2](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.1...engine.io-client@6.6.2) (2024-10-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **types:** remove ws type from .d.ts file ([175a2c5](https://github.com/socketio/socket.io/commit/175a2c58c1bc37eb9b87f87df47e1f9388b01d55))
|
||||
* prevent infinite loop with Node.js built-in WebSocket ([4865f2e](https://github.com/socketio/socket.io/commit/4865f2e62eff9cf59f602e753d9f84159a3139af))
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.1](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.0...engine.io-client@6.6.1) (2024-09-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move 'offline' event listener at the top ([8a2f5a3](https://github.com/socketio/socket.io/commit/8a2f5a3da0addb386e7a0f4970e1a9696b82797e))
|
||||
* only remove the event listener if it exists ([9b3c9ab](https://github.com/socketio/socket.io/commit/9b3c9abecab028822357beb6e2b502f548e312eb)), closes [/github.com/socketio/socket.io/issues/5088#issuecomment-2217202350](https://github.com//github.com/socketio/socket.io/issues/5088/issues/issuecomment-2217202350)
|
||||
* do not send a packet on an expired connection ([#5134](https://github.com/socketio/socket.io/issues/5134)) ([8adcfbf](https://github.com/socketio/socket.io/commit/8adcfbfde50679095ec2abe376650cf2b6814325))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* do not reset the heartbeat timer on each packet ([7a23dde](https://github.com/socketio/socket.io/commit/7a23dde6efff3079edeeda951fe0ee25516da833))
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.0](https://github.com/socketio/engine.io-client/compare/6.5.3...6.6.0) (2024-06-21)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
729
packages/engine.io-client/dist/engine.io.js
vendored
729
packages/engine.io-client/dist/engine.io.js
vendored
File diff suppressed because it is too large
Load Diff
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
@@ -55,7 +55,7 @@ export function parse(setCookieString: string): Cookie {
|
||||
case "Max-Age":
|
||||
const expiration = new Date();
|
||||
expiration.setUTCSeconds(
|
||||
expiration.getUTCSeconds() + parseInt(value, 10)
|
||||
expiration.getUTCSeconds() + parseInt(value, 10),
|
||||
);
|
||||
cookie.expires = expiration;
|
||||
break;
|
||||
|
||||
@@ -10,11 +10,34 @@ import {
|
||||
CookieJar,
|
||||
createCookieJar,
|
||||
defaultBinaryType,
|
||||
nextTick,
|
||||
} from "./globals.node.js";
|
||||
import debugModule from "debug"; // debug()
|
||||
|
||||
const debug = debugModule("engine.io-client:socket"); // debug()
|
||||
|
||||
const withEventListeners =
|
||||
typeof addEventListener === "function" &&
|
||||
typeof removeEventListener === "function";
|
||||
|
||||
const OFFLINE_EVENT_LISTENERS = [];
|
||||
|
||||
if (withEventListeners) {
|
||||
// within a ServiceWorker, any event handler for the 'offline' event must be added on the initial evaluation of the
|
||||
// script, so we create one single event listener here which will forward the event to the socket instances
|
||||
addEventListener(
|
||||
"offline",
|
||||
() => {
|
||||
debug(
|
||||
"closing %d connection(s) because the network was lost",
|
||||
OFFLINE_EVENT_LISTENERS.length,
|
||||
);
|
||||
OFFLINE_EVENT_LISTENERS.forEach((listener) => listener());
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
export interface SocketOptions {
|
||||
/**
|
||||
* The host that we're connecting to. Set from the URI passed when connecting
|
||||
@@ -85,7 +108,9 @@ export interface SocketOptions {
|
||||
*
|
||||
* @default ['polling','websocket', 'webtransport']
|
||||
*/
|
||||
transports?: string[] | TransportCtor[];
|
||||
transports?:
|
||||
| ("polling" | "websocket" | "webtransport" | string)[]
|
||||
| TransportCtor[];
|
||||
|
||||
/**
|
||||
* Whether all the transports should be tested, instead of just the first one.
|
||||
@@ -318,6 +343,11 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
private _pingTimeout: number = -1;
|
||||
private _maxPayload?: number = -1;
|
||||
private _pingTimeoutTimer: NodeJS.Timer;
|
||||
/**
|
||||
* The expiration timestamp of the {@link _pingTimeoutTimer} object is tracked, in case the timer is throttled and the
|
||||
* callback is not fired on time. This can happen for example when a laptop is suspended or when a phone is locked.
|
||||
*/
|
||||
private _pingTimeoutTime = Infinity;
|
||||
private clearTimeoutFn: typeof clearTimeout;
|
||||
private readonly _beforeunloadEventListener: () => void;
|
||||
private readonly _offlineEventListener: () => void;
|
||||
@@ -379,8 +409,8 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
(typeof location !== "undefined" && location.port
|
||||
? location.port
|
||||
: this.secure
|
||||
? "443"
|
||||
: "80");
|
||||
? "443"
|
||||
: "80");
|
||||
|
||||
this.transports = [];
|
||||
this._transportsByName = {};
|
||||
@@ -406,7 +436,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
transportOptions: {},
|
||||
closeOnBeforeunload: false,
|
||||
},
|
||||
opts
|
||||
opts,
|
||||
);
|
||||
|
||||
this.opts.path =
|
||||
@@ -417,7 +447,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
this.opts.query = decode(this.opts.query);
|
||||
}
|
||||
|
||||
if (typeof addEventListener === "function") {
|
||||
if (withEventListeners) {
|
||||
if (this.opts.closeOnBeforeunload) {
|
||||
// Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
|
||||
// ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
|
||||
@@ -432,16 +462,17 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
addEventListener(
|
||||
"beforeunload",
|
||||
this._beforeunloadEventListener,
|
||||
false
|
||||
false,
|
||||
);
|
||||
}
|
||||
if (this.hostname !== "localhost") {
|
||||
debug("adding listener for the 'offline' event");
|
||||
this._offlineEventListener = () => {
|
||||
this._onClose("transport close", {
|
||||
description: "network connection lost",
|
||||
});
|
||||
};
|
||||
addEventListener("offline", this._offlineEventListener, false);
|
||||
OFFLINE_EVENT_LISTENERS.push(this._offlineEventListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +513,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
secure: this.secure,
|
||||
port: this.port,
|
||||
},
|
||||
this.opts.transportOptions[name]
|
||||
this.opts.transportOptions[name],
|
||||
);
|
||||
|
||||
debug("options: %j", opts);
|
||||
@@ -572,7 +603,6 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
|
||||
// Socket is live - any packet counts
|
||||
this.emitReserved("heartbeat");
|
||||
this._resetPingTimeout();
|
||||
|
||||
switch (packet.type) {
|
||||
case "open":
|
||||
@@ -583,6 +613,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
this._sendPacket("pong");
|
||||
this.emitReserved("ping");
|
||||
this.emitReserved("pong");
|
||||
this._resetPingTimeout();
|
||||
break;
|
||||
|
||||
case "error":
|
||||
@@ -628,9 +659,11 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
*/
|
||||
private _resetPingTimeout() {
|
||||
this.clearTimeoutFn(this._pingTimeoutTimer);
|
||||
const delay = this._pingInterval + this._pingTimeout;
|
||||
this._pingTimeoutTime = Date.now() + delay;
|
||||
this._pingTimeoutTimer = this.setTimeoutFn(() => {
|
||||
this._onClose("ping timeout");
|
||||
}, this._pingInterval + this._pingTimeout);
|
||||
}, delay);
|
||||
if (this.opts.autoUnref) {
|
||||
this._pingTimeoutTimer.unref();
|
||||
}
|
||||
@@ -708,6 +741,31 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
return this.writeBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the heartbeat timer has expired but the socket has not yet been notified.
|
||||
*
|
||||
* Note: this method is private for now because it does not really fit the WebSocket API, but if we put it in the
|
||||
* `write()` method then the message would not be buffered by the Socket.IO client.
|
||||
*
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
/* private */ _hasPingExpired() {
|
||||
if (!this._pingTimeoutTime) return true;
|
||||
|
||||
const hasExpired = Date.now() > this._pingTimeoutTime;
|
||||
if (hasExpired) {
|
||||
debug("throttled timer detected, scheduling connection close");
|
||||
this._pingTimeoutTime = 0;
|
||||
|
||||
nextTick(() => {
|
||||
this._onClose("ping timeout");
|
||||
}, this.setTimeoutFn);
|
||||
}
|
||||
|
||||
return hasExpired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message.
|
||||
*
|
||||
@@ -747,7 +805,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
type: PacketType,
|
||||
data?: RawData,
|
||||
options?: WriteOptions,
|
||||
fn?: () => void
|
||||
fn?: () => void,
|
||||
) {
|
||||
if ("function" === typeof data) {
|
||||
fn = data;
|
||||
@@ -868,13 +926,21 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
// ignore further transport communication
|
||||
this.transport.removeAllListeners();
|
||||
|
||||
if (typeof removeEventListener === "function") {
|
||||
removeEventListener(
|
||||
"beforeunload",
|
||||
this._beforeunloadEventListener,
|
||||
false
|
||||
);
|
||||
removeEventListener("offline", this._offlineEventListener, false);
|
||||
if (withEventListeners) {
|
||||
if (this._beforeunloadEventListener) {
|
||||
removeEventListener(
|
||||
"beforeunload",
|
||||
this._beforeunloadEventListener,
|
||||
false,
|
||||
);
|
||||
}
|
||||
if (this._offlineEventListener) {
|
||||
const i = OFFLINE_EVENT_LISTENERS.indexOf(this._offlineEventListener);
|
||||
if (i !== -1) {
|
||||
debug("removing listener for the 'offline' event");
|
||||
OFFLINE_EVENT_LISTENERS.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set ready state
|
||||
|
||||
@@ -14,7 +14,7 @@ export class TransportError extends Error {
|
||||
constructor(
|
||||
reason: string,
|
||||
readonly description: any,
|
||||
readonly context: any
|
||||
readonly context: any,
|
||||
) {
|
||||
super(reason);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export abstract class Transport extends Emitter<
|
||||
protected onError(reason: string, description: any, context?: any) {
|
||||
super.emitReserved(
|
||||
"error",
|
||||
new TransportError(reason, description, context)
|
||||
new TransportError(reason, description, context),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ export class XHR extends BaseXHR {
|
||||
Object.assign(
|
||||
opts,
|
||||
{ xd: this.xd, cookieJar: this.socket?._cookieJar },
|
||||
this.opts
|
||||
this.opts,
|
||||
);
|
||||
return new Request(
|
||||
(opts) => new XMLHttpRequest(opts),
|
||||
this.uri(),
|
||||
opts as RequestOptions
|
||||
opts as RequestOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export class Request extends Emitter<
|
||||
constructor(
|
||||
private readonly createRequest: (opts: RequestOptions) => XMLHttpRequest,
|
||||
uri: string,
|
||||
opts: RequestOptions
|
||||
opts: RequestOptions,
|
||||
) {
|
||||
super();
|
||||
installTimerFunctions(this, opts);
|
||||
@@ -151,7 +151,7 @@ export class Request extends Emitter<
|
||||
"ca",
|
||||
"ciphers",
|
||||
"rejectUnauthorized",
|
||||
"autoUnref"
|
||||
"autoUnref",
|
||||
);
|
||||
opts.xdomain = !!this._opts.xd;
|
||||
|
||||
@@ -197,7 +197,7 @@ export class Request extends Emitter<
|
||||
if (xhr.readyState === 3) {
|
||||
this._opts.cookieJar?.parseCookies(
|
||||
// @ts-ignore
|
||||
xhr.getResponseHeader("set-cookie")
|
||||
xhr.getResponseHeader("set-cookie"),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ function newRequest(opts) {
|
||||
if (!xdomain) {
|
||||
try {
|
||||
return new globalThis[["Active"].concat("Object").join("X")](
|
||||
"Microsoft.XMLHTTP"
|
||||
"Microsoft.XMLHTTP",
|
||||
);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebSocket } from "ws";
|
||||
import * as ws from "ws";
|
||||
import type { Packet, RawData } from "engine.io-parser";
|
||||
import { BaseWS } from "./websocket.js";
|
||||
|
||||
@@ -14,8 +14,8 @@ export class WS extends BaseWS {
|
||||
createSocket(
|
||||
uri: string,
|
||||
protocols: string | string[] | undefined,
|
||||
opts: Record<string, any>
|
||||
) {
|
||||
opts: Record<string, any>,
|
||||
): any {
|
||||
if (this.socket?._cookieJar) {
|
||||
opts.headers = opts.headers || {};
|
||||
|
||||
@@ -27,7 +27,7 @@ export class WS extends BaseWS {
|
||||
opts.headers.cookie.push(`${name}=${cookie.value}`);
|
||||
}
|
||||
}
|
||||
return new WebSocket(uri, protocols, opts);
|
||||
return new ws.WebSocket(uri, protocols, opts);
|
||||
}
|
||||
|
||||
doWrite(packet: Packet, data: RawData) {
|
||||
|
||||
@@ -43,7 +43,7 @@ export abstract class BaseWS extends Transport {
|
||||
"origin",
|
||||
"maxPayload",
|
||||
"family",
|
||||
"checkServerIdentity"
|
||||
"checkServerIdentity",
|
||||
);
|
||||
|
||||
if (this.opts.extraHeaders) {
|
||||
@@ -64,7 +64,7 @@ export abstract class BaseWS extends Transport {
|
||||
abstract createSocket(
|
||||
uri: string,
|
||||
protocols: string | string[] | undefined,
|
||||
opts: Record<string, any>
|
||||
opts: Record<string, any>,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -123,6 +123,7 @@ export abstract class BaseWS extends Transport {
|
||||
|
||||
override doClose() {
|
||||
if (typeof this.ws !== "undefined") {
|
||||
this.ws.onerror = () => {};
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
@@ -166,7 +167,7 @@ export class WS extends BaseWS {
|
||||
createSocket(
|
||||
uri: string,
|
||||
protocols: string | string[] | undefined,
|
||||
opts: Record<string, any>
|
||||
opts: Record<string, any>,
|
||||
) {
|
||||
return !isReactNative
|
||||
? protocols
|
||||
|
||||
@@ -30,7 +30,7 @@ export class WT extends Transport {
|
||||
// @ts-ignore
|
||||
this._transport = new WebTransport(
|
||||
this.createUri("https"),
|
||||
this.opts.transportOptions[this.name]
|
||||
this.opts.transportOptions[this.name],
|
||||
);
|
||||
} catch (err) {
|
||||
return this.emitReserved("error", err);
|
||||
@@ -51,7 +51,7 @@ export class WT extends Transport {
|
||||
this._transport.createBidirectionalStream().then((stream) => {
|
||||
const decoderStream = createPacketDecoderStream(
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
this.socket.binaryType
|
||||
this.socket.binaryType,
|
||||
);
|
||||
const reader = stream.readable.pipeThrough(decoderStream).getReader();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "engine.io-client",
|
||||
"description": "Client for the realtime Engine",
|
||||
"license": "MIT",
|
||||
"version": "6.6.0",
|
||||
"version": "6.6.3",
|
||||
"main": "./build/cjs/index.js",
|
||||
"module": "./build/esm/index.js",
|
||||
"exports": {
|
||||
@@ -56,13 +56,14 @@
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
},
|
||||
"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 --bail --require test/support/hooks.js test/index.js test/webtransport.mjs",
|
||||
"test:node-fetch": "USE_FETCH=1 npm run test:node",
|
||||
"test:node-builtin-ws": "USE_BUILTIN_WS=1 npm run test:node",
|
||||
"test:browser": "zuul test/index.js",
|
||||
"build": "rimraf ./dist && rollup -c support/rollup.config.umd.js && rollup -c support/rollup.config.esm.js",
|
||||
"bundle-size": "node support/bundle-size.js",
|
||||
|
||||
@@ -17,6 +17,19 @@ describe("connection", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it("should connect to localhost (ws)", (done) => {
|
||||
const socket = new Socket({
|
||||
transports: ["websocket"],
|
||||
});
|
||||
socket.on("open", () => {
|
||||
socket.on("message", (data) => {
|
||||
expect(data).to.equal("hi");
|
||||
socket.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should receive multibyte utf-8 strings with polling", (done) => {
|
||||
const socket = new Socket();
|
||||
socket.on("open", () => {
|
||||
@@ -34,12 +47,12 @@ describe("connection", function () {
|
||||
const socket = new Socket();
|
||||
socket.on("open", () => {
|
||||
socket.send(
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF"
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF",
|
||||
);
|
||||
socket.on("message", (data) => {
|
||||
if ("hi" === data) return;
|
||||
expect(data).to.be(
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF"
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF",
|
||||
);
|
||||
socket.close();
|
||||
done();
|
||||
@@ -59,7 +72,7 @@ describe("connection", function () {
|
||||
setTimeout(() => {
|
||||
expect(noPacket).to.be(true);
|
||||
done();
|
||||
}, 1200);
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -177,7 +190,7 @@ describe("connection", function () {
|
||||
setTimeout(() => {
|
||||
expect(noPacket).to.be(true);
|
||||
done();
|
||||
}, 1200);
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ const socket = new Socket("http://localhost:3000", {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should not exit");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -10,4 +10,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -10,4 +10,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -9,4 +9,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -7,8 +7,6 @@ if (env.browser) {
|
||||
require("./node");
|
||||
}
|
||||
|
||||
const Blob = require("blob");
|
||||
|
||||
require("./engine.io-client");
|
||||
require("./socket");
|
||||
require("./transport");
|
||||
@@ -23,6 +21,6 @@ if (typeof ArrayBuffer !== "undefined") {
|
||||
}
|
||||
|
||||
// Blob is available in Node.js since v18, but not yet supported by the `engine.io-parser` package
|
||||
if (Blob && env.browser) {
|
||||
if (typeof Blob === "function" && env.browser) {
|
||||
require("./blob");
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ describe("node.js", () => {
|
||||
isComplete = true;
|
||||
process.kill();
|
||||
done();
|
||||
}, 1000);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ describe("Socket", function () {
|
||||
|
||||
socket.on("error", (err) => {
|
||||
expect(err.message).to.eql(
|
||||
useFetch ? "fetch read error" : "xhr poll error"
|
||||
useFetch ? "fetch read error" : "xhr poll error",
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -237,7 +237,7 @@ describe("Socket", function () {
|
||||
// err.context is a XMLHttpRequest object
|
||||
expect(err.context.readyState).to.eql(4);
|
||||
expect(err.context.responseText).to.eql(
|
||||
'{"code":1,"message":"Session ID unknown"}'
|
||||
'{"code":1,"message":"Session ID unknown"}',
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -270,4 +270,30 @@ describe("Socket", function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("throttled timer", () => {
|
||||
it("checks the state of the timer", (done) => {
|
||||
const socket = new Socket();
|
||||
|
||||
expect(socket._hasPingExpired()).to.be(false);
|
||||
|
||||
socket.on("open", () => {
|
||||
expect(socket._hasPingExpired()).to.be(false);
|
||||
|
||||
// simulate a throttled timer
|
||||
socket._pingTimeoutTime = Date.now() - 1;
|
||||
|
||||
expect(socket._hasPingExpired()).to.be(true);
|
||||
|
||||
// subsequent calls should not trigger more 'close' events
|
||||
expect(socket._hasPingExpired()).to.be(true);
|
||||
expect(socket._hasPingExpired()).to.be(true);
|
||||
});
|
||||
|
||||
socket.on("close", (reason) => {
|
||||
expect(reason).to.eql("ping timeout");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,3 +35,11 @@ if (exports.useFetch) {
|
||||
const { transports, Fetch } = require("../..");
|
||||
transports.polling = Fetch;
|
||||
}
|
||||
|
||||
exports.useBuiltinWs = process.env.USE_BUILTIN_WS !== undefined;
|
||||
|
||||
if (exports.useBuiltinWs) {
|
||||
console.warn("testing with built-in WebSocket object");
|
||||
const { transports, WebSocket } = require("../..");
|
||||
transports.websocket = WebSocket;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.mochaHooks = {
|
||||
maxHttpBufferSize: 100,
|
||||
allowRequest: (req, fn) => {
|
||||
const denyRequest = new URL(`http://${req.url}`).searchParams.has(
|
||||
"deny"
|
||||
"deny",
|
||||
);
|
||||
fn(null, !denyRequest);
|
||||
},
|
||||
|
||||
@@ -100,7 +100,7 @@ describe("Transport", () => {
|
||||
timestampRequests: false,
|
||||
});
|
||||
expect(polling.uri()).to.contain(
|
||||
"http://localhost:3000/engine.io?sid=test"
|
||||
"http://localhost:3000/engine.io?sid=test",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ describe("Transport", () => {
|
||||
timestampRequests: true,
|
||||
});
|
||||
expect(polling.uri()).to.match(
|
||||
/http:\/\/localhost\/engine\.io\?(j=[0-9]+&)?(t=[0-9A-Za-z-_]+)/
|
||||
/http:\/\/localhost\/engine\.io\?(j=[0-9]+&)?(t=[0-9A-Za-z-_]+)/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -180,7 +180,7 @@ describe("Transport", () => {
|
||||
timestampRequests: true,
|
||||
});
|
||||
expect(ws.uri()).to.match(
|
||||
/ws:\/\/localhost\/engine\.io\?woot=[0-9A-Za-z-_]+/
|
||||
/ws:\/\/localhost\/engine\.io\?woot=[0-9A-Za-z-_]+/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -210,7 +210,10 @@ describe("Transport", () => {
|
||||
// these are server only
|
||||
if (!env.browser) {
|
||||
describe("options", () => {
|
||||
it("should accept an `agent` option for WebSockets", (done) => {
|
||||
it("should accept an `agent` option for WebSockets", function (done) {
|
||||
if (env.useBuiltinWs) {
|
||||
return this.skip();
|
||||
}
|
||||
const polling = new eio.transports.websocket({
|
||||
path: "/engine.io",
|
||||
hostname: "localhost",
|
||||
@@ -269,7 +272,10 @@ describe("Transport", () => {
|
||||
});
|
||||
|
||||
describe("perMessageDeflate", () => {
|
||||
it("should set threshold", (done) => {
|
||||
it("should set threshold", function (done) {
|
||||
if (env.useBuiltinWs) {
|
||||
return this.skip();
|
||||
}
|
||||
const socket = new eio.Socket({
|
||||
transports: ["websocket"],
|
||||
perMessageDeflate: { threshold: 0 },
|
||||
@@ -289,7 +295,10 @@ describe("Transport", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should not compress when the byte size is below threshold", (done) => {
|
||||
it("should not compress when the byte size is below threshold", function (done) {
|
||||
if (env.useBuiltinWs) {
|
||||
return this.skip();
|
||||
}
|
||||
const socket = new eio.Socket({ transports: ["websocket"] });
|
||||
socket.on("open", () => {
|
||||
const ws = socket.transport.ws;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Http3Server, WebTransport } from "@fails-components/webtransport";
|
||||
import { Http3EventLoop } from "@fails-components/webtransport/lib/event-loop.js";
|
||||
import expect from "expect.js";
|
||||
import { Server } from "engine.io";
|
||||
import { Socket } from "../build/esm-debug/index.js";
|
||||
@@ -16,8 +15,8 @@ async function setup(opts, cb) {
|
||||
const certificate = await generateWebTransportCertificate(
|
||||
[{ shortName: "CN", value: "localhost" }],
|
||||
{
|
||||
days: 14, // the total length of the validity period MUST NOT exceed two weeks (https://w3c.github.io/webtransport/#custom-certificate-requirements)
|
||||
}
|
||||
days: 13, // the total length of the validity period MUST NOT exceed two weeks (https://w3c.github.io/webtransport/#custom-certificate-requirements)
|
||||
},
|
||||
);
|
||||
|
||||
const engine = new Server(opts);
|
||||
@@ -48,7 +47,10 @@ async function setup(opts, cb) {
|
||||
})();
|
||||
|
||||
h3Server.startServer();
|
||||
h3Server.onServerListening = () => cb({ engine, h3Server, certificate });
|
||||
|
||||
await h3Server.ready;
|
||||
|
||||
cb({ engine, h3Server, certificate });
|
||||
}
|
||||
|
||||
function success(engine, h3server, done) {
|
||||
@@ -73,16 +75,12 @@ function createSocket(port, certificate, opts) {
|
||||
},
|
||||
},
|
||||
},
|
||||
opts
|
||||
)
|
||||
opts,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
describe("WebTransport", () => {
|
||||
after(() => {
|
||||
Http3EventLoop.globalLoop.shutdownEventLoop(); // manually shutdown the event loop, instead of waiting 20s
|
||||
});
|
||||
|
||||
it("should allow to connect with WebTransport directly", (done) => {
|
||||
setup({}, ({ engine, h3Server, certificate }) => {
|
||||
const socket = createSocket(h3Server.port, certificate, {
|
||||
@@ -113,7 +111,7 @@ describe("WebTransport", () => {
|
||||
httpServer.close();
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -137,7 +135,7 @@ describe("WebTransport", () => {
|
||||
httpServer.close();
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -160,7 +158,7 @@ describe("WebTransport", () => {
|
||||
success(engine, h3Server, done);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
'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,
|
||||
|
||||
server: './test/support/server.js',
|
||||
builder: 'zuul-builder-webpack',
|
||||
webpack: require('./support/webpack.config.js')
|
||||
};
|
||||
|
||||
if (process.env.CI === 'true') {
|
||||
zuulConfig.local = false;
|
||||
zuulConfig.tunnel = {
|
||||
type: 'ngrok',
|
||||
bind_tls: true
|
||||
};
|
||||
}
|
||||
|
||||
zuulConfig.browsers = [
|
||||
{
|
||||
name: 'firefox',
|
||||
version: 'latest'
|
||||
}, {
|
||||
name: 'internet explorer',
|
||||
version: '9..11'
|
||||
}, {
|
||||
name: 'safari',
|
||||
version: '14'
|
||||
}, {
|
||||
name: 'iphone',
|
||||
version: '14'
|
||||
}, {
|
||||
name: 'android',
|
||||
version: '5.1..6.0'
|
||||
}, {
|
||||
name: 'ipad',
|
||||
version: '14'
|
||||
}, {
|
||||
name: 'MicrosoftEdge',
|
||||
version: 'latest'
|
||||
}
|
||||
];
|
||||
@@ -51,7 +51,7 @@ const mapBinary = (data: RawData, binaryType?: BinaryType) => {
|
||||
);
|
||||
} else {
|
||||
// from WebTransport (Uint8Array)
|
||||
return data.buffer;
|
||||
return data.slice().buffer;
|
||||
}
|
||||
case "nodebuffer":
|
||||
default:
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
"require": "./build/cjs/index.js"
|
||||
},
|
||||
"types": "build/esm/index.d.ts",
|
||||
"devDependencies": {
|
||||
"prettier": "^3.3.2"
|
||||
},
|
||||
"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",
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
| Version | Release date |
|
||||
|------------------------------------------------------------------------------------------------------|----------------|
|
||||
| [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 |
|
||||
| [6.6.1](#661-2024-09-21) | September 2024 |
|
||||
| [6.6.0](#660-2024-06-21) | June 2024 |
|
||||
| [6.5.5](#655-2024-06-18) (from the [6.5.x](https://github.com/socketio/engine.io/tree/6.5.x) branch) | June 2024 |
|
||||
| [3.6.2](#362-2024-06-18) (from the [3.x](https://github.com/socketio/engine.io/tree/3.x) branch) | June 2024 |
|
||||
@@ -45,6 +49,58 @@
|
||||
|
||||
# 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)
|
||||
|
||||
The bump of the `cookie` dependency was reverted, as it drops support for older Node.js versions (< 14).
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.3](https://github.com/socketio/socket.io/compare/engine.io@6.6.2...engine.io@6.6.3) (2025-01-23)
|
||||
|
||||
This release contains a bump of the `cookie` dependency.
|
||||
|
||||
Release notes: https://github.com/jshttp/cookie/releases/tag/v1.0.0
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.2](https://github.com/socketio/socket.io/compare/engine.io@6.6.1...engine.io@6.6.2) (2024-10-09)
|
||||
|
||||
This release contains a bump of the `cookie` dependency.
|
||||
|
||||
See also: https://github.com/advisories/GHSA-pxg6-pf52-xh8x
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.1](https://github.com/socketio/socket.io/compare/engine.io@6.6.0...engine.io@6.6.1) (2024-09-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* discard all pending packets when the server is closed ([923a12e](https://github.com/socketio/socket.io/commit/923a12e2de83ecaa75746a575e71a4739815d5c5))
|
||||
* **uws:** prevent the client from upgrading twice ([d5095fe](https://github.com/socketio/socket.io/commit/d5095fe98c3976673c19f433c0114d06dbd8de1b))
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.0](https://github.com/socketio/engine.io/compare/6.5.4...6.6.0) (2024-06-21)
|
||||
|
||||
|
||||
|
||||
117
packages/engine.io/lib/contrib/types.cookie.ts
Normal file
117
packages/engine.io/lib/contrib/types.cookie.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
// imported from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b83cf9ef8b044e69f05b2a00aa7c6cb767a9acd2/types/cookie/index.d.ts (now deleted)
|
||||
/**
|
||||
* Basic HTTP cookie parser and serializer for HTTP servers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Additional serialization options
|
||||
*/
|
||||
export interface CookieSerializeOptions {
|
||||
/**
|
||||
* Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.3|Domain Set-Cookie attribute}. By default, no
|
||||
* domain is set, and most clients will consider the cookie to apply to only
|
||||
* the current domain.
|
||||
*/
|
||||
domain?: string | undefined;
|
||||
|
||||
/**
|
||||
* Specifies a function that will be used to encode a cookie's value. Since
|
||||
* value of a cookie has a limited character set (and must be a simple
|
||||
* string), this function can be used to encode a value into a string suited
|
||||
* for a cookie's value.
|
||||
*
|
||||
* The default function is the global `encodeURIComponent`, which will
|
||||
* encode a JavaScript string into UTF-8 byte sequences and then URL-encode
|
||||
* any that fall outside of the cookie range.
|
||||
*/
|
||||
encode?(value: string): string;
|
||||
|
||||
/**
|
||||
* Specifies the `Date` object to be the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.1|`Expires` `Set-Cookie` attribute}. By default,
|
||||
* no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete
|
||||
* it on a condition like exiting a web browser application.
|
||||
*
|
||||
* *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
|
||||
* states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
|
||||
* possible not all clients by obey this, so if both are set, they should
|
||||
* point to the same date and time.
|
||||
*/
|
||||
expires?: Date | undefined;
|
||||
/**
|
||||
* Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.6|`HttpOnly` `Set-Cookie` attribute}.
|
||||
* When truthy, the `HttpOnly` attribute is set, otherwise it is not. By
|
||||
* default, the `HttpOnly` attribute is not set.
|
||||
*
|
||||
* *Note* be careful when setting this to true, as compliant clients will
|
||||
* not allow client-side JavaScript to see the cookie in `document.cookie`.
|
||||
*/
|
||||
httpOnly?: boolean | undefined;
|
||||
/**
|
||||
* Specifies the number (in seconds) to be the value for the `Max-Age`
|
||||
* `Set-Cookie` attribute. The given number will be converted to an integer
|
||||
* by rounding down. By default, no maximum age is set.
|
||||
*
|
||||
* *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
|
||||
* states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
|
||||
* possible not all clients by obey this, so if both are set, they should
|
||||
* point to the same date and time.
|
||||
*/
|
||||
maxAge?: number | undefined;
|
||||
/**
|
||||
* Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
|
||||
* attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
|
||||
* `Partitioned` attribute is not set.
|
||||
*
|
||||
* **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
||||
* This also means many clients may ignore this attribute until they understand it.
|
||||
*
|
||||
* More information about can be found in [the proposal](https://github.com/privacycg/CHIPS)
|
||||
*/
|
||||
partitioned?: boolean | undefined;
|
||||
/**
|
||||
* Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.4|`Path` `Set-Cookie` attribute}.
|
||||
* By default, the path is considered the "default path".
|
||||
*/
|
||||
path?: string | undefined;
|
||||
/**
|
||||
* Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
|
||||
*
|
||||
* - `'low'` will set the `Priority` attribute to `Low`.
|
||||
* - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
|
||||
* - `'high'` will set the `Priority` attribute to `High`.
|
||||
*
|
||||
* More information about the different priority levels can be found in
|
||||
* [the specification][rfc-west-cookie-priority-00-4.1].
|
||||
*
|
||||
* **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
||||
* This also means many clients may ignore this attribute until they understand it.
|
||||
*/
|
||||
priority?: "low" | "medium" | "high" | undefined;
|
||||
/**
|
||||
* Specifies the boolean or string to be the value for the {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|`SameSite` `Set-Cookie` attribute}.
|
||||
*
|
||||
* - `true` will set the `SameSite` attribute to `Strict` for strict same
|
||||
* site enforcement.
|
||||
* - `false` will not set the `SameSite` attribute.
|
||||
* - `'lax'` will set the `SameSite` attribute to Lax for lax same site
|
||||
* enforcement.
|
||||
* - `'strict'` will set the `SameSite` attribute to Strict for strict same
|
||||
* site enforcement.
|
||||
* - `'none'` will set the SameSite attribute to None for an explicit
|
||||
* cross-site cookie.
|
||||
*
|
||||
* More information about the different enforcement levels can be found in {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|the specification}.
|
||||
*
|
||||
* *note* This is an attribute that has not yet been fully standardized, and may change in the future. This also means many clients may ignore this attribute until they understand it.
|
||||
*/
|
||||
sameSite?: true | false | "lax" | "strict" | "none" | undefined;
|
||||
/**
|
||||
* Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.5|`Secure` `Set-Cookie` attribute}. When truthy, the
|
||||
* `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
|
||||
*
|
||||
* *Note* be careful when setting this to `true`, as compliant clients will
|
||||
* not send the cookie back to the server in the future if the browser does
|
||||
* not have an HTTPS connection.
|
||||
*/
|
||||
secure?: boolean | undefined;
|
||||
}
|
||||
@@ -12,12 +12,12 @@ import type {
|
||||
Server as HttpServer,
|
||||
ServerResponse,
|
||||
} from "http";
|
||||
import type { CookieSerializeOptions } from "cookie";
|
||||
import type { CorsOptions, CorsOptionsDelegate } from "cors";
|
||||
import type { Duplex } from "stream";
|
||||
import { WebTransport } from "./transports/webtransport";
|
||||
import { createPacketDecoderStream } from "engine.io-parser";
|
||||
import type { EngineRequest } from "./transport";
|
||||
import type { CookieSerializeOptions } from "./contrib/types.cookie";
|
||||
|
||||
const debug = debugModule("engine");
|
||||
|
||||
@@ -78,7 +78,7 @@ export interface ServerOptions {
|
||||
*/
|
||||
allowRequest?: (
|
||||
req: IncomingMessage,
|
||||
fn: (err: string | null | undefined, success: boolean) => void
|
||||
fn: (err: string | null | undefined, success: boolean) => void,
|
||||
) => void;
|
||||
/**
|
||||
* The low-level transports that are enabled. WebTransport is disabled by default and must be manually enabled:
|
||||
@@ -146,7 +146,7 @@ export interface ServerOptions {
|
||||
type Middleware = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: (err?: any) => void
|
||||
next: (err?: any) => void,
|
||||
) => void;
|
||||
|
||||
function parseSessionId(data: string) {
|
||||
@@ -192,7 +192,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
cors: false,
|
||||
allowEIO3: false,
|
||||
},
|
||||
opts
|
||||
opts,
|
||||
);
|
||||
|
||||
if (opts.cookie) {
|
||||
@@ -204,7 +204,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
httpOnly: opts.cookie.path !== false,
|
||||
sameSite: "lax",
|
||||
},
|
||||
opts.cookie
|
||||
opts.cookie,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
{
|
||||
threshold: 1024,
|
||||
},
|
||||
opts.perMessageDeflate
|
||||
opts.perMessageDeflate,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
protected verify(
|
||||
req: any,
|
||||
upgrade: boolean,
|
||||
fn: (errorCode?: number, errorContext?: any) => void
|
||||
fn: (errorCode?: number, errorContext?: any) => void,
|
||||
) {
|
||||
// transport check
|
||||
const transport = req._query.transport;
|
||||
@@ -361,7 +361,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
protected _applyMiddlewares(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
callback: (err?: any) => void
|
||||
callback: (err?: any) => void,
|
||||
) {
|
||||
if (this.middlewares.length === 0) {
|
||||
debug("no middleware to apply, skipping");
|
||||
@@ -424,7 +424,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
protected async handshake(
|
||||
transportName: string,
|
||||
req: any,
|
||||
closeConnection: (errorCode?: number, errorContext?: any) => void
|
||||
closeConnection: (errorCode?: number, errorContext?: any) => void,
|
||||
) {
|
||||
const protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default
|
||||
if (protocol === 3 && !this.opts.allowEIO3) {
|
||||
@@ -519,7 +519,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
public async onWebTransportSession(session: any) {
|
||||
const timeout = setTimeout(() => {
|
||||
debug(
|
||||
"the client failed to establish a bidirectional stream in the given period"
|
||||
"the client failed to establish a bidirectional stream in the given period",
|
||||
);
|
||||
session.close();
|
||||
}, this.opts.upgradeTimeout);
|
||||
@@ -535,7 +535,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
const stream = result.value;
|
||||
const transformStream = createPacketDecoderStream(
|
||||
this.opts.maxHttpBufferSize,
|
||||
"nodebuffer"
|
||||
"nodebuffer",
|
||||
);
|
||||
const reader = stream.readable.pipeThrough(transformStream).getReader();
|
||||
|
||||
@@ -632,7 +632,10 @@ export abstract class BaseServer extends EventEmitter {
|
||||
* @see https://nodejs.org/api/http.html#class-httpserverresponse
|
||||
*/
|
||||
class WebSocketResponse {
|
||||
constructor(readonly req, readonly socket: Duplex) {
|
||||
constructor(
|
||||
readonly req,
|
||||
readonly socket: Duplex,
|
||||
) {
|
||||
// temporarily store the response headers on the req object (see the "headers" event)
|
||||
req[kResponseHeaders] = {};
|
||||
}
|
||||
@@ -659,6 +662,9 @@ class WebSocketResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Engine.IO server based on Node.js built-in HTTP server and the `ws` package for WebSocket connections.
|
||||
*/
|
||||
export class Server extends BaseServer {
|
||||
public httpServer?: HttpServer;
|
||||
private ws: any;
|
||||
@@ -776,7 +782,7 @@ export class Server extends BaseServer {
|
||||
public handleUpgrade(
|
||||
req: EngineRequest,
|
||||
socket: Duplex,
|
||||
upgradeHead: Buffer
|
||||
upgradeHead: Buffer,
|
||||
) {
|
||||
this.prepare(req);
|
||||
|
||||
@@ -953,7 +959,7 @@ function abortRequest(res, errorCode, errorContext) {
|
||||
JSON.stringify({
|
||||
code: errorCode,
|
||||
message,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -968,7 +974,7 @@ function abortRequest(res, errorCode, errorContext) {
|
||||
function abortUpgrade(
|
||||
socket,
|
||||
errorCode,
|
||||
errorContext: { message?: string } = {}
|
||||
errorContext: { message?: string } = {},
|
||||
) {
|
||||
socket.on("error", () => {
|
||||
debug("ignoring error from closed connection");
|
||||
@@ -984,7 +990,7 @@ function abortUpgrade(
|
||||
length +
|
||||
"\r\n" +
|
||||
"\r\n" +
|
||||
message
|
||||
message,
|
||||
);
|
||||
}
|
||||
socket.destroy();
|
||||
|
||||
@@ -80,7 +80,7 @@ export class Socket extends EventEmitter {
|
||||
server: BaseServer,
|
||||
transport: Transport,
|
||||
req: EngineRequest,
|
||||
protocol: number
|
||||
protocol: number,
|
||||
) {
|
||||
super();
|
||||
this.id = id;
|
||||
@@ -125,7 +125,7 @@ export class Socket extends EventEmitter {
|
||||
pingInterval: this.server.opts.pingInterval,
|
||||
pingTimeout: this.server.opts.pingTimeout,
|
||||
maxPayload: this.server.opts.maxHttpBufferSize,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (this.server.opts.initialPacket) {
|
||||
@@ -212,7 +212,7 @@ export class Socket extends EventEmitter {
|
||||
this.pingIntervalTimer = setTimeout(() => {
|
||||
debug(
|
||||
"writing ping packet - expecting pong within %sms",
|
||||
this.server.opts.pingTimeout
|
||||
this.server.opts.pingTimeout,
|
||||
);
|
||||
this.sendPacket("ping");
|
||||
this.resetPingTimeout();
|
||||
@@ -233,7 +233,7 @@ export class Socket extends EventEmitter {
|
||||
},
|
||||
this.protocol === 3
|
||||
? this.server.opts.pingInterval + this.server.opts.pingTimeout
|
||||
: this.server.opts.pingTimeout
|
||||
: this.server.opts.pingTimeout,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ export class Socket extends EventEmitter {
|
||||
debug(
|
||||
'might upgrade socket transport from "%s" to "%s"',
|
||||
this.transport.name,
|
||||
transport.name
|
||||
transport.name,
|
||||
);
|
||||
|
||||
this.upgrading = true;
|
||||
@@ -468,7 +468,7 @@ export class Socket extends EventEmitter {
|
||||
type: PacketType,
|
||||
data?: RawData,
|
||||
options: SendOptions = {},
|
||||
callback?: SendCallback
|
||||
callback?: SendCallback,
|
||||
) {
|
||||
if ("function" === typeof options) {
|
||||
callback = options;
|
||||
@@ -554,6 +554,13 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} for chaining
|
||||
*/
|
||||
public close(discard?: boolean) {
|
||||
if (
|
||||
discard &&
|
||||
(this.readyState === "open" || this.readyState === "closing")
|
||||
) {
|
||||
return this.closeTransport(discard);
|
||||
}
|
||||
|
||||
if ("open" !== this.readyState) return;
|
||||
|
||||
this.readyState = "closing";
|
||||
@@ -561,7 +568,7 @@ export class Socket extends EventEmitter {
|
||||
if (this.writeBuffer.length) {
|
||||
debug(
|
||||
"there are %d remaining packets in the buffer, waiting for the 'drain' event",
|
||||
this.writeBuffer.length
|
||||
this.writeBuffer.length,
|
||||
);
|
||||
this.once("drain", () => {
|
||||
debug("all packets have been sent, closing the transport");
|
||||
@@ -570,7 +577,7 @@ export class Socket extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
debug("the buffer is empty, closing the transport right away", discard);
|
||||
debug("the buffer is empty, closing the transport right away");
|
||||
this.closeTransport(discard);
|
||||
}
|
||||
|
||||
@@ -581,7 +588,7 @@ export class Socket extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
private closeTransport(discard: boolean) {
|
||||
debug("closing the transport (discard? %s)", discard);
|
||||
debug("closing the transport (discard? %s)", !!discard);
|
||||
if (discard) this.transport.discard();
|
||||
this.transport.close(this.onClose.bind(this, "forced close"));
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export abstract class Transport extends EventEmitter {
|
||||
"readyState updated from %s to %s (%s)",
|
||||
this._readyState,
|
||||
state,
|
||||
this.name
|
||||
this.name,
|
||||
);
|
||||
this._readyState = state;
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ export class WebSocket extends Transport {
|
||||
this.socket._sender.sendFrame(
|
||||
// @ts-ignore
|
||||
packet.options.wsPreEncodedFrame,
|
||||
isLast ? this._onSentLast : this._onSent
|
||||
isLast ? this._onSentLast : this._onSent,
|
||||
);
|
||||
} else {
|
||||
this.parser.encodePacket(
|
||||
packet,
|
||||
this.supportsBinary,
|
||||
isLast ? this._doSendLast : this._doSend
|
||||
isLast ? this._doSendLast : this._doSend,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,11 @@ const debug = debugModule("engine:webtransport");
|
||||
export class WebTransport extends Transport {
|
||||
private readonly writer;
|
||||
|
||||
constructor(private readonly session, stream, reader) {
|
||||
constructor(
|
||||
private readonly session,
|
||||
stream,
|
||||
reader,
|
||||
) {
|
||||
super({ _query: { EIO: "4" } });
|
||||
|
||||
const transformStream = createPacketEncoderStream();
|
||||
|
||||
@@ -23,6 +23,10 @@ export interface uOptions {
|
||||
maxBackpressure?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Engine.IO server based on the `uWebSockets.js` package.
|
||||
*/
|
||||
// TODO export it into its own package
|
||||
export class uServer extends BaseServer {
|
||||
protected init() {}
|
||||
protected cleanup() {}
|
||||
@@ -64,7 +68,7 @@ export class uServer extends BaseServer {
|
||||
*/
|
||||
public attach(
|
||||
app /* : TemplatedApp */,
|
||||
options: AttachOptions & uOptions = {}
|
||||
options: AttachOptions & uOptions = {},
|
||||
) {
|
||||
const path = this._computePath(options);
|
||||
(app as TemplatedApp)
|
||||
@@ -84,7 +88,7 @@ export class uServer extends BaseServer {
|
||||
},
|
||||
message: (ws, message, isBinary) => {
|
||||
ws.getUserData().transport.onData(
|
||||
isBinary ? message : Buffer.from(message).toString()
|
||||
isBinary ? message : Buffer.from(message).toString(),
|
||||
);
|
||||
},
|
||||
close: (ws, code, message) => {
|
||||
@@ -96,7 +100,7 @@ export class uServer extends BaseServer {
|
||||
override _applyMiddlewares(
|
||||
req: any,
|
||||
res: any,
|
||||
callback: (err?: any) => void
|
||||
callback: (err?: any) => void,
|
||||
): void {
|
||||
if (this.middlewares.length === 0) {
|
||||
return callback();
|
||||
@@ -116,7 +120,7 @@ export class uServer extends BaseServer {
|
||||
|
||||
private handleRequest(
|
||||
res: HttpResponse,
|
||||
req: HttpRequest & { res: any; _query: any }
|
||||
req: HttpRequest & { res: any; _query: any },
|
||||
) {
|
||||
debug('handling "%s" http request "%s"', req.getMethod(), req.getUrl());
|
||||
this.prepare(req, res);
|
||||
@@ -158,7 +162,7 @@ export class uServer extends BaseServer {
|
||||
private handleUpgrade(
|
||||
res: HttpResponse,
|
||||
req: HttpRequest & { res: any; _query: any },
|
||||
context
|
||||
context,
|
||||
) {
|
||||
debug("on upgrade");
|
||||
|
||||
@@ -185,13 +189,13 @@ export class uServer extends BaseServer {
|
||||
const client = this.clients[id];
|
||||
if (!client) {
|
||||
debug("upgrade attempt for closed client");
|
||||
res.close();
|
||||
return res.close();
|
||||
} else if (client.upgrading) {
|
||||
debug("transport has already been trying to upgrade");
|
||||
res.close();
|
||||
return res.close();
|
||||
} else if (client.upgraded) {
|
||||
debug("transport had already been upgraded");
|
||||
res.close();
|
||||
return res.close();
|
||||
} else {
|
||||
debug("upgrading existing transport");
|
||||
transport = this.createTransport(req._query.transport, req);
|
||||
@@ -202,7 +206,7 @@ export class uServer extends BaseServer {
|
||||
req._query.transport,
|
||||
req,
|
||||
(errorCode, errorContext) =>
|
||||
this.abortRequest(res, errorCode, errorContext)
|
||||
this.abortRequest(res, errorCode, errorContext),
|
||||
);
|
||||
if (!transport) {
|
||||
return;
|
||||
@@ -219,7 +223,7 @@ export class uServer extends BaseServer {
|
||||
req.getHeader("sec-websocket-key"),
|
||||
req.getHeader("sec-websocket-protocol"),
|
||||
req.getHeader("sec-websocket-extensions"),
|
||||
context
|
||||
context,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -235,7 +239,7 @@ export class uServer extends BaseServer {
|
||||
private abortRequest(
|
||||
res: HttpResponse | ResponseWrapper,
|
||||
errorCode,
|
||||
errorContext
|
||||
errorContext,
|
||||
) {
|
||||
const statusCode =
|
||||
errorCode === Server.errors.FORBIDDEN
|
||||
@@ -252,7 +256,7 @@ export class uServer extends BaseServer {
|
||||
JSON.stringify({
|
||||
code: errorCode,
|
||||
message,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "engine.io",
|
||||
"version": "6.6.0",
|
||||
"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",
|
||||
@@ -31,12 +31,11 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cookie": "~0.7.2",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
if (process.env.EIO_CLIENT === "3" && process.versions.node.startsWith("22")) {
|
||||
// FIXME WebSocket error with engine.io-client@3
|
||||
global.WebSocket = null;
|
||||
}
|
||||
|
||||
const { listen, uServer } = require("..");
|
||||
const { Socket } =
|
||||
process.env.EIO_CLIENT === "3"
|
||||
? require("engine.io-client-v3")
|
||||
: require("engine.io-client");
|
||||
|
||||
switch (process.env.EIO_WS_ENGINE) {
|
||||
case "uws":
|
||||
console.log(
|
||||
"[WARN] testing with uWebSockets.js instead of Node.js built-in HTTP server",
|
||||
);
|
||||
break;
|
||||
case "eiows":
|
||||
console.log("[WARN] testing with eiows instead of ws");
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen shortcut that fires a callback on an ephemeral port.
|
||||
*/
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
const check = setTimeout(() => {
|
||||
@@ -122,7 +122,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
@@ -154,7 +154,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
// send from client to server
|
||||
@@ -198,7 +198,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
// test that socket is still open by writing after the timeout period
|
||||
@@ -245,7 +245,7 @@ describe("engine", () => {
|
||||
server.once("close", done);
|
||||
server.close();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("middlewares", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.on("upgrade", (res) => {
|
||||
@@ -131,7 +131,7 @@ describe("middlewares", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.addEventListener("error", () => {
|
||||
@@ -169,7 +169,7 @@ describe("middlewares", () => {
|
||||
engine.use(helmet());
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.on("upgrade", (res) => {
|
||||
@@ -196,7 +196,7 @@ describe("middlewares", () => {
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
request
|
||||
@@ -206,7 +206,7 @@ describe("middlewares", () => {
|
||||
expect(err).to.be(null);
|
||||
// expect(res.status).to.eql(200);
|
||||
expect(res.headers["set-cookie"][0].startsWith("connect.sid=")).to.be(
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
if (engine.httpServer) {
|
||||
@@ -225,16 +225,16 @@ describe("middlewares", () => {
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.on("upgrade", (res) => {
|
||||
expect(res.headers["set-cookie"][0].startsWith("connect.sid=")).to.be(
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
if (engine.httpServer) {
|
||||
@@ -280,7 +280,7 @@ describe("middlewares", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.addEventListener("error", () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ describe("parser", () => {
|
||||
expect(decoded.data).to.eql("€€€€");
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -143,7 +143,7 @@ describe("server", () => {
|
||||
expect(res.body.message).to.be("Thou shall not pass");
|
||||
partialDone();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -161,7 +161,7 @@ describe("server", () => {
|
||||
client.on("error", () => {
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -205,6 +205,26 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should prevent the client from upgrading twice", (done) => {
|
||||
engine = listen((port) => {
|
||||
const client = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
client.on("upgrade", () => {
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket&sid=${client.id}`,
|
||||
);
|
||||
|
||||
socket.on("error", () => {});
|
||||
|
||||
socket.on("close", () => {
|
||||
client.close();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should disallow `__proto__` as transport (polling)", (done) => {
|
||||
const partialDone = createPartialDone(done, 2);
|
||||
|
||||
@@ -243,7 +263,7 @@ describe("server", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=__proto__`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=__proto__`,
|
||||
);
|
||||
|
||||
socket.onerror = partialDone;
|
||||
@@ -262,7 +282,7 @@ describe("server", () => {
|
||||
// hack-obtain sid
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -278,7 +298,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`woot=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`woot=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -294,7 +314,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/custom; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/custom; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -310,7 +330,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; SameSite=Lax`
|
||||
`io=${sid}; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -326,7 +346,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -342,7 +362,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Strict`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Strict`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -358,7 +378,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; SameSite=Lax`
|
||||
`io=${sid}; Path=/; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -374,7 +394,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -681,14 +701,14 @@ describe("server", () => {
|
||||
expect(res.body.code).to.be(3);
|
||||
expect(res.body.message).to.be("Bad request");
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://engine.io"
|
||||
"http://engine.io",
|
||||
);
|
||||
partialDone();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -817,7 +837,7 @@ describe("server", () => {
|
||||
.end((err, res) => {
|
||||
if (process.env.EIO_WS_ENGINE === "uws") {
|
||||
expect(err).to.not.be(null);
|
||||
expect(err.message).to.be("socket hang up");
|
||||
expect(err.status).to.be(404);
|
||||
} else {
|
||||
expect(err).to.be(null);
|
||||
// this should not work, but it is kept for backward-compatibility
|
||||
@@ -1130,7 +1150,7 @@ describe("server", () => {
|
||||
expect(res.statusCode).to.eql(400);
|
||||
res.resume();
|
||||
res.on("end", done);
|
||||
}
|
||||
},
|
||||
);
|
||||
req.end();
|
||||
});
|
||||
@@ -1174,7 +1194,7 @@ describe("server", () => {
|
||||
// OPENED readyState is expected - we are actually polling
|
||||
expect(
|
||||
socket.transport.pollXhr[IS_CLIENT_V3 ? "xhr" : "_xhr"]
|
||||
.readyState
|
||||
.readyState,
|
||||
).to.be(1);
|
||||
|
||||
// 2 requests sent to the server over an unique port means
|
||||
@@ -1194,7 +1214,7 @@ describe("server", () => {
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("should not trigger with connection: close header", ($done) => {
|
||||
@@ -1260,7 +1280,7 @@ describe("server", () => {
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
@@ -1295,7 +1315,7 @@ describe("server", () => {
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
@@ -1331,7 +1351,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (IS_CLIENT_V3) {
|
||||
@@ -1370,7 +1390,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
it(
|
||||
@@ -1408,7 +1428,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1435,7 +1455,7 @@ describe("server", () => {
|
||||
socket.send("test");
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// tests https://github.com/LearnBoost/engine.io-client/issues/207
|
||||
@@ -1634,6 +1654,67 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should discard the packets in the writeBuffer when stopping the server", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
clientSocket.on("close", (reason) => {
|
||||
expect(reason).to.eql("transport error");
|
||||
|
||||
clientSocket.close();
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
engine.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should discard the packets in the writeBuffer when stopping the server (2)", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
clientSocket.on("close", (reason) => {
|
||||
expect(reason).to.eql("transport error");
|
||||
|
||||
clientSocket.close();
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
socket.close(); // readyState is now "closing"
|
||||
engine.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should not discard the packets in the writeBuffer when closing gracefully", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", (val) => {
|
||||
expect(val).to.eql("hello");
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
socket.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("graceful close", () => {
|
||||
before(function () {
|
||||
if (process.env.EIO_WS_ENGINE === "uws") {
|
||||
@@ -1727,7 +1808,7 @@ describe("server", () => {
|
||||
engine.on("connection", (conn) => {
|
||||
conn.on("message", (msg) => {
|
||||
done(
|
||||
new Error("Test invalidation (message is longer than allowed)")
|
||||
new Error("Test invalidation (message is longer than allowed)"),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1749,7 +1830,7 @@ describe("server", () => {
|
||||
engine.on("connection", (conn) => {
|
||||
conn.on("message", (msg) => {
|
||||
done(
|
||||
new Error("Test invalidation (message is longer than allowed)")
|
||||
new Error("Test invalidation (message is longer than allowed)"),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -2060,7 +2141,7 @@ describe("server", () => {
|
||||
client.on("open", () => {
|
||||
client.send("a".repeat(1e6));
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2202,7 +2283,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("should support chinese", (done) => {
|
||||
@@ -2546,7 +2627,7 @@ describe("server", () => {
|
||||
j,
|
||||
((value) => {
|
||||
j++;
|
||||
})(j)
|
||||
})(j),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2585,7 +2666,7 @@ describe("server", () => {
|
||||
j,
|
||||
((value) => {
|
||||
j++;
|
||||
})(j)
|
||||
})(j),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2999,7 +3080,7 @@ describe("server", () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3031,7 +3112,7 @@ describe("server", () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3174,11 +3255,11 @@ describe("server", () => {
|
||||
.on("error", done)
|
||||
.on("end", done)
|
||||
.resume();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3212,11 +3293,11 @@ describe("server", () => {
|
||||
.on("error", done)
|
||||
.on("end", done)
|
||||
.resume();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3250,11 +3331,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.equal("gzip");
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3284,11 +3365,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.be(undefined);
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3318,11 +3399,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.be(undefined);
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3352,11 +3433,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.be(undefined);
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3599,20 +3680,20 @@ describe("server", () => {
|
||||
expect(res.status).to.be(204);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://engine.io"
|
||||
"http://engine.io",
|
||||
);
|
||||
expect(res.header["access-control-allow-methods"]).to.be(
|
||||
"GET,HEAD,PUT,PATCH,POST,DELETE"
|
||||
"GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||
);
|
||||
expect(res.header["access-control-allow-headers"]).to.be(
|
||||
"my-header"
|
||||
"my-header",
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3629,20 +3710,20 @@ describe("server", () => {
|
||||
expect(res.status).to.be(200);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://engine.io"
|
||||
"http://engine.io",
|
||||
);
|
||||
expect(res.header["access-control-allow-methods"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(res.header["access-control-allow-headers"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3663,14 +3744,14 @@ describe("server", () => {
|
||||
expect(res.status).to.be(204);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3697,24 +3778,24 @@ describe("server", () => {
|
||||
expect(res.status).to.be(200);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://good-domain.com"
|
||||
"http://good-domain.com",
|
||||
);
|
||||
expect(res.header["access-control-allow-methods"]).to.be(
|
||||
"GET,PUT,POST"
|
||||
"GET,PUT,POST",
|
||||
);
|
||||
expect(res.header["access-control-allow-headers"]).to.be(
|
||||
"my-header"
|
||||
"my-header",
|
||||
);
|
||||
expect(res.header["access-control-expose-headers"]).to.be(
|
||||
"my-exposed-header"
|
||||
"my-exposed-header",
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
expect(res.header["access-control-max-age"]).to.be("123");
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3739,7 +3820,7 @@ describe("server", () => {
|
||||
client.close();
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3767,7 +3848,7 @@ describe("server", () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as eio from "../build/server.js";
|
||||
import { Http3Server, WebTransport } from "@fails-components/webtransport";
|
||||
import { Http3EventLoop } from "@fails-components/webtransport/lib/event-loop.js";
|
||||
import expect from "expect.js";
|
||||
import request from "superagent";
|
||||
import { createServer } from "http";
|
||||
@@ -30,8 +29,8 @@ async function setupServer(opts, cb) {
|
||||
const certificate = await generateWebTransportCertificate(
|
||||
[{ shortName: "CN", value: "localhost" }],
|
||||
{
|
||||
days: 14, // the total length of the validity period MUST NOT exceed two weeks (https://w3c.github.io/webtransport/#custom-certificate-requirements)
|
||||
}
|
||||
days: 13, // the total length of the validity period MUST NOT exceed two weeks (https://w3c.github.io/webtransport/#custom-certificate-requirements)
|
||||
},
|
||||
);
|
||||
|
||||
const engine = new eio.Server(opts);
|
||||
@@ -62,7 +61,10 @@ async function setupServer(opts, cb) {
|
||||
})();
|
||||
|
||||
h3Server.startServer();
|
||||
h3Server.onServerListening = () => cb({ engine, h3Server, certificate });
|
||||
|
||||
await h3Server.ready;
|
||||
|
||||
cb({ engine, h3Server, certificate });
|
||||
}
|
||||
|
||||
function setup(opts, cb) {
|
||||
@@ -76,7 +78,7 @@ function setup(opts, cb) {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -98,15 +100,11 @@ function setup(opts, cb) {
|
||||
}
|
||||
|
||||
describe("WebTransport", () => {
|
||||
after(() => {
|
||||
Http3EventLoop.globalLoop.shutdownEventLoop(); // manually shutdown the event loop, instead of waiting 20s
|
||||
});
|
||||
|
||||
it("should allow to connect with WebTransport directly", (done) => {
|
||||
setupServer({}, async ({ engine, h3Server, certificate }) => {
|
||||
const partialDone = createPartialDone(
|
||||
() => success(engine, h3Server, done),
|
||||
2
|
||||
2,
|
||||
);
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
@@ -123,7 +121,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -188,7 +186,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -216,14 +214,14 @@ describe("WebTransport", () => {
|
||||
|
||||
await writer.write(Uint8Array.of(31));
|
||||
await writer.write(
|
||||
TEXT_ENCODER.encode(`0{"sid":"${payload.sid}"}`)
|
||||
TEXT_ENCODER.encode(`0{"sid":"${payload.sid}"}`),
|
||||
);
|
||||
await writer.write(Uint8Array.of(6));
|
||||
await writer.write(TEXT_ENCODER.encode(`2probe`));
|
||||
await writer.write(Uint8Array.of(1));
|
||||
await writer.write(TEXT_ENCODER.encode(`5`));
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -242,7 +240,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -250,7 +248,7 @@ describe("WebTransport", () => {
|
||||
client.closed.then(() => {
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -269,7 +267,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -281,7 +279,7 @@ describe("WebTransport", () => {
|
||||
client.closed.then(() => {
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -304,7 +302,7 @@ describe("WebTransport", () => {
|
||||
}
|
||||
|
||||
success(engine, h3Server, done);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -322,7 +320,7 @@ describe("WebTransport", () => {
|
||||
});
|
||||
|
||||
client.closed.then(() => success(engine, h3Server, partialDone));
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -440,7 +438,7 @@ describe("WebTransport", () => {
|
||||
|
||||
const header = await reader.read();
|
||||
expect(header.value).to.eql(
|
||||
Uint8Array.of(255, 0, 0, 0, 0, 0, 15, 66, 64)
|
||||
Uint8Array.of(255, 0, 0, 0, 0, 0, 15, 66, 64),
|
||||
);
|
||||
|
||||
const chunk1 = await reader.read();
|
||||
|
||||
@@ -203,7 +203,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
"[%s] new event of type %d from %s",
|
||||
this.uid,
|
||||
message.type,
|
||||
message.uid
|
||||
message.uid,
|
||||
);
|
||||
|
||||
switch (message.type) {
|
||||
@@ -217,7 +217,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
"[%s] waiting for %d client acknowledgements",
|
||||
this.uid,
|
||||
clientCount
|
||||
clientCount,
|
||||
);
|
||||
this.publishResponse(message.uid, {
|
||||
type: MessageType.BROADCAST_CLIENT_COUNT,
|
||||
@@ -231,7 +231,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
"[%s] received acknowledgement with value %j",
|
||||
this.uid,
|
||||
arg
|
||||
arg,
|
||||
);
|
||||
this.publishResponse(message.uid, {
|
||||
type: MessageType.BROADCAST_ACK,
|
||||
@@ -240,7 +240,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
packet: arg,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const packet = message.data.packet;
|
||||
@@ -264,7 +264,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
case MessageType.DISCONNECT_SOCKETS:
|
||||
super.disconnectSockets(
|
||||
decodeOptions(message.data.opts),
|
||||
message.data.close
|
||||
message.data.close,
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -272,7 +272,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
"[%s] calling fetchSockets with opts %j",
|
||||
this.uid,
|
||||
message.data.opts
|
||||
message.data.opts,
|
||||
);
|
||||
super
|
||||
.fetchSockets(decodeOptions(message.data.opts))
|
||||
@@ -356,7 +356,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
"[%s] received response %s to request %s",
|
||||
this.uid,
|
||||
response.type,
|
||||
requestId
|
||||
requestId,
|
||||
);
|
||||
|
||||
switch (response.type) {
|
||||
@@ -381,7 +381,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
|
||||
request.current++;
|
||||
response.data.sockets.forEach((socket) =>
|
||||
request.responses.push(socket)
|
||||
request.responses.push(socket),
|
||||
);
|
||||
|
||||
if (request.current === request.expected) {
|
||||
@@ -433,7 +433,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
return debug(
|
||||
"[%s] error while broadcasting message: %s",
|
||||
this.uid,
|
||||
e.message
|
||||
e.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -453,7 +453,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
private addOffsetIfNecessary(
|
||||
packet: any,
|
||||
opts: BroadcastOptions,
|
||||
offset: Offset
|
||||
offset: Offset,
|
||||
) {
|
||||
if (!this.nsp.server.opts.connectionStateRecovery) {
|
||||
return;
|
||||
@@ -473,7 +473,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
packet: any,
|
||||
opts: BroadcastOptions,
|
||||
clientCountCallback: (clientCount: number) => void,
|
||||
ack: (...args: any[]) => void
|
||||
ack: (...args: any[]) => void,
|
||||
) {
|
||||
const onlyLocal = opts?.flags?.local;
|
||||
if (!onlyLocal) {
|
||||
@@ -582,8 +582,8 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
if (storedRequest) {
|
||||
reject(
|
||||
new Error(
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`
|
||||
)
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`,
|
||||
),
|
||||
);
|
||||
this.requests.delete(requestId);
|
||||
}
|
||||
@@ -627,7 +627,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
'[%s] waiting for %d responses to "serverSideEmit" request',
|
||||
this.uid,
|
||||
expectedResponseCount
|
||||
expectedResponseCount,
|
||||
);
|
||||
|
||||
if (expectedResponseCount <= 0) {
|
||||
@@ -641,9 +641,9 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
if (storedRequest) {
|
||||
ack(
|
||||
new Error(
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`,
|
||||
),
|
||||
storedRequest.responses
|
||||
storedRequest.responses,
|
||||
);
|
||||
this.requests.delete(requestId);
|
||||
}
|
||||
@@ -669,7 +669,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
}
|
||||
|
||||
protected publish(
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">,
|
||||
): void {
|
||||
this.publishAndReturnOffset(message).catch((err) => {
|
||||
debug("[%s] error while publishing message: %s", this.uid, err);
|
||||
@@ -677,7 +677,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
}
|
||||
|
||||
protected publishAndReturnOffset(
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">,
|
||||
) {
|
||||
(message as ClusterMessage).uid = this.uid;
|
||||
(message as ClusterMessage).nsp = this.nsp.name;
|
||||
@@ -695,14 +695,14 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
|
||||
protected publishResponse(
|
||||
requesterUid: ServerId,
|
||||
response: Omit<ClusterResponse, "nsp" | "uid">
|
||||
response: Omit<ClusterResponse, "nsp" | "uid">,
|
||||
) {
|
||||
(response as ClusterResponse).uid = this.uid;
|
||||
(response as ClusterResponse).nsp = this.nsp.name;
|
||||
this.doPublishResponse(requesterUid, response as ClusterResponse).catch(
|
||||
(err) => {
|
||||
debug("[%s] error while publishing response: %s", this.uid, err);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
*/
|
||||
protected abstract doPublishResponse(
|
||||
requesterUid: ServerId,
|
||||
response: ClusterResponse
|
||||
response: ClusterResponse,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -742,7 +742,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
heartbeatInterval: 5_000,
|
||||
heartbeatTimeout: 10_000,
|
||||
},
|
||||
opts
|
||||
opts,
|
||||
);
|
||||
this.cleanupTimer = setInterval(() => {
|
||||
const now = Date.now();
|
||||
@@ -798,7 +798,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
"[%s] new event of type %d from %s",
|
||||
this.uid,
|
||||
message.type,
|
||||
message.uid
|
||||
message.uid,
|
||||
);
|
||||
|
||||
switch (message.type) {
|
||||
@@ -846,7 +846,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
debug(
|
||||
'[%s] waiting for %d responses to "serverSideEmit" request',
|
||||
this.uid,
|
||||
expectedResponseCount
|
||||
expectedResponseCount,
|
||||
);
|
||||
|
||||
if (expectedResponseCount <= 0) {
|
||||
@@ -860,9 +860,9 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
if (storedRequest) {
|
||||
ack(
|
||||
new Error(
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`,
|
||||
),
|
||||
storedRequest.responses
|
||||
storedRequest.responses,
|
||||
);
|
||||
this.customRequests.delete(requestId);
|
||||
}
|
||||
@@ -911,8 +911,8 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
if (storedRequest) {
|
||||
reject(
|
||||
new Error(
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`
|
||||
)
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`,
|
||||
),
|
||||
);
|
||||
this.customRequests.delete(requestId);
|
||||
}
|
||||
@@ -944,7 +944,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
"[%s] received response %s to request %s",
|
||||
this.uid,
|
||||
response.type,
|
||||
requestId
|
||||
requestId,
|
||||
);
|
||||
|
||||
switch (response.type) {
|
||||
@@ -956,7 +956,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
}
|
||||
|
||||
(response.data.sockets as any[]).forEach((socket) =>
|
||||
request.responses.push(socket)
|
||||
request.responses.push(socket),
|
||||
);
|
||||
|
||||
request.missingUids.delete(response.uid);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
const alphabet =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(
|
||||
""
|
||||
"",
|
||||
),
|
||||
length = 64,
|
||||
map = {};
|
||||
|
||||
@@ -198,7 +198,7 @@ export class Adapter extends EventEmitter {
|
||||
packet: any,
|
||||
opts: BroadcastOptions,
|
||||
clientCountCallback: (clientCount: number) => void,
|
||||
ack: (...args: any[]) => void
|
||||
ack: (...args: any[]) => void,
|
||||
) {
|
||||
const flags = opts.flags || {};
|
||||
const packetOpts = {
|
||||
@@ -375,7 +375,7 @@ export class Adapter extends EventEmitter {
|
||||
*/
|
||||
public serverSideEmit(packet: any[]): void {
|
||||
console.warn(
|
||||
"this adapter does not support the serverSideEmit() functionality"
|
||||
"this adapter does not support the serverSideEmit() functionality",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@ export class Adapter extends EventEmitter {
|
||||
*/
|
||||
public restoreSession(
|
||||
pid: PrivateSessionId,
|
||||
offset: string
|
||||
offset: string,
|
||||
): Promise<Session> {
|
||||
return null;
|
||||
}
|
||||
@@ -444,7 +444,7 @@ export class SessionAwareAdapter extends Adapter {
|
||||
|
||||
override restoreSession(
|
||||
pid: PrivateSessionId,
|
||||
offset: string
|
||||
offset: string,
|
||||
): Promise<Session> {
|
||||
const session = this.sessions.get(pid);
|
||||
if (!session) {
|
||||
@@ -500,7 +500,7 @@ export class SessionAwareAdapter extends Adapter {
|
||||
|
||||
function shouldIncludePacket(
|
||||
sessionRooms: Room[],
|
||||
opts: BroadcastOptions
|
||||
opts: BroadcastOptions,
|
||||
): boolean {
|
||||
const included =
|
||||
opts.rooms.size === 0 || sessionRooms.some((room) => opts.rooms.has(room));
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc",
|
||||
"compile": "rimraf ./dist && tsc",
|
||||
"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'",
|
||||
|
||||
@@ -16,7 +16,10 @@ const NODES_COUNT = 3;
|
||||
class EventEmitterAdapter extends ClusterAdapterWithHeartbeat {
|
||||
private offset = 1;
|
||||
|
||||
constructor(nsp, readonly eventBus) {
|
||||
constructor(
|
||||
nsp,
|
||||
readonly eventBus,
|
||||
) {
|
||||
super(nsp, {});
|
||||
this.eventBus.on("message", (message) => {
|
||||
this.onMessage(message as ClusterMessage);
|
||||
@@ -30,7 +33,7 @@ class EventEmitterAdapter extends ClusterAdapterWithHeartbeat {
|
||||
|
||||
protected doPublishResponse(
|
||||
requesterUid: string,
|
||||
response: ClusterResponse
|
||||
response: ClusterResponse,
|
||||
): Promise<void> {
|
||||
this.eventBus.emit("message", response);
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -153,7 +153,7 @@ describe("socket.io-adapter", () => {
|
||||
expect(opts.wsPreEncodedFrame.length).to.eql(2);
|
||||
expect(opts.wsPreEncodedFrame[0]).to.eql(Buffer.from([129, 4]));
|
||||
expect(opts.wsPreEncodedFrame[1]).to.eql(
|
||||
Buffer.from([52, 49, 50, 51])
|
||||
Buffer.from([52, 49, 50, 51]),
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -352,7 +352,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const offset = packetData[1];
|
||||
@@ -398,7 +398,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -410,7 +410,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -422,7 +422,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(["r1"]),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -434,7 +434,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(["r2"]),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -446,7 +446,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(["r3"]),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -459,7 +459,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -471,7 +471,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -486,7 +486,7 @@ describe("socket.io-adapter", () => {
|
||||
flags: {
|
||||
volatile: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const offset = packetData[1];
|
||||
|
||||
@@ -1,73 +1,154 @@
|
||||
# History
|
||||
|
||||
## 2024
|
||||
|
||||
- [4.7.5](#475-2024-03-14) (Mar 2024)
|
||||
- [4.7.4](#474-2024-01-12) (Jan 2024)
|
||||
- [4.7.3](#473-2024-01-03) (Jan 2024)
|
||||
|
||||
## 2023
|
||||
|
||||
- [4.7.2](#472-2023-08-02) (Aug 2023)
|
||||
- [4.7.1](#471-2023-06-28) (Jun 2023)
|
||||
- [4.7.0](#470-2023-06-22) (Jun 2023)
|
||||
- [4.6.2](#462-2023-05-31) (May 2023)
|
||||
- [4.6.1](#461-2023-02-20) (Feb 2023)
|
||||
- [4.6.0](#460-2023-02-07) (Feb 2023)
|
||||
|
||||
## 2022
|
||||
|
||||
- [4.5.4](#454-2022-11-22) (Nov 2022)
|
||||
- [4.5.3](#453-2022-10-15) (Oct 2022)
|
||||
- [4.5.2](#452-2022-09-02) (Sep 2022)
|
||||
- [2.5.0](#250-2022-06-26) (Jun 2022) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch)
|
||||
- [4.5.1](#451-2022-05-17) (May 2022)
|
||||
- [4.5.0](#450-2022-04-23) (Apr 2022)
|
||||
- [4.4.1](#441-2022-01-06) (Jan 2022)
|
||||
|
||||
## 2021
|
||||
|
||||
- [4.4.0](#440-2021-11-18) (Nov 2021)
|
||||
- [4.3.2](#432-2021-10-16) (Oct 2021)
|
||||
- [4.3.1](#431-2021-10-15) (Oct 2021)
|
||||
- [4.3.0](#430-2021-10-14) (Oct 2021)
|
||||
- [4.2.0](#420-2021-08-30) (Aug 2021)
|
||||
- [4.1.3](#413-2021-07-10) (Jul 2021)
|
||||
- [4.1.2](#412-2021-05-17) (May 2021)
|
||||
- [4.1.1](#411-2021-05-11) (May 2021)
|
||||
- [4.1.0](#410-2021-05-11) (May 2021)
|
||||
- [4.0.2](#402-2021-05-06) (May 2021)
|
||||
- [4.0.1](#401-2021-03-31) (Mar 2021)
|
||||
- [3.1.3](#313-2021-03-12) (Mar 2021) (from the [3.1.x](https://github.com/socketio/socket.io-client/tree/3.1.x) branch)
|
||||
- [**4.0.0**](#400-2021-03-10) (Mar 2021)
|
||||
- [3.1.2](#312-2021-02-26) (Feb 2021)
|
||||
- [3.1.1](#311-2021-02-03) (Feb 2021)
|
||||
- [3.1.0](#310-2021-01-15) (Jan 2021)
|
||||
- [3.0.5](#305-2021-01-05) (Jan 2021)
|
||||
- [2.4.0](#240-2021-01-04) (Jan 2021) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch)
|
||||
|
||||
## 2020
|
||||
|
||||
- [3.0.4](#304-2020-12-07) (Dec 2020)
|
||||
- [3.0.3](#303-2020-11-19) (Nov 2020)
|
||||
- [3.0.2](#302-2020-11-17) (Nov 2020)
|
||||
- [3.0.1](#301-2020-11-09) (Nov 2020)
|
||||
- [**3.0.0**](#300-2020-11-05) (Nov 2020)
|
||||
- [2.3.1](#231-2020-09-30) (Sep 2020)
|
||||
|
||||
## 2019
|
||||
|
||||
- [2.3.0](#230-2019-09-20) (Sep 2019)
|
||||
|
||||
## 2018
|
||||
|
||||
- [2.2.0](#220-2018-11-29) (Nov 2018)
|
||||
- [2.1.1](#211-2018-05-17) (May 2018)
|
||||
- [2.1.0](#210-2018-03-29) (Mar 2018)
|
||||
| Version | Release date | Bundle size (UMD min+gzip) |
|
||||
|-------------------------------------------------------------------------------------------------------------|----------------|----------------------------|
|
||||
| [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` |
|
||||
| [4.7.4](#474-2024-01-12) | January 2024 | `14.5 KB` |
|
||||
| [4.7.3](#473-2024-01-03) | January 2024 | `14.5 KB` |
|
||||
| [4.7.2](#472-2023-08-02) | August 2023 | `14.5 KB` |
|
||||
| [4.7.1](#471-2023-06-28) | June 2023 | `14.1 KB` |
|
||||
| [4.7.0](#470-2023-06-22) | June 2023 | `14.0 KB` |
|
||||
| [4.6.2](#462-2023-05-31) | May 2023 | `13.4 KB` |
|
||||
| [4.6.1](#461-2023-02-20) | February 2023 | `13.3 KB` |
|
||||
| [4.6.0](#460-2023-02-07) | February 2023 | `13.3 KB` |
|
||||
| [4.5.4](#454-2022-11-22) | November 2022 | `12.8 KB` |
|
||||
| [4.5.3](#453-2022-10-15) | October 2022 | `12.8 KB` |
|
||||
| [4.5.2](#452-2022-09-02) | September 2022 | `12.7 KB` |
|
||||
| [2.5.0](#250-2022-06-26) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch) | June 2022 | `18.8 KB` |
|
||||
| [4.5.1](#451-2022-05-17) | May 2022 | `12.7 KB` |
|
||||
| [4.5.0](#450-2022-04-23) | April 2022 | `12.7 KB` |
|
||||
| [4.4.1](#441-2022-01-06) | January 2022 | `12.3 KB` |
|
||||
| [4.4.0](#440-2021-11-18) | November 2021 | `12.3 KB` |
|
||||
| [4.3.2](#432-2021-10-16) | October 2021 | `12.1 KB` |
|
||||
| [4.3.1](#431-2021-10-15) | October 2021 | `12.1 KB` |
|
||||
| [4.3.0](#430-2021-10-14) | October 2021 | `12.1 KB` |
|
||||
| [4.2.0](#420-2021-08-30) | August 2021 | `15.2 KB` |
|
||||
| [4.1.3](#413-2021-07-10) | July 2021 | `14.9 KB` |
|
||||
| [4.1.2](#412-2021-05-17) | May 2021 | `14.9 KB` |
|
||||
| [4.1.1](#411-2021-05-11) | May 2021 | `14.9 KB` |
|
||||
| [4.1.0](#410-2021-05-11) | May 2021 | `14.9 KB` |
|
||||
| [4.0.2](#402-2021-05-06) | May 2021 | `14.9 KB` |
|
||||
| [4.0.1](#401-2021-03-31) | March 2021 | `14.9 KB` |
|
||||
| [3.1.3](#313-2021-03-12) (from the [3.1.x](https://github.com/socketio/socket.io-client/tree/3.1.x) branch) | March 2021 | `14.6 KB` |
|
||||
| [**4.0.0**](#400-2021-03-10) | March 2021 | `14.9 KB` |
|
||||
| [3.1.2](#312-2021-02-26) | February 2021 | `14.6 KB` |
|
||||
| [3.1.1](#311-2021-02-03) | February 2021 | `14.5 KB` |
|
||||
| [3.1.0](#310-2021-01-15) | January 2021 | `14.5 KB` |
|
||||
| [3.0.5](#305-2021-01-05) | January 2021 | `14.5 KB` |
|
||||
| [2.4.0](#240-2021-01-04) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch) | January 2021 | `18.8 KB` |
|
||||
| [3.0.4](#304-2020-12-07) | December 2020 | `14.6 KB` |
|
||||
| [3.0.3](#303-2020-11-19) | November 2020 | `14.5 KB` |
|
||||
| [3.0.2](#302-2020-11-17) | November 2020 | `14.5 KB` |
|
||||
| [3.0.1](#301-2020-11-09) | November 2020 | `14.7 KB` |
|
||||
| [**3.0.0**](#300-2020-11-05) | November 2020 | `14.6 KB` |
|
||||
| [2.3.1](#231-2020-09-30) | September 2020 | `18.8 KB` |
|
||||
| [2.3.0](#230-2019-09-20) | September 2019 | `19.6 KB` |
|
||||
| [2.2.0](#220-2018-11-29) | November 2018 | `18.6 KB` |
|
||||
| [2.1.1](#211-2018-05-17) | May 2018 | `18.7 KB` |
|
||||
| [2.1.0](#210-2018-03-29) | March 2018 | `18.7 KB` |
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bundle:** do not mangle the "_placeholder" attribute ([ca9e994](https://github.com/socketio/socket.io/commit/ca9e994815aa2e31e0342e37ccdc2e9e8c5fd13c))
|
||||
|
||||
|
||||
### 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)
|
||||
|
||||
|
||||
|
||||
## [4.8.0](https://github.com/socketio/socket.io/compare/socket.io-client@4.7.5...socket.io-client@4.8.0) (2024-09-21)
|
||||
|
||||
### Features
|
||||
|
||||
#### Custom transport implementations
|
||||
|
||||
The `transports` option now accepts an array of transport implementations:
|
||||
|
||||
```js
|
||||
import { io } from "socket.io-client";
|
||||
import { XHR, WebSocket } from "engine.io-client";
|
||||
|
||||
const socket = io({
|
||||
transports: [XHR, WebSocket]
|
||||
});
|
||||
```
|
||||
|
||||
Here is the list of provided implementations:
|
||||
|
||||
| Transport | Description |
|
||||
|-----------------|------------------------------------------------------------------------------------------------------|
|
||||
| `Fetch` | HTTP long-polling based on the built-in `fetch()` method. |
|
||||
| `NodeXHR` | HTTP long-polling based on the `XMLHttpRequest` object provided by the `xmlhttprequest-ssl` package. |
|
||||
| `XHR` | HTTP long-polling based on the built-in `XMLHttpRequest` object. |
|
||||
| `NodeWebSocket` | WebSocket transport based on the `WebSocket` object provided by the `ws` package. |
|
||||
| `WebSocket` | WebSocket transport based on the built-in `WebSocket` object. |
|
||||
| `WebTransport` | WebTransport transport based on the built-in `WebTransport` object. |
|
||||
|
||||
Usage:
|
||||
|
||||
| Transport | browser | Node.js | Deno | Bun |
|
||||
|-----------------|--------------------|------------------------|--------------------|--------------------|
|
||||
| `Fetch` | :white_check_mark: | :white_check_mark: (1) | :white_check_mark: | :white_check_mark: |
|
||||
| `NodeXHR` | | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| `XHR` | :white_check_mark: | | | |
|
||||
| `NodeWebSocket` | | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| `WebSocket` | :white_check_mark: | :white_check_mark: (2) | :white_check_mark: | :white_check_mark: |
|
||||
| `WebTransport` | :white_check_mark: | :white_check_mark: | | |
|
||||
|
||||
(1) since [v18.0.0](https://nodejs.org/api/globals.html#fetch)
|
||||
(2) since [v21.0.0](https://nodejs.org/api/globals.html#websocket)
|
||||
|
||||
Added in [f4d898e](https://github.com/socketio/engine.io-client/commit/f4d898ee9652939a4550a41ac0e8143056154c0a) and [b11763b](https://github.com/socketio/engine.io-client/commit/b11763beecfe4622867b4dec9d1db77460733ffb).
|
||||
|
||||
|
||||
#### Test each low-level transports
|
||||
|
||||
When setting the `tryAllTransports` option to `true`, if the first transport (usually, HTTP long-polling) fails, then the other transports will be tested too:
|
||||
|
||||
```js
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const socket = io({
|
||||
tryAllTransports: true
|
||||
});
|
||||
```
|
||||
|
||||
This feature is useful in two cases:
|
||||
|
||||
- when HTTP long-polling is disabled on the server, or if CORS fails
|
||||
- when WebSocket is tested first (with `transports: ["websocket", "polling"]`)
|
||||
|
||||
The only potential downside is that the connection attempt could take more time in case of failure, as there have been reports of WebSocket connection errors taking several seconds before being detected (that's one reason for using HTTP long-polling first). That's why the option defaults to `false` for now.
|
||||
|
||||
Added in [579b243](https://github.com/socketio/engine.io-client/commit/579b243e89ac7dc58233f9844ef70817364ecf52).
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* accept string | undefined as init argument (bis) ([60c757f](https://github.com/socketio/socket.io/commit/60c757f718d400e052c3160ee377bbe4973277c9))
|
||||
* allow to manually stop the reconnection loop ([13c6d2e](https://github.com/socketio/socket.io/commit/13c6d2e89deb1e6c6c8c7245118f9b37d66537cb))
|
||||
* close the engine upon decoding exception ([04c8dd9](https://github.com/socketio/socket.io/commit/04c8dd979ce40acaceec1f4507c1ae69325d6158))
|
||||
* do not send a packet on an expired connection ([#5134](https://github.com/socketio/socket.io/issues/5134)) ([8adcfbf](https://github.com/socketio/socket.io/commit/8adcfbfde50679095ec2abe376650cf2b6814325))
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`engine.io-client@~6.6.1`](https://github.com/socketio/engine.io-client/releases/tag/6.5.2) ([diff](https://github.com/socketio/engine.io-client/compare/6.5.3...6.6.0) and [diff](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.0...engine.io-client@6.6.1))
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) ([diff](https://github.com/websockets/ws/compare/8.11.0...8.17.1))
|
||||
|
||||
|
||||
|
||||
## [4.7.5](https://github.com/socketio/socket.io-client/compare/4.7.4...4.7.5) (2024-03-14)
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user