├── assets
├── adapter.png
├── adapter_dark.png
└── adapter.excalidraw
├── .gitignore
├── tsconfig.json
├── test
├── util.ts
├── connection-state-recovery.ts
└── index.ts
├── examples
├── ttl-example
│ ├── package.json
│ ├── index.js
│ └── package-lock.json
└── capped-example
│ ├── package.json
│ └── index.js
├── compose.yaml
├── .github
└── workflows
│ ├── publish.yml
│ └── ci.yml
├── LICENSE
├── package.json
├── README.md
├── CHANGELOG.md
└── lib
└── index.ts
/assets/adapter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-mongo-adapter/HEAD/assets/adapter.png
--------------------------------------------------------------------------------
/assets/adapter_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-mongo-adapter/HEAD/assets/adapter_dark.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 | .idea
17 | .nyc_output/
18 | dist/
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./dist",
4 | "allowJs": false,
5 | "target": "es2017",
6 | "module": "commonjs",
7 | "declaration": true,
8 | "strict": true
9 | },
10 | "include": [
11 | "./lib/**/*"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/test/util.ts:
--------------------------------------------------------------------------------
1 | export function times(count: number, fn: () => void) {
2 | let i = 0;
3 | return () => {
4 | i++;
5 | if (i === count) {
6 | fn();
7 | }
8 | };
9 | }
10 |
11 | export function sleep(duration: number) {
12 | return new Promise((resolve) => setTimeout(resolve, duration));
13 | }
14 |
--------------------------------------------------------------------------------
/examples/ttl-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "ttl-example",
4 | "version": "0.0.1",
5 | "description": "",
6 | "main": "index.js",
7 | "type": "module",
8 | "dependencies": {
9 | "@socket.io/mongo-adapter": "^0.3.2",
10 | "mongodb": "^6.3.0",
11 | "socket.io": "^4.7.4",
12 | "socket.io-client": "^4.7.4"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/capped-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "capped-example",
4 | "version": "0.0.1",
5 | "description": "",
6 | "main": "index.js",
7 | "type": "module",
8 | "dependencies": {
9 | "@socket.io/mongo-adapter": "^0.3.2",
10 | "mongodb": "^6.3.0",
11 | "socket.io": "^4.7.4",
12 | "socket.io-client": "^4.7.4"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | mongo:
3 | image: mongo:4.4
4 | entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
5 | # you'll need to run "rs.initiate()" on the node (https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/)
6 | # commands:
7 | # $ docker compose exec mongo /bin/bash
8 | # $ mongosh
9 | # $ rs.initiate()
10 | # $ rs.status()
11 | ports:
12 | - "27017:27017"
13 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | # reference: https://docs.npmjs.com/generating-provenance-statements
2 |
3 | name: Publish
4 |
5 | on:
6 | push:
7 | tags:
8 | - '*'
9 |
10 | jobs:
11 | publish:
12 | runs-on: ubuntu-latest
13 | permissions:
14 | contents: read
15 | id-token: write
16 |
17 | steps:
18 | - name: Checkout repository
19 | uses: actions/checkout@v4
20 |
21 | - name: Use Node.js 20
22 | uses: actions/setup-node@v4
23 | with:
24 | node-version: 20
25 | registry-url: 'https://registry.npmjs.org'
26 |
27 | - name: Install dependencies
28 | run: npm ci
29 |
30 | - name: Publish package
31 | run: npm publish --provenance --access public
32 | env:
33 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
34 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | pull_request:
6 | schedule:
7 | - cron: '0 0 * * 0'
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | test-node:
14 | runs-on: ubuntu-latest
15 | timeout-minutes: 10
16 |
17 | strategy:
18 | matrix:
19 | node-version:
20 | - 16
21 | - 20
22 |
23 | steps:
24 | - name: Checkout repository
25 | uses: actions/checkout@v3
26 |
27 | - name: Use Node.js ${{ matrix.node-version }}
28 | uses: actions/setup-node@v3
29 | with:
30 | node-version: ${{ matrix.node-version }}
31 |
32 | - name: Start MongoDB
33 | uses: supercharge/mongodb-github-action@v1
34 | with:
35 | mongodb-version: 5.0
36 | mongodb-replica-set: rs0
37 |
38 | - name: Install dependencies
39 | run: npm ci
40 |
41 | - name: Run tests
42 | run: npm test
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Damien Arrachequesne (@darrachequesne)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@socket.io/mongo-adapter",
3 | "version": "0.4.0",
4 | "description": "The Socket.IO MongoDB adapter, allowing to broadcast events between several Socket.IO servers",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git@github.com:socketio/socket.io-mongo-adapter.git"
9 | },
10 | "files": [
11 | "dist/"
12 | ],
13 | "main": "./dist/index.js",
14 | "types": "./dist/index.d.ts",
15 | "scripts": {
16 | "compile": "rimraf ./dist && tsc",
17 | "test": "npm run format:check && npm run compile && nyc mocha --require ts-node/register test/index.ts",
18 | "format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
19 | "format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
20 | "prepack": "npm run compile"
21 | },
22 | "dependencies": {
23 | "debug": "~4.3.1",
24 | "mongodb": "*"
25 | },
26 | "peerDependencies": {
27 | "socket.io-adapter": "^2.5.2"
28 | },
29 | "devDependencies": {
30 | "@types/expect.js": "^0.3.29",
31 | "@types/mocha": "^8.2.1",
32 | "@types/node": "^14.14.7",
33 | "expect.js": "0.3.1",
34 | "mocha": "^10.2.0",
35 | "nyc": "^15.1.0",
36 | "prettier": "^2.1.2",
37 | "rimraf": "^6.0.1",
38 | "socket.io": "^4.6.1",
39 | "socket.io-client": "^4.6.1",
40 | "ts-node": "^10.9.1",
41 | "typescript": "^4.9.4"
42 | },
43 | "engines": {
44 | "node": ">=10.0.0"
45 | },
46 | "keywords": [
47 | "socket.io",
48 | "mongodb",
49 | "mongo",
50 | "adapter"
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/examples/capped-example/index.js:
--------------------------------------------------------------------------------
1 | import { MongoClient } from "mongodb";
2 | import { Server } from "socket.io";
3 | import { createAdapter } from "@socket.io/mongo-adapter";
4 | import { io } from "socket.io-client";
5 |
6 | async function initMongoCollection() {
7 | const DB = "mydb";
8 | const COLLECTION = "socket.io-adapter-events-capped";
9 |
10 | const mongoClient = new MongoClient(
11 | "mongodb://localhost:27017/?replicaSet=rs0&directConnection=true"
12 | );
13 |
14 | await mongoClient.connect();
15 |
16 | try {
17 | await mongoClient.db(DB).createCollection(COLLECTION, {
18 | capped: true,
19 | size: 1e6,
20 | });
21 | } catch (e) {
22 | // collection already exists
23 | }
24 |
25 | return mongoClient.db(DB).collection(COLLECTION);
26 | }
27 |
28 | function initServer(mongoCollection) {
29 | const io = new Server({
30 | connectionStateRecovery: {},
31 | });
32 |
33 | io.adapter(createAdapter(mongoCollection));
34 |
35 | return io;
36 | }
37 |
38 | function initClient(port) {
39 | const socket = io(`http://localhost:${port}`);
40 |
41 | socket.on("connect", () => {
42 | console.log(`[${port}] connected (recovered? ${socket.recovered})`);
43 | });
44 |
45 | socket.on("ping", () => {
46 | console.log(`[${port}] got ping`);
47 | });
48 |
49 | socket.on("disconnect", (reason) => {
50 | console.log(`[${port}] disconnected due to ${reason}`);
51 | });
52 |
53 | return socket;
54 | }
55 |
56 | const mongoCollection = await initMongoCollection();
57 |
58 | const io1 = initServer(mongoCollection);
59 | const io2 = initServer(mongoCollection);
60 | const io3 = initServer(mongoCollection);
61 |
62 | io1.listen(3000);
63 | io2.listen(3001);
64 | io3.listen(3002);
65 |
66 | initClient(3000);
67 | initClient(3001);
68 | initClient(3002);
69 |
70 | setInterval(() => {
71 | io1.emit("ping");
72 | }, 2000);
73 |
74 | // uncomment to test connection state recovery
75 | // setTimeout(() => {
76 | // io2.close(() => {
77 | // io2.listen(3001);
78 | // });
79 | // }, 3000);
80 |
--------------------------------------------------------------------------------
/examples/ttl-example/index.js:
--------------------------------------------------------------------------------
1 | import { MongoClient } from "mongodb";
2 | import { Server } from "socket.io";
3 | import { createAdapter } from "@socket.io/mongo-adapter";
4 | import { io } from "socket.io-client";
5 |
6 | async function initMongoCollection() {
7 | const mongoClient = new MongoClient(
8 | "mongodb://localhost:27017/?replicaSet=rs0&directConnection=true"
9 | );
10 |
11 | await mongoClient.connect();
12 |
13 | const mongoCollection = mongoClient
14 | .db("mydb")
15 | .collection("socket.io-adapter-events-ttl");
16 |
17 | await mongoCollection.createIndex(
18 | { createdAt: 1 },
19 | { expireAfterSeconds: 3600, background: true }
20 | );
21 |
22 | return mongoCollection;
23 | }
24 |
25 | function initServer(mongoCollection) {
26 | const io = new Server({
27 | connectionStateRecovery: {},
28 | });
29 |
30 | io.adapter(
31 | createAdapter(mongoCollection, {
32 | addCreatedAtField: true,
33 | })
34 | );
35 |
36 | return io;
37 | }
38 |
39 | function initClient(port) {
40 | const socket = io(`http://localhost:${port}`);
41 |
42 | socket.on("connect", () => {
43 | console.log(`[${port}] connected (recovered? ${socket.recovered})`);
44 | });
45 |
46 | socket.on("ping", () => {
47 | console.log(`[${port}] got ping`);
48 | });
49 |
50 | socket.on("disconnect", (reason) => {
51 | console.log(`[${port}] disconnected due to ${reason}`);
52 | });
53 |
54 | return socket;
55 | }
56 |
57 | const mongoCollection = await initMongoCollection();
58 |
59 | const io1 = initServer(mongoCollection);
60 | const io2 = initServer(mongoCollection);
61 | const io3 = initServer(mongoCollection);
62 |
63 | io1.listen(3000);
64 | io2.listen(3001);
65 | io3.listen(3002);
66 |
67 | initClient(3000);
68 | initClient(3001);
69 | initClient(3002);
70 |
71 | setInterval(() => {
72 | io1.emit("ping");
73 | }, 2000);
74 |
75 | // uncomment to test connection state recovery
76 | // setTimeout(() => {
77 | // io2.close(() => {
78 | // io2.listen(3001);
79 | // });
80 | // }, 3000);
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Socket.IO MongoDB adapter
2 |
3 | The `@socket.io/mongo-adapter` package allows broadcasting packets between multiple Socket.IO servers.
4 |
5 |
6 |
7 |
8 |
9 |
10 | Unlike the existing [`socket.io-adapter-mongo`](https://github.com/lklepner/socket.io-adapter-mongo) package which uses [tailable cursors](https://docs.mongodb.com/manual/core/tailable-cursors/), this package relies on [change streams](https://docs.mongodb.com/manual/changeStreams/) and thus requires a replica set or a sharded cluster.
11 |
12 | **Table of contents**
13 |
14 | - [Supported features](#supported-features)
15 | - [Installation](#installation)
16 | - [Usage](#usage)
17 | - [Usage with a capped collection](#usage-with-a-capped-collection)
18 | - [Usage with a TTL index](#usage-with-a-ttl-index)
19 | - [Known errors](#known-errors)
20 | - [License](#license)
21 |
22 | ## Supported features
23 |
24 | | Feature | `socket.io` version | Support |
25 | |---------------------------------|---------------------|------------------------------------------------|
26 | | Socket management | `4.0.0` | :white_check_mark: YES (since version `0.1.0`) |
27 | | Inter-server communication | `4.1.0` | :white_check_mark: YES (since version `0.1.0`) |
28 | | Broadcast with acknowledgements | `4.5.0` | :white_check_mark: YES (since version `0.2.0`) |
29 | | Connection state recovery | `4.6.0` | :white_check_mark: YES (since version `0.3.0`) |
30 |
31 | ## Installation
32 |
33 | ```
34 | npm install @socket.io/mongo-adapter mongodb
35 | ```
36 |
37 | ## Usage
38 |
39 | Broadcasting packets within a Socket.IO cluster is achieved by creating MongoDB documents and using a [change stream](https://docs.mongodb.com/manual/changeStreams/) on each Socket.IO server.
40 |
41 | There are two ways to clean up the documents in MongoDB:
42 |
43 | - a [capped collection](https://www.mongodb.com/docs/manual/core/capped-collections/)
44 | - a [TTL index](https://www.mongodb.com/docs/manual/core/index-ttl/)
45 |
46 | ### Usage with a capped collection
47 |
48 | ```js
49 | import { Server } from "socket.io";
50 | import { createAdapter } from "@socket.io/mongo-adapter";
51 | import { MongoClient } from "mongodb";
52 |
53 | const DB = "mydb";
54 | const COLLECTION = "socket.io-adapter-events";
55 |
56 | const io = new Server();
57 |
58 | const mongoClient = new MongoClient("mongodb://localhost:27017/?replicaSet=rs0");
59 |
60 | await mongoClient.connect();
61 |
62 | try {
63 | await mongoClient.db(DB).createCollection(COLLECTION, {
64 | capped: true,
65 | size: 1e6
66 | });
67 | } catch (e) {
68 | // collection already exists
69 | }
70 | const mongoCollection = mongoClient.db(DB).collection(COLLECTION);
71 |
72 | io.adapter(createAdapter(mongoCollection));
73 | io.listen(3000);
74 | ```
75 |
76 | ### Usage with a TTL index
77 |
78 | ```js
79 | import { Server } from "socket.io";
80 | import { createAdapter } from "@socket.io/mongo-adapter";
81 | import { MongoClient } from "mongodb";
82 |
83 | const DB = "mydb";
84 | const COLLECTION = "socket.io-adapter-events";
85 |
86 | const io = new Server();
87 |
88 | const mongoClient = new MongoClient("mongodb://localhost:27017/?replicaSet=rs0");
89 |
90 | await mongoClient.connect();
91 |
92 | const mongoCollection = mongoClient.db(DB).collection(COLLECTION);
93 |
94 | await mongoCollection.createIndex(
95 | { createdAt: 1 },
96 | { expireAfterSeconds: 3600, background: true }
97 | );
98 |
99 | io.adapter(createAdapter(mongoCollection, {
100 | addCreatedAtField: true
101 | }));
102 |
103 | io.listen(3000);
104 | ```
105 |
106 | ## Known errors
107 |
108 | - `MongoError: The $changeStream stage is only supported on replica sets`
109 |
110 | Change streams are only available for replica sets and sharded clusters.
111 |
112 | More information [here](https://docs.mongodb.com/manual/changeStreams/).
113 |
114 | Please note that, for development purposes, you can have a single MongoDB process acting as a replica set by running `rs.initiate()` on the node.
115 |
116 | - `TypeError: this.mongoCollection.insertOne is not a function`
117 |
118 | You probably passed a MongoDB client instead of a MongoDB collection to the `createAdapter` method.
119 |
120 | ## License
121 |
122 | [MIT](LICENSE)
123 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | | Version | Release date |
4 | |--------------------------|---------------|
5 | | [0.4.0](#040-2025-08-10) | August 2025 |
6 | | [0.3.2](#032-2024-01-23) | January 2024 |
7 | | [0.3.1](#031-2024-01-10) | January 2024 |
8 | | [0.3.0](#030-2023-02-23) | February 2023 |
9 | | [0.2.1](#021-2022-05-03) | May 2022 |
10 | | [0.2.0](#020-2022-04-27) | April 2022 |
11 | | [0.1.0](#010-2021-06-01) | June 2021 |
12 |
13 | # Release notes
14 |
15 | ## [0.4.0](https://github.com/socketio/socket.io-mongo-adapter/compare/0.3.2...0.4.0) (2025-08-10)
16 |
17 |
18 | ### Features
19 |
20 | * allow to specify additional change stream options ([#26](https://github.com/socketio/socket.io-mongo-adapter/issues/26)) ([eae849b](https://github.com/socketio/socket.io-mongo-adapter/commit/eae849b02202afa7ea7cfcf1e48ba2775aaaa982))
21 |
22 |
23 |
24 |
25 | ## [0.3.2](https://github.com/socketio/socket.io-mongo-adapter/compare/0.3.1...0.3.2) (2024-01-23)
26 |
27 |
28 | ### Bug Fixes
29 |
30 | * add support for AWS DocumentDB ([#21](https://github.com/socketio/socket.io-mongo-adapter/issues/21)) ([0c80f7f](https://github.com/socketio/socket.io-mongo-adapter/commit/0c80f7fd1da772cc54971fd93a1fa93f0c5e47d0))
31 | * ensure CSR works with a capped collection ([d3fa038](https://github.com/socketio/socket.io-mongo-adapter/commit/d3fa03874038ed9ec011d8795ac7dc6d840f4abe))
32 | * exclude offline nodes when calling serverCount() ([e2fb8c2](https://github.com/socketio/socket.io-mongo-adapter/commit/e2fb8c2f9d126e763e4f0c0ffba158f2d0c5c17a))
33 |
34 |
35 |
36 | ## [0.3.1](https://github.com/socketio/socket.io-mongo-adapter/compare/0.3.0...0.3.1) (2024-01-10)
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * add support for mongodb@6 ([1a04885](https://github.com/socketio/socket.io-mongo-adapter/commit/1a0488562f1e8b4171af20378aacfa43072980dd))
42 | * properly handle promise rejections ([075216f](https://github.com/socketio/socket.io-mongo-adapter/commit/075216f7decac3e8660c39dc1009a27d786ca1ad))
43 |
44 |
45 |
46 | ## [0.3.0](https://github.com/socketio/socket.io-mongo-adapter/compare/0.2.1...0.3.0) (2023-02-23)
47 |
48 |
49 | ### Features
50 |
51 | #### Connection state recovery
52 |
53 | This adapter is now compatible with the connection state recovery feature, which was added in `socket.io@4.6.0`.
54 |
55 | Reference: https://socket.io/docs/v4/connection-state-recovery
56 |
57 | Added in [02e4d57](https://github.com/socketio/socket.io-mongo-adapter/commit/02e4d57721937ce832fc9a83abddaecd4f8d38aa).
58 |
59 | #### Resume token
60 |
61 | Upon reconnection to the MongoDB server, the client will now try to resume the stream at the last offset it has processed.
62 |
63 | If the MongoDB client is disconnected for too long and its token is no longer valid, then the Socket.IO clients connected to this server may miss some packets (which was the previous behavior).
64 |
65 | Added in [e77063b](https://github.com/socketio/socket.io-mongo-adapter/commit/e77063b8fd88b68df58e7bfdc7f3ef4edb51dca0).
66 |
67 |
68 |
69 | ## [0.2.1](https://github.com/socketio/socket.io-mongo-adapter/compare/0.2.0...0.2.1) (2022-05-03)
70 |
71 |
72 | ### Bug Fixes
73 |
74 | * properly handle invalidate events ([938674d](https://github.com/socketio/socket.io-mongo-adapter/commit/938674d101fc01add3b6e01d59d20c2aa84b48eb))
75 |
76 |
77 |
78 | ## [0.2.0](https://github.com/socketio/socket.io-mongo-adapter/compare/0.1.0...0.2.0) (2022-04-27)
79 |
80 |
81 | ### Features
82 |
83 | * add an option to use a TTL index ([#4](https://github.com/socketio/socket.io-mongo-adapter/issues/4)) ([7fdbb25](https://github.com/socketio/socket.io-mongo-adapter/commit/7fdbb25831255e5f6a37a5df25b4fc41c770ab6a))
84 |
85 | The `addCreatedAtField` option allows to use a TTL index instead of a capped collection, which is slightly less efficient but more predictable.
86 |
87 | * broadcast and expect multiple acks ([e87a0ce](https://github.com/socketio/socket.io-mongo-adapter/commit/e87a0cec4c6920b5e4ef38c4de3e45c1eba5e4cf))
88 |
89 | This feature was added in `socket.io@4.5.0`:
90 |
91 | ```js
92 | io.timeout(1000).emit("some-event", (err, responses) => {
93 | // ...
94 | });
95 | ```
96 |
97 | Thanks to this change, it will now work with multiple Socket.IO servers.
98 |
99 | * use a single stream for all namespaces ([9b5f4c8](https://github.com/socketio/socket.io-mongo-adapter/commit/9b5f4c83038cc212b898b7fb7ff0ccec3124447c))
100 |
101 | The adapter will now create one single MongoDB stream for all namespaces, instead of one per namespace, which could lead to performance issues.
102 |
103 | ## 0.1.0 (2021-06-01)
104 |
105 | Initial commit
106 |
107 |
--------------------------------------------------------------------------------
/test/connection-state-recovery.ts:
--------------------------------------------------------------------------------
1 | import { createServer } from "http";
2 | import { Server } from "socket.io";
3 | import expect = require("expect.js");
4 | import { io as ioc } from "socket.io-client";
5 | import { MongoClient } from "mongodb";
6 | import { createAdapter } from "../lib";
7 | import { AddressInfo } from "net";
8 |
9 | const NODES_COUNT = 3;
10 |
11 | describe("connection state recovery", () => {
12 | describe("with a capped collection", () => {
13 | let servers: Server[], ports: number[], mongoClient: MongoClient;
14 |
15 | beforeEach(async () => {
16 | servers = [];
17 | ports = [];
18 |
19 | mongoClient = new MongoClient(
20 | "mongodb://localhost:27017/?replicaSet=rs0&directConnection=true"
21 | );
22 | await mongoClient.connect();
23 |
24 | try {
25 | await mongoClient.db("test").createCollection("events-capped", {
26 | capped: true,
27 | size: 1e6,
28 | });
29 | } catch (e) {
30 | // collection already exists
31 | }
32 |
33 | const collection = mongoClient.db("test").collection("events-capped");
34 |
35 | return new Promise((resolve) => {
36 | for (let i = 1; i <= NODES_COUNT; i++) {
37 | const httpServer = createServer();
38 | const io = new Server(httpServer, {
39 | pingInterval: 1500,
40 | pingTimeout: 1600,
41 | connectionStateRecovery: {
42 | maxDisconnectionDuration: 5000,
43 | },
44 | adapter: createAdapter(collection),
45 | });
46 | httpServer.listen(async () => {
47 | const port = (httpServer.address() as AddressInfo).port;
48 |
49 | servers.push(io);
50 | ports.push(port);
51 |
52 | if (servers.length === NODES_COUNT) {
53 | resolve();
54 | }
55 | });
56 | }
57 | });
58 | });
59 |
60 | afterEach(async () => {
61 | servers.forEach((server) => server.close());
62 | await mongoClient.close();
63 | });
64 |
65 | it("should restore the session", (done) => {
66 | const socket = ioc(`http://localhost:${ports[0]}`, {
67 | reconnectionDelay: 20,
68 | });
69 |
70 | let initialId: string;
71 |
72 | socket.once("connect", () => {
73 | expect(socket.recovered).to.eql(false);
74 | initialId = socket.id;
75 |
76 | servers[0].emit("init");
77 | });
78 |
79 | socket.on("init", () => {
80 | // under the hood, the client saves the offset of this packet, so now we force the reconnection
81 | socket.io.engine.close();
82 |
83 | socket.on("connect", () => {
84 | expect(socket.recovered).to.eql(true);
85 | expect(socket.id).to.eql(initialId);
86 |
87 | socket.disconnect();
88 | done();
89 | });
90 | });
91 | });
92 |
93 | it("should restore any missed packets", (done) => {
94 | const socket = ioc(`http://localhost:${ports[0]}`, {
95 | reconnectionDelay: 20,
96 | });
97 |
98 | servers[0].once("connection", (socket) => {
99 | socket.join("room1");
100 |
101 | socket.on("disconnect", () => {
102 | // let's send some packets while the client is disconnected
103 | socket.emit("myEvent", 1);
104 | servers[0].emit("myEvent", 2);
105 | servers[0].to("room1").emit("myEvent", 3);
106 |
107 | // those packets should not be received by the client upon reconnection (room mismatch)
108 | servers[0].to("room2").emit("myEvent", 4);
109 | servers[0].except("room1").emit("myEvent", 5);
110 | servers[0].of("/foo").emit("myEvent", 6);
111 | });
112 | });
113 |
114 | socket.once("connect", () => {
115 | servers[1].emit("init");
116 | });
117 |
118 | socket.on("init", () => {
119 | // under the hood, the client saves the offset of this packet, so now we force the reconnection
120 | socket.io.engine.close();
121 |
122 | socket.on("connect", () => {
123 | expect(socket.recovered).to.eql(true);
124 |
125 | setTimeout(() => {
126 | expect(events).to.eql([1, 2, 3]);
127 |
128 | socket.disconnect();
129 | done();
130 | }, 50);
131 | });
132 | });
133 |
134 | const events: number[] = [];
135 |
136 | socket.on("myEvent", (val) => {
137 | events.push(val);
138 | });
139 | });
140 |
141 | it("should restore the session only once", (done) => {
142 | const socket = ioc(`http://localhost:${ports[0]}`, {
143 | reconnectionDelay: 20,
144 | });
145 |
146 | let initialId: string;
147 |
148 | socket.once("connect", () => {
149 | expect(socket.recovered).to.eql(false);
150 | initialId = socket.id;
151 |
152 | servers[0].emit("init");
153 | });
154 |
155 | socket.once("init", () => {
156 | // under the hood, the client saves the offset of this packet, so now we force the reconnection
157 | socket.io.engine.close();
158 |
159 | socket.once("connect", () => {
160 | expect(socket.recovered).to.eql(true);
161 | expect(socket.id).to.eql(initialId);
162 |
163 | // unlike above, manual disconnection is not recoverable
164 | socket.disconnect().connect();
165 | socket.once("connect", () => {
166 | expect(socket.recovered).to.eql(false);
167 |
168 | socket.disconnect();
169 | done();
170 | });
171 | });
172 | });
173 | });
174 |
175 | it("should fail to restore an unknown session (invalid session ID)", (done) => {
176 | const socket = ioc(`http://localhost:${ports[0]}`, {
177 | reconnectionDelay: 20,
178 | });
179 |
180 | socket.once("connect", () => {
181 | // @ts-ignore
182 | socket._pid = "abc";
183 | // @ts-ignore
184 | socket._lastOffset = "507f191e810c19729de860ea";
185 | // force reconnection
186 | socket.io.engine.close();
187 |
188 | socket.on("connect", () => {
189 | expect(socket.recovered).to.eql(false);
190 |
191 | socket.disconnect();
192 | done();
193 | });
194 | });
195 | });
196 |
197 | it("should fail to restore an unknown session (invalid offset)", (done) => {
198 | const socket = ioc(`http://localhost:${ports[0]}`, {
199 | reconnectionDelay: 20,
200 | upgrade: false,
201 | });
202 |
203 | socket.once("connect", () => {
204 | // @ts-ignore
205 | socket._lastOffset = "abc";
206 | socket.io.engine.close();
207 |
208 | socket.on("connect", () => {
209 | expect(socket.recovered).to.eql(false);
210 |
211 | socket.disconnect();
212 | done();
213 | });
214 | });
215 | });
216 | });
217 |
218 | describe("with a TTL index", () => {
219 | let servers: Server[], ports: number[], mongoClient: MongoClient;
220 |
221 | beforeEach(async () => {
222 | servers = [];
223 | ports = [];
224 |
225 | mongoClient = new MongoClient(
226 | "mongodb://localhost:27017/?replicaSet=rs0&directConnection=true"
227 | );
228 | await mongoClient.connect();
229 |
230 | const collection = mongoClient.db("test").collection("events-ttl");
231 |
232 | await collection.createIndex(
233 | { createdAt: 1 },
234 | { expireAfterSeconds: 3600, background: true }
235 | );
236 |
237 | return new Promise((resolve) => {
238 | for (let i = 1; i <= NODES_COUNT; i++) {
239 | const httpServer = createServer();
240 | const io = new Server(httpServer, {
241 | pingInterval: 1500,
242 | pingTimeout: 1600,
243 | connectionStateRecovery: {
244 | maxDisconnectionDuration: 5000,
245 | },
246 | adapter: createAdapter(collection, {
247 | addCreatedAtField: true,
248 | }),
249 | });
250 | httpServer.listen(async () => {
251 | const port = (httpServer.address() as AddressInfo).port;
252 |
253 | servers.push(io);
254 | ports.push(port);
255 |
256 | if (servers.length === NODES_COUNT) {
257 | resolve();
258 | }
259 | });
260 | }
261 | });
262 | });
263 |
264 | afterEach(async () => {
265 | servers.forEach((server) => server.close());
266 | await mongoClient.close();
267 | });
268 |
269 | it("should restore the session", (done) => {
270 | const socket = ioc(`http://localhost:${ports[0]}`, {
271 | reconnectionDelay: 20,
272 | });
273 |
274 | let initialId: string;
275 |
276 | socket.once("connect", () => {
277 | expect(socket.recovered).to.eql(false);
278 | initialId = socket.id;
279 |
280 | servers[0].emit("init");
281 | });
282 |
283 | socket.on("init", () => {
284 | // under the hood, the client saves the offset of this packet, so now we force the reconnection
285 | socket.io.engine.close();
286 |
287 | socket.on("connect", () => {
288 | expect(socket.recovered).to.eql(true);
289 | expect(socket.id).to.eql(initialId);
290 |
291 | socket.disconnect();
292 | done();
293 | });
294 | });
295 | });
296 |
297 | it("should restore any missed packets", (done) => {
298 | const socket = ioc(`http://localhost:${ports[0]}`, {
299 | reconnectionDelay: 20,
300 | });
301 |
302 | servers[0].once("connection", (socket) => {
303 | socket.join("room1");
304 |
305 | socket.on("disconnect", () => {
306 | // let's send some packets while the client is disconnected
307 | socket.emit("myEvent", 1);
308 | servers[0].emit("myEvent", 2);
309 | servers[0].to("room1").emit("myEvent", 3);
310 |
311 | // those packets should not be received by the client upon reconnection (room mismatch)
312 | servers[0].to("room2").emit("myEvent", 4);
313 | servers[0].except("room1").emit("myEvent", 5);
314 | servers[0].of("/foo").emit("myEvent", 6);
315 | });
316 | });
317 |
318 | socket.once("connect", () => {
319 | servers[1].emit("init");
320 | });
321 |
322 | socket.on("init", () => {
323 | // under the hood, the client saves the offset of this packet, so now we force the reconnection
324 | socket.io.engine.close();
325 |
326 | socket.on("connect", () => {
327 | expect(socket.recovered).to.eql(true);
328 |
329 | setTimeout(() => {
330 | expect(events).to.eql([1, 2, 3]);
331 |
332 | socket.disconnect();
333 | done();
334 | }, 50);
335 | });
336 | });
337 |
338 | const events: number[] = [];
339 |
340 | socket.on("myEvent", (val) => {
341 | events.push(val);
342 | });
343 | });
344 |
345 | it("should restore the session only once", (done) => {
346 | const socket = ioc(`http://localhost:${ports[0]}`, {
347 | reconnectionDelay: 20,
348 | });
349 |
350 | let initialId: string;
351 |
352 | socket.once("connect", () => {
353 | expect(socket.recovered).to.eql(false);
354 | initialId = socket.id;
355 |
356 | servers[0].emit("init");
357 | });
358 |
359 | socket.once("init", () => {
360 | // under the hood, the client saves the offset of this packet, so now we force the reconnection
361 | socket.io.engine.close();
362 |
363 | socket.once("connect", () => {
364 | expect(socket.recovered).to.eql(true);
365 | expect(socket.id).to.eql(initialId);
366 |
367 | // unlike above, manual disconnection is not recoverable
368 | socket.disconnect().connect();
369 | socket.once("connect", () => {
370 | expect(socket.recovered).to.eql(false);
371 |
372 | socket.disconnect();
373 | done();
374 | });
375 | });
376 | });
377 | });
378 |
379 | it("should fail to restore an unknown session (invalid session ID)", (done) => {
380 | const socket = ioc(`http://localhost:${ports[0]}`, {
381 | reconnectionDelay: 20,
382 | });
383 |
384 | socket.once("connect", () => {
385 | // @ts-ignore
386 | socket._pid = "abc";
387 | // @ts-ignore
388 | socket._lastOffset = "507f191e810c19729de860ea";
389 | // force reconnection
390 | socket.io.engine.close();
391 |
392 | socket.on("connect", () => {
393 | expect(socket.recovered).to.eql(false);
394 |
395 | socket.disconnect();
396 | done();
397 | });
398 | });
399 | });
400 |
401 | it("should fail to restore an unknown session (invalid offset)", (done) => {
402 | const socket = ioc(`http://localhost:${ports[0]}`, {
403 | reconnectionDelay: 20,
404 | upgrade: false,
405 | });
406 |
407 | socket.once("connect", () => {
408 | // @ts-ignore
409 | socket._lastOffset = "abc";
410 | socket.io.engine.close();
411 |
412 | socket.on("connect", () => {
413 | expect(socket.recovered).to.eql(false);
414 |
415 | socket.disconnect();
416 | done();
417 | });
418 | });
419 | });
420 | });
421 | });
422 |
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | import { createServer } from "http";
2 | import { Server, Socket as ServerSocket } from "socket.io";
3 | import { io as ioc, Socket as ClientSocket } from "socket.io-client";
4 | import expect = require("expect.js");
5 | import { createAdapter, MongoAdapter } from "../lib";
6 | import type { AddressInfo } from "net";
7 | import { MongoClient } from "mongodb";
8 | import { times, sleep } from "./util";
9 |
10 | const NODES_COUNT = 3;
11 |
12 | describe("@socket.io/mongodb-adapter", () => {
13 | let servers: Server[],
14 | serverSockets: ServerSocket[],
15 | clientSockets: ClientSocket[],
16 | mongoClient: MongoClient;
17 |
18 | beforeEach(async () => {
19 | servers = [];
20 | serverSockets = [];
21 | clientSockets = [];
22 |
23 | mongoClient = new MongoClient(
24 | "mongodb://localhost:27017/?replicaSet=rs0&directConnection=true"
25 | );
26 | await mongoClient.connect();
27 |
28 | const collection = mongoClient.db("test").collection("events");
29 |
30 | return new Promise((resolve) => {
31 | for (let i = 1; i <= NODES_COUNT; i++) {
32 | const httpServer = createServer();
33 | const io = new Server(httpServer);
34 | io.adapter(createAdapter(collection));
35 | httpServer.listen(() => {
36 | const port = (httpServer.address() as AddressInfo).port;
37 | const clientSocket = ioc(`http://localhost:${port}`);
38 |
39 | io.on("connection", async (socket) => {
40 | clientSockets.push(clientSocket);
41 | serverSockets.push(socket);
42 | servers.push(io);
43 | if (servers.length === NODES_COUNT) {
44 | // ensure all nodes know each other
45 | servers[0].emit("ping");
46 | servers[1].emit("ping");
47 | servers[2].emit("ping");
48 |
49 | await sleep(200);
50 |
51 | resolve();
52 | }
53 | });
54 | });
55 | }
56 | });
57 | });
58 |
59 | afterEach(async () => {
60 | servers.forEach((server) => server.close());
61 | clientSockets.forEach((socket) => socket.disconnect());
62 | await mongoClient.close();
63 | });
64 |
65 | describe("broadcast", function () {
66 | it("broadcasts to all clients", (done) => {
67 | const partialDone = times(3, done);
68 |
69 | clientSockets.forEach((clientSocket) => {
70 | clientSocket.on("test", (arg1, arg2, arg3) => {
71 | expect(arg1).to.eql(1);
72 | expect(arg2).to.eql("2");
73 | expect(Buffer.isBuffer(arg3)).to.be(true);
74 | partialDone();
75 | });
76 | });
77 |
78 | servers[0].emit("test", 1, "2", Buffer.from([3, 4]));
79 | });
80 |
81 | it("broadcasts to all clients in a namespace", (done) => {
82 | const partialDone = times(3, done);
83 |
84 | servers.forEach((server) => server.of("/custom"));
85 |
86 | const onConnect = times(3, () => {
87 | servers[0].of("/custom").emit("test");
88 | });
89 |
90 | clientSockets.forEach((clientSocket) => {
91 | const socket = clientSocket.io.socket("/custom");
92 | socket.on("connect", onConnect);
93 | socket.on("test", () => {
94 | socket.disconnect();
95 | partialDone();
96 | });
97 | });
98 | });
99 |
100 | it("broadcasts to all clients in a room", (done) => {
101 | serverSockets[1].join("room1");
102 |
103 | clientSockets[0].on("test", () => {
104 | done(new Error("should not happen"));
105 | });
106 |
107 | clientSockets[1].on("test", () => {
108 | done();
109 | });
110 |
111 | clientSockets[2].on("test", () => {
112 | done(new Error("should not happen"));
113 | });
114 |
115 | servers[0].to("room1").emit("test");
116 | });
117 |
118 | it("broadcasts to all clients except in room", (done) => {
119 | const partialDone = times(2, done);
120 | serverSockets[1].join("room1");
121 |
122 | clientSockets[0].on("test", () => {
123 | partialDone();
124 | });
125 |
126 | clientSockets[1].on("test", () => {
127 | done(new Error("should not happen"));
128 | });
129 |
130 | clientSockets[2].on("test", () => {
131 | partialDone();
132 | });
133 |
134 | servers[0].of("/").except("room1").emit("test");
135 | });
136 |
137 | it("broadcasts to local clients only", (done) => {
138 | clientSockets[0].on("test", () => {
139 | done();
140 | });
141 |
142 | clientSockets[1].on("test", () => {
143 | done(new Error("should not happen"));
144 | });
145 |
146 | clientSockets[2].on("test", () => {
147 | done(new Error("should not happen"));
148 | });
149 |
150 | servers[0].local.emit("test");
151 | });
152 |
153 | it("broadcasts with multiple acknowledgements", (done) => {
154 | clientSockets[0].on("test", (cb) => {
155 | cb(1);
156 | });
157 |
158 | clientSockets[1].on("test", (cb) => {
159 | cb(2);
160 | });
161 |
162 | clientSockets[2].on("test", (cb) => {
163 | cb(3);
164 | });
165 |
166 | servers[0].timeout(500).emit("test", (err: Error, responses: any[]) => {
167 | expect(err).to.be(null);
168 | expect(responses).to.contain(1);
169 | expect(responses).to.contain(2);
170 | expect(responses).to.contain(3);
171 |
172 | setTimeout(() => {
173 | // @ts-ignore
174 | expect(servers[0].of("/").adapter.ackRequests.size).to.eql(0);
175 |
176 | done();
177 | }, 500);
178 | });
179 | });
180 |
181 | it("broadcasts with multiple acknowledgements (binary content)", (done) => {
182 | clientSockets[0].on("test", (cb) => {
183 | cb(Buffer.from([1]));
184 | });
185 |
186 | clientSockets[1].on("test", (cb) => {
187 | cb(Buffer.from([2]));
188 | });
189 |
190 | clientSockets[2].on("test", (cb) => {
191 | cb(Buffer.from([3]));
192 | });
193 |
194 | servers[0].timeout(500).emit("test", (err: Error, responses: any[]) => {
195 | expect(err).to.be(null);
196 | responses.forEach((response) => {
197 | expect(Buffer.isBuffer(response)).to.be(true);
198 | });
199 |
200 | done();
201 | });
202 | });
203 |
204 | it("broadcasts with multiple acknowledgements (no client)", (done) => {
205 | servers[0]
206 | .to("abc")
207 | .timeout(500)
208 | .emit("test", (err: Error, responses: any[]) => {
209 | expect(err).to.be(null);
210 | expect(responses).to.eql([]);
211 |
212 | done();
213 | });
214 | });
215 |
216 | it("broadcasts with multiple acknowledgements (timeout)", (done) => {
217 | clientSockets[0].on("test", (cb) => {
218 | cb(1);
219 | });
220 |
221 | clientSockets[1].on("test", (cb) => {
222 | cb(2);
223 | });
224 |
225 | clientSockets[2].on("test", (cb) => {
226 | // do nothing
227 | });
228 |
229 | servers[0].timeout(500).emit("test", (err: Error, responses: any[]) => {
230 | expect(err).to.be.an(Error);
231 | expect(responses).to.contain(1);
232 | expect(responses).to.contain(2);
233 |
234 | done();
235 | });
236 | });
237 |
238 | it("broadcasts with a single acknowledgement (local)", async () => {
239 | clientSockets[0].on("test", () => expect().fail());
240 | clientSockets[1].on("test", (cb) => cb(2));
241 | clientSockets[2].on("test", () => expect().fail());
242 |
243 | const response = await serverSockets[1].emitWithAck("test");
244 | expect(response).to.eql(2);
245 | });
246 |
247 | it("broadcasts with a single acknowledgement (remote)", async () => {
248 | clientSockets[0].on("test", () => expect().fail());
249 | clientSockets[1].on("test", (cb) => cb(2));
250 | clientSockets[2].on("test", () => expect().fail());
251 |
252 | const sockets = await servers[0].in(serverSockets[1].id).fetchSockets();
253 | expect(sockets.length).to.eql(1);
254 |
255 | const response = await sockets[0].timeout(500).emitWithAck("test");
256 | expect(response).to.eql(2);
257 | });
258 | });
259 |
260 | describe("socketsJoin", () => {
261 | it("makes all socket instances join the specified room", async () => {
262 | servers[0].socketsJoin("room1");
263 |
264 | await sleep(200);
265 |
266 | expect(serverSockets[0].rooms.has("room1")).to.be(true);
267 | expect(serverSockets[1].rooms.has("room1")).to.be(true);
268 | expect(serverSockets[2].rooms.has("room1")).to.be(true);
269 | });
270 |
271 | it("makes the matching socket instances join the specified room", async () => {
272 | serverSockets[0].join("room1");
273 | serverSockets[2].join("room1");
274 |
275 | servers[0].in("room1").socketsJoin("room2");
276 |
277 | await sleep(200);
278 |
279 | expect(serverSockets[0].rooms.has("room2")).to.be(true);
280 | expect(serverSockets[1].rooms.has("room2")).to.be(false);
281 | expect(serverSockets[2].rooms.has("room2")).to.be(true);
282 | });
283 |
284 | it("makes the given socket instance join the specified room", async () => {
285 | servers[0].in(serverSockets[1].id).socketsJoin("room3");
286 |
287 | await sleep(200);
288 |
289 | expect(serverSockets[0].rooms.has("room3")).to.be(false);
290 | expect(serverSockets[1].rooms.has("room3")).to.be(true);
291 | expect(serverSockets[2].rooms.has("room3")).to.be(false);
292 | });
293 | });
294 |
295 | describe("socketsLeave", () => {
296 | it("makes all socket instances leave the specified room", async () => {
297 | serverSockets[0].join("room1");
298 | serverSockets[2].join("room1");
299 |
300 | servers[0].socketsLeave("room1");
301 |
302 | await sleep(200);
303 |
304 | expect(serverSockets[0].rooms.has("room1")).to.be(false);
305 | expect(serverSockets[1].rooms.has("room1")).to.be(false);
306 | expect(serverSockets[2].rooms.has("room1")).to.be(false);
307 | });
308 |
309 | it("makes the matching socket instances leave the specified room", async () => {
310 | serverSockets[0].join(["room1", "room2"]);
311 | serverSockets[1].join(["room1", "room2"]);
312 | serverSockets[2].join(["room2"]);
313 |
314 | servers[0].in("room1").socketsLeave("room2");
315 |
316 | await sleep(200);
317 |
318 | expect(serverSockets[0].rooms.has("room2")).to.be(false);
319 | expect(serverSockets[1].rooms.has("room2")).to.be(false);
320 | expect(serverSockets[2].rooms.has("room2")).to.be(true);
321 | });
322 |
323 | it("makes the given socket instance leave the specified room", async () => {
324 | serverSockets[0].join("room3");
325 | serverSockets[1].join("room3");
326 | serverSockets[2].join("room3");
327 |
328 | servers[0].in(serverSockets[1].id).socketsLeave("room3");
329 |
330 | await sleep(200);
331 |
332 | expect(serverSockets[0].rooms.has("room3")).to.be(true);
333 | expect(serverSockets[1].rooms.has("room3")).to.be(false);
334 | expect(serverSockets[2].rooms.has("room3")).to.be(true);
335 | });
336 | });
337 |
338 | describe("disconnectSockets", () => {
339 | it("makes all socket instances disconnect", (done) => {
340 | const partialDone = times(3, done);
341 |
342 | clientSockets.forEach((clientSocket) => {
343 | clientSocket.on("disconnect", (reason) => {
344 | expect(reason).to.eql("io server disconnect");
345 | partialDone();
346 | });
347 | });
348 |
349 | servers[0].disconnectSockets();
350 | });
351 | });
352 |
353 | describe("fetchSockets", () => {
354 | it("returns all socket instances", async () => {
355 | const sockets = await servers[0].fetchSockets();
356 |
357 | expect(sockets).to.be.an(Array);
358 | expect(sockets).to.have.length(3);
359 | // @ts-ignore
360 | expect(servers[0].of("/").adapter.requests.size).to.eql(0); // clean up
361 | });
362 |
363 | it("returns a single socket instance", async () => {
364 | serverSockets[1].data = "test" as any;
365 |
366 | const [remoteSocket] = await servers[0]
367 | .in(serverSockets[1].id)
368 | .fetchSockets();
369 |
370 | expect(remoteSocket.handshake).to.eql(serverSockets[1].handshake);
371 | expect(remoteSocket.data).to.eql("test");
372 | expect(remoteSocket.rooms.size).to.eql(1);
373 | });
374 |
375 | it("returns only local socket instances", async () => {
376 | const sockets = await servers[0].local.fetchSockets();
377 |
378 | expect(sockets).to.have.length(1);
379 | });
380 | });
381 |
382 | describe("serverSideEmit", () => {
383 | it("sends an event to other server instances", (done) => {
384 | const partialDone = times(2, done);
385 |
386 | servers[0].serverSideEmit("hello", "world", 1, "2");
387 |
388 | servers[0].on("hello", () => {
389 | done(new Error("should not happen"));
390 | });
391 |
392 | servers[1].on("hello", (arg1, arg2, arg3) => {
393 | expect(arg1).to.eql("world");
394 | expect(arg2).to.eql(1);
395 | expect(arg3).to.eql("2");
396 | partialDone();
397 | });
398 |
399 | servers[2].of("/").on("hello", () => {
400 | partialDone();
401 | });
402 | });
403 |
404 | it("sends an event and receives a response from the other server instances", (done) => {
405 | servers[0].serverSideEmit("hello", (err: Error, response: any) => {
406 | expect(err).to.be(null);
407 | expect(response).to.be.an(Array);
408 | expect(response).to.contain(2);
409 | expect(response).to.contain("3");
410 | done();
411 | });
412 |
413 | servers[0].on("hello", () => {
414 | done(new Error("should not happen"));
415 | });
416 |
417 | servers[1].on("hello", (cb) => {
418 | cb(2);
419 | });
420 |
421 | servers[2].on("hello", (cb) => {
422 | cb("3");
423 | });
424 | });
425 |
426 | it("sends an event but timeout if one server does not respond", (done) => {
427 | (servers[0].of("/").adapter as MongoAdapter).requestsTimeout = 200;
428 |
429 | servers[0].serverSideEmit("hello", (err: Error, response: any) => {
430 | expect(err.message).to.be(
431 | "timeout reached: only 1 responses received out of 2"
432 | );
433 | expect(response).to.be.an(Array);
434 | expect(response).to.contain(2);
435 | done();
436 | });
437 |
438 | servers[0].on("hello", () => {
439 | done(new Error("should not happen"));
440 | });
441 |
442 | servers[1].on("hello", (cb) => {
443 | cb(2);
444 | });
445 |
446 | servers[2].on("hello", () => {
447 | // do nothing
448 | });
449 | });
450 | });
451 |
452 | it("should not throw when receiving a drop event", async () => {
453 | await mongoClient.db("test").dropCollection("events");
454 |
455 | await sleep(100);
456 | });
457 |
458 | it("should resume the change stream upon reconnection", async () => {
459 | await mongoClient.close(true);
460 |
461 | return new Promise(async (resolve) => {
462 | const partialDone = times(3, resolve);
463 | clientSockets[0].on("test1", partialDone);
464 | clientSockets[1].on("test2", partialDone);
465 | clientSockets[2].on("test3", partialDone);
466 |
467 | await mongoClient.connect();
468 | servers[0].to(clientSockets[1].id).emit("test2");
469 |
470 | await sleep(500);
471 |
472 | servers[1].to(clientSockets[2].id).emit("test3");
473 | servers[2].to(clientSockets[0].id).emit("test1");
474 | });
475 | });
476 |
477 | import("./connection-state-recovery");
478 | });
479 |
--------------------------------------------------------------------------------
/lib/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Adapter,
3 | BroadcastOptions,
4 | PrivateSessionId,
5 | Room,
6 | Session,
7 | } from "socket.io-adapter";
8 | import { randomBytes } from "crypto";
9 | import { ObjectId, MongoServerError, WithId, Document } from "mongodb";
10 | import type { Collection, ChangeStream, ChangeStreamOptions } from "mongodb";
11 |
12 | const randomId = () => randomBytes(8).toString("hex");
13 | const debug = require("debug")("socket.io-mongo-adapter");
14 |
15 | /**
16 | * Event types, for messages between nodes
17 | */
18 |
19 | enum EventType {
20 | INITIAL_HEARTBEAT = 1,
21 | HEARTBEAT,
22 | BROADCAST,
23 | SOCKETS_JOIN,
24 | SOCKETS_LEAVE,
25 | DISCONNECT_SOCKETS,
26 | FETCH_SOCKETS,
27 | FETCH_SOCKETS_RESPONSE,
28 | SERVER_SIDE_EMIT,
29 | SERVER_SIDE_EMIT_RESPONSE,
30 | BROADCAST_CLIENT_COUNT,
31 | BROADCAST_ACK,
32 | SESSION,
33 | }
34 |
35 | /**
36 | * The format of the documents in the MongoDB collection
37 | */
38 | interface AdapterEvent {
39 | /**
40 | * The type of the event
41 | */
42 | type: EventType;
43 | /**
44 | * The UID of the server, to filter event created by itself (see watch() call)
45 | */
46 | uid?: string;
47 | /**
48 | * The namespace
49 | */
50 | nsp?: string;
51 | /**
52 | * The date of creation of the event, to be able to manually clean up the collection.
53 | *
54 | * @see MongoAdapterOptions.addCreatedAtField
55 | */
56 | createdAt?: Date;
57 | /**
58 | * Some additional data, depending on the event type
59 | */
60 | data?: any;
61 | }
62 |
63 | interface Request {
64 | type: EventType;
65 | resolve: Function;
66 | timeout: NodeJS.Timeout;
67 | expected: number;
68 | current: number;
69 | responses: any[];
70 | }
71 |
72 | interface AckRequest {
73 | type: EventType.BROADCAST;
74 | clientCountCallback: (clientCount: number) => void;
75 | ack: (...args: any[]) => void;
76 | }
77 |
78 | /**
79 | * UID of an emitter using the `@socket.io/mongo-emitter` package
80 | */
81 | const EMITTER_UID = "emitter";
82 |
83 | export interface MongoAdapterOptions {
84 | /**
85 | * the name of this node
86 | * @default a random id
87 | */
88 | uid: string;
89 | /**
90 | * after this timeout the adapter will stop waiting from responses to request
91 | * @default 5000
92 | */
93 | requestsTimeout: number;
94 | /**
95 | * Number of ms between two heartbeats
96 | * @default 5000
97 | */
98 | heartbeatInterval: number;
99 | /**
100 | * Number of ms without heartbeat before we consider a node down
101 | * @default 10000
102 | */
103 | heartbeatTimeout: number;
104 |
105 | /**
106 | * Add a createdAt field to each MongoDB document
107 | * @default false
108 | */
109 | addCreatedAtField: boolean;
110 |
111 | /**
112 | * Options to pass to the MongoDB change stream.
113 | */
114 | changeStreamOptions?: Partial;
115 | }
116 |
117 | /**
118 | * It seems the `promoteBuffers` option is not always honored, so we manually replace Binary objects by the underlying
119 | * Buffer objects.
120 | *
121 | * Update: it seems to be fixed with `mongodb@4`, but we'll keep it for backward compatibility
122 | *
123 | * Reference:
124 | * - http://mongodb.github.io/node-mongodb-native/3.6/api/Binary.html
125 | * - https://jira.mongodb.org/browse/NODE-1421
126 | */
127 | const replaceBinaryObjectsByBuffers = (obj: any) => {
128 | if (!obj || typeof obj !== "object") {
129 | return obj;
130 | }
131 | if (obj._bsontype === "Binary" && Buffer.isBuffer(obj.buffer)) {
132 | return obj.buffer;
133 | }
134 | if (Array.isArray(obj)) {
135 | for (let i = 0; i < obj.length; i++) {
136 | obj[i] = replaceBinaryObjectsByBuffers(obj[i]);
137 | }
138 | } else {
139 | for (const key in obj) {
140 | if (Object.prototype.hasOwnProperty.call(obj, key)) {
141 | obj[key] = replaceBinaryObjectsByBuffers(obj[key]);
142 | }
143 | }
144 | }
145 | return obj;
146 | };
147 |
148 | function onPublishError(err: Error) {
149 | debug("something went wrong when inserting the MongoDB document: %s", err);
150 | }
151 |
152 | /**
153 | * Returns a function that will create a MongoAdapter instance.
154 | *
155 | * @param mongoCollection - a MongoDB collection instance
156 | * @param opts - additional options
157 | *
158 | * @public
159 | */
160 | export function createAdapter(
161 | mongoCollection: Collection,
162 | opts: Partial = {}
163 | ) {
164 | opts.uid = opts.uid || randomId();
165 |
166 | let isClosed = false;
167 | let adapters = new Map();
168 | let changeStream: ChangeStream;
169 | let changeStreamOpts: ChangeStreamOptions = opts.changeStreamOptions ?? {};
170 |
171 | const initChangeStream = () => {
172 | if (isClosed || (changeStream && !changeStream.closed)) {
173 | return;
174 | }
175 | debug("opening change stream");
176 | changeStream = mongoCollection.watch(
177 | [
178 | {
179 | $match: {
180 | "fullDocument.uid": {
181 | $ne: opts.uid, // ignore events from self
182 | },
183 | },
184 | },
185 | ],
186 | changeStreamOpts
187 | );
188 |
189 | changeStream.on("change", (event: any) => {
190 | if (event.operationType === "insert") {
191 | changeStreamOpts.resumeAfter = changeStream.resumeToken;
192 | adapters.get(event.fullDocument?.nsp)?.onEvent(event);
193 | }
194 | });
195 |
196 | changeStream.on("error", (err: Error) => {
197 | debug("change stream encountered an error: %s", err.message);
198 | if (
199 | err instanceof MongoServerError &&
200 | !err.hasErrorLabel("ResumableChangeStreamError")
201 | ) {
202 | // the resume token was not found in the oplog
203 | changeStreamOpts = {};
204 | }
205 | });
206 |
207 | changeStream.on("close", () => {
208 | debug("change stream was closed, scheduling reconnection...");
209 | setTimeout(() => {
210 | initChangeStream();
211 | }, 1000);
212 | });
213 | };
214 |
215 | return function (nsp: any) {
216 | if (!changeStream) {
217 | isClosed = false;
218 | initChangeStream();
219 | }
220 |
221 | let adapter = new MongoAdapter(nsp, mongoCollection, opts);
222 |
223 | adapters.set(nsp.name, adapter);
224 |
225 | const defaultClose = adapter.close;
226 |
227 | adapter.close = async () => {
228 | adapters.delete(nsp.name);
229 |
230 | if (adapters.size === 0) {
231 | changeStream.removeAllListeners("close");
232 | await changeStream.close();
233 | // @ts-ignore
234 | changeStream = null;
235 | isClosed = true;
236 | }
237 |
238 | defaultClose.call(adapter);
239 | };
240 |
241 | return adapter;
242 | };
243 | }
244 |
245 | export class MongoAdapter extends Adapter {
246 | public readonly uid: string;
247 | public requestsTimeout: number;
248 | public heartbeatInterval: number;
249 | public heartbeatTimeout: number;
250 | public addCreatedAtField: boolean;
251 |
252 | private readonly mongoCollection: Collection;
253 | private nodesMap: Map = new Map(); // uid => timestamp of last message
254 | private heartbeatTimer: NodeJS.Timeout | undefined;
255 | private requests: Map = new Map();
256 | private ackRequests: Map = new Map();
257 | private isClosed = false;
258 |
259 | /**
260 | * Adapter constructor.
261 | *
262 | * @param nsp - the namespace
263 | * @param mongoCollection - a MongoDB collection instance
264 | * @param opts - additional options
265 | *
266 | * @public
267 | */
268 | constructor(
269 | nsp: any,
270 | mongoCollection: Collection,
271 | opts: Partial = {}
272 | ) {
273 | super(nsp);
274 | this.mongoCollection = mongoCollection;
275 | this.uid = opts.uid!;
276 | this.requestsTimeout = opts.requestsTimeout || 5000;
277 | this.heartbeatInterval = opts.heartbeatInterval || 5000;
278 | this.heartbeatTimeout = opts.heartbeatTimeout || 10000;
279 | this.addCreatedAtField = !!opts.addCreatedAtField;
280 |
281 | this.publish({
282 | type: EventType.INITIAL_HEARTBEAT,
283 | }).catch(onPublishError);
284 | }
285 |
286 | close(): Promise | void {
287 | this.isClosed = true;
288 | if (this.heartbeatTimer) {
289 | clearTimeout(this.heartbeatTimer);
290 | }
291 | return;
292 | }
293 |
294 | public async onEvent(event: any) {
295 | const document = event.fullDocument;
296 | debug(
297 | "new event of type %d for %s from %s",
298 | document.type,
299 | document.nsp,
300 | document.uid
301 | );
302 |
303 | if (document.uid && document.uid !== EMITTER_UID) {
304 | this.nodesMap.set(document.uid, Date.now());
305 | }
306 |
307 | switch (document.type) {
308 | case EventType.INITIAL_HEARTBEAT: {
309 | this.publish({
310 | type: EventType.HEARTBEAT,
311 | }).catch(onPublishError);
312 | break;
313 | }
314 | case EventType.BROADCAST: {
315 | debug("broadcast with opts %j", document.data.opts);
316 |
317 | const withAck = document.data.requestId !== undefined;
318 | if (withAck) {
319 | super.broadcastWithAck(
320 | replaceBinaryObjectsByBuffers(document.data.packet),
321 | MongoAdapter.deserializeOptions(document.data.opts),
322 | (clientCount) => {
323 | debug("waiting for %d client acknowledgements", clientCount);
324 | this.publish({
325 | type: EventType.BROADCAST_CLIENT_COUNT,
326 | data: {
327 | requestId: document.data.requestId,
328 | clientCount,
329 | },
330 | });
331 | },
332 | (arg) => {
333 | debug("received acknowledgement with value %j", arg);
334 | this.publish({
335 | type: EventType.BROADCAST_ACK,
336 | data: {
337 | requestId: document.data.requestId,
338 | packet: arg,
339 | },
340 | });
341 | }
342 | );
343 | } else {
344 | const packet = replaceBinaryObjectsByBuffers(document.data.packet);
345 | const opts = MongoAdapter.deserializeOptions(document.data.opts);
346 |
347 | this.addOffsetIfNecessary(packet, opts, document._id);
348 |
349 | super.broadcast(packet, opts);
350 | }
351 | break;
352 | }
353 |
354 | case EventType.BROADCAST_CLIENT_COUNT: {
355 | const request = this.ackRequests.get(document.data.requestId);
356 | request?.clientCountCallback(document.data.clientCount);
357 | break;
358 | }
359 |
360 | case EventType.BROADCAST_ACK: {
361 | const request = this.ackRequests.get(document.data.requestId);
362 | const clientResponse = replaceBinaryObjectsByBuffers(
363 | document.data.packet
364 | );
365 | request?.ack(clientResponse);
366 | break;
367 | }
368 |
369 | case EventType.SOCKETS_JOIN: {
370 | debug("calling addSockets with opts %j", document.data.opts);
371 | super.addSockets(
372 | MongoAdapter.deserializeOptions(document.data.opts),
373 | document.data.rooms
374 | );
375 | break;
376 | }
377 | case EventType.SOCKETS_LEAVE: {
378 | debug("calling delSockets with opts %j", document.data.opts);
379 | super.delSockets(
380 | MongoAdapter.deserializeOptions(document.data.opts),
381 | document.data.rooms
382 | );
383 | break;
384 | }
385 | case EventType.DISCONNECT_SOCKETS: {
386 | debug("calling disconnectSockets with opts %j", document.data.opts);
387 | super.disconnectSockets(
388 | MongoAdapter.deserializeOptions(document.data.opts),
389 | document.data.close
390 | );
391 | break;
392 | }
393 | case EventType.FETCH_SOCKETS: {
394 | debug("calling fetchSockets with opts %j", document.data.opts);
395 | const localSockets = await super.fetchSockets(
396 | MongoAdapter.deserializeOptions(document.data.opts)
397 | );
398 |
399 | this.publish({
400 | type: EventType.FETCH_SOCKETS_RESPONSE,
401 | data: {
402 | requestId: document.data.requestId,
403 | sockets: localSockets.map((socket) => ({
404 | id: socket.id,
405 | handshake: socket.handshake,
406 | rooms: [...socket.rooms],
407 | data: socket.data,
408 | })),
409 | },
410 | }).catch(onPublishError);
411 | break;
412 | }
413 | case EventType.FETCH_SOCKETS_RESPONSE: {
414 | const request = this.requests.get(document.data.requestId);
415 |
416 | if (!request) {
417 | return;
418 | }
419 |
420 | request.current++;
421 | document.data.sockets.forEach((socket: any) =>
422 | request.responses.push(socket)
423 | );
424 |
425 | if (request.current === request.expected) {
426 | clearTimeout(request.timeout);
427 | request.resolve(request.responses);
428 | this.requests.delete(document.data.requestId);
429 | }
430 | break;
431 | }
432 | case EventType.SERVER_SIDE_EMIT: {
433 | const packet = document.data.packet;
434 | const withAck = document.data.requestId !== undefined;
435 | if (!withAck) {
436 | this.nsp._onServerSideEmit(packet);
437 | return;
438 | }
439 | let called = false;
440 | const callback = (arg: any) => {
441 | // only one argument is expected
442 | if (called) {
443 | return;
444 | }
445 | called = true;
446 | debug("calling acknowledgement with %j", arg);
447 | this.publish({
448 | type: EventType.SERVER_SIDE_EMIT_RESPONSE,
449 | data: {
450 | requestId: document.data.requestId,
451 | packet: arg,
452 | },
453 | });
454 | };
455 |
456 | packet.push(callback);
457 | this.nsp._onServerSideEmit(packet);
458 | break;
459 | }
460 | case EventType.SERVER_SIDE_EMIT_RESPONSE: {
461 | const request = this.requests.get(document.data.requestId);
462 |
463 | if (!request) {
464 | return;
465 | }
466 |
467 | request.current++;
468 | request.responses.push(document.data.packet);
469 |
470 | if (request.current === request.expected) {
471 | clearTimeout(request.timeout);
472 | request.resolve(null, request.responses);
473 | this.requests.delete(document.data.requestId);
474 | }
475 | }
476 | }
477 | }
478 |
479 | private scheduleHeartbeat() {
480 | if (this.heartbeatTimer) {
481 | clearTimeout(this.heartbeatTimer);
482 | }
483 | this.heartbeatTimer = setTimeout(() => {
484 | debug("sending heartbeat");
485 | this.publish({
486 | type: EventType.HEARTBEAT,
487 | }).catch(onPublishError);
488 | this.scheduleHeartbeat();
489 | }, this.heartbeatInterval);
490 | }
491 |
492 | private publish(document: AdapterEvent): Promise {
493 | if (this.isClosed) {
494 | return Promise.reject("adapter is closed");
495 | }
496 | debug("publish document %d", document.type);
497 | document.uid = this.uid;
498 | document.nsp = this.nsp.name;
499 |
500 | if (this.addCreatedAtField) {
501 | document.createdAt = new Date();
502 | }
503 |
504 | this.scheduleHeartbeat();
505 |
506 | return this.mongoCollection
507 | .insertOne(document)
508 | .then((result) => result.insertedId.toString("hex"));
509 | }
510 |
511 | /**
512 | * Transform ES6 Set into plain arrays
513 | */
514 | private static serializeOptions(opts: BroadcastOptions) {
515 | return {
516 | rooms: [...opts.rooms],
517 | except: opts.except ? [...opts.except] : [],
518 | flags: opts.flags,
519 | };
520 | }
521 |
522 | private static deserializeOptions(opts: any): BroadcastOptions {
523 | return {
524 | rooms: new Set(opts.rooms),
525 | except: new Set(opts.except),
526 | flags: opts.flags,
527 | };
528 | }
529 |
530 | public async broadcast(packet: any, opts: BroadcastOptions) {
531 | const onlyLocal = opts?.flags?.local;
532 | if (!onlyLocal) {
533 | try {
534 | const offset = await this.publish({
535 | type: EventType.BROADCAST,
536 | data: {
537 | packet,
538 | opts: MongoAdapter.serializeOptions(opts),
539 | },
540 | });
541 | this.addOffsetIfNecessary(packet, opts, offset);
542 | } catch (err) {
543 | debug("error while inserting document: %s", err);
544 | return;
545 | }
546 | }
547 |
548 | // packets with binary contents are modified by the broadcast method, hence the nextTick()
549 | // update: this should be fixed now, but we'll keep it for backward compatibility
550 | // see: https://github.com/socketio/socket.io-parser/commit/ae8dd88995dbd7f89c97e5cc15e5b489fa0efece
551 | process.nextTick(() => {
552 | super.broadcast(packet, opts);
553 | });
554 | }
555 |
556 | /**
557 | * Adds an offset at the end of the data array in order to allow the client to receive any missed packets when it
558 | * reconnects after a temporary disconnection.
559 | *
560 | * @param packet
561 | * @param opts
562 | * @param offset
563 | * @private
564 | */
565 | private addOffsetIfNecessary(
566 | packet: any,
567 | opts: BroadcastOptions,
568 | offset: string
569 | ) {
570 | if (!this.nsp.server.opts.connectionStateRecovery) {
571 | return;
572 | }
573 | const isEventPacket = packet.type === 2;
574 | // packets with acknowledgement are not stored because the acknowledgement function cannot be serialized and
575 | // restored on another server upon reconnection
576 | const withoutAcknowledgement = packet.id === undefined;
577 | const notVolatile = opts.flags?.volatile === undefined;
578 |
579 | if (isEventPacket && withoutAcknowledgement && notVolatile) {
580 | packet.data.push(offset);
581 | }
582 | }
583 |
584 | public broadcastWithAck(
585 | packet: any,
586 | opts: BroadcastOptions,
587 | clientCountCallback: (clientCount: number) => void,
588 | ack: (...args: any[]) => void
589 | ) {
590 | const onlyLocal = opts?.flags?.local;
591 | if (!onlyLocal) {
592 | const requestId = randomId();
593 |
594 | this.publish({
595 | type: EventType.BROADCAST,
596 | data: {
597 | packet,
598 | requestId,
599 | opts: MongoAdapter.serializeOptions(opts),
600 | },
601 | }).catch(onPublishError);
602 |
603 | this.ackRequests.set(requestId, {
604 | type: EventType.BROADCAST,
605 | clientCountCallback,
606 | ack,
607 | });
608 |
609 | // we have no way to know at this level whether the server has received an acknowledgement from each client, so we
610 | // will simply clean up the ackRequests map after the given delay
611 | setTimeout(() => {
612 | this.ackRequests.delete(requestId);
613 | }, opts.flags!.timeout);
614 | }
615 |
616 | // packets with binary contents are modified by the broadcast method, hence the nextTick()
617 | process.nextTick(() => {
618 | super.broadcastWithAck(packet, opts, clientCountCallback, ack);
619 | });
620 | }
621 |
622 | public serverCount(): Promise {
623 | this.nodesMap.forEach((lastSeen, uid) => {
624 | const nodeSeemsDown = Date.now() - lastSeen > this.heartbeatTimeout;
625 | if (nodeSeemsDown) {
626 | debug("node %s seems down", uid);
627 | this.nodesMap.delete(uid);
628 | }
629 | });
630 | return Promise.resolve(1 + this.nodesMap.size);
631 | }
632 |
633 | addSockets(opts: BroadcastOptions, rooms: Room[]) {
634 | super.addSockets(opts, rooms);
635 |
636 | const onlyLocal = opts.flags?.local;
637 | if (onlyLocal) {
638 | return;
639 | }
640 |
641 | this.publish({
642 | type: EventType.SOCKETS_JOIN,
643 | data: {
644 | opts: MongoAdapter.serializeOptions(opts),
645 | rooms,
646 | },
647 | }).catch(onPublishError);
648 | }
649 |
650 | delSockets(opts: BroadcastOptions, rooms: Room[]) {
651 | super.delSockets(opts, rooms);
652 |
653 | const onlyLocal = opts.flags?.local;
654 | if (onlyLocal) {
655 | return;
656 | }
657 |
658 | this.publish({
659 | type: EventType.SOCKETS_LEAVE,
660 | data: {
661 | opts: MongoAdapter.serializeOptions(opts),
662 | rooms,
663 | },
664 | }).catch(onPublishError);
665 | }
666 |
667 | disconnectSockets(opts: BroadcastOptions, close: boolean) {
668 | super.disconnectSockets(opts, close);
669 |
670 | const onlyLocal = opts.flags?.local;
671 | if (onlyLocal) {
672 | return;
673 | }
674 |
675 | this.publish({
676 | type: EventType.DISCONNECT_SOCKETS,
677 | data: {
678 | opts: MongoAdapter.serializeOptions(opts),
679 | close,
680 | },
681 | }).catch(onPublishError);
682 | }
683 |
684 | async fetchSockets(opts: BroadcastOptions): Promise {
685 | const localSockets = await super.fetchSockets(opts);
686 | const expectedResponseCount = (await this.serverCount()) - 1;
687 |
688 | if (opts.flags?.local || expectedResponseCount === 0) {
689 | return localSockets;
690 | }
691 |
692 | const requestId = randomId();
693 |
694 | return new Promise((resolve, reject) => {
695 | const timeout = setTimeout(() => {
696 | const storedRequest = this.requests.get(requestId);
697 | if (storedRequest) {
698 | reject(
699 | new Error(
700 | `timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`
701 | )
702 | );
703 | this.requests.delete(requestId);
704 | }
705 | }, this.requestsTimeout);
706 |
707 | const storedRequest = {
708 | type: EventType.FETCH_SOCKETS,
709 | resolve,
710 | timeout,
711 | current: 0,
712 | expected: expectedResponseCount,
713 | responses: localSockets,
714 | };
715 | this.requests.set(requestId, storedRequest);
716 |
717 | this.publish({
718 | type: EventType.FETCH_SOCKETS,
719 | data: {
720 | opts: MongoAdapter.serializeOptions(opts),
721 | requestId,
722 | },
723 | });
724 | });
725 | }
726 |
727 | public serverSideEmit(packet: any[]): void {
728 | const withAck = typeof packet[packet.length - 1] === "function";
729 |
730 | if (withAck) {
731 | this.serverSideEmitWithAck(packet).catch(() => {
732 | // ignore errors
733 | });
734 | return;
735 | }
736 |
737 | this.publish({
738 | type: EventType.SERVER_SIDE_EMIT,
739 | data: {
740 | packet,
741 | },
742 | }).catch(onPublishError);
743 | }
744 |
745 | private async serverSideEmitWithAck(packet: any[]) {
746 | const ack = packet.pop();
747 | const expectedResponseCount = (await this.serverCount()) - 1;
748 |
749 | debug(
750 | 'waiting for %d responses to "serverSideEmit" request',
751 | expectedResponseCount
752 | );
753 |
754 | if (expectedResponseCount <= 0) {
755 | return ack(null, []);
756 | }
757 |
758 | const requestId = randomId();
759 |
760 | const timeout = setTimeout(() => {
761 | const storedRequest = this.requests.get(requestId);
762 | if (storedRequest) {
763 | ack(
764 | new Error(
765 | `timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`
766 | ),
767 | storedRequest.responses
768 | );
769 | this.requests.delete(requestId);
770 | }
771 | }, this.requestsTimeout);
772 |
773 | const storedRequest = {
774 | type: EventType.FETCH_SOCKETS,
775 | resolve: ack,
776 | timeout,
777 | current: 0,
778 | expected: expectedResponseCount,
779 | responses: [],
780 | };
781 | this.requests.set(requestId, storedRequest);
782 |
783 | this.publish({
784 | type: EventType.SERVER_SIDE_EMIT,
785 | data: {
786 | requestId, // the presence of this attribute defines whether an acknowledgement is needed
787 | packet,
788 | },
789 | }).catch(onPublishError);
790 | }
791 |
792 | override persistSession(session: any) {
793 | debug("persisting session: %j", session);
794 | this.publish({
795 | type: EventType.SESSION,
796 | data: session,
797 | }).catch(onPublishError);
798 | }
799 |
800 | override async restoreSession(
801 | pid: PrivateSessionId,
802 | offset: string
803 | ): Promise {
804 | if (!ObjectId.isValid(offset)) {
805 | return Promise.reject("invalid offset");
806 | }
807 | debug("restoring session: %s", pid);
808 | const eventOffset = new ObjectId(offset);
809 |
810 | let results;
811 | try {
812 | results = await Promise.all([
813 | // could use a sparse index on [data.pid] (only index the documents whose type is EventType.SESSION)
814 | this.findSession(pid),
815 | this.mongoCollection.findOne({
816 | type: EventType.BROADCAST,
817 | _id: eventOffset,
818 | }),
819 | ]);
820 | } catch (e) {
821 | debug("error while fetching session: %s", (e as Error).message);
822 | return Promise.reject("error while fetching session");
823 | }
824 |
825 | if (!results[0] || !results[1]) {
826 | return Promise.reject("session or offset not found");
827 | }
828 |
829 | const session = results[0].data;
830 |
831 | // could use a sparse index on [_id, nsp, data.opts.rooms, data.opts.except] (only index the documents whose type is EventType.BROADCAST)
832 | const cursor = this.mongoCollection.find({
833 | $and: [
834 | {
835 | type: EventType.BROADCAST,
836 | },
837 | {
838 | _id: {
839 | $gt: eventOffset,
840 | },
841 | },
842 | {
843 | nsp: this.nsp.name,
844 | },
845 | {
846 | $or: [
847 | {
848 | "data.opts.rooms": {
849 | $size: 0,
850 | },
851 | },
852 | {
853 | "data.opts.rooms": {
854 | $in: session.rooms,
855 | },
856 | },
857 | ],
858 | },
859 | {
860 | $or: [
861 | {
862 | "data.opts.except": {
863 | $size: 0,
864 | },
865 | },
866 | {
867 | "data.opts.except": {
868 | $nin: session.rooms,
869 | },
870 | },
871 | ],
872 | },
873 | ],
874 | });
875 |
876 | session.missedPackets = [];
877 |
878 | try {
879 | for await (const document of cursor) {
880 | const packetData = document?.data?.packet?.data;
881 | if (packetData) {
882 | session.missedPackets.push(packetData);
883 | }
884 | }
885 | } catch (e) {
886 | return Promise.reject("error while fetching missed packets");
887 | }
888 |
889 | return session;
890 | }
891 |
892 | private findSession(
893 | pid: PrivateSessionId
894 | ): Promise | undefined> {
895 | const isCollectionCapped = !this.addCreatedAtField;
896 | if (isCollectionCapped) {
897 | return this.mongoCollection
898 | .findOne(
899 | {
900 | type: EventType.SESSION,
901 | "data.pid": pid,
902 | },
903 | {
904 | sort: {
905 | _id: -1,
906 | },
907 | }
908 | )
909 | .then((result) => {
910 | if (!result) {
911 | debug("session not found");
912 | return;
913 | }
914 |
915 | if (result.data.sid) {
916 | debug("session found, adding tombstone");
917 |
918 | // since the collection is capped, we cannot remove documents from it, so we add a tombstone to prevent recovering the same session twice
919 | // note: we could also have used two distinct collections, one for the events (capped) and the other for the sessions (not capped, with a TTL)
920 | const TOMBSTONE_SESSION = { pid, tombstone: true };
921 | this.persistSession(TOMBSTONE_SESSION);
922 |
923 | return result;
924 | } else {
925 | debug("tombstone session found");
926 | }
927 | });
928 | } else {
929 | return this.mongoCollection
930 | .findOneAndDelete({
931 | type: EventType.SESSION,
932 | "data.pid": pid,
933 | })
934 | .then((result) => {
935 | return result?.ok && result.value
936 | ? result.value // mongodb@5
937 | : (result as unknown as WithId); // mongodb@6
938 | });
939 | }
940 | }
941 | }
942 |
--------------------------------------------------------------------------------
/assets/adapter.excalidraw:
--------------------------------------------------------------------------------
1 | {
2 | "type": "excalidraw",
3 | "version": 2,
4 | "source": "https://excalidraw.com",
5 | "elements": [
6 | {
7 | "type": "text",
8 | "version": 133,
9 | "versionNonce": 840310243,
10 | "isDeleted": false,
11 | "id": "5hUB5ALUlsn26W0PzU4fM",
12 | "fillStyle": "hachure",
13 | "strokeWidth": 1,
14 | "strokeStyle": "solid",
15 | "roughness": 1,
16 | "opacity": 100,
17 | "angle": 0,
18 | "x": 894,
19 | "y": 3.5,
20 | "strokeColor": "#000000",
21 | "backgroundColor": "transparent",
22 | "width": 64,
23 | "height": 25,
24 | "seed": 28708370,
25 | "groupIds": [],
26 | "strokeSharpness": "sharp",
27 | "boundElementIds": [],
28 | "fontSize": 20,
29 | "fontFamily": 1,
30 | "text": "socket",
31 | "baseline": 18,
32 | "textAlign": "center",
33 | "verticalAlign": "middle"
34 | },
35 | {
36 | "type": "rectangle",
37 | "version": 133,
38 | "versionNonce": 944596429,
39 | "isDeleted": false,
40 | "id": "lmQ4o4New7xuXQLwavuSn",
41 | "fillStyle": "hachure",
42 | "strokeWidth": 1,
43 | "strokeStyle": "solid",
44 | "roughness": 1,
45 | "opacity": 100,
46 | "angle": 0,
47 | "x": 824,
48 | "y": -80,
49 | "strokeColor": "#000000",
50 | "backgroundColor": "transparent",
51 | "width": 277,
52 | "height": 311,
53 | "seed": 1594950354,
54 | "groupIds": [],
55 | "strokeSharpness": "sharp",
56 | "boundElementIds": [
57 | "_wBO22vaQplcoKyBXbWRC",
58 | "BZVwnsrGk9G-X87ZHkh-6"
59 | ]
60 | },
61 | {
62 | "type": "text",
63 | "version": 74,
64 | "versionNonce": 1241409923,
65 | "isDeleted": false,
66 | "id": "ZQsZmj4NaTubBHMkVG2dl",
67 | "fillStyle": "hachure",
68 | "strokeWidth": 1,
69 | "strokeStyle": "solid",
70 | "roughness": 1,
71 | "opacity": 100,
72 | "angle": 0,
73 | "x": 843,
74 | "y": -69,
75 | "strokeColor": "#000000",
76 | "backgroundColor": "transparent",
77 | "width": 85,
78 | "height": 26,
79 | "seed": 126533902,
80 | "groupIds": [],
81 | "strokeSharpness": "sharp",
82 | "boundElementIds": [],
83 | "fontSize": 20,
84 | "fontFamily": 1,
85 | "text": "Server A",
86 | "baseline": 18,
87 | "textAlign": "left",
88 | "verticalAlign": "top"
89 | },
90 | {
91 | "type": "arrow",
92 | "version": 152,
93 | "versionNonce": 1430498829,
94 | "isDeleted": false,
95 | "id": "ABQydsvmkN5ptLyYQaUA3",
96 | "fillStyle": "hachure",
97 | "strokeWidth": 2,
98 | "strokeStyle": "solid",
99 | "roughness": 1,
100 | "opacity": 100,
101 | "angle": 0,
102 | "x": 837.8983868047594,
103 | "y": 21.868707241881623,
104 | "strokeColor": "#000000",
105 | "backgroundColor": "transparent",
106 | "width": 251.33111393617446,
107 | "height": 0.7613046474941143,
108 | "seed": 1466702734,
109 | "groupIds": [],
110 | "strokeSharpness": "round",
111 | "boundElementIds": [],
112 | "lastCommittedPoint": null,
113 | "startArrowhead": null,
114 | "endArrowhead": "arrow",
115 | "points": [
116 | [
117 | 0,
118 | 0
119 | ],
120 | [
121 | -251.33111393617446,
122 | -0.7613046474941143
123 | ]
124 | ]
125 | },
126 | {
127 | "type": "rectangle",
128 | "version": 159,
129 | "versionNonce": 1109147939,
130 | "isDeleted": false,
131 | "id": "x54ljUV2PW8AfubZ6fiVJ",
132 | "fillStyle": "hachure",
133 | "strokeWidth": 1,
134 | "strokeStyle": "solid",
135 | "roughness": 1,
136 | "opacity": 100,
137 | "angle": 0,
138 | "x": 436,
139 | "y": -8,
140 | "strokeColor": "#000000",
141 | "backgroundColor": "transparent",
142 | "width": 129,
143 | "height": 56,
144 | "seed": 486293390,
145 | "groupIds": [],
146 | "strokeSharpness": "sharp",
147 | "boundElementIds": []
148 | },
149 | {
150 | "type": "arrow",
151 | "version": 168,
152 | "versionNonce": 438068333,
153 | "isDeleted": false,
154 | "id": "zdzgdf3hgOYX0SgjEtyIZ",
155 | "fillStyle": "hachure",
156 | "strokeWidth": 2,
157 | "strokeStyle": "solid",
158 | "roughness": 1,
159 | "opacity": 100,
160 | "angle": 0,
161 | "x": 837.2434176281095,
162 | "y": 87.19281457587147,
163 | "strokeColor": "#000000",
164 | "backgroundColor": "transparent",
165 | "width": 247.23231148719788,
166 | "height": 2.2114410393964476,
167 | "seed": 1674715794,
168 | "groupIds": [],
169 | "strokeSharpness": "round",
170 | "boundElementIds": [],
171 | "lastCommittedPoint": null,
172 | "startArrowhead": null,
173 | "endArrowhead": "arrow",
174 | "points": [
175 | [
176 | 0,
177 | 0
178 | ],
179 | [
180 | -247.23231148719788,
181 | 2.2114410393964476
182 | ]
183 | ]
184 | },
185 | {
186 | "type": "text",
187 | "version": 136,
188 | "versionNonce": 333325507,
189 | "isDeleted": false,
190 | "id": "dXknKeuYe3X3K-0Hw9P95",
191 | "fillStyle": "hachure",
192 | "strokeWidth": 1,
193 | "strokeStyle": "solid",
194 | "roughness": 1,
195 | "opacity": 100,
196 | "angle": 0,
197 | "x": 484,
198 | "y": 9,
199 | "strokeColor": "#000000",
200 | "backgroundColor": "transparent",
201 | "width": 40,
202 | "height": 20,
203 | "seed": 1858283854,
204 | "groupIds": [],
205 | "strokeSharpness": "sharp",
206 | "boundElementIds": [],
207 | "fontSize": 16,
208 | "fontFamily": 1,
209 | "text": "client",
210 | "baseline": 14,
211 | "textAlign": "left",
212 | "verticalAlign": "top"
213 | },
214 | {
215 | "type": "rectangle",
216 | "version": 179,
217 | "versionNonce": 1008057581,
218 | "isDeleted": false,
219 | "id": "Ce1Lw4MMOtiunstd3FPJv",
220 | "fillStyle": "hachure",
221 | "strokeWidth": 1,
222 | "strokeStyle": "solid",
223 | "roughness": 1,
224 | "opacity": 100,
225 | "angle": 0,
226 | "x": 437.5,
227 | "y": 67,
228 | "strokeColor": "#000000",
229 | "backgroundColor": "transparent",
230 | "width": 129,
231 | "height": 56,
232 | "seed": 568384654,
233 | "groupIds": [],
234 | "strokeSharpness": "sharp",
235 | "boundElementIds": []
236 | },
237 | {
238 | "type": "text",
239 | "version": 157,
240 | "versionNonce": 115512419,
241 | "isDeleted": false,
242 | "id": "rcCUGk-XM0jKzcGaeO0iS",
243 | "fillStyle": "hachure",
244 | "strokeWidth": 1,
245 | "strokeStyle": "solid",
246 | "roughness": 1,
247 | "opacity": 100,
248 | "angle": 0,
249 | "x": 484.5,
250 | "y": 84,
251 | "strokeColor": "#000000",
252 | "backgroundColor": "transparent",
253 | "width": 40,
254 | "height": 20,
255 | "seed": 244546386,
256 | "groupIds": [],
257 | "strokeSharpness": "sharp",
258 | "boundElementIds": [],
259 | "fontSize": 16,
260 | "fontFamily": 1,
261 | "text": "client",
262 | "baseline": 14,
263 | "textAlign": "left",
264 | "verticalAlign": "top"
265 | },
266 | {
267 | "type": "rectangle",
268 | "version": 220,
269 | "versionNonce": 1032427341,
270 | "isDeleted": false,
271 | "id": "4iido5zQ7QhoIfnOzWp3h",
272 | "fillStyle": "hachure",
273 | "strokeWidth": 1,
274 | "strokeStyle": "solid",
275 | "roughness": 1,
276 | "opacity": 100,
277 | "angle": 0,
278 | "x": 437.5,
279 | "y": 142,
280 | "strokeColor": "#000000",
281 | "backgroundColor": "transparent",
282 | "width": 129,
283 | "height": 56,
284 | "seed": 1055485070,
285 | "groupIds": [],
286 | "strokeSharpness": "sharp",
287 | "boundElementIds": []
288 | },
289 | {
290 | "type": "text",
291 | "version": 198,
292 | "versionNonce": 1794641923,
293 | "isDeleted": false,
294 | "id": "D1E2DkimaDb8hGxIfXKmq",
295 | "fillStyle": "hachure",
296 | "strokeWidth": 1,
297 | "strokeStyle": "solid",
298 | "roughness": 1,
299 | "opacity": 100,
300 | "angle": 0,
301 | "x": 484.5,
302 | "y": 159,
303 | "strokeColor": "#000000",
304 | "backgroundColor": "transparent",
305 | "width": 40,
306 | "height": 20,
307 | "seed": 270265170,
308 | "groupIds": [],
309 | "strokeSharpness": "sharp",
310 | "boundElementIds": [],
311 | "fontSize": 16,
312 | "fontFamily": 1,
313 | "text": "client",
314 | "baseline": 14,
315 | "textAlign": "left",
316 | "verticalAlign": "top"
317 | },
318 | {
319 | "type": "rectangle",
320 | "version": 191,
321 | "versionNonce": 1817388461,
322 | "isDeleted": false,
323 | "id": "RRrk3Vsl-pM8Z1r8Fj3Vu",
324 | "fillStyle": "hachure",
325 | "strokeWidth": 1,
326 | "strokeStyle": "solid",
327 | "roughness": 1,
328 | "opacity": 100,
329 | "angle": 0,
330 | "x": 860.5,
331 | "y": -8,
332 | "strokeColor": "#000000",
333 | "backgroundColor": "transparent",
334 | "width": 129,
335 | "height": 56,
336 | "seed": 1013161166,
337 | "groupIds": [],
338 | "strokeSharpness": "sharp",
339 | "boundElementIds": []
340 | },
341 | {
342 | "type": "text",
343 | "version": 174,
344 | "versionNonce": 303896483,
345 | "isDeleted": false,
346 | "id": "8pCtm42TpakWdZ7WNS4VN",
347 | "fillStyle": "hachure",
348 | "strokeWidth": 1,
349 | "strokeStyle": "solid",
350 | "roughness": 1,
351 | "opacity": 100,
352 | "angle": 0,
353 | "x": 893,
354 | "y": 73.5,
355 | "strokeColor": "#000000",
356 | "backgroundColor": "transparent",
357 | "width": 64,
358 | "height": 25,
359 | "seed": 684338382,
360 | "groupIds": [],
361 | "strokeSharpness": "sharp",
362 | "boundElementIds": [],
363 | "fontSize": 20,
364 | "fontFamily": 1,
365 | "text": "socket",
366 | "baseline": 18,
367 | "textAlign": "center",
368 | "verticalAlign": "middle"
369 | },
370 | {
371 | "type": "rectangle",
372 | "version": 232,
373 | "versionNonce": 2073815053,
374 | "isDeleted": false,
375 | "id": "thsI1AfZ_VshmC8wdQoT_",
376 | "fillStyle": "hachure",
377 | "strokeWidth": 1,
378 | "strokeStyle": "solid",
379 | "roughness": 1,
380 | "opacity": 100,
381 | "angle": 0,
382 | "x": 859.5,
383 | "y": 62,
384 | "strokeColor": "#000000",
385 | "backgroundColor": "transparent",
386 | "width": 129,
387 | "height": 56,
388 | "seed": 1104563986,
389 | "groupIds": [],
390 | "strokeSharpness": "sharp",
391 | "boundElementIds": []
392 | },
393 | {
394 | "type": "text",
395 | "version": 195,
396 | "versionNonce": 176171843,
397 | "isDeleted": false,
398 | "id": "dfFxeVTIg6OH8ny7WuBsb",
399 | "fillStyle": "hachure",
400 | "strokeWidth": 1,
401 | "strokeStyle": "solid",
402 | "roughness": 1,
403 | "opacity": 100,
404 | "angle": 0,
405 | "x": 890,
406 | "y": 150.5,
407 | "strokeColor": "#000000",
408 | "backgroundColor": "transparent",
409 | "width": 64,
410 | "height": 25,
411 | "seed": 1000469902,
412 | "groupIds": [],
413 | "strokeSharpness": "sharp",
414 | "boundElementIds": [],
415 | "fontSize": 20,
416 | "fontFamily": 1,
417 | "text": "socket",
418 | "baseline": 18,
419 | "textAlign": "center",
420 | "verticalAlign": "middle"
421 | },
422 | {
423 | "type": "rectangle",
424 | "version": 253,
425 | "versionNonce": 2103271021,
426 | "isDeleted": false,
427 | "id": "Ejm4QTgpRy-0064kg5DDC",
428 | "fillStyle": "hachure",
429 | "strokeWidth": 1,
430 | "strokeStyle": "solid",
431 | "roughness": 1,
432 | "opacity": 100,
433 | "angle": 0,
434 | "x": 856.5,
435 | "y": 139,
436 | "strokeColor": "#000000",
437 | "backgroundColor": "transparent",
438 | "width": 129,
439 | "height": 56,
440 | "seed": 1070363218,
441 | "groupIds": [],
442 | "strokeSharpness": "sharp",
443 | "boundElementIds": []
444 | },
445 | {
446 | "type": "arrow",
447 | "version": 203,
448 | "versionNonce": 1869999405,
449 | "isDeleted": false,
450 | "id": "yn0_EJ_FjGmr2PHYTCPsC",
451 | "fillStyle": "hachure",
452 | "strokeWidth": 2,
453 | "strokeStyle": "solid",
454 | "roughness": 1,
455 | "opacity": 100,
456 | "angle": 0,
457 | "x": 837.6161557435989,
458 | "y": 166.89427948030175,
459 | "strokeColor": "#000000",
460 | "backgroundColor": "transparent",
461 | "width": 247.23231148719788,
462 | "height": 2.2114410393964476,
463 | "seed": 1559186084,
464 | "groupIds": [],
465 | "strokeSharpness": "round",
466 | "boundElementIds": [],
467 | "lastCommittedPoint": null,
468 | "startArrowhead": null,
469 | "endArrowhead": "arrow",
470 | "points": [
471 | [
472 | 0,
473 | 0
474 | ],
475 | [
476 | -247.23231148719788,
477 | 2.2114410393964476
478 | ]
479 | ]
480 | },
481 | {
482 | "type": "text",
483 | "version": 178,
484 | "versionNonce": 140576973,
485 | "isDeleted": false,
486 | "id": "2KQuRzgUL-iSoMHZQ9zbS",
487 | "fillStyle": "hachure",
488 | "strokeWidth": 1,
489 | "strokeStyle": "solid",
490 | "roughness": 1,
491 | "opacity": 100,
492 | "angle": 0,
493 | "x": 892.5,
494 | "y": 406,
495 | "strokeColor": "#000000",
496 | "backgroundColor": "transparent",
497 | "width": 64,
498 | "height": 25,
499 | "seed": 1479277478,
500 | "groupIds": [],
501 | "strokeSharpness": "sharp",
502 | "boundElementIds": [],
503 | "fontSize": 20,
504 | "fontFamily": 1,
505 | "text": "socket",
506 | "baseline": 18,
507 | "textAlign": "center",
508 | "verticalAlign": "middle"
509 | },
510 | {
511 | "type": "rectangle",
512 | "version": 209,
513 | "versionNonce": 1890219651,
514 | "isDeleted": false,
515 | "id": "dJhDWOnAJOszWt_UNEXdt",
516 | "fillStyle": "hachure",
517 | "strokeWidth": 1,
518 | "strokeStyle": "solid",
519 | "roughness": 1,
520 | "opacity": 100,
521 | "angle": 0,
522 | "x": 822.5,
523 | "y": 322.5,
524 | "strokeColor": "#000000",
525 | "backgroundColor": "transparent",
526 | "width": 277,
527 | "height": 280,
528 | "seed": 224360890,
529 | "groupIds": [],
530 | "strokeSharpness": "sharp",
531 | "boundElementIds": [
532 | "qmYaJfZ9NO1RK7YHGQGo6",
533 | "GsCkqpyPppqmnpvbaTChx",
534 | "x_nMpLlFEV43XGOAM6Gxj"
535 | ]
536 | },
537 | {
538 | "type": "text",
539 | "version": 115,
540 | "versionNonce": 507537197,
541 | "isDeleted": false,
542 | "id": "lyh4RgaTTCZNLUjl519k9",
543 | "fillStyle": "hachure",
544 | "strokeWidth": 1,
545 | "strokeStyle": "solid",
546 | "roughness": 1,
547 | "opacity": 100,
548 | "angle": 0,
549 | "x": 841.5,
550 | "y": 333.5,
551 | "strokeColor": "#000000",
552 | "backgroundColor": "transparent",
553 | "width": 87,
554 | "height": 26,
555 | "seed": 364484326,
556 | "groupIds": [],
557 | "strokeSharpness": "sharp",
558 | "boundElementIds": [],
559 | "fontSize": 20,
560 | "fontFamily": 1,
561 | "text": "Server B",
562 | "baseline": 18,
563 | "textAlign": "left",
564 | "verticalAlign": "top"
565 | },
566 | {
567 | "type": "arrow",
568 | "version": 190,
569 | "versionNonce": 388860867,
570 | "isDeleted": false,
571 | "id": "x7ujWlTTvv0aN7XIFTWjr",
572 | "fillStyle": "hachure",
573 | "strokeWidth": 2,
574 | "strokeStyle": "solid",
575 | "roughness": 1,
576 | "opacity": 100,
577 | "angle": 0,
578 | "x": 842.3983868047594,
579 | "y": 425.3687072418816,
580 | "strokeColor": "#000000",
581 | "backgroundColor": "transparent",
582 | "width": 251.33111393617446,
583 | "height": 0.7613046474941143,
584 | "seed": 1836855930,
585 | "groupIds": [],
586 | "strokeSharpness": "round",
587 | "boundElementIds": [],
588 | "lastCommittedPoint": null,
589 | "startArrowhead": null,
590 | "endArrowhead": "arrow",
591 | "points": [
592 | [
593 | 0,
594 | 0
595 | ],
596 | [
597 | -251.33111393617446,
598 | -0.7613046474941143
599 | ]
600 | ]
601 | },
602 | {
603 | "type": "rectangle",
604 | "version": 197,
605 | "versionNonce": 1365571981,
606 | "isDeleted": false,
607 | "id": "cqdTPTcZefvtqeNEAMTBe",
608 | "fillStyle": "hachure",
609 | "strokeWidth": 1,
610 | "strokeStyle": "solid",
611 | "roughness": 1,
612 | "opacity": 100,
613 | "angle": 0,
614 | "x": 440.5,
615 | "y": 395.5,
616 | "strokeColor": "#000000",
617 | "backgroundColor": "transparent",
618 | "width": 129,
619 | "height": 56,
620 | "seed": 1567738406,
621 | "groupIds": [],
622 | "strokeSharpness": "sharp",
623 | "boundElementIds": []
624 | },
625 | {
626 | "type": "arrow",
627 | "version": 206,
628 | "versionNonce": 1504516963,
629 | "isDeleted": false,
630 | "id": "59kripFevaDD2Mo2bkYk-",
631 | "fillStyle": "hachure",
632 | "strokeWidth": 2,
633 | "strokeStyle": "solid",
634 | "roughness": 1,
635 | "opacity": 100,
636 | "angle": 0,
637 | "x": 841.7434176281095,
638 | "y": 490.69281457587147,
639 | "strokeColor": "#000000",
640 | "backgroundColor": "transparent",
641 | "width": 247.23231148719788,
642 | "height": 2.2114410393964476,
643 | "seed": 1124324154,
644 | "groupIds": [],
645 | "strokeSharpness": "round",
646 | "boundElementIds": [],
647 | "lastCommittedPoint": null,
648 | "startArrowhead": null,
649 | "endArrowhead": "arrow",
650 | "points": [
651 | [
652 | 0,
653 | 0
654 | ],
655 | [
656 | -247.23231148719788,
657 | 2.2114410393964476
658 | ]
659 | ]
660 | },
661 | {
662 | "type": "text",
663 | "version": 174,
664 | "versionNonce": 721960941,
665 | "isDeleted": false,
666 | "id": "U0x2FIFxg4BZgOIK6sVnW",
667 | "fillStyle": "hachure",
668 | "strokeWidth": 1,
669 | "strokeStyle": "solid",
670 | "roughness": 1,
671 | "opacity": 100,
672 | "angle": 0,
673 | "x": 488.5,
674 | "y": 412.5,
675 | "strokeColor": "#000000",
676 | "backgroundColor": "transparent",
677 | "width": 40,
678 | "height": 20,
679 | "seed": 1044485478,
680 | "groupIds": [],
681 | "strokeSharpness": "sharp",
682 | "boundElementIds": [],
683 | "fontSize": 16,
684 | "fontFamily": 1,
685 | "text": "client",
686 | "baseline": 14,
687 | "textAlign": "left",
688 | "verticalAlign": "top"
689 | },
690 | {
691 | "type": "rectangle",
692 | "version": 217,
693 | "versionNonce": 411943267,
694 | "isDeleted": false,
695 | "id": "NU9potS0F6f8sxY5IT0Lt",
696 | "fillStyle": "hachure",
697 | "strokeWidth": 1,
698 | "strokeStyle": "solid",
699 | "roughness": 1,
700 | "opacity": 100,
701 | "angle": 0,
702 | "x": 442,
703 | "y": 470.5,
704 | "strokeColor": "#000000",
705 | "backgroundColor": "transparent",
706 | "width": 129,
707 | "height": 56,
708 | "seed": 1884904442,
709 | "groupIds": [],
710 | "strokeSharpness": "sharp",
711 | "boundElementIds": []
712 | },
713 | {
714 | "type": "text",
715 | "version": 195,
716 | "versionNonce": 1362344525,
717 | "isDeleted": false,
718 | "id": "IpJJ20xja0yqXQC_netfw",
719 | "fillStyle": "hachure",
720 | "strokeWidth": 1,
721 | "strokeStyle": "solid",
722 | "roughness": 1,
723 | "opacity": 100,
724 | "angle": 0,
725 | "x": 489,
726 | "y": 487.5,
727 | "strokeColor": "#000000",
728 | "backgroundColor": "transparent",
729 | "width": 40,
730 | "height": 20,
731 | "seed": 1635121318,
732 | "groupIds": [],
733 | "strokeSharpness": "sharp",
734 | "boundElementIds": [],
735 | "fontSize": 16,
736 | "fontFamily": 1,
737 | "text": "client",
738 | "baseline": 14,
739 | "textAlign": "left",
740 | "verticalAlign": "top"
741 | },
742 | {
743 | "type": "rectangle",
744 | "version": 236,
745 | "versionNonce": 1488297219,
746 | "isDeleted": false,
747 | "id": "scSxnujNYgELyMUDbnTNS",
748 | "fillStyle": "hachure",
749 | "strokeWidth": 1,
750 | "strokeStyle": "solid",
751 | "roughness": 1,
752 | "opacity": 100,
753 | "angle": 0,
754 | "x": 859,
755 | "y": 394.5,
756 | "strokeColor": "#000000",
757 | "backgroundColor": "transparent",
758 | "width": 129,
759 | "height": 56,
760 | "seed": 303703418,
761 | "groupIds": [],
762 | "strokeSharpness": "sharp",
763 | "boundElementIds": []
764 | },
765 | {
766 | "type": "text",
767 | "version": 219,
768 | "versionNonce": 1824581805,
769 | "isDeleted": false,
770 | "id": "Lyv2NwV0SfYm5kvp9sJEn",
771 | "fillStyle": "hachure",
772 | "strokeWidth": 1,
773 | "strokeStyle": "solid",
774 | "roughness": 1,
775 | "opacity": 100,
776 | "angle": 0,
777 | "x": 891.5,
778 | "y": 476,
779 | "strokeColor": "#000000",
780 | "backgroundColor": "transparent",
781 | "width": 64,
782 | "height": 25,
783 | "seed": 1344309030,
784 | "groupIds": [],
785 | "strokeSharpness": "sharp",
786 | "boundElementIds": [],
787 | "fontSize": 20,
788 | "fontFamily": 1,
789 | "text": "socket",
790 | "baseline": 18,
791 | "textAlign": "center",
792 | "verticalAlign": "middle"
793 | },
794 | {
795 | "type": "rectangle",
796 | "version": 277,
797 | "versionNonce": 1788937379,
798 | "isDeleted": false,
799 | "id": "e3D2rl_rbVQwQUKshOG8E",
800 | "fillStyle": "hachure",
801 | "strokeWidth": 1,
802 | "strokeStyle": "solid",
803 | "roughness": 1,
804 | "opacity": 100,
805 | "angle": 0,
806 | "x": 858,
807 | "y": 464.5,
808 | "strokeColor": "#000000",
809 | "backgroundColor": "transparent",
810 | "width": 129,
811 | "height": 56,
812 | "seed": 627795514,
813 | "groupIds": [],
814 | "strokeSharpness": "sharp",
815 | "boundElementIds": []
816 | },
817 | {
818 | "type": "diamond",
819 | "version": 258,
820 | "versionNonce": 1331251981,
821 | "isDeleted": false,
822 | "id": "k0pJTVL4F3HHsfRPlE-gO",
823 | "fillStyle": "hachure",
824 | "strokeWidth": 2,
825 | "strokeStyle": "solid",
826 | "roughness": 0,
827 | "opacity": 100,
828 | "angle": 0,
829 | "x": 1149,
830 | "y": 66,
831 | "strokeColor": "#000000",
832 | "backgroundColor": "transparent",
833 | "width": 46,
834 | "height": 46,
835 | "seed": 1260350118,
836 | "groupIds": [],
837 | "strokeSharpness": "sharp",
838 | "boundElementIds": [
839 | "Sp9AvxDh8gwRvSC53VFKe"
840 | ]
841 | },
842 | {
843 | "type": "text",
844 | "version": 243,
845 | "versionNonce": 1711175747,
846 | "isDeleted": false,
847 | "id": "DiLMkDsU2SrPef3STL9fw",
848 | "fillStyle": "hachure",
849 | "strokeWidth": 1,
850 | "strokeStyle": "dashed",
851 | "roughness": 0,
852 | "opacity": 100,
853 | "angle": 0,
854 | "x": 1111.5,
855 | "y": 27.5,
856 | "strokeColor": "#000000",
857 | "backgroundColor": "transparent",
858 | "width": 144,
859 | "height": 26,
860 | "seed": 1810644198,
861 | "groupIds": [],
862 | "strokeSharpness": "sharp",
863 | "boundElementIds": [],
864 | "fontSize": 20,
865 | "fontFamily": 1,
866 | "text": "Mongo adapter",
867 | "baseline": 18,
868 | "textAlign": "center",
869 | "verticalAlign": "top"
870 | },
871 | {
872 | "type": "arrow",
873 | "version": 28,
874 | "versionNonce": 1500930413,
875 | "isDeleted": false,
876 | "id": "Sp9AvxDh8gwRvSC53VFKe",
877 | "fillStyle": "hachure",
878 | "strokeWidth": 2,
879 | "strokeStyle": "solid",
880 | "roughness": 0,
881 | "opacity": 100,
882 | "angle": 0,
883 | "x": 1129,
884 | "y": 89,
885 | "strokeColor": "#000000",
886 | "backgroundColor": "transparent",
887 | "width": 109,
888 | "height": 1,
889 | "seed": 714162918,
890 | "groupIds": [],
891 | "strokeSharpness": "round",
892 | "boundElementIds": [],
893 | "startBinding": {
894 | "elementId": "k0pJTVL4F3HHsfRPlE-gO",
895 | "focus": -0.01715197447147986,
896 | "gap": 14.142135623730947
897 | },
898 | "endBinding": null,
899 | "lastCommittedPoint": null,
900 | "startArrowhead": null,
901 | "endArrowhead": "arrow",
902 | "points": [
903 | [
904 | 0,
905 | 0
906 | ],
907 | [
908 | -109,
909 | -1
910 | ]
911 | ]
912 | },
913 | {
914 | "type": "arrow",
915 | "version": 44,
916 | "versionNonce": 1756133347,
917 | "isDeleted": false,
918 | "id": "_wBO22vaQplcoKyBXbWRC",
919 | "fillStyle": "hachure",
920 | "strokeWidth": 2,
921 | "strokeStyle": "solid",
922 | "roughness": 0,
923 | "opacity": 100,
924 | "angle": 0,
925 | "x": 1126,
926 | "y": 83,
927 | "strokeColor": "#000000",
928 | "backgroundColor": "transparent",
929 | "width": 105,
930 | "height": 57,
931 | "seed": 1243541542,
932 | "groupIds": [],
933 | "strokeSharpness": "round",
934 | "boundElementIds": [],
935 | "startBinding": {
936 | "elementId": "lmQ4o4New7xuXQLwavuSn",
937 | "focus": 0.35224176368590543,
938 | "gap": 25
939 | },
940 | "endBinding": null,
941 | "lastCommittedPoint": null,
942 | "startArrowhead": null,
943 | "endArrowhead": "arrow",
944 | "points": [
945 | [
946 | 0,
947 | 0
948 | ],
949 | [
950 | -105,
951 | -57
952 | ]
953 | ]
954 | },
955 | {
956 | "type": "arrow",
957 | "version": 59,
958 | "versionNonce": 543271885,
959 | "isDeleted": false,
960 | "id": "BZVwnsrGk9G-X87ZHkh-6",
961 | "fillStyle": "hachure",
962 | "strokeWidth": 2,
963 | "strokeStyle": "solid",
964 | "roughness": 0,
965 | "opacity": 100,
966 | "angle": 0,
967 | "x": 1128,
968 | "y": 96,
969 | "strokeColor": "#000000",
970 | "backgroundColor": "transparent",
971 | "width": 95,
972 | "height": 62,
973 | "seed": 1890534970,
974 | "groupIds": [],
975 | "strokeSharpness": "round",
976 | "boundElementIds": [],
977 | "startBinding": {
978 | "elementId": "lmQ4o4New7xuXQLwavuSn",
979 | "focus": -0.522635330379503,
980 | "gap": 27
981 | },
982 | "endBinding": null,
983 | "lastCommittedPoint": null,
984 | "startArrowhead": null,
985 | "endArrowhead": "arrow",
986 | "points": [
987 | [
988 | 0,
989 | 0
990 | ],
991 | [
992 | -95,
993 | 62
994 | ]
995 | ]
996 | },
997 | {
998 | "type": "diamond",
999 | "version": 364,
1000 | "versionNonce": 1354335107,
1001 | "isDeleted": false,
1002 | "id": "vJwd2LS9grrvUFlbCugEG",
1003 | "fillStyle": "hachure",
1004 | "strokeWidth": 2,
1005 | "strokeStyle": "solid",
1006 | "roughness": 0,
1007 | "opacity": 100,
1008 | "angle": 0,
1009 | "x": 1149.25,
1010 | "y": 467,
1011 | "strokeColor": "#000000",
1012 | "backgroundColor": "transparent",
1013 | "width": 46,
1014 | "height": 46,
1015 | "seed": 1072510330,
1016 | "groupIds": [],
1017 | "strokeSharpness": "sharp",
1018 | "boundElementIds": [
1019 | "x_nMpLlFEV43XGOAM6Gxj"
1020 | ]
1021 | },
1022 | {
1023 | "type": "text",
1024 | "version": 325,
1025 | "versionNonce": 1412737581,
1026 | "isDeleted": false,
1027 | "id": "BC5sEBFfRV7OfrhN1L1Gq",
1028 | "fillStyle": "hachure",
1029 | "strokeWidth": 1,
1030 | "strokeStyle": "dashed",
1031 | "roughness": 0,
1032 | "opacity": 100,
1033 | "angle": 0,
1034 | "x": 1111.75,
1035 | "y": 428.5,
1036 | "strokeColor": "#000000",
1037 | "backgroundColor": "transparent",
1038 | "width": 144,
1039 | "height": 26,
1040 | "seed": 1757837094,
1041 | "groupIds": [],
1042 | "strokeSharpness": "sharp",
1043 | "boundElementIds": [
1044 | "xDobZ6graJnZZP8g59wJ4"
1045 | ],
1046 | "fontSize": 20,
1047 | "fontFamily": 1,
1048 | "text": "Mongo adapter",
1049 | "baseline": 18,
1050 | "textAlign": "center",
1051 | "verticalAlign": "top"
1052 | },
1053 | {
1054 | "type": "arrow",
1055 | "version": 248,
1056 | "versionNonce": 912530211,
1057 | "isDeleted": false,
1058 | "id": "x_nMpLlFEV43XGOAM6Gxj",
1059 | "fillStyle": "hachure",
1060 | "strokeWidth": 2,
1061 | "strokeStyle": "solid",
1062 | "roughness": 0,
1063 | "opacity": 100,
1064 | "angle": 0,
1065 | "x": 1123.25,
1066 | "y": 489,
1067 | "strokeColor": "#000000",
1068 | "backgroundColor": "transparent",
1069 | "width": 109,
1070 | "height": 1,
1071 | "seed": 1180464698,
1072 | "groupIds": [],
1073 | "strokeSharpness": "round",
1074 | "boundElementIds": [],
1075 | "startBinding": {
1076 | "elementId": "dJhDWOnAJOszWt_UNEXdt",
1077 | "focus": -0.17704646556482773,
1078 | "gap": 23.75
1079 | },
1080 | "endBinding": null,
1081 | "lastCommittedPoint": null,
1082 | "startArrowhead": null,
1083 | "endArrowhead": "arrow",
1084 | "points": [
1085 | [
1086 | 0,
1087 | 0
1088 | ],
1089 | [
1090 | -109,
1091 | -1
1092 | ]
1093 | ]
1094 | },
1095 | {
1096 | "type": "arrow",
1097 | "version": 239,
1098 | "versionNonce": 1708711053,
1099 | "isDeleted": false,
1100 | "id": "qmYaJfZ9NO1RK7YHGQGo6",
1101 | "fillStyle": "hachure",
1102 | "strokeWidth": 2,
1103 | "strokeStyle": "solid",
1104 | "roughness": 0,
1105 | "opacity": 100,
1106 | "angle": 0,
1107 | "x": 1119.9214748277186,
1108 | "y": 479.7229508196721,
1109 | "strokeColor": "#000000",
1110 | "backgroundColor": "transparent",
1111 | "width": 104.67147482771861,
1112 | "height": 53.72295081967212,
1113 | "seed": 880321126,
1114 | "groupIds": [],
1115 | "strokeSharpness": "round",
1116 | "boundElementIds": [],
1117 | "startBinding": {
1118 | "elementId": "dJhDWOnAJOszWt_UNEXdt",
1119 | "focus": 0.304824173970933,
1120 | "gap": 20.421474827718612
1121 | },
1122 | "endBinding": null,
1123 | "lastCommittedPoint": null,
1124 | "startArrowhead": null,
1125 | "endArrowhead": "arrow",
1126 | "points": [
1127 | [
1128 | 0,
1129 | 0
1130 | ],
1131 | [
1132 | -104.67147482771861,
1133 | -53.72295081967212
1134 | ]
1135 | ]
1136 | },
1137 | {
1138 | "type": "ellipse",
1139 | "version": 77,
1140 | "versionNonce": 639286979,
1141 | "isDeleted": false,
1142 | "id": "EQmjbilyrf3OcSwGbMZrg",
1143 | "fillStyle": "hachure",
1144 | "strokeWidth": 2,
1145 | "strokeStyle": "solid",
1146 | "roughness": 0,
1147 | "opacity": 100,
1148 | "angle": 0,
1149 | "x": 1224,
1150 | "y": 222,
1151 | "strokeColor": "#000000",
1152 | "backgroundColor": "transparent",
1153 | "width": 104.99999999999999,
1154 | "height": 93.00000000000001,
1155 | "seed": 1885795942,
1156 | "groupIds": [],
1157 | "strokeSharpness": "sharp",
1158 | "boundElementIds": [
1159 | "xDobZ6graJnZZP8g59wJ4",
1160 | "eU1gfEXnHSjxc-pEgv43A"
1161 | ]
1162 | },
1163 | {
1164 | "type": "text",
1165 | "version": 26,
1166 | "versionNonce": 1829225197,
1167 | "isDeleted": false,
1168 | "id": "wV6Y3XyIP5TbX50EF6xs6",
1169 | "fillStyle": "hachure",
1170 | "strokeWidth": 2,
1171 | "strokeStyle": "solid",
1172 | "roughness": 0,
1173 | "opacity": 100,
1174 | "angle": 0,
1175 | "x": 1231,
1176 | "y": 256.5,
1177 | "strokeColor": "#000000",
1178 | "backgroundColor": "transparent",
1179 | "width": 90,
1180 | "height": 26,
1181 | "seed": 1433614630,
1182 | "groupIds": [],
1183 | "strokeSharpness": "sharp",
1184 | "boundElementIds": [],
1185 | "fontSize": 20,
1186 | "fontFamily": 1,
1187 | "text": "MongoDB",
1188 | "baseline": 18,
1189 | "textAlign": "center",
1190 | "verticalAlign": "middle"
1191 | },
1192 | {
1193 | "type": "arrow",
1194 | "version": 59,
1195 | "versionNonce": 444329571,
1196 | "isDeleted": false,
1197 | "id": "eU1gfEXnHSjxc-pEgv43A",
1198 | "fillStyle": "hachure",
1199 | "strokeWidth": 2,
1200 | "strokeStyle": "solid",
1201 | "roughness": 0,
1202 | "opacity": 100,
1203 | "angle": 0,
1204 | "x": 1194,
1205 | "y": 115,
1206 | "strokeColor": "#000000",
1207 | "backgroundColor": "transparent",
1208 | "width": 48.96786219306841,
1209 | "height": 92.0339835266262,
1210 | "seed": 1145880934,
1211 | "groupIds": [],
1212 | "strokeSharpness": "round",
1213 | "boundElementIds": [],
1214 | "startBinding": null,
1215 | "endBinding": {
1216 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
1217 | "focus": -0.01427272665357157,
1218 | "gap": 22.26959346244992
1219 | },
1220 | "lastCommittedPoint": null,
1221 | "startArrowhead": null,
1222 | "endArrowhead": "arrow",
1223 | "points": [
1224 | [
1225 | 0,
1226 | 0
1227 | ],
1228 | [
1229 | 48.96786219306841,
1230 | 92.0339835266262
1231 | ]
1232 | ]
1233 | },
1234 | {
1235 | "type": "arrow",
1236 | "version": 97,
1237 | "versionNonce": 1313529165,
1238 | "isDeleted": false,
1239 | "id": "xDobZ6graJnZZP8g59wJ4",
1240 | "fillStyle": "hachure",
1241 | "strokeWidth": 2,
1242 | "strokeStyle": "solid",
1243 | "roughness": 0,
1244 | "opacity": 100,
1245 | "angle": 0,
1246 | "x": 1248.7795172073997,
1247 | "y": 327.50331785153037,
1248 | "strokeColor": "#000000",
1249 | "backgroundColor": "transparent",
1250 | "width": 28.990742099195813,
1251 | "height": 90.08927474106224,
1252 | "seed": 1443544058,
1253 | "groupIds": [],
1254 | "strokeSharpness": "round",
1255 | "boundElementIds": [],
1256 | "startBinding": {
1257 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
1258 | "gap": 17.719220537742967,
1259 | "focus": 0.13877232938640205
1260 | },
1261 | "endBinding": null,
1262 | "lastCommittedPoint": null,
1263 | "startArrowhead": null,
1264 | "endArrowhead": "arrow",
1265 | "points": [
1266 | [
1267 | 0,
1268 | 0
1269 | ],
1270 | [
1271 | -28.990742099195813,
1272 | 90.08927474106224
1273 | ]
1274 | ]
1275 | }
1276 | ],
1277 | "appState": {
1278 | "gridSize": null,
1279 | "viewBackgroundColor": "#ffffff"
1280 | }
1281 | }
--------------------------------------------------------------------------------
/examples/ttl-example/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ttl-example",
3 | "version": "0.0.1",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "ttl-example",
9 | "version": "0.0.1",
10 | "dependencies": {
11 | "@socket.io/mongo-adapter": "^0.3.2",
12 | "mongodb": "^6.3.0",
13 | "socket.io": "^4.7.4",
14 | "socket.io-client": "^4.7.4"
15 | }
16 | },
17 | "node_modules/@aws-crypto/crc32": {
18 | "version": "3.0.0",
19 | "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz",
20 | "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==",
21 | "optional": true,
22 | "peer": true,
23 | "dependencies": {
24 | "@aws-crypto/util": "^3.0.0",
25 | "@aws-sdk/types": "^3.222.0",
26 | "tslib": "^1.11.1"
27 | }
28 | },
29 | "node_modules/@aws-crypto/crc32/node_modules/tslib": {
30 | "version": "1.14.1",
31 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
32 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
33 | "optional": true,
34 | "peer": true
35 | },
36 | "node_modules/@aws-crypto/ie11-detection": {
37 | "version": "3.0.0",
38 | "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz",
39 | "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==",
40 | "optional": true,
41 | "peer": true,
42 | "dependencies": {
43 | "tslib": "^1.11.1"
44 | }
45 | },
46 | "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": {
47 | "version": "1.14.1",
48 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
49 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
50 | "optional": true,
51 | "peer": true
52 | },
53 | "node_modules/@aws-crypto/sha256-browser": {
54 | "version": "3.0.0",
55 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz",
56 | "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==",
57 | "optional": true,
58 | "peer": true,
59 | "dependencies": {
60 | "@aws-crypto/ie11-detection": "^3.0.0",
61 | "@aws-crypto/sha256-js": "^3.0.0",
62 | "@aws-crypto/supports-web-crypto": "^3.0.0",
63 | "@aws-crypto/util": "^3.0.0",
64 | "@aws-sdk/types": "^3.222.0",
65 | "@aws-sdk/util-locate-window": "^3.0.0",
66 | "@aws-sdk/util-utf8-browser": "^3.0.0",
67 | "tslib": "^1.11.1"
68 | }
69 | },
70 | "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": {
71 | "version": "1.14.1",
72 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
73 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
74 | "optional": true,
75 | "peer": true
76 | },
77 | "node_modules/@aws-crypto/sha256-js": {
78 | "version": "3.0.0",
79 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz",
80 | "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==",
81 | "optional": true,
82 | "peer": true,
83 | "dependencies": {
84 | "@aws-crypto/util": "^3.0.0",
85 | "@aws-sdk/types": "^3.222.0",
86 | "tslib": "^1.11.1"
87 | }
88 | },
89 | "node_modules/@aws-crypto/sha256-js/node_modules/tslib": {
90 | "version": "1.14.1",
91 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
92 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
93 | "optional": true,
94 | "peer": true
95 | },
96 | "node_modules/@aws-crypto/supports-web-crypto": {
97 | "version": "3.0.0",
98 | "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz",
99 | "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==",
100 | "optional": true,
101 | "peer": true,
102 | "dependencies": {
103 | "tslib": "^1.11.1"
104 | }
105 | },
106 | "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": {
107 | "version": "1.14.1",
108 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
109 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
110 | "optional": true,
111 | "peer": true
112 | },
113 | "node_modules/@aws-crypto/util": {
114 | "version": "3.0.0",
115 | "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz",
116 | "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==",
117 | "optional": true,
118 | "peer": true,
119 | "dependencies": {
120 | "@aws-sdk/types": "^3.222.0",
121 | "@aws-sdk/util-utf8-browser": "^3.0.0",
122 | "tslib": "^1.11.1"
123 | }
124 | },
125 | "node_modules/@aws-crypto/util/node_modules/tslib": {
126 | "version": "1.14.1",
127 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
128 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
129 | "optional": true,
130 | "peer": true
131 | },
132 | "node_modules/@aws-sdk/client-cognito-identity": {
133 | "version": "3.496.0",
134 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.496.0.tgz",
135 | "integrity": "sha512-rb0Pv8jzJ8XBNmhKl/Up8jnaLWPKuW622s9RR9JyVEu/uUR5tyhdEJvEsS88A9a0+BTRt4G7X1VnUXWAgi8hxQ==",
136 | "optional": true,
137 | "peer": true,
138 | "dependencies": {
139 | "@aws-crypto/sha256-browser": "3.0.0",
140 | "@aws-crypto/sha256-js": "3.0.0",
141 | "@aws-sdk/client-sts": "3.496.0",
142 | "@aws-sdk/core": "3.496.0",
143 | "@aws-sdk/credential-provider-node": "3.496.0",
144 | "@aws-sdk/middleware-host-header": "3.496.0",
145 | "@aws-sdk/middleware-logger": "3.496.0",
146 | "@aws-sdk/middleware-recursion-detection": "3.496.0",
147 | "@aws-sdk/middleware-signing": "3.496.0",
148 | "@aws-sdk/middleware-user-agent": "3.496.0",
149 | "@aws-sdk/region-config-resolver": "3.496.0",
150 | "@aws-sdk/types": "3.496.0",
151 | "@aws-sdk/util-endpoints": "3.496.0",
152 | "@aws-sdk/util-user-agent-browser": "3.496.0",
153 | "@aws-sdk/util-user-agent-node": "3.496.0",
154 | "@smithy/config-resolver": "^2.1.1",
155 | "@smithy/core": "^1.3.1",
156 | "@smithy/fetch-http-handler": "^2.4.1",
157 | "@smithy/hash-node": "^2.1.1",
158 | "@smithy/invalid-dependency": "^2.1.1",
159 | "@smithy/middleware-content-length": "^2.1.1",
160 | "@smithy/middleware-endpoint": "^2.4.1",
161 | "@smithy/middleware-retry": "^2.1.1",
162 | "@smithy/middleware-serde": "^2.1.1",
163 | "@smithy/middleware-stack": "^2.1.1",
164 | "@smithy/node-config-provider": "^2.2.1",
165 | "@smithy/node-http-handler": "^2.3.1",
166 | "@smithy/protocol-http": "^3.1.1",
167 | "@smithy/smithy-client": "^2.3.1",
168 | "@smithy/types": "^2.9.1",
169 | "@smithy/url-parser": "^2.1.1",
170 | "@smithy/util-base64": "^2.1.1",
171 | "@smithy/util-body-length-browser": "^2.1.1",
172 | "@smithy/util-body-length-node": "^2.2.1",
173 | "@smithy/util-defaults-mode-browser": "^2.1.1",
174 | "@smithy/util-defaults-mode-node": "^2.1.1",
175 | "@smithy/util-endpoints": "^1.1.1",
176 | "@smithy/util-retry": "^2.1.1",
177 | "@smithy/util-utf8": "^2.1.1",
178 | "tslib": "^2.5.0"
179 | },
180 | "engines": {
181 | "node": ">=14.0.0"
182 | }
183 | },
184 | "node_modules/@aws-sdk/client-sso": {
185 | "version": "3.496.0",
186 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.496.0.tgz",
187 | "integrity": "sha512-fuaMuxKg7CMUsP9l3kxYWCOxFsBjdA0xj5nlikaDm1661/gB4KkAiGqRY8LsQkpNXvXU8Nj+f7oCFADFyGYzyw==",
188 | "optional": true,
189 | "peer": true,
190 | "dependencies": {
191 | "@aws-crypto/sha256-browser": "3.0.0",
192 | "@aws-crypto/sha256-js": "3.0.0",
193 | "@aws-sdk/core": "3.496.0",
194 | "@aws-sdk/middleware-host-header": "3.496.0",
195 | "@aws-sdk/middleware-logger": "3.496.0",
196 | "@aws-sdk/middleware-recursion-detection": "3.496.0",
197 | "@aws-sdk/middleware-user-agent": "3.496.0",
198 | "@aws-sdk/region-config-resolver": "3.496.0",
199 | "@aws-sdk/types": "3.496.0",
200 | "@aws-sdk/util-endpoints": "3.496.0",
201 | "@aws-sdk/util-user-agent-browser": "3.496.0",
202 | "@aws-sdk/util-user-agent-node": "3.496.0",
203 | "@smithy/config-resolver": "^2.1.1",
204 | "@smithy/core": "^1.3.1",
205 | "@smithy/fetch-http-handler": "^2.4.1",
206 | "@smithy/hash-node": "^2.1.1",
207 | "@smithy/invalid-dependency": "^2.1.1",
208 | "@smithy/middleware-content-length": "^2.1.1",
209 | "@smithy/middleware-endpoint": "^2.4.1",
210 | "@smithy/middleware-retry": "^2.1.1",
211 | "@smithy/middleware-serde": "^2.1.1",
212 | "@smithy/middleware-stack": "^2.1.1",
213 | "@smithy/node-config-provider": "^2.2.1",
214 | "@smithy/node-http-handler": "^2.3.1",
215 | "@smithy/protocol-http": "^3.1.1",
216 | "@smithy/smithy-client": "^2.3.1",
217 | "@smithy/types": "^2.9.1",
218 | "@smithy/url-parser": "^2.1.1",
219 | "@smithy/util-base64": "^2.1.1",
220 | "@smithy/util-body-length-browser": "^2.1.1",
221 | "@smithy/util-body-length-node": "^2.2.1",
222 | "@smithy/util-defaults-mode-browser": "^2.1.1",
223 | "@smithy/util-defaults-mode-node": "^2.1.1",
224 | "@smithy/util-endpoints": "^1.1.1",
225 | "@smithy/util-retry": "^2.1.1",
226 | "@smithy/util-utf8": "^2.1.1",
227 | "tslib": "^2.5.0"
228 | },
229 | "engines": {
230 | "node": ">=14.0.0"
231 | }
232 | },
233 | "node_modules/@aws-sdk/client-sts": {
234 | "version": "3.496.0",
235 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.496.0.tgz",
236 | "integrity": "sha512-3pSdqgegdwbK3CT1WvGHhA+Bf91R9cr8G1Ynp+iU2wZvy8ueJfMUk0NYfjo3EEv0YhSbMLKuduzZfvQHFHXYhw==",
237 | "optional": true,
238 | "peer": true,
239 | "dependencies": {
240 | "@aws-crypto/sha256-browser": "3.0.0",
241 | "@aws-crypto/sha256-js": "3.0.0",
242 | "@aws-sdk/core": "3.496.0",
243 | "@aws-sdk/credential-provider-node": "3.496.0",
244 | "@aws-sdk/middleware-host-header": "3.496.0",
245 | "@aws-sdk/middleware-logger": "3.496.0",
246 | "@aws-sdk/middleware-recursion-detection": "3.496.0",
247 | "@aws-sdk/middleware-user-agent": "3.496.0",
248 | "@aws-sdk/region-config-resolver": "3.496.0",
249 | "@aws-sdk/types": "3.496.0",
250 | "@aws-sdk/util-endpoints": "3.496.0",
251 | "@aws-sdk/util-user-agent-browser": "3.496.0",
252 | "@aws-sdk/util-user-agent-node": "3.496.0",
253 | "@smithy/config-resolver": "^2.1.1",
254 | "@smithy/core": "^1.3.1",
255 | "@smithy/fetch-http-handler": "^2.4.1",
256 | "@smithy/hash-node": "^2.1.1",
257 | "@smithy/invalid-dependency": "^2.1.1",
258 | "@smithy/middleware-content-length": "^2.1.1",
259 | "@smithy/middleware-endpoint": "^2.4.1",
260 | "@smithy/middleware-retry": "^2.1.1",
261 | "@smithy/middleware-serde": "^2.1.1",
262 | "@smithy/middleware-stack": "^2.1.1",
263 | "@smithy/node-config-provider": "^2.2.1",
264 | "@smithy/node-http-handler": "^2.3.1",
265 | "@smithy/protocol-http": "^3.1.1",
266 | "@smithy/smithy-client": "^2.3.1",
267 | "@smithy/types": "^2.9.1",
268 | "@smithy/url-parser": "^2.1.1",
269 | "@smithy/util-base64": "^2.1.1",
270 | "@smithy/util-body-length-browser": "^2.1.1",
271 | "@smithy/util-body-length-node": "^2.2.1",
272 | "@smithy/util-defaults-mode-browser": "^2.1.1",
273 | "@smithy/util-defaults-mode-node": "^2.1.1",
274 | "@smithy/util-endpoints": "^1.1.1",
275 | "@smithy/util-middleware": "^2.1.1",
276 | "@smithy/util-retry": "^2.1.1",
277 | "@smithy/util-utf8": "^2.1.1",
278 | "fast-xml-parser": "4.2.5",
279 | "tslib": "^2.5.0"
280 | },
281 | "engines": {
282 | "node": ">=14.0.0"
283 | }
284 | },
285 | "node_modules/@aws-sdk/core": {
286 | "version": "3.496.0",
287 | "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.496.0.tgz",
288 | "integrity": "sha512-yT+ug7Cw/3eJi7x2es0+46x12+cIJm5Xv+GPWsrTFD1TKgqO/VPEgfDtHFagDNbFmjNQA65Ygc/kEdIX9ICX/A==",
289 | "optional": true,
290 | "peer": true,
291 | "dependencies": {
292 | "@smithy/core": "^1.3.1",
293 | "@smithy/protocol-http": "^3.1.1",
294 | "@smithy/signature-v4": "^2.1.1",
295 | "@smithy/smithy-client": "^2.3.1",
296 | "@smithy/types": "^2.9.1",
297 | "tslib": "^2.5.0"
298 | },
299 | "engines": {
300 | "node": ">=14.0.0"
301 | }
302 | },
303 | "node_modules/@aws-sdk/credential-provider-cognito-identity": {
304 | "version": "3.496.0",
305 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.496.0.tgz",
306 | "integrity": "sha512-LIB9hom5mqGxk+hdbpZnxIJ4F1c5ZuY5uu3aWy9luowci03Z5nzYYepzBwpoE5Lk102gqVKeia//mRr25blzWQ==",
307 | "optional": true,
308 | "peer": true,
309 | "dependencies": {
310 | "@aws-sdk/client-cognito-identity": "3.496.0",
311 | "@aws-sdk/types": "3.496.0",
312 | "@smithy/property-provider": "^2.1.1",
313 | "@smithy/types": "^2.9.1",
314 | "tslib": "^2.5.0"
315 | },
316 | "engines": {
317 | "node": ">=14.0.0"
318 | }
319 | },
320 | "node_modules/@aws-sdk/credential-provider-env": {
321 | "version": "3.496.0",
322 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.496.0.tgz",
323 | "integrity": "sha512-lukQMJ8SWWP5RqkRNOHi/H+WMhRvSWa3Fc5Jf/VP6xHiPLfF1XafcvthtV91e0VwPCiseI+HqChrcGq8pvnxHw==",
324 | "optional": true,
325 | "peer": true,
326 | "dependencies": {
327 | "@aws-sdk/types": "3.496.0",
328 | "@smithy/property-provider": "^2.1.1",
329 | "@smithy/types": "^2.9.1",
330 | "tslib": "^2.5.0"
331 | },
332 | "engines": {
333 | "node": ">=14.0.0"
334 | }
335 | },
336 | "node_modules/@aws-sdk/credential-provider-http": {
337 | "version": "3.496.0",
338 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.496.0.tgz",
339 | "integrity": "sha512-iphFlFX0qDFsE24XmFlcKmsR4uyNaqQrK+Y18mwSZMs1yWtL4Sck0rcTXU/cU2W3/xisjh7xFXK5L5aowjMZOg==",
340 | "optional": true,
341 | "peer": true,
342 | "dependencies": {
343 | "@aws-sdk/types": "3.496.0",
344 | "@smithy/fetch-http-handler": "^2.4.1",
345 | "@smithy/node-http-handler": "^2.3.1",
346 | "@smithy/property-provider": "^2.1.1",
347 | "@smithy/protocol-http": "^3.1.1",
348 | "@smithy/smithy-client": "^2.3.1",
349 | "@smithy/types": "^2.9.1",
350 | "@smithy/util-stream": "^2.1.1",
351 | "tslib": "^2.5.0"
352 | },
353 | "engines": {
354 | "node": ">=14.0.0"
355 | }
356 | },
357 | "node_modules/@aws-sdk/credential-provider-ini": {
358 | "version": "3.496.0",
359 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.496.0.tgz",
360 | "integrity": "sha512-2nD1jp1sIwcQaWK1y/9ruQOkW16RUxZpzgjbW/gnK3iiUXwx+/FNQWxshud+GTSx3Q4x6eIhqsbjtP4VVPPuUA==",
361 | "optional": true,
362 | "peer": true,
363 | "dependencies": {
364 | "@aws-sdk/credential-provider-env": "3.496.0",
365 | "@aws-sdk/credential-provider-process": "3.496.0",
366 | "@aws-sdk/credential-provider-sso": "3.496.0",
367 | "@aws-sdk/credential-provider-web-identity": "3.496.0",
368 | "@aws-sdk/types": "3.496.0",
369 | "@smithy/credential-provider-imds": "^2.2.1",
370 | "@smithy/property-provider": "^2.1.1",
371 | "@smithy/shared-ini-file-loader": "^2.3.1",
372 | "@smithy/types": "^2.9.1",
373 | "tslib": "^2.5.0"
374 | },
375 | "engines": {
376 | "node": ">=14.0.0"
377 | }
378 | },
379 | "node_modules/@aws-sdk/credential-provider-node": {
380 | "version": "3.496.0",
381 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.496.0.tgz",
382 | "integrity": "sha512-IVF9RvLePfRa5S5/eBIRChJCWOzQkGwM8P/L79Gl84u/cH2oSG4NtUI/YTDlrtmnYn7YsGhINSV0WnzfF2twfQ==",
383 | "optional": true,
384 | "peer": true,
385 | "dependencies": {
386 | "@aws-sdk/credential-provider-env": "3.496.0",
387 | "@aws-sdk/credential-provider-ini": "3.496.0",
388 | "@aws-sdk/credential-provider-process": "3.496.0",
389 | "@aws-sdk/credential-provider-sso": "3.496.0",
390 | "@aws-sdk/credential-provider-web-identity": "3.496.0",
391 | "@aws-sdk/types": "3.496.0",
392 | "@smithy/credential-provider-imds": "^2.2.1",
393 | "@smithy/property-provider": "^2.1.1",
394 | "@smithy/shared-ini-file-loader": "^2.3.1",
395 | "@smithy/types": "^2.9.1",
396 | "tslib": "^2.5.0"
397 | },
398 | "engines": {
399 | "node": ">=14.0.0"
400 | }
401 | },
402 | "node_modules/@aws-sdk/credential-provider-process": {
403 | "version": "3.496.0",
404 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.496.0.tgz",
405 | "integrity": "sha512-/YZscCTGOKVmGr916Th4XF8Sz6JDtZ/n2loHG9exok9iy/qIbACsTRNLP9zexPxhPoue/oZqecY5xbVljfY34A==",
406 | "optional": true,
407 | "peer": true,
408 | "dependencies": {
409 | "@aws-sdk/types": "3.496.0",
410 | "@smithy/property-provider": "^2.1.1",
411 | "@smithy/shared-ini-file-loader": "^2.3.1",
412 | "@smithy/types": "^2.9.1",
413 | "tslib": "^2.5.0"
414 | },
415 | "engines": {
416 | "node": ">=14.0.0"
417 | }
418 | },
419 | "node_modules/@aws-sdk/credential-provider-sso": {
420 | "version": "3.496.0",
421 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.496.0.tgz",
422 | "integrity": "sha512-eP7GxpT2QYubSDG7uk1GJW4eNymZCq65IxDyEFCXOP/kfqkxriCY+iVEFG6/Mo3LxvgrgHXU4jxrCAXMAWN43g==",
423 | "optional": true,
424 | "peer": true,
425 | "dependencies": {
426 | "@aws-sdk/client-sso": "3.496.0",
427 | "@aws-sdk/token-providers": "3.496.0",
428 | "@aws-sdk/types": "3.496.0",
429 | "@smithy/property-provider": "^2.1.1",
430 | "@smithy/shared-ini-file-loader": "^2.3.1",
431 | "@smithy/types": "^2.9.1",
432 | "tslib": "^2.5.0"
433 | },
434 | "engines": {
435 | "node": ">=14.0.0"
436 | }
437 | },
438 | "node_modules/@aws-sdk/credential-provider-web-identity": {
439 | "version": "3.496.0",
440 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.496.0.tgz",
441 | "integrity": "sha512-IbP+qLlvJSpNPj+zW6TtFuLRTK5Tf0hW+2pom4vFyi5YSH4pn8UOC136UdewX8vhXGS9BJQ5zBDMasIyl5VeGQ==",
442 | "optional": true,
443 | "peer": true,
444 | "dependencies": {
445 | "@aws-sdk/types": "3.496.0",
446 | "@smithy/property-provider": "^2.1.1",
447 | "@smithy/types": "^2.9.1",
448 | "tslib": "^2.5.0"
449 | },
450 | "engines": {
451 | "node": ">=14.0.0"
452 | }
453 | },
454 | "node_modules/@aws-sdk/credential-providers": {
455 | "version": "3.496.0",
456 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.496.0.tgz",
457 | "integrity": "sha512-JqdSHFY3t+QMdS7Iok/ymvU3bZjVY7YuX9xroJJjMM/gkw+TxnJtVw/uIGsmoK1FT2KX+Dg4i/gmVyQAWubSJw==",
458 | "optional": true,
459 | "peer": true,
460 | "dependencies": {
461 | "@aws-sdk/client-cognito-identity": "3.496.0",
462 | "@aws-sdk/client-sso": "3.496.0",
463 | "@aws-sdk/client-sts": "3.496.0",
464 | "@aws-sdk/credential-provider-cognito-identity": "3.496.0",
465 | "@aws-sdk/credential-provider-env": "3.496.0",
466 | "@aws-sdk/credential-provider-http": "3.496.0",
467 | "@aws-sdk/credential-provider-ini": "3.496.0",
468 | "@aws-sdk/credential-provider-node": "3.496.0",
469 | "@aws-sdk/credential-provider-process": "3.496.0",
470 | "@aws-sdk/credential-provider-sso": "3.496.0",
471 | "@aws-sdk/credential-provider-web-identity": "3.496.0",
472 | "@aws-sdk/types": "3.496.0",
473 | "@smithy/credential-provider-imds": "^2.2.1",
474 | "@smithy/property-provider": "^2.1.1",
475 | "@smithy/types": "^2.9.1",
476 | "tslib": "^2.5.0"
477 | },
478 | "engines": {
479 | "node": ">=14.0.0"
480 | }
481 | },
482 | "node_modules/@aws-sdk/middleware-host-header": {
483 | "version": "3.496.0",
484 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.496.0.tgz",
485 | "integrity": "sha512-jUdPpSJeqCYXf6hSjfwsfHway7peIV8Vz51w/BN91bF4vB/bYwAC5o9/iJiK/EoByp5asxA8fg9wFOyGjzdbLg==",
486 | "optional": true,
487 | "peer": true,
488 | "dependencies": {
489 | "@aws-sdk/types": "3.496.0",
490 | "@smithy/protocol-http": "^3.1.1",
491 | "@smithy/types": "^2.9.1",
492 | "tslib": "^2.5.0"
493 | },
494 | "engines": {
495 | "node": ">=14.0.0"
496 | }
497 | },
498 | "node_modules/@aws-sdk/middleware-logger": {
499 | "version": "3.496.0",
500 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.496.0.tgz",
501 | "integrity": "sha512-EwMVSY6iBMeGbVnvwdaFl/ClMS/YWtxCAo+bcEtgk8ltRuo7qgbJem8Km/fvWC1vdWvIbe4ArdJ8iGzq62ffAw==",
502 | "optional": true,
503 | "peer": true,
504 | "dependencies": {
505 | "@aws-sdk/types": "3.496.0",
506 | "@smithy/types": "^2.9.1",
507 | "tslib": "^2.5.0"
508 | },
509 | "engines": {
510 | "node": ">=14.0.0"
511 | }
512 | },
513 | "node_modules/@aws-sdk/middleware-recursion-detection": {
514 | "version": "3.496.0",
515 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.496.0.tgz",
516 | "integrity": "sha512-+IuOcFsfqg2WAnaEzH6KhVbicqCxtOq9w3DH2jwTpddRlCx2Kqf6wCzg8luhHRGyjBZdsbIS+OXwyMevoppawA==",
517 | "optional": true,
518 | "peer": true,
519 | "dependencies": {
520 | "@aws-sdk/types": "3.496.0",
521 | "@smithy/protocol-http": "^3.1.1",
522 | "@smithy/types": "^2.9.1",
523 | "tslib": "^2.5.0"
524 | },
525 | "engines": {
526 | "node": ">=14.0.0"
527 | }
528 | },
529 | "node_modules/@aws-sdk/middleware-signing": {
530 | "version": "3.496.0",
531 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.496.0.tgz",
532 | "integrity": "sha512-Oq73Brs4IConvWnRlh8jM1V7LHoTw9SVQklu/QW2FPlNrB3B8fuTdWHHYIWv7ybw1bykXoCY99v865Mmq/Or/g==",
533 | "optional": true,
534 | "peer": true,
535 | "dependencies": {
536 | "@aws-sdk/types": "3.496.0",
537 | "@smithy/property-provider": "^2.1.1",
538 | "@smithy/protocol-http": "^3.1.1",
539 | "@smithy/signature-v4": "^2.1.1",
540 | "@smithy/types": "^2.9.1",
541 | "@smithy/util-middleware": "^2.1.1",
542 | "tslib": "^2.5.0"
543 | },
544 | "engines": {
545 | "node": ">=14.0.0"
546 | }
547 | },
548 | "node_modules/@aws-sdk/middleware-user-agent": {
549 | "version": "3.496.0",
550 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.496.0.tgz",
551 | "integrity": "sha512-+iMtRxFk0GmFWNUF4ilxylOQd9PZdR4ZC9jkcPIh1PZlvKtpCyFywKlk5RRZKklSoJ/CttcqwhMvOXTNbWm/0w==",
552 | "optional": true,
553 | "peer": true,
554 | "dependencies": {
555 | "@aws-sdk/types": "3.496.0",
556 | "@aws-sdk/util-endpoints": "3.496.0",
557 | "@smithy/protocol-http": "^3.1.1",
558 | "@smithy/types": "^2.9.1",
559 | "tslib": "^2.5.0"
560 | },
561 | "engines": {
562 | "node": ">=14.0.0"
563 | }
564 | },
565 | "node_modules/@aws-sdk/region-config-resolver": {
566 | "version": "3.496.0",
567 | "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.496.0.tgz",
568 | "integrity": "sha512-URrNVOPHPgEDm6QFu6lDC2cUFs+Jx23mA3jEwCvoKlXiEY/ZoWjH8wlX3OMUlLrF1qoUTuD03jjrJzF6zoCgug==",
569 | "optional": true,
570 | "peer": true,
571 | "dependencies": {
572 | "@aws-sdk/types": "3.496.0",
573 | "@smithy/node-config-provider": "^2.2.1",
574 | "@smithy/types": "^2.9.1",
575 | "@smithy/util-config-provider": "^2.2.1",
576 | "@smithy/util-middleware": "^2.1.1",
577 | "tslib": "^2.5.0"
578 | },
579 | "engines": {
580 | "node": ">=14.0.0"
581 | }
582 | },
583 | "node_modules/@aws-sdk/token-providers": {
584 | "version": "3.496.0",
585 | "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.496.0.tgz",
586 | "integrity": "sha512-fyi8RcObEa1jNETJdc2H6q9VHrrdKCj/b6+fbLvymb7mUVRd0aWUn+24SNUImnSOnrwYnwaMfyyEC388X4MbFQ==",
587 | "optional": true,
588 | "peer": true,
589 | "dependencies": {
590 | "@aws-crypto/sha256-browser": "3.0.0",
591 | "@aws-crypto/sha256-js": "3.0.0",
592 | "@aws-sdk/middleware-host-header": "3.496.0",
593 | "@aws-sdk/middleware-logger": "3.496.0",
594 | "@aws-sdk/middleware-recursion-detection": "3.496.0",
595 | "@aws-sdk/middleware-user-agent": "3.496.0",
596 | "@aws-sdk/region-config-resolver": "3.496.0",
597 | "@aws-sdk/types": "3.496.0",
598 | "@aws-sdk/util-endpoints": "3.496.0",
599 | "@aws-sdk/util-user-agent-browser": "3.496.0",
600 | "@aws-sdk/util-user-agent-node": "3.496.0",
601 | "@smithy/config-resolver": "^2.1.1",
602 | "@smithy/fetch-http-handler": "^2.4.1",
603 | "@smithy/hash-node": "^2.1.1",
604 | "@smithy/invalid-dependency": "^2.1.1",
605 | "@smithy/middleware-content-length": "^2.1.1",
606 | "@smithy/middleware-endpoint": "^2.4.1",
607 | "@smithy/middleware-retry": "^2.1.1",
608 | "@smithy/middleware-serde": "^2.1.1",
609 | "@smithy/middleware-stack": "^2.1.1",
610 | "@smithy/node-config-provider": "^2.2.1",
611 | "@smithy/node-http-handler": "^2.3.1",
612 | "@smithy/property-provider": "^2.1.1",
613 | "@smithy/protocol-http": "^3.1.1",
614 | "@smithy/shared-ini-file-loader": "^2.3.1",
615 | "@smithy/smithy-client": "^2.3.1",
616 | "@smithy/types": "^2.9.1",
617 | "@smithy/url-parser": "^2.1.1",
618 | "@smithy/util-base64": "^2.1.1",
619 | "@smithy/util-body-length-browser": "^2.1.1",
620 | "@smithy/util-body-length-node": "^2.2.1",
621 | "@smithy/util-defaults-mode-browser": "^2.1.1",
622 | "@smithy/util-defaults-mode-node": "^2.1.1",
623 | "@smithy/util-endpoints": "^1.1.1",
624 | "@smithy/util-retry": "^2.1.1",
625 | "@smithy/util-utf8": "^2.1.1",
626 | "tslib": "^2.5.0"
627 | },
628 | "engines": {
629 | "node": ">=14.0.0"
630 | }
631 | },
632 | "node_modules/@aws-sdk/types": {
633 | "version": "3.496.0",
634 | "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz",
635 | "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==",
636 | "optional": true,
637 | "peer": true,
638 | "dependencies": {
639 | "@smithy/types": "^2.9.1",
640 | "tslib": "^2.5.0"
641 | },
642 | "engines": {
643 | "node": ">=14.0.0"
644 | }
645 | },
646 | "node_modules/@aws-sdk/util-endpoints": {
647 | "version": "3.496.0",
648 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.496.0.tgz",
649 | "integrity": "sha512-1QzOiWHi383ZwqSi/R2KgKCd7M+6DxkxI5acqLPm8mvDRDP2jRjrnVaC0g9/tlttWousGEemDUWStwrD2mVYSw==",
650 | "optional": true,
651 | "peer": true,
652 | "dependencies": {
653 | "@aws-sdk/types": "3.496.0",
654 | "@smithy/types": "^2.9.1",
655 | "@smithy/util-endpoints": "^1.1.1",
656 | "tslib": "^2.5.0"
657 | },
658 | "engines": {
659 | "node": ">=14.0.0"
660 | }
661 | },
662 | "node_modules/@aws-sdk/util-locate-window": {
663 | "version": "3.495.0",
664 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.495.0.tgz",
665 | "integrity": "sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==",
666 | "optional": true,
667 | "peer": true,
668 | "dependencies": {
669 | "tslib": "^2.5.0"
670 | },
671 | "engines": {
672 | "node": ">=14.0.0"
673 | }
674 | },
675 | "node_modules/@aws-sdk/util-user-agent-browser": {
676 | "version": "3.496.0",
677 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.496.0.tgz",
678 | "integrity": "sha512-4j2spN+h0I0qfSMsGvJXTfQBu1e18rPdekKvzsGJxhaAE1tNgUfUT4nbvc5uVn0sNjZmirskmJ3kfbzVOrqIFg==",
679 | "optional": true,
680 | "peer": true,
681 | "dependencies": {
682 | "@aws-sdk/types": "3.496.0",
683 | "@smithy/types": "^2.9.1",
684 | "bowser": "^2.11.0",
685 | "tslib": "^2.5.0"
686 | }
687 | },
688 | "node_modules/@aws-sdk/util-user-agent-node": {
689 | "version": "3.496.0",
690 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.496.0.tgz",
691 | "integrity": "sha512-h0Ax0jlDc7UIo3KoSI4C4tVLBFoiAdx3+DhTVfgLS7x93d41dMlziPoBX2RgdcFn37qnzw6AQKTVTMwDbRCGpg==",
692 | "optional": true,
693 | "peer": true,
694 | "dependencies": {
695 | "@aws-sdk/types": "3.496.0",
696 | "@smithy/node-config-provider": "^2.2.1",
697 | "@smithy/types": "^2.9.1",
698 | "tslib": "^2.5.0"
699 | },
700 | "engines": {
701 | "node": ">=14.0.0"
702 | },
703 | "peerDependencies": {
704 | "aws-crt": ">=1.0.0"
705 | },
706 | "peerDependenciesMeta": {
707 | "aws-crt": {
708 | "optional": true
709 | }
710 | }
711 | },
712 | "node_modules/@aws-sdk/util-utf8-browser": {
713 | "version": "3.259.0",
714 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz",
715 | "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==",
716 | "optional": true,
717 | "peer": true,
718 | "dependencies": {
719 | "tslib": "^2.3.1"
720 | }
721 | },
722 | "node_modules/@mongodb-js/saslprep": {
723 | "version": "1.1.4",
724 | "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz",
725 | "integrity": "sha512-8zJ8N1x51xo9hwPh6AWnKdLGEC5N3lDa6kms1YHmFBoRhTpJR6HG8wWk0td1MVCu9cD4YBrvjZEtd5Obw0Fbnw==",
726 | "dependencies": {
727 | "sparse-bitfield": "^3.0.3"
728 | }
729 | },
730 | "node_modules/@smithy/abort-controller": {
731 | "version": "2.1.1",
732 | "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.1.tgz",
733 | "integrity": "sha512-1+qdrUqLhaALYL0iOcN43EP6yAXXQ2wWZ6taf4S2pNGowmOc5gx+iMQv+E42JizNJjB0+gEadOXeV1Bf7JWL1Q==",
734 | "optional": true,
735 | "peer": true,
736 | "dependencies": {
737 | "@smithy/types": "^2.9.1",
738 | "tslib": "^2.5.0"
739 | },
740 | "engines": {
741 | "node": ">=14.0.0"
742 | }
743 | },
744 | "node_modules/@smithy/config-resolver": {
745 | "version": "2.1.1",
746 | "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.1.1.tgz",
747 | "integrity": "sha512-lxfLDpZm+AWAHPFZps5JfDoO9Ux1764fOgvRUBpHIO8HWHcSN1dkgsago1qLRVgm1BZ8RCm8cgv99QvtaOWIhw==",
748 | "optional": true,
749 | "peer": true,
750 | "dependencies": {
751 | "@smithy/node-config-provider": "^2.2.1",
752 | "@smithy/types": "^2.9.1",
753 | "@smithy/util-config-provider": "^2.2.1",
754 | "@smithy/util-middleware": "^2.1.1",
755 | "tslib": "^2.5.0"
756 | },
757 | "engines": {
758 | "node": ">=14.0.0"
759 | }
760 | },
761 | "node_modules/@smithy/core": {
762 | "version": "1.3.1",
763 | "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.1.tgz",
764 | "integrity": "sha512-tf+NIu9FkOh312b6M9G4D68is4Xr7qptzaZGZUREELF8ysE1yLKphqt7nsomjKZVwW7WE5pDDex9idowNGRQ/Q==",
765 | "optional": true,
766 | "peer": true,
767 | "dependencies": {
768 | "@smithy/middleware-endpoint": "^2.4.1",
769 | "@smithy/middleware-retry": "^2.1.1",
770 | "@smithy/middleware-serde": "^2.1.1",
771 | "@smithy/protocol-http": "^3.1.1",
772 | "@smithy/smithy-client": "^2.3.1",
773 | "@smithy/types": "^2.9.1",
774 | "@smithy/util-middleware": "^2.1.1",
775 | "tslib": "^2.5.0"
776 | },
777 | "engines": {
778 | "node": ">=14.0.0"
779 | }
780 | },
781 | "node_modules/@smithy/credential-provider-imds": {
782 | "version": "2.2.1",
783 | "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.2.1.tgz",
784 | "integrity": "sha512-7XHjZUxmZYnONheVQL7j5zvZXga+EWNgwEAP6OPZTi7l8J4JTeNh9aIOfE5fKHZ/ee2IeNOh54ZrSna+Vc6TFA==",
785 | "optional": true,
786 | "peer": true,
787 | "dependencies": {
788 | "@smithy/node-config-provider": "^2.2.1",
789 | "@smithy/property-provider": "^2.1.1",
790 | "@smithy/types": "^2.9.1",
791 | "@smithy/url-parser": "^2.1.1",
792 | "tslib": "^2.5.0"
793 | },
794 | "engines": {
795 | "node": ">=14.0.0"
796 | }
797 | },
798 | "node_modules/@smithy/eventstream-codec": {
799 | "version": "2.1.1",
800 | "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.1.1.tgz",
801 | "integrity": "sha512-E8KYBxBIuU4c+zrpR22VsVrOPoEDzk35bQR3E+xm4k6Pa6JqzkDOdMyf9Atac5GPNKHJBdVaQ4JtjdWX2rl/nw==",
802 | "optional": true,
803 | "peer": true,
804 | "dependencies": {
805 | "@aws-crypto/crc32": "3.0.0",
806 | "@smithy/types": "^2.9.1",
807 | "@smithy/util-hex-encoding": "^2.1.1",
808 | "tslib": "^2.5.0"
809 | }
810 | },
811 | "node_modules/@smithy/fetch-http-handler": {
812 | "version": "2.4.1",
813 | "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.4.1.tgz",
814 | "integrity": "sha512-VYGLinPsFqH68lxfRhjQaSkjXM7JysUOJDTNjHBuN/ykyRb2f1gyavN9+VhhPTWCy32L4yZ2fdhpCs/nStEicg==",
815 | "optional": true,
816 | "peer": true,
817 | "dependencies": {
818 | "@smithy/protocol-http": "^3.1.1",
819 | "@smithy/querystring-builder": "^2.1.1",
820 | "@smithy/types": "^2.9.1",
821 | "@smithy/util-base64": "^2.1.1",
822 | "tslib": "^2.5.0"
823 | }
824 | },
825 | "node_modules/@smithy/hash-node": {
826 | "version": "2.1.1",
827 | "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.1.1.tgz",
828 | "integrity": "sha512-Qhoq0N8f2OtCnvUpCf+g1vSyhYQrZjhSwvJ9qvR8BUGOtTXiyv2x1OD2e6jVGmlpC4E4ax1USHoyGfV9JFsACg==",
829 | "optional": true,
830 | "peer": true,
831 | "dependencies": {
832 | "@smithy/types": "^2.9.1",
833 | "@smithy/util-buffer-from": "^2.1.1",
834 | "@smithy/util-utf8": "^2.1.1",
835 | "tslib": "^2.5.0"
836 | },
837 | "engines": {
838 | "node": ">=14.0.0"
839 | }
840 | },
841 | "node_modules/@smithy/invalid-dependency": {
842 | "version": "2.1.1",
843 | "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.1.1.tgz",
844 | "integrity": "sha512-7WTgnKw+VPg8fxu2v9AlNOQ5yaz6RA54zOVB4f6vQuR0xFKd+RzlCpt0WidYTsye7F+FYDIaS/RnJW4pxjNInw==",
845 | "optional": true,
846 | "peer": true,
847 | "dependencies": {
848 | "@smithy/types": "^2.9.1",
849 | "tslib": "^2.5.0"
850 | }
851 | },
852 | "node_modules/@smithy/is-array-buffer": {
853 | "version": "2.1.1",
854 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz",
855 | "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==",
856 | "optional": true,
857 | "peer": true,
858 | "dependencies": {
859 | "tslib": "^2.5.0"
860 | },
861 | "engines": {
862 | "node": ">=14.0.0"
863 | }
864 | },
865 | "node_modules/@smithy/middleware-content-length": {
866 | "version": "2.1.1",
867 | "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.1.1.tgz",
868 | "integrity": "sha512-rSr9ezUl9qMgiJR0UVtVOGEZElMdGFyl8FzWEF5iEKTlcWxGr2wTqGfDwtH3LAB7h+FPkxqv4ZU4cpuCN9Kf/g==",
869 | "optional": true,
870 | "peer": true,
871 | "dependencies": {
872 | "@smithy/protocol-http": "^3.1.1",
873 | "@smithy/types": "^2.9.1",
874 | "tslib": "^2.5.0"
875 | },
876 | "engines": {
877 | "node": ">=14.0.0"
878 | }
879 | },
880 | "node_modules/@smithy/middleware-endpoint": {
881 | "version": "2.4.1",
882 | "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.4.1.tgz",
883 | "integrity": "sha512-XPZTb1E2Oav60Ven3n2PFx+rX9EDsU/jSTA8VDamt7FXks67ekjPY/XrmmPDQaFJOTUHJNKjd8+kZxVO5Ael4Q==",
884 | "optional": true,
885 | "peer": true,
886 | "dependencies": {
887 | "@smithy/middleware-serde": "^2.1.1",
888 | "@smithy/node-config-provider": "^2.2.1",
889 | "@smithy/shared-ini-file-loader": "^2.3.1",
890 | "@smithy/types": "^2.9.1",
891 | "@smithy/url-parser": "^2.1.1",
892 | "@smithy/util-middleware": "^2.1.1",
893 | "tslib": "^2.5.0"
894 | },
895 | "engines": {
896 | "node": ">=14.0.0"
897 | }
898 | },
899 | "node_modules/@smithy/middleware-retry": {
900 | "version": "2.1.1",
901 | "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.1.1.tgz",
902 | "integrity": "sha512-eMIHOBTXro6JZ+WWzZWd/8fS8ht5nS5KDQjzhNMHNRcG5FkNTqcKpYhw7TETMYzbLfhO5FYghHy1vqDWM4FLDA==",
903 | "optional": true,
904 | "peer": true,
905 | "dependencies": {
906 | "@smithy/node-config-provider": "^2.2.1",
907 | "@smithy/protocol-http": "^3.1.1",
908 | "@smithy/service-error-classification": "^2.1.1",
909 | "@smithy/smithy-client": "^2.3.1",
910 | "@smithy/types": "^2.9.1",
911 | "@smithy/util-middleware": "^2.1.1",
912 | "@smithy/util-retry": "^2.1.1",
913 | "tslib": "^2.5.0",
914 | "uuid": "^8.3.2"
915 | },
916 | "engines": {
917 | "node": ">=14.0.0"
918 | }
919 | },
920 | "node_modules/@smithy/middleware-serde": {
921 | "version": "2.1.1",
922 | "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.1.1.tgz",
923 | "integrity": "sha512-D8Gq0aQBeE1pxf3cjWVkRr2W54t+cdM2zx78tNrVhqrDykRA7asq8yVJij1u5NDtKzKqzBSPYh7iW0svUKg76g==",
924 | "optional": true,
925 | "peer": true,
926 | "dependencies": {
927 | "@smithy/types": "^2.9.1",
928 | "tslib": "^2.5.0"
929 | },
930 | "engines": {
931 | "node": ">=14.0.0"
932 | }
933 | },
934 | "node_modules/@smithy/middleware-stack": {
935 | "version": "2.1.1",
936 | "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.1.1.tgz",
937 | "integrity": "sha512-KPJhRlhsl8CjgGXK/DoDcrFGfAqoqvuwlbxy+uOO4g2Azn1dhH+GVfC3RAp+6PoL5PWPb+vt6Z23FP+Mr6qeCw==",
938 | "optional": true,
939 | "peer": true,
940 | "dependencies": {
941 | "@smithy/types": "^2.9.1",
942 | "tslib": "^2.5.0"
943 | },
944 | "engines": {
945 | "node": ">=14.0.0"
946 | }
947 | },
948 | "node_modules/@smithy/node-config-provider": {
949 | "version": "2.2.1",
950 | "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.2.1.tgz",
951 | "integrity": "sha512-epzK3x1xNxA9oJgHQ5nz+2j6DsJKdHfieb+YgJ7ATWxzNcB7Hc+Uya2TUck5MicOPhDV8HZImND7ZOecVr+OWg==",
952 | "optional": true,
953 | "peer": true,
954 | "dependencies": {
955 | "@smithy/property-provider": "^2.1.1",
956 | "@smithy/shared-ini-file-loader": "^2.3.1",
957 | "@smithy/types": "^2.9.1",
958 | "tslib": "^2.5.0"
959 | },
960 | "engines": {
961 | "node": ">=14.0.0"
962 | }
963 | },
964 | "node_modules/@smithy/node-http-handler": {
965 | "version": "2.3.1",
966 | "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.3.1.tgz",
967 | "integrity": "sha512-gLA8qK2nL9J0Rk/WEZSvgin4AppvuCYRYg61dcUo/uKxvMZsMInL5I5ZdJTogOvdfVug3N2dgI5ffcUfS4S9PA==",
968 | "optional": true,
969 | "peer": true,
970 | "dependencies": {
971 | "@smithy/abort-controller": "^2.1.1",
972 | "@smithy/protocol-http": "^3.1.1",
973 | "@smithy/querystring-builder": "^2.1.1",
974 | "@smithy/types": "^2.9.1",
975 | "tslib": "^2.5.0"
976 | },
977 | "engines": {
978 | "node": ">=14.0.0"
979 | }
980 | },
981 | "node_modules/@smithy/property-provider": {
982 | "version": "2.1.1",
983 | "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.1.1.tgz",
984 | "integrity": "sha512-FX7JhhD/o5HwSwg6GLK9zxrMUrGnb3PzNBrcthqHKBc3dH0UfgEAU24xnJ8F0uow5mj17UeBEOI6o3CF2k7Mhw==",
985 | "optional": true,
986 | "peer": true,
987 | "dependencies": {
988 | "@smithy/types": "^2.9.1",
989 | "tslib": "^2.5.0"
990 | },
991 | "engines": {
992 | "node": ">=14.0.0"
993 | }
994 | },
995 | "node_modules/@smithy/protocol-http": {
996 | "version": "3.1.1",
997 | "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.1.1.tgz",
998 | "integrity": "sha512-6ZRTSsaXuSL9++qEwH851hJjUA0OgXdQFCs+VDw4tGH256jQ3TjYY/i34N4vd24RV3nrjNsgd1yhb57uMoKbzQ==",
999 | "optional": true,
1000 | "peer": true,
1001 | "dependencies": {
1002 | "@smithy/types": "^2.9.1",
1003 | "tslib": "^2.5.0"
1004 | },
1005 | "engines": {
1006 | "node": ">=14.0.0"
1007 | }
1008 | },
1009 | "node_modules/@smithy/querystring-builder": {
1010 | "version": "2.1.1",
1011 | "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.1.tgz",
1012 | "integrity": "sha512-C/ko/CeEa8jdYE4gt6nHO5XDrlSJ3vdCG0ZAc6nD5ZIE7LBp0jCx4qoqp7eoutBu7VrGMXERSRoPqwi1WjCPbg==",
1013 | "optional": true,
1014 | "peer": true,
1015 | "dependencies": {
1016 | "@smithy/types": "^2.9.1",
1017 | "@smithy/util-uri-escape": "^2.1.1",
1018 | "tslib": "^2.5.0"
1019 | },
1020 | "engines": {
1021 | "node": ">=14.0.0"
1022 | }
1023 | },
1024 | "node_modules/@smithy/querystring-parser": {
1025 | "version": "2.1.1",
1026 | "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.1.1.tgz",
1027 | "integrity": "sha512-H4+6jKGVhG1W4CIxfBaSsbm98lOO88tpDWmZLgkJpt8Zkk/+uG0FmmqMuCAc3HNM2ZDV+JbErxr0l5BcuIf/XQ==",
1028 | "optional": true,
1029 | "peer": true,
1030 | "dependencies": {
1031 | "@smithy/types": "^2.9.1",
1032 | "tslib": "^2.5.0"
1033 | },
1034 | "engines": {
1035 | "node": ">=14.0.0"
1036 | }
1037 | },
1038 | "node_modules/@smithy/service-error-classification": {
1039 | "version": "2.1.1",
1040 | "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.1.tgz",
1041 | "integrity": "sha512-txEdZxPUgM1PwGvDvHzqhXisrc5LlRWYCf2yyHfvITWioAKat7srQvpjMAvgzf0t6t7j8yHrryXU9xt7RZqFpw==",
1042 | "optional": true,
1043 | "peer": true,
1044 | "dependencies": {
1045 | "@smithy/types": "^2.9.1"
1046 | },
1047 | "engines": {
1048 | "node": ">=14.0.0"
1049 | }
1050 | },
1051 | "node_modules/@smithy/shared-ini-file-loader": {
1052 | "version": "2.3.1",
1053 | "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.3.1.tgz",
1054 | "integrity": "sha512-2E2kh24igmIznHLB6H05Na4OgIEilRu0oQpYXo3LCNRrawHAcfDKq9004zJs+sAMt2X5AbY87CUCJ7IpqpSgdw==",
1055 | "optional": true,
1056 | "peer": true,
1057 | "dependencies": {
1058 | "@smithy/types": "^2.9.1",
1059 | "tslib": "^2.5.0"
1060 | },
1061 | "engines": {
1062 | "node": ">=14.0.0"
1063 | }
1064 | },
1065 | "node_modules/@smithy/signature-v4": {
1066 | "version": "2.1.1",
1067 | "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.1.1.tgz",
1068 | "integrity": "sha512-Hb7xub0NHuvvQD3YwDSdanBmYukoEkhqBjqoxo+bSdC0ryV9cTfgmNjuAQhTPYB6yeU7hTR+sPRiFMlxqv6kmg==",
1069 | "optional": true,
1070 | "peer": true,
1071 | "dependencies": {
1072 | "@smithy/eventstream-codec": "^2.1.1",
1073 | "@smithy/is-array-buffer": "^2.1.1",
1074 | "@smithy/types": "^2.9.1",
1075 | "@smithy/util-hex-encoding": "^2.1.1",
1076 | "@smithy/util-middleware": "^2.1.1",
1077 | "@smithy/util-uri-escape": "^2.1.1",
1078 | "@smithy/util-utf8": "^2.1.1",
1079 | "tslib": "^2.5.0"
1080 | },
1081 | "engines": {
1082 | "node": ">=14.0.0"
1083 | }
1084 | },
1085 | "node_modules/@smithy/smithy-client": {
1086 | "version": "2.3.1",
1087 | "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.3.1.tgz",
1088 | "integrity": "sha512-YsTdU8xVD64r2pLEwmltrNvZV6XIAC50LN6ivDopdt+YiF/jGH6PY9zUOu0CXD/d8GMB8gbhnpPsdrjAXHS9QA==",
1089 | "optional": true,
1090 | "peer": true,
1091 | "dependencies": {
1092 | "@smithy/middleware-endpoint": "^2.4.1",
1093 | "@smithy/middleware-stack": "^2.1.1",
1094 | "@smithy/protocol-http": "^3.1.1",
1095 | "@smithy/types": "^2.9.1",
1096 | "@smithy/util-stream": "^2.1.1",
1097 | "tslib": "^2.5.0"
1098 | },
1099 | "engines": {
1100 | "node": ">=14.0.0"
1101 | }
1102 | },
1103 | "node_modules/@smithy/types": {
1104 | "version": "2.9.1",
1105 | "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz",
1106 | "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==",
1107 | "optional": true,
1108 | "peer": true,
1109 | "dependencies": {
1110 | "tslib": "^2.5.0"
1111 | },
1112 | "engines": {
1113 | "node": ">=14.0.0"
1114 | }
1115 | },
1116 | "node_modules/@smithy/url-parser": {
1117 | "version": "2.1.1",
1118 | "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.1.1.tgz",
1119 | "integrity": "sha512-qC9Bv8f/vvFIEkHsiNrUKYNl8uKQnn4BdhXl7VzQRP774AwIjiSMMwkbT+L7Fk8W8rzYVifzJNYxv1HwvfBo3Q==",
1120 | "optional": true,
1121 | "peer": true,
1122 | "dependencies": {
1123 | "@smithy/querystring-parser": "^2.1.1",
1124 | "@smithy/types": "^2.9.1",
1125 | "tslib": "^2.5.0"
1126 | }
1127 | },
1128 | "node_modules/@smithy/util-base64": {
1129 | "version": "2.1.1",
1130 | "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.1.1.tgz",
1131 | "integrity": "sha512-UfHVpY7qfF/MrgndI5PexSKVTxSZIdz9InghTFa49QOvuu9I52zLPLUHXvHpNuMb1iD2vmc6R+zbv/bdMipR/g==",
1132 | "optional": true,
1133 | "peer": true,
1134 | "dependencies": {
1135 | "@smithy/util-buffer-from": "^2.1.1",
1136 | "tslib": "^2.5.0"
1137 | },
1138 | "engines": {
1139 | "node": ">=14.0.0"
1140 | }
1141 | },
1142 | "node_modules/@smithy/util-body-length-browser": {
1143 | "version": "2.1.1",
1144 | "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.1.1.tgz",
1145 | "integrity": "sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==",
1146 | "optional": true,
1147 | "peer": true,
1148 | "dependencies": {
1149 | "tslib": "^2.5.0"
1150 | }
1151 | },
1152 | "node_modules/@smithy/util-body-length-node": {
1153 | "version": "2.2.1",
1154 | "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.2.1.tgz",
1155 | "integrity": "sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==",
1156 | "optional": true,
1157 | "peer": true,
1158 | "dependencies": {
1159 | "tslib": "^2.5.0"
1160 | },
1161 | "engines": {
1162 | "node": ">=14.0.0"
1163 | }
1164 | },
1165 | "node_modules/@smithy/util-buffer-from": {
1166 | "version": "2.1.1",
1167 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz",
1168 | "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==",
1169 | "optional": true,
1170 | "peer": true,
1171 | "dependencies": {
1172 | "@smithy/is-array-buffer": "^2.1.1",
1173 | "tslib": "^2.5.0"
1174 | },
1175 | "engines": {
1176 | "node": ">=14.0.0"
1177 | }
1178 | },
1179 | "node_modules/@smithy/util-config-provider": {
1180 | "version": "2.2.1",
1181 | "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.2.1.tgz",
1182 | "integrity": "sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==",
1183 | "optional": true,
1184 | "peer": true,
1185 | "dependencies": {
1186 | "tslib": "^2.5.0"
1187 | },
1188 | "engines": {
1189 | "node": ">=14.0.0"
1190 | }
1191 | },
1192 | "node_modules/@smithy/util-defaults-mode-browser": {
1193 | "version": "2.1.1",
1194 | "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.1.1.tgz",
1195 | "integrity": "sha512-lqLz/9aWRO6mosnXkArtRuQqqZBhNpgI65YDpww4rVQBuUT7qzKbDLG5AmnQTCiU4rOquaZO/Kt0J7q9Uic7MA==",
1196 | "optional": true,
1197 | "peer": true,
1198 | "dependencies": {
1199 | "@smithy/property-provider": "^2.1.1",
1200 | "@smithy/smithy-client": "^2.3.1",
1201 | "@smithy/types": "^2.9.1",
1202 | "bowser": "^2.11.0",
1203 | "tslib": "^2.5.0"
1204 | },
1205 | "engines": {
1206 | "node": ">= 10.0.0"
1207 | }
1208 | },
1209 | "node_modules/@smithy/util-defaults-mode-node": {
1210 | "version": "2.1.1",
1211 | "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.1.1.tgz",
1212 | "integrity": "sha512-tYVrc+w+jSBfBd267KDnvSGOh4NMz+wVH7v4CClDbkdPfnjvImBZsOURncT5jsFwR9KCuDyPoSZq4Pa6+eCUrA==",
1213 | "optional": true,
1214 | "peer": true,
1215 | "dependencies": {
1216 | "@smithy/config-resolver": "^2.1.1",
1217 | "@smithy/credential-provider-imds": "^2.2.1",
1218 | "@smithy/node-config-provider": "^2.2.1",
1219 | "@smithy/property-provider": "^2.1.1",
1220 | "@smithy/smithy-client": "^2.3.1",
1221 | "@smithy/types": "^2.9.1",
1222 | "tslib": "^2.5.0"
1223 | },
1224 | "engines": {
1225 | "node": ">= 10.0.0"
1226 | }
1227 | },
1228 | "node_modules/@smithy/util-endpoints": {
1229 | "version": "1.1.1",
1230 | "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.1.1.tgz",
1231 | "integrity": "sha512-sI4d9rjoaekSGEtq3xSb2nMjHMx8QXcz2cexnVyRWsy4yQ9z3kbDpX+7fN0jnbdOp0b3KSTZJZ2Yb92JWSanLw==",
1232 | "optional": true,
1233 | "peer": true,
1234 | "dependencies": {
1235 | "@smithy/node-config-provider": "^2.2.1",
1236 | "@smithy/types": "^2.9.1",
1237 | "tslib": "^2.5.0"
1238 | },
1239 | "engines": {
1240 | "node": ">= 14.0.0"
1241 | }
1242 | },
1243 | "node_modules/@smithy/util-hex-encoding": {
1244 | "version": "2.1.1",
1245 | "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.1.1.tgz",
1246 | "integrity": "sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==",
1247 | "optional": true,
1248 | "peer": true,
1249 | "dependencies": {
1250 | "tslib": "^2.5.0"
1251 | },
1252 | "engines": {
1253 | "node": ">=14.0.0"
1254 | }
1255 | },
1256 | "node_modules/@smithy/util-middleware": {
1257 | "version": "2.1.1",
1258 | "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.1.1.tgz",
1259 | "integrity": "sha512-mKNrk8oz5zqkNcbcgAAepeJbmfUW6ogrT2Z2gDbIUzVzNAHKJQTYmH9jcy0jbWb+m7ubrvXKb6uMjkSgAqqsFA==",
1260 | "optional": true,
1261 | "peer": true,
1262 | "dependencies": {
1263 | "@smithy/types": "^2.9.1",
1264 | "tslib": "^2.5.0"
1265 | },
1266 | "engines": {
1267 | "node": ">=14.0.0"
1268 | }
1269 | },
1270 | "node_modules/@smithy/util-retry": {
1271 | "version": "2.1.1",
1272 | "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.1.1.tgz",
1273 | "integrity": "sha512-Mg+xxWPTeSPrthpC5WAamJ6PW4Kbo01Fm7lWM1jmGRvmrRdsd3192Gz2fBXAMURyXpaNxyZf6Hr/nQ4q70oVEA==",
1274 | "optional": true,
1275 | "peer": true,
1276 | "dependencies": {
1277 | "@smithy/service-error-classification": "^2.1.1",
1278 | "@smithy/types": "^2.9.1",
1279 | "tslib": "^2.5.0"
1280 | },
1281 | "engines": {
1282 | "node": ">= 14.0.0"
1283 | }
1284 | },
1285 | "node_modules/@smithy/util-stream": {
1286 | "version": "2.1.1",
1287 | "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.1.1.tgz",
1288 | "integrity": "sha512-J7SMIpUYvU4DQN55KmBtvaMc7NM3CZ2iWICdcgaovtLzseVhAqFRYqloT3mh0esrFw+3VEK6nQFteFsTqZSECQ==",
1289 | "optional": true,
1290 | "peer": true,
1291 | "dependencies": {
1292 | "@smithy/fetch-http-handler": "^2.4.1",
1293 | "@smithy/node-http-handler": "^2.3.1",
1294 | "@smithy/types": "^2.9.1",
1295 | "@smithy/util-base64": "^2.1.1",
1296 | "@smithy/util-buffer-from": "^2.1.1",
1297 | "@smithy/util-hex-encoding": "^2.1.1",
1298 | "@smithy/util-utf8": "^2.1.1",
1299 | "tslib": "^2.5.0"
1300 | },
1301 | "engines": {
1302 | "node": ">=14.0.0"
1303 | }
1304 | },
1305 | "node_modules/@smithy/util-uri-escape": {
1306 | "version": "2.1.1",
1307 | "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz",
1308 | "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==",
1309 | "optional": true,
1310 | "peer": true,
1311 | "dependencies": {
1312 | "tslib": "^2.5.0"
1313 | },
1314 | "engines": {
1315 | "node": ">=14.0.0"
1316 | }
1317 | },
1318 | "node_modules/@smithy/util-utf8": {
1319 | "version": "2.1.1",
1320 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.1.1.tgz",
1321 | "integrity": "sha512-BqTpzYEcUMDwAKr7/mVRUtHDhs6ZoXDi9NypMvMfOr/+u1NW7JgqodPDECiiLboEm6bobcPcECxzjtQh865e9A==",
1322 | "optional": true,
1323 | "peer": true,
1324 | "dependencies": {
1325 | "@smithy/util-buffer-from": "^2.1.1",
1326 | "tslib": "^2.5.0"
1327 | },
1328 | "engines": {
1329 | "node": ">=14.0.0"
1330 | }
1331 | },
1332 | "node_modules/@socket.io/component-emitter": {
1333 | "version": "3.1.0",
1334 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
1335 | "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
1336 | },
1337 | "node_modules/@socket.io/mongo-adapter": {
1338 | "version": "0.3.2",
1339 | "resolved": "https://registry.npmjs.org/@socket.io/mongo-adapter/-/mongo-adapter-0.3.2.tgz",
1340 | "integrity": "sha512-PcVlNuMJgAwDC+iVXmEDvmSik3TqzLqeBJz9uj18+FGApa5WEc35LgEnU0jCZPqZjvPQ2/i6sB/sAMsr58rHfA==",
1341 | "dependencies": {
1342 | "debug": "~4.3.1",
1343 | "mongodb": "*"
1344 | },
1345 | "engines": {
1346 | "node": ">=10.0.0"
1347 | },
1348 | "peerDependencies": {
1349 | "socket.io-adapter": "^2.5.2"
1350 | }
1351 | },
1352 | "node_modules/@types/cookie": {
1353 | "version": "0.4.1",
1354 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
1355 | "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
1356 | },
1357 | "node_modules/@types/cors": {
1358 | "version": "2.8.17",
1359 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
1360 | "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
1361 | "dependencies": {
1362 | "@types/node": "*"
1363 | }
1364 | },
1365 | "node_modules/@types/node": {
1366 | "version": "20.11.5",
1367 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz",
1368 | "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==",
1369 | "dependencies": {
1370 | "undici-types": "~5.26.4"
1371 | }
1372 | },
1373 | "node_modules/@types/webidl-conversions": {
1374 | "version": "7.0.3",
1375 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
1376 | "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
1377 | },
1378 | "node_modules/@types/whatwg-url": {
1379 | "version": "11.0.4",
1380 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz",
1381 | "integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==",
1382 | "dependencies": {
1383 | "@types/webidl-conversions": "*"
1384 | }
1385 | },
1386 | "node_modules/accepts": {
1387 | "version": "1.3.8",
1388 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
1389 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
1390 | "dependencies": {
1391 | "mime-types": "~2.1.34",
1392 | "negotiator": "0.6.3"
1393 | },
1394 | "engines": {
1395 | "node": ">= 0.6"
1396 | }
1397 | },
1398 | "node_modules/base64id": {
1399 | "version": "2.0.0",
1400 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
1401 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
1402 | "engines": {
1403 | "node": "^4.5.0 || >= 5.9"
1404 | }
1405 | },
1406 | "node_modules/bowser": {
1407 | "version": "2.11.0",
1408 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz",
1409 | "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==",
1410 | "optional": true,
1411 | "peer": true
1412 | },
1413 | "node_modules/bson": {
1414 | "version": "6.2.0",
1415 | "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz",
1416 | "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==",
1417 | "engines": {
1418 | "node": ">=16.20.1"
1419 | }
1420 | },
1421 | "node_modules/cookie": {
1422 | "version": "0.4.2",
1423 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
1424 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
1425 | "engines": {
1426 | "node": ">= 0.6"
1427 | }
1428 | },
1429 | "node_modules/cors": {
1430 | "version": "2.8.5",
1431 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
1432 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
1433 | "dependencies": {
1434 | "object-assign": "^4",
1435 | "vary": "^1"
1436 | },
1437 | "engines": {
1438 | "node": ">= 0.10"
1439 | }
1440 | },
1441 | "node_modules/debug": {
1442 | "version": "4.3.4",
1443 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1444 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1445 | "dependencies": {
1446 | "ms": "2.1.2"
1447 | },
1448 | "engines": {
1449 | "node": ">=6.0"
1450 | },
1451 | "peerDependenciesMeta": {
1452 | "supports-color": {
1453 | "optional": true
1454 | }
1455 | }
1456 | },
1457 | "node_modules/engine.io": {
1458 | "version": "6.5.4",
1459 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz",
1460 | "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==",
1461 | "dependencies": {
1462 | "@types/cookie": "^0.4.1",
1463 | "@types/cors": "^2.8.12",
1464 | "@types/node": ">=10.0.0",
1465 | "accepts": "~1.3.4",
1466 | "base64id": "2.0.0",
1467 | "cookie": "~0.4.1",
1468 | "cors": "~2.8.5",
1469 | "debug": "~4.3.1",
1470 | "engine.io-parser": "~5.2.1",
1471 | "ws": "~8.11.0"
1472 | },
1473 | "engines": {
1474 | "node": ">=10.2.0"
1475 | }
1476 | },
1477 | "node_modules/engine.io-client": {
1478 | "version": "6.5.3",
1479 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
1480 | "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
1481 | "dependencies": {
1482 | "@socket.io/component-emitter": "~3.1.0",
1483 | "debug": "~4.3.1",
1484 | "engine.io-parser": "~5.2.1",
1485 | "ws": "~8.11.0",
1486 | "xmlhttprequest-ssl": "~2.0.0"
1487 | }
1488 | },
1489 | "node_modules/engine.io-parser": {
1490 | "version": "5.2.1",
1491 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
1492 | "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
1493 | "engines": {
1494 | "node": ">=10.0.0"
1495 | }
1496 | },
1497 | "node_modules/fast-xml-parser": {
1498 | "version": "4.2.5",
1499 | "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz",
1500 | "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==",
1501 | "funding": [
1502 | {
1503 | "type": "paypal",
1504 | "url": "https://paypal.me/naturalintelligence"
1505 | },
1506 | {
1507 | "type": "github",
1508 | "url": "https://github.com/sponsors/NaturalIntelligence"
1509 | }
1510 | ],
1511 | "optional": true,
1512 | "peer": true,
1513 | "dependencies": {
1514 | "strnum": "^1.0.5"
1515 | },
1516 | "bin": {
1517 | "fxparser": "src/cli/cli.js"
1518 | }
1519 | },
1520 | "node_modules/ip": {
1521 | "version": "2.0.0",
1522 | "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
1523 | "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
1524 | "optional": true,
1525 | "peer": true
1526 | },
1527 | "node_modules/memory-pager": {
1528 | "version": "1.5.0",
1529 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1530 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
1531 | },
1532 | "node_modules/mime-db": {
1533 | "version": "1.52.0",
1534 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1535 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1536 | "engines": {
1537 | "node": ">= 0.6"
1538 | }
1539 | },
1540 | "node_modules/mime-types": {
1541 | "version": "2.1.35",
1542 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1543 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1544 | "dependencies": {
1545 | "mime-db": "1.52.0"
1546 | },
1547 | "engines": {
1548 | "node": ">= 0.6"
1549 | }
1550 | },
1551 | "node_modules/mongodb": {
1552 | "version": "6.3.0",
1553 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.3.0.tgz",
1554 | "integrity": "sha512-tt0KuGjGtLUhLoU263+xvQmPHEGTw5LbcNC73EoFRYgSHwZt5tsoJC110hDyO1kjQzpgNrpdcSza9PknWN4LrA==",
1555 | "dependencies": {
1556 | "@mongodb-js/saslprep": "^1.1.0",
1557 | "bson": "^6.2.0",
1558 | "mongodb-connection-string-url": "^3.0.0"
1559 | },
1560 | "engines": {
1561 | "node": ">=16.20.1"
1562 | },
1563 | "peerDependencies": {
1564 | "@aws-sdk/credential-providers": "^3.188.0",
1565 | "@mongodb-js/zstd": "^1.1.0",
1566 | "gcp-metadata": "^5.2.0",
1567 | "kerberos": "^2.0.1",
1568 | "mongodb-client-encryption": ">=6.0.0 <7",
1569 | "snappy": "^7.2.2",
1570 | "socks": "^2.7.1"
1571 | },
1572 | "peerDependenciesMeta": {
1573 | "@aws-sdk/credential-providers": {
1574 | "optional": true
1575 | },
1576 | "@mongodb-js/zstd": {
1577 | "optional": true
1578 | },
1579 | "gcp-metadata": {
1580 | "optional": true
1581 | },
1582 | "kerberos": {
1583 | "optional": true
1584 | },
1585 | "mongodb-client-encryption": {
1586 | "optional": true
1587 | },
1588 | "snappy": {
1589 | "optional": true
1590 | },
1591 | "socks": {
1592 | "optional": true
1593 | }
1594 | }
1595 | },
1596 | "node_modules/mongodb-connection-string-url": {
1597 | "version": "3.0.0",
1598 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz",
1599 | "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==",
1600 | "dependencies": {
1601 | "@types/whatwg-url": "^11.0.2",
1602 | "whatwg-url": "^13.0.0"
1603 | }
1604 | },
1605 | "node_modules/ms": {
1606 | "version": "2.1.2",
1607 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1608 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1609 | },
1610 | "node_modules/negotiator": {
1611 | "version": "0.6.3",
1612 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1613 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
1614 | "engines": {
1615 | "node": ">= 0.6"
1616 | }
1617 | },
1618 | "node_modules/object-assign": {
1619 | "version": "4.1.1",
1620 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1621 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1622 | "engines": {
1623 | "node": ">=0.10.0"
1624 | }
1625 | },
1626 | "node_modules/punycode": {
1627 | "version": "2.3.1",
1628 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
1629 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
1630 | "engines": {
1631 | "node": ">=6"
1632 | }
1633 | },
1634 | "node_modules/smart-buffer": {
1635 | "version": "4.2.0",
1636 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
1637 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
1638 | "optional": true,
1639 | "peer": true,
1640 | "engines": {
1641 | "node": ">= 6.0.0",
1642 | "npm": ">= 3.0.0"
1643 | }
1644 | },
1645 | "node_modules/socket.io": {
1646 | "version": "4.7.4",
1647 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz",
1648 | "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==",
1649 | "dependencies": {
1650 | "accepts": "~1.3.4",
1651 | "base64id": "~2.0.0",
1652 | "cors": "~2.8.5",
1653 | "debug": "~4.3.2",
1654 | "engine.io": "~6.5.2",
1655 | "socket.io-adapter": "~2.5.2",
1656 | "socket.io-parser": "~4.2.4"
1657 | },
1658 | "engines": {
1659 | "node": ">=10.2.0"
1660 | }
1661 | },
1662 | "node_modules/socket.io-adapter": {
1663 | "version": "2.5.2",
1664 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
1665 | "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
1666 | "dependencies": {
1667 | "ws": "~8.11.0"
1668 | }
1669 | },
1670 | "node_modules/socket.io-client": {
1671 | "version": "4.7.4",
1672 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
1673 | "integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
1674 | "dependencies": {
1675 | "@socket.io/component-emitter": "~3.1.0",
1676 | "debug": "~4.3.2",
1677 | "engine.io-client": "~6.5.2",
1678 | "socket.io-parser": "~4.2.4"
1679 | },
1680 | "engines": {
1681 | "node": ">=10.0.0"
1682 | }
1683 | },
1684 | "node_modules/socket.io-parser": {
1685 | "version": "4.2.4",
1686 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
1687 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
1688 | "dependencies": {
1689 | "@socket.io/component-emitter": "~3.1.0",
1690 | "debug": "~4.3.1"
1691 | },
1692 | "engines": {
1693 | "node": ">=10.0.0"
1694 | }
1695 | },
1696 | "node_modules/socks": {
1697 | "version": "2.7.1",
1698 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
1699 | "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
1700 | "optional": true,
1701 | "peer": true,
1702 | "dependencies": {
1703 | "ip": "^2.0.0",
1704 | "smart-buffer": "^4.2.0"
1705 | },
1706 | "engines": {
1707 | "node": ">= 10.13.0",
1708 | "npm": ">= 3.0.0"
1709 | }
1710 | },
1711 | "node_modules/sparse-bitfield": {
1712 | "version": "3.0.3",
1713 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
1714 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
1715 | "dependencies": {
1716 | "memory-pager": "^1.0.2"
1717 | }
1718 | },
1719 | "node_modules/strnum": {
1720 | "version": "1.0.5",
1721 | "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
1722 | "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==",
1723 | "optional": true,
1724 | "peer": true
1725 | },
1726 | "node_modules/tr46": {
1727 | "version": "4.1.1",
1728 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
1729 | "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
1730 | "dependencies": {
1731 | "punycode": "^2.3.0"
1732 | },
1733 | "engines": {
1734 | "node": ">=14"
1735 | }
1736 | },
1737 | "node_modules/tslib": {
1738 | "version": "2.6.2",
1739 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
1740 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
1741 | "optional": true,
1742 | "peer": true
1743 | },
1744 | "node_modules/undici-types": {
1745 | "version": "5.26.5",
1746 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
1747 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
1748 | },
1749 | "node_modules/uuid": {
1750 | "version": "8.3.2",
1751 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
1752 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
1753 | "optional": true,
1754 | "peer": true,
1755 | "bin": {
1756 | "uuid": "dist/bin/uuid"
1757 | }
1758 | },
1759 | "node_modules/vary": {
1760 | "version": "1.1.2",
1761 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1762 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1763 | "engines": {
1764 | "node": ">= 0.8"
1765 | }
1766 | },
1767 | "node_modules/webidl-conversions": {
1768 | "version": "7.0.0",
1769 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
1770 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
1771 | "engines": {
1772 | "node": ">=12"
1773 | }
1774 | },
1775 | "node_modules/whatwg-url": {
1776 | "version": "13.0.0",
1777 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz",
1778 | "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==",
1779 | "dependencies": {
1780 | "tr46": "^4.1.1",
1781 | "webidl-conversions": "^7.0.0"
1782 | },
1783 | "engines": {
1784 | "node": ">=16"
1785 | }
1786 | },
1787 | "node_modules/ws": {
1788 | "version": "8.11.0",
1789 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
1790 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
1791 | "engines": {
1792 | "node": ">=10.0.0"
1793 | },
1794 | "peerDependencies": {
1795 | "bufferutil": "^4.0.1",
1796 | "utf-8-validate": "^5.0.2"
1797 | },
1798 | "peerDependenciesMeta": {
1799 | "bufferutil": {
1800 | "optional": true
1801 | },
1802 | "utf-8-validate": {
1803 | "optional": true
1804 | }
1805 | }
1806 | },
1807 | "node_modules/xmlhttprequest-ssl": {
1808 | "version": "2.0.0",
1809 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
1810 | "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
1811 | "engines": {
1812 | "node": ">=0.4.0"
1813 | }
1814 | }
1815 | }
1816 | }
1817 |
--------------------------------------------------------------------------------