├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── assets
├── socket.io-cluster-redis.excalidraw
├── socket.io-cluster-redis.png
├── socket.io-cluster.excalidraw
└── socket.io-cluster.png
├── index.d.ts
├── index.js
├── package-lock.json
├── package.json
└── test
├── fixtures
├── connection.js
├── cors.js
├── failing.js
└── util.js
└── index.js
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | pull_request:
6 | schedule:
7 | - cron: '0 0 * * 0'
8 |
9 | jobs:
10 | test-node:
11 | runs-on: ubuntu-latest
12 | timeout-minutes: 10
13 |
14 | strategy:
15 | matrix:
16 | node-version:
17 | - 10
18 | - 18
19 |
20 | steps:
21 | - name: Checkout repository
22 | uses: actions/checkout@v3
23 |
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v3
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 |
29 | - name: Install dependencies
30 | run: npm ci
31 |
32 | - name: Run tests
33 | run: npm test
34 | env:
35 | CI: true
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .nyc_output
3 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | - [1.0.4](#104-2023-08-12) (Aug 2023)
4 | - [1.0.3](#103-2023-02-24) (Feb 2023)
5 | - [1.0.2](#102-2022-11-01) (Nov 2022)
6 | - [1.0.1](#101-2021-07-01) (Jul 2021)
7 | - [1.0.0](#100-2021-01-25) (Jan 2021)
8 |
9 | # Release notes
10 |
11 | ## [1.0.4](https://github.com/socketio/socket.io-sticky/compare/1.0.3...1.0.4) (2023-08-12)
12 |
13 |
14 | ### Bug Fixes
15 |
16 | * cleanup sid to worker map on worker exit ([4b430e7](https://github.com/socketio/socket.io-sticky/commit/4b430e7e9383006e4641e40e8a5082156ed862a4))
17 | * properly detect requests without body ([ac7bb8e](https://github.com/socketio/socket.io-sticky/commit/ac7bb8e851d6a458736281568ed6946c512e4251))
18 |
19 |
20 |
21 | ## [1.0.3](https://github.com/socketio/socket.io-sticky/compare/1.0.2...1.0.3) (2023-02-24)
22 |
23 |
24 | ### Bug Fixes
25 |
26 | * handle case with no available worker ([e8b4203](https://github.com/socketio/socket.io-sticky/commit/e8b4203d18fc9601e05af3457baba49fafdb15f0))
27 |
28 |
29 |
30 | ## [1.0.2](https://github.com/socketio/socket.io-sticky/compare/1.0.1...1.0.2) (2022-11-01)
31 |
32 |
33 | ### Bug Fixes
34 |
35 | * properly handle large request body ([a124d0b](https://github.com/socketio/socket.io-sticky/commit/a124d0beb5c1b78be5b75f10153859a9e4672862))
36 |
37 |
38 |
39 | ## [1.0.1](https://github.com/socketio/socket.io-sticky/compare/1.0.0...1.0.1) (2021-07-01)
40 |
41 |
42 | ### Bug Fixes
43 |
44 | * check if the socket exists in the worker ([7069fbc](https://github.com/socketio/socket.io-sticky/commit/7069fbc5bfbc845556f4a5cb8fd8240a1ef24b0e))
45 |
46 |
47 | ## 1.0.0 (2021-01-25)
48 |
49 | Initial release
50 |
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Copyright (c) 2021 Damien Arrachequesne (@darrachequesne)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | 'Software'), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sticky sessions for Socket.IO
2 |
3 | A simple and performant way to use [Socket.IO](https://socket.io/) within a [cluster](http://nodejs.org/docs/latest/api/cluster.html).
4 |
5 | Unlike other packages like [sticky-session](https://github.com/indutny/sticky-session), the routing is based on the session ID (the `sid` query parameter).
6 |
7 | 
8 |
9 | See also:
10 |
11 | - [sticky-session](https://github.com/indutny/sticky-session) (routing based on `connection.remoteAddress`)
12 | - [socketio-sticky-session](https://github.com/wzrdtales/socket-io-sticky-session) (routing based on the `x-forwarded-for` header)
13 |
14 | **Table of contents**
15 |
16 | - [Installation](#installation)
17 | - [Usage](#usage)
18 | - [How it works](#how-it-works)
19 | - [Notes](#notes)
20 | - [License](#license)
21 |
22 | ## Installation
23 |
24 | ```
25 | npm install @socket.io/sticky
26 | ```
27 |
28 | ## Usage
29 |
30 | ```js
31 | const cluster = require("cluster");
32 | const http = require("http");
33 | const { Server } = require("socket.io");
34 | const numCPUs = require("os").cpus().length;
35 | const { setupMaster, setupWorker } = require("@socket.io/sticky");
36 | const { createAdapter, setupPrimary } = require("@socket.io/cluster-adapter");
37 |
38 | if (cluster.isMaster) {
39 | console.log(`Master ${process.pid} is running`);
40 |
41 | const httpServer = http.createServer();
42 |
43 | setupMaster(httpServer, {
44 | loadBalancingMethod: "least-connection", // either "random", "round-robin" or "least-connection"
45 | });
46 |
47 | setupPrimary();
48 |
49 | httpServer.listen(3000);
50 |
51 | for (let i = 0; i < numCPUs; i++) {
52 | cluster.fork();
53 | }
54 |
55 | cluster.on("exit", (worker) => {
56 | console.log(`Worker ${worker.process.pid} died`);
57 | cluster.fork();
58 | });
59 | } else {
60 | console.log(`Worker ${process.pid} started`);
61 |
62 | const httpServer = http.createServer();
63 | const io = new Server(httpServer);
64 | io.adapter(createAdapter());
65 | setupWorker(io);
66 |
67 | io.on("connection", (socket) => {
68 | /* ... */
69 | });
70 | }
71 | ```
72 |
73 | ## How it works
74 |
75 | The first HTTP request (without `sid` query parameter) is forwarded to a random worker (based on the `loadBalancingMethod` option).
76 |
77 | The underlying Engine.IO server creates a new session and emits a `connection` event with the session ID. The worker sends this session ID to the master, which stores the relationship between the worker ID and the session ID.
78 |
79 | For subsequent requests, the `sid` query parameter is extracted by the master process, which then forwards the handle to the right worker.
80 |
81 | ## Notes
82 |
83 | - this package is not needed if you only use WebSockets (which might be a sensible choice as of 2021)
84 |
85 | ```js
86 | // client-side
87 | const socket = io({
88 | transports: ["websocket"] // HTTP long-polling is disabled
89 | });
90 | ```
91 |
92 | - in a multi-server setup, you will need to use another adapter, like the [Redis adapter](https://socket.io/docs/v4/redis-adapter/)
93 |
94 | 
95 |
96 | - this module is not compatible with an HTTPS server
97 |
98 | For more information, please see [this issue](https://github.com/socketio/socket.io-sticky/issues/3).
99 |
100 | ## License
101 |
102 | MIT
103 |
--------------------------------------------------------------------------------
/assets/socket.io-cluster-redis.excalidraw:
--------------------------------------------------------------------------------
1 | {
2 | "type": "excalidraw",
3 | "version": 2,
4 | "source": "https://excalidraw.com",
5 | "elements": [
6 | {
7 | "type": "text",
8 | "version": 264,
9 | "versionNonce": 1085373869,
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": 639,
19 | "y": -20.5,
20 | "strokeColor": "#000000",
21 | "backgroundColor": "transparent",
22 | "width": 78,
23 | "height": 26,
24 | "seed": 28708370,
25 | "groupIds": [],
26 | "strokeSharpness": "sharp",
27 | "boundElementIds": [
28 | "_wBO22vaQplcoKyBXbWRC"
29 | ],
30 | "fontSize": 20,
31 | "fontFamily": 1,
32 | "text": "worker 1",
33 | "baseline": 18,
34 | "textAlign": "center",
35 | "verticalAlign": "middle"
36 | },
37 | {
38 | "type": "rectangle",
39 | "version": 178,
40 | "versionNonce": 1203989197,
41 | "isDeleted": false,
42 | "id": "lmQ4o4New7xuXQLwavuSn",
43 | "fillStyle": "hachure",
44 | "strokeWidth": 1,
45 | "strokeStyle": "solid",
46 | "roughness": 1,
47 | "opacity": 100,
48 | "angle": 0,
49 | "x": 428,
50 | "y": -101,
51 | "strokeColor": "#000000",
52 | "backgroundColor": "transparent",
53 | "width": 345.00000000000006,
54 | "height": 311,
55 | "seed": 1594950354,
56 | "groupIds": [],
57 | "strokeSharpness": "sharp",
58 | "boundElementIds": [
59 | "_wBO22vaQplcoKyBXbWRC",
60 | "BZVwnsrGk9G-X87ZHkh-6",
61 | "eU1gfEXnHSjxc-pEgv43A",
62 | "XZpY0rnxgeDlxu5b8fgRQ",
63 | "4mjxZzapHnLuRx7KU2JeH",
64 | "zkLKnuWAYxJGCPBZp9UAB"
65 | ]
66 | },
67 | {
68 | "type": "text",
69 | "version": 113,
70 | "versionNonce": 1651458061,
71 | "isDeleted": false,
72 | "id": "ZQsZmj4NaTubBHMkVG2dl",
73 | "fillStyle": "hachure",
74 | "strokeWidth": 1,
75 | "strokeStyle": "solid",
76 | "roughness": 1,
77 | "opacity": 100,
78 | "angle": 0,
79 | "x": 447,
80 | "y": -90,
81 | "strokeColor": "#000000",
82 | "backgroundColor": "transparent",
83 | "width": 66,
84 | "height": 26,
85 | "seed": 126533902,
86 | "groupIds": [],
87 | "strokeSharpness": "sharp",
88 | "boundElementIds": [],
89 | "fontSize": 20,
90 | "fontFamily": 1,
91 | "text": "Host A",
92 | "baseline": 18,
93 | "textAlign": "left",
94 | "verticalAlign": "top"
95 | },
96 | {
97 | "type": "rectangle",
98 | "version": 222,
99 | "versionNonce": 117774787,
100 | "isDeleted": false,
101 | "id": "RRrk3Vsl-pM8Z1r8Fj3Vu",
102 | "fillStyle": "hachure",
103 | "strokeWidth": 1,
104 | "strokeStyle": "solid",
105 | "roughness": 1,
106 | "opacity": 100,
107 | "angle": 0,
108 | "x": 626.5,
109 | "y": -36,
110 | "strokeColor": "#000000",
111 | "backgroundColor": "transparent",
112 | "width": 129,
113 | "height": 56,
114 | "seed": 1013161166,
115 | "groupIds": [],
116 | "strokeSharpness": "sharp",
117 | "boundElementIds": [
118 | "use4Bp2hbb77Fq5njtwBi"
119 | ]
120 | },
121 | {
122 | "type": "diamond",
123 | "version": 349,
124 | "versionNonce": 2102462467,
125 | "isDeleted": false,
126 | "id": "k0pJTVL4F3HHsfRPlE-gO",
127 | "fillStyle": "hachure",
128 | "strokeWidth": 2,
129 | "strokeStyle": "solid",
130 | "roughness": 0,
131 | "opacity": 100,
132 | "angle": 0,
133 | "x": 733,
134 | "y": -14,
135 | "strokeColor": "#000000",
136 | "backgroundColor": "transparent",
137 | "width": 16,
138 | "height": 18,
139 | "seed": 1260350118,
140 | "groupIds": [],
141 | "strokeSharpness": "sharp",
142 | "boundElementIds": [
143 | "Sp9AvxDh8gwRvSC53VFKe",
144 | "XZpY0rnxgeDlxu5b8fgRQ"
145 | ]
146 | },
147 | {
148 | "type": "ellipse",
149 | "version": 110,
150 | "versionNonce": 44665507,
151 | "isDeleted": false,
152 | "id": "EQmjbilyrf3OcSwGbMZrg",
153 | "fillStyle": "hachure",
154 | "strokeWidth": 2,
155 | "strokeStyle": "solid",
156 | "roughness": 0,
157 | "opacity": 100,
158 | "angle": 0,
159 | "x": 873,
160 | "y": 197,
161 | "strokeColor": "#000000",
162 | "backgroundColor": "transparent",
163 | "width": 92,
164 | "height": 81,
165 | "seed": 1885795942,
166 | "groupIds": [],
167 | "strokeSharpness": "sharp",
168 | "boundElementIds": [
169 | "xDobZ6graJnZZP8g59wJ4",
170 | "eU1gfEXnHSjxc-pEgv43A",
171 | "4mjxZzapHnLuRx7KU2JeH",
172 | "XZpY0rnxgeDlxu5b8fgRQ",
173 | "CKKC2fK8c7VggdJKNATSf",
174 | "H6kPRLfMhpJHuNpq28DBh"
175 | ]
176 | },
177 | {
178 | "type": "text",
179 | "version": 55,
180 | "versionNonce": 320845955,
181 | "isDeleted": false,
182 | "id": "wV6Y3XyIP5TbX50EF6xs6",
183 | "fillStyle": "hachure",
184 | "strokeWidth": 2,
185 | "strokeStyle": "solid",
186 | "roughness": 0,
187 | "opacity": 100,
188 | "angle": 0,
189 | "x": 893.5,
190 | "y": 224.5,
191 | "strokeColor": "#000000",
192 | "backgroundColor": "transparent",
193 | "width": 51,
194 | "height": 26,
195 | "seed": 1433614630,
196 | "groupIds": [],
197 | "strokeSharpness": "sharp",
198 | "boundElementIds": [],
199 | "fontSize": 20,
200 | "fontFamily": 1,
201 | "text": "Redis",
202 | "baseline": 18,
203 | "textAlign": "center",
204 | "verticalAlign": "middle"
205 | },
206 | {
207 | "type": "arrow",
208 | "version": 237,
209 | "versionNonce": 1968322851,
210 | "isDeleted": false,
211 | "id": "eU1gfEXnHSjxc-pEgv43A",
212 | "fillStyle": "hachure",
213 | "strokeWidth": 2,
214 | "strokeStyle": "solid",
215 | "roughness": 0,
216 | "opacity": 100,
217 | "angle": 0,
218 | "x": 782,
219 | "y": 160,
220 | "strokeColor": "#000000",
221 | "backgroundColor": "transparent",
222 | "width": 79,
223 | "height": 50,
224 | "seed": 1145880934,
225 | "groupIds": [],
226 | "strokeSharpness": "round",
227 | "boundElementIds": [],
228 | "startBinding": {
229 | "elementId": "lmQ4o4New7xuXQLwavuSn",
230 | "focus": -0.03541452449843372,
231 | "gap": 9
232 | },
233 | "endBinding": {
234 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
235 | "focus": -0.18462564038762336,
236 | "gap": 19.293806306612936
237 | },
238 | "points": [
239 | [
240 | 0,
241 | 0
242 | ],
243 | [
244 | 79,
245 | 50
246 | ]
247 | ],
248 | "lastCommittedPoint": null,
249 | "startArrowhead": "arrow",
250 | "endArrowhead": "arrow"
251 | },
252 | {
253 | "type": "text",
254 | "version": 302,
255 | "versionNonce": 1588664205,
256 | "isDeleted": false,
257 | "id": "qfQdcJHnwYnCMtLCV51X8",
258 | "fillStyle": "hachure",
259 | "strokeWidth": 1,
260 | "strokeStyle": "solid",
261 | "roughness": 1,
262 | "opacity": 100,
263 | "angle": 0,
264 | "x": 633,
265 | "y": 48.5,
266 | "strokeColor": "#000000",
267 | "backgroundColor": "transparent",
268 | "width": 90,
269 | "height": 26,
270 | "seed": 1535426147,
271 | "groupIds": [],
272 | "strokeSharpness": "sharp",
273 | "boundElementIds": [
274 | "_wBO22vaQplcoKyBXbWRC",
275 | "2DIFacJXJtC5QIuMuo3pK"
276 | ],
277 | "fontSize": 20,
278 | "fontFamily": 1,
279 | "text": "worker 2",
280 | "baseline": 18,
281 | "textAlign": "center",
282 | "verticalAlign": "middle"
283 | },
284 | {
285 | "type": "rectangle",
286 | "version": 255,
287 | "versionNonce": 1916253123,
288 | "isDeleted": false,
289 | "id": "IRd1nPQbv0PQdJQn_yLOs",
290 | "fillStyle": "hachure",
291 | "strokeWidth": 1,
292 | "strokeStyle": "solid",
293 | "roughness": 1,
294 | "opacity": 100,
295 | "angle": 0,
296 | "x": 626.5,
297 | "y": 33,
298 | "strokeColor": "#000000",
299 | "backgroundColor": "transparent",
300 | "width": 129,
301 | "height": 56,
302 | "seed": 452398413,
303 | "groupIds": [],
304 | "strokeSharpness": "sharp",
305 | "boundElementIds": [
306 | "2DIFacJXJtC5QIuMuo3pK",
307 | "NhqDM6wVMhgbRvXrQJQge"
308 | ]
309 | },
310 | {
311 | "type": "diamond",
312 | "version": 380,
313 | "versionNonce": 891330029,
314 | "isDeleted": false,
315 | "id": "tnpfCYwrVzd694_kUfzPn",
316 | "fillStyle": "hachure",
317 | "strokeWidth": 2,
318 | "strokeStyle": "solid",
319 | "roughness": 0,
320 | "opacity": 100,
321 | "angle": 0,
322 | "x": 733,
323 | "y": 55,
324 | "strokeColor": "#000000",
325 | "backgroundColor": "transparent",
326 | "width": 16,
327 | "height": 18,
328 | "seed": 2110061059,
329 | "groupIds": [],
330 | "strokeSharpness": "sharp",
331 | "boundElementIds": [
332 | "Sp9AvxDh8gwRvSC53VFKe",
333 | "4mjxZzapHnLuRx7KU2JeH"
334 | ]
335 | },
336 | {
337 | "type": "text",
338 | "version": 287,
339 | "versionNonce": 556942179,
340 | "isDeleted": false,
341 | "id": "ENOSqQ4visNbCN7ZMZwxP",
342 | "fillStyle": "hachure",
343 | "strokeWidth": 1,
344 | "strokeStyle": "solid",
345 | "roughness": 1,
346 | "opacity": 100,
347 | "angle": 0,
348 | "x": 634.5,
349 | "y": 114.5,
350 | "strokeColor": "#000000",
351 | "backgroundColor": "transparent",
352 | "width": 89,
353 | "height": 26,
354 | "seed": 1916984429,
355 | "groupIds": [],
356 | "strokeSharpness": "sharp",
357 | "boundElementIds": [
358 | "_wBO22vaQplcoKyBXbWRC"
359 | ],
360 | "fontSize": 20,
361 | "fontFamily": 1,
362 | "text": "worker 3",
363 | "baseline": 18,
364 | "textAlign": "center",
365 | "verticalAlign": "middle"
366 | },
367 | {
368 | "type": "rectangle",
369 | "version": 240,
370 | "versionNonce": 1955616845,
371 | "isDeleted": false,
372 | "id": "IqdB8EO7s50UY1EU9TVVP",
373 | "fillStyle": "hachure",
374 | "strokeWidth": 1,
375 | "strokeStyle": "solid",
376 | "roughness": 1,
377 | "opacity": 100,
378 | "angle": 0,
379 | "x": 627.5,
380 | "y": 99,
381 | "strokeColor": "#000000",
382 | "backgroundColor": "transparent",
383 | "width": 129,
384 | "height": 56,
385 | "seed": 1832463587,
386 | "groupIds": [],
387 | "strokeSharpness": "sharp",
388 | "boundElementIds": [
389 | "NhqDM6wVMhgbRvXrQJQge"
390 | ]
391 | },
392 | {
393 | "type": "diamond",
394 | "version": 371,
395 | "versionNonce": 364044397,
396 | "isDeleted": false,
397 | "id": "zCwNorsYWY3fLtRl9zxB1",
398 | "fillStyle": "hachure",
399 | "strokeWidth": 2,
400 | "strokeStyle": "solid",
401 | "roughness": 0,
402 | "opacity": 100,
403 | "angle": 0,
404 | "x": 734,
405 | "y": 121,
406 | "strokeColor": "#000000",
407 | "backgroundColor": "transparent",
408 | "width": 16,
409 | "height": 18,
410 | "seed": 2145830605,
411 | "groupIds": [],
412 | "strokeSharpness": "sharp",
413 | "boundElementIds": [
414 | "Sp9AvxDh8gwRvSC53VFKe",
415 | "eU1gfEXnHSjxc-pEgv43A"
416 | ]
417 | },
418 | {
419 | "type": "text",
420 | "version": 19,
421 | "versionNonce": 1368196771,
422 | "isDeleted": false,
423 | "id": "D8P7Bclj4xdmqfd3xlM9w",
424 | "fillStyle": "hachure",
425 | "strokeWidth": 1,
426 | "strokeStyle": "solid",
427 | "roughness": 1,
428 | "opacity": 100,
429 | "angle": 0,
430 | "x": 476,
431 | "y": 45,
432 | "strokeColor": "#000000",
433 | "backgroundColor": "transparent",
434 | "width": 67,
435 | "height": 26,
436 | "seed": 415223619,
437 | "groupIds": [],
438 | "strokeSharpness": "sharp",
439 | "boundElementIds": [],
440 | "fontSize": 20,
441 | "fontFamily": 1,
442 | "text": "master",
443 | "baseline": 18,
444 | "textAlign": "center",
445 | "verticalAlign": "middle"
446 | },
447 | {
448 | "type": "rectangle",
449 | "version": 251,
450 | "versionNonce": 514222349,
451 | "isDeleted": false,
452 | "id": "SlTRvTrZRavsPt44aEe3R",
453 | "fillStyle": "hachure",
454 | "strokeWidth": 1,
455 | "strokeStyle": "solid",
456 | "roughness": 1,
457 | "opacity": 100,
458 | "angle": 0,
459 | "x": 442.5,
460 | "y": 32,
461 | "strokeColor": "#000000",
462 | "backgroundColor": "transparent",
463 | "width": 129,
464 | "height": 56,
465 | "seed": 813326061,
466 | "groupIds": [],
467 | "strokeSharpness": "sharp",
468 | "boundElementIds": [
469 | "use4Bp2hbb77Fq5njtwBi",
470 | "2DIFacJXJtC5QIuMuo3pK",
471 | "NhqDM6wVMhgbRvXrQJQge"
472 | ]
473 | },
474 | {
475 | "type": "arrow",
476 | "version": 29,
477 | "versionNonce": 1644165603,
478 | "isDeleted": false,
479 | "id": "use4Bp2hbb77Fq5njtwBi",
480 | "fillStyle": "hachure",
481 | "strokeWidth": 1,
482 | "strokeStyle": "solid",
483 | "roughness": 1,
484 | "opacity": 100,
485 | "angle": 0,
486 | "x": 581,
487 | "y": 53,
488 | "strokeColor": "#000000",
489 | "backgroundColor": "transparent",
490 | "width": 34,
491 | "height": 48,
492 | "seed": 1423358221,
493 | "groupIds": [],
494 | "strokeSharpness": "round",
495 | "boundElementIds": [],
496 | "startBinding": {
497 | "elementId": "SlTRvTrZRavsPt44aEe3R",
498 | "focus": 0.8186758893280632,
499 | "gap": 9.5
500 | },
501 | "endBinding": {
502 | "elementId": "RRrk3Vsl-pM8Z1r8Fj3Vu",
503 | "focus": 0.7919960474308301,
504 | "gap": 11.5
505 | },
506 | "points": [
507 | [
508 | 0,
509 | 0
510 | ],
511 | [
512 | 34,
513 | -48
514 | ]
515 | ],
516 | "lastCommittedPoint": null,
517 | "startArrowhead": null,
518 | "endArrowhead": "arrow"
519 | },
520 | {
521 | "type": "arrow",
522 | "version": 85,
523 | "versionNonce": 964643277,
524 | "isDeleted": false,
525 | "id": "2DIFacJXJtC5QIuMuo3pK",
526 | "fillStyle": "hachure",
527 | "strokeWidth": 1,
528 | "strokeStyle": "solid",
529 | "roughness": 1,
530 | "opacity": 100,
531 | "angle": 0,
532 | "x": 583.706318583712,
533 | "y": 59.504354361072174,
534 | "strokeColor": "#000000",
535 | "backgroundColor": "transparent",
536 | "width": 32.383044731616906,
537 | "height": 0.6793771122768604,
538 | "seed": 1764672259,
539 | "groupIds": [],
540 | "strokeSharpness": "round",
541 | "boundElementIds": [],
542 | "startBinding": {
543 | "elementId": "SlTRvTrZRavsPt44aEe3R",
544 | "focus": -0.07170941580148099,
545 | "gap": 12.206318583712005
546 | },
547 | "endBinding": {
548 | "elementId": "IRd1nPQbv0PQdJQn_yLOs",
549 | "focus": -0.025731879981101647,
550 | "gap": 10.41063668467109
551 | },
552 | "points": [
553 | [
554 | 0,
555 | 0
556 | ],
557 | [
558 | 32.383044731616906,
559 | 0.6793771122768604
560 | ]
561 | ],
562 | "lastCommittedPoint": null,
563 | "startArrowhead": null,
564 | "endArrowhead": "arrow"
565 | },
566 | {
567 | "type": "arrow",
568 | "version": 140,
569 | "versionNonce": 407684483,
570 | "isDeleted": false,
571 | "id": "NhqDM6wVMhgbRvXrQJQge",
572 | "fillStyle": "hachure",
573 | "strokeWidth": 1,
574 | "strokeStyle": "solid",
575 | "roughness": 1,
576 | "opacity": 100,
577 | "angle": 0,
578 | "x": 585.8084776341915,
579 | "y": 71.66031144386157,
580 | "strokeColor": "#000000",
581 | "backgroundColor": "transparent",
582 | "width": 32.40004203654814,
583 | "height": 43.76823068360791,
584 | "seed": 1285959341,
585 | "groupIds": [],
586 | "strokeSharpness": "round",
587 | "boundElementIds": [],
588 | "startBinding": {
589 | "elementId": "SlTRvTrZRavsPt44aEe3R",
590 | "focus": -0.8234063011749806,
591 | "gap": 14.30847763419149
592 | },
593 | "endBinding": {
594 | "elementId": "IqdB8EO7s50UY1EU9TVVP",
595 | "focus": -0.7653120403381738,
596 | "gap": 9.291480329260366
597 | },
598 | "points": [
599 | [
600 | 0,
601 | 0
602 | ],
603 | [
604 | 32.40004203654814,
605 | 43.76823068360791
606 | ]
607 | ],
608 | "lastCommittedPoint": null,
609 | "startArrowhead": null,
610 | "endArrowhead": "arrow"
611 | },
612 | {
613 | "type": "arrow",
614 | "version": 301,
615 | "versionNonce": 247399085,
616 | "isDeleted": false,
617 | "id": "4mjxZzapHnLuRx7KU2JeH",
618 | "fillStyle": "hachure",
619 | "strokeWidth": 2,
620 | "strokeStyle": "solid",
621 | "roughness": 0,
622 | "opacity": 100,
623 | "angle": 0,
624 | "x": 782.5,
625 | "y": 93.5,
626 | "strokeColor": "#000000",
627 | "backgroundColor": "transparent",
628 | "width": 95,
629 | "height": 105,
630 | "seed": 1192703469,
631 | "groupIds": [],
632 | "strokeSharpness": "round",
633 | "boundElementIds": [],
634 | "startBinding": {
635 | "elementId": "lmQ4o4New7xuXQLwavuSn",
636 | "focus": -0.4684506613957731,
637 | "gap": 9.5
638 | },
639 | "endBinding": {
640 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
641 | "focus": -0.10566589454963482,
642 | "gap": 13.70698078356314
643 | },
644 | "points": [
645 | [
646 | 0,
647 | 0
648 | ],
649 | [
650 | 95,
651 | 105
652 | ]
653 | ],
654 | "lastCommittedPoint": null,
655 | "startArrowhead": "arrow",
656 | "endArrowhead": "arrow"
657 | },
658 | {
659 | "type": "arrow",
660 | "version": 351,
661 | "versionNonce": 356767395,
662 | "isDeleted": false,
663 | "id": "XZpY0rnxgeDlxu5b8fgRQ",
664 | "fillStyle": "hachure",
665 | "strokeWidth": 2,
666 | "strokeStyle": "solid",
667 | "roughness": 0,
668 | "opacity": 100,
669 | "angle": 0,
670 | "x": 791.5,
671 | "y": 15,
672 | "strokeColor": "#000000",
673 | "backgroundColor": "transparent",
674 | "width": 111,
675 | "height": 169,
676 | "seed": 1996215427,
677 | "groupIds": [],
678 | "strokeSharpness": "round",
679 | "boundElementIds": [],
680 | "startBinding": {
681 | "elementId": "lmQ4o4New7xuXQLwavuSn",
682 | "focus": -0.789940318445263,
683 | "gap": 18.5
684 | },
685 | "endBinding": {
686 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
687 | "focus": 0.35077038369679053,
688 | "gap": 15.061067030244878
689 | },
690 | "points": [
691 | [
692 | 0,
693 | 0
694 | ],
695 | [
696 | 111,
697 | 169
698 | ]
699 | ],
700 | "lastCommittedPoint": null,
701 | "startArrowhead": "arrow",
702 | "endArrowhead": "arrow"
703 | },
704 | {
705 | "type": "text",
706 | "version": 321,
707 | "versionNonce": 1856436877,
708 | "isDeleted": false,
709 | "id": "-t5tOJW9p_LjgKO1rENdv",
710 | "fillStyle": "hachure",
711 | "strokeWidth": 1,
712 | "strokeStyle": "solid",
713 | "roughness": 1,
714 | "opacity": 100,
715 | "angle": 0,
716 | "x": 640.5,
717 | "y": 307,
718 | "strokeColor": "#000000",
719 | "backgroundColor": "transparent",
720 | "width": 78,
721 | "height": 26,
722 | "seed": 1081021827,
723 | "groupIds": [],
724 | "strokeSharpness": "sharp",
725 | "boundElementIds": [
726 | "_wBO22vaQplcoKyBXbWRC"
727 | ],
728 | "fontSize": 20,
729 | "fontFamily": 1,
730 | "text": "worker 1",
731 | "baseline": 18,
732 | "textAlign": "center",
733 | "verticalAlign": "middle"
734 | },
735 | {
736 | "type": "rectangle",
737 | "version": 235,
738 | "versionNonce": 1685650659,
739 | "isDeleted": false,
740 | "id": "Yp5Kpa1JPtKUjJlgEDAwU",
741 | "fillStyle": "hachure",
742 | "strokeWidth": 1,
743 | "strokeStyle": "solid",
744 | "roughness": 1,
745 | "opacity": 100,
746 | "angle": 0,
747 | "x": 429.5,
748 | "y": 226.5,
749 | "strokeColor": "#000000",
750 | "backgroundColor": "transparent",
751 | "width": 345.00000000000006,
752 | "height": 311,
753 | "seed": 299448365,
754 | "groupIds": [],
755 | "strokeSharpness": "sharp",
756 | "boundElementIds": [
757 | "_wBO22vaQplcoKyBXbWRC",
758 | "BZVwnsrGk9G-X87ZHkh-6",
759 | "CKKC2fK8c7VggdJKNATSf",
760 | "H6kPRLfMhpJHuNpq28DBh",
761 | "s6bEUrOJ4kLZeJLk9dJST",
762 | "SkslE91eN8Chjc7oKry2J"
763 | ]
764 | },
765 | {
766 | "type": "text",
767 | "version": 170,
768 | "versionNonce": 845291757,
769 | "isDeleted": false,
770 | "id": "YNewOdVcj3FK_bEFPz2gX",
771 | "fillStyle": "hachure",
772 | "strokeWidth": 1,
773 | "strokeStyle": "solid",
774 | "roughness": 1,
775 | "opacity": 100,
776 | "angle": 0,
777 | "x": 449.5,
778 | "y": 238.5,
779 | "strokeColor": "#000000",
780 | "backgroundColor": "transparent",
781 | "width": 68,
782 | "height": 26,
783 | "seed": 2107075875,
784 | "groupIds": [],
785 | "strokeSharpness": "sharp",
786 | "boundElementIds": [],
787 | "fontSize": 20,
788 | "fontFamily": 1,
789 | "text": "Host B",
790 | "baseline": 18,
791 | "textAlign": "left",
792 | "verticalAlign": "top"
793 | },
794 | {
795 | "type": "rectangle",
796 | "version": 281,
797 | "versionNonce": 889090147,
798 | "isDeleted": false,
799 | "id": "6QhcK7EmeSnlNA6mELnWw",
800 | "fillStyle": "hachure",
801 | "strokeWidth": 1,
802 | "strokeStyle": "solid",
803 | "roughness": 1,
804 | "opacity": 100,
805 | "angle": 0,
806 | "x": 628,
807 | "y": 291.5,
808 | "strokeColor": "#000000",
809 | "backgroundColor": "transparent",
810 | "width": 129,
811 | "height": 56,
812 | "seed": 1539025549,
813 | "groupIds": [],
814 | "strokeSharpness": "sharp",
815 | "boundElementIds": [
816 | "MEmprCJaM-n292s9xtiMc"
817 | ]
818 | },
819 | {
820 | "type": "diamond",
821 | "version": 404,
822 | "versionNonce": 1957264205,
823 | "isDeleted": false,
824 | "id": "yi99XpjStdyF5QoSSbpua",
825 | "fillStyle": "hachure",
826 | "strokeWidth": 2,
827 | "strokeStyle": "solid",
828 | "roughness": 0,
829 | "opacity": 100,
830 | "angle": 0,
831 | "x": 734.5,
832 | "y": 313.5,
833 | "strokeColor": "#000000",
834 | "backgroundColor": "transparent",
835 | "width": 16,
836 | "height": 18,
837 | "seed": 252956867,
838 | "groupIds": [],
839 | "strokeSharpness": "sharp",
840 | "boundElementIds": [
841 | "Sp9AvxDh8gwRvSC53VFKe",
842 | "XZpY0rnxgeDlxu5b8fgRQ"
843 | ]
844 | },
845 | {
846 | "type": "text",
847 | "version": 359,
848 | "versionNonce": 557345795,
849 | "isDeleted": false,
850 | "id": "m_-rmUgV8rzVPm9wJLnWj",
851 | "fillStyle": "hachure",
852 | "strokeWidth": 1,
853 | "strokeStyle": "solid",
854 | "roughness": 1,
855 | "opacity": 100,
856 | "angle": 0,
857 | "x": 634.5,
858 | "y": 376,
859 | "strokeColor": "#000000",
860 | "backgroundColor": "transparent",
861 | "width": 90,
862 | "height": 26,
863 | "seed": 2036388077,
864 | "groupIds": [],
865 | "strokeSharpness": "sharp",
866 | "boundElementIds": [
867 | "_wBO22vaQplcoKyBXbWRC",
868 | "wi3_pEzGG6Yyne5m3_yJi"
869 | ],
870 | "fontSize": 20,
871 | "fontFamily": 1,
872 | "text": "worker 2",
873 | "baseline": 18,
874 | "textAlign": "center",
875 | "verticalAlign": "middle"
876 | },
877 | {
878 | "type": "rectangle",
879 | "version": 314,
880 | "versionNonce": 2111211949,
881 | "isDeleted": false,
882 | "id": "ROA9477OMY_jpRWcfxUw6",
883 | "fillStyle": "hachure",
884 | "strokeWidth": 1,
885 | "strokeStyle": "solid",
886 | "roughness": 1,
887 | "opacity": 100,
888 | "angle": 0,
889 | "x": 628,
890 | "y": 360.5,
891 | "strokeColor": "#000000",
892 | "backgroundColor": "transparent",
893 | "width": 129,
894 | "height": 56,
895 | "seed": 1719844963,
896 | "groupIds": [],
897 | "strokeSharpness": "sharp",
898 | "boundElementIds": [
899 | "wi3_pEzGG6Yyne5m3_yJi",
900 | "BwLeUURxsJb0kYyPr25hY"
901 | ]
902 | },
903 | {
904 | "type": "diamond",
905 | "version": 437,
906 | "versionNonce": 1475474339,
907 | "isDeleted": false,
908 | "id": "ZpKpnER4tz6BC8v3Ioci4",
909 | "fillStyle": "hachure",
910 | "strokeWidth": 2,
911 | "strokeStyle": "solid",
912 | "roughness": 0,
913 | "opacity": 100,
914 | "angle": 0,
915 | "x": 734.5,
916 | "y": 382.5,
917 | "strokeColor": "#000000",
918 | "backgroundColor": "transparent",
919 | "width": 16,
920 | "height": 18,
921 | "seed": 1213344589,
922 | "groupIds": [],
923 | "strokeSharpness": "sharp",
924 | "boundElementIds": [
925 | "Sp9AvxDh8gwRvSC53VFKe",
926 | "4mjxZzapHnLuRx7KU2JeH"
927 | ]
928 | },
929 | {
930 | "type": "text",
931 | "version": 344,
932 | "versionNonce": 1326631949,
933 | "isDeleted": false,
934 | "id": "lnKKGJYWby9w4kCUJ_3IF",
935 | "fillStyle": "hachure",
936 | "strokeWidth": 1,
937 | "strokeStyle": "solid",
938 | "roughness": 1,
939 | "opacity": 100,
940 | "angle": 0,
941 | "x": 636,
942 | "y": 442,
943 | "strokeColor": "#000000",
944 | "backgroundColor": "transparent",
945 | "width": 89,
946 | "height": 26,
947 | "seed": 1035123715,
948 | "groupIds": [],
949 | "strokeSharpness": "sharp",
950 | "boundElementIds": [
951 | "_wBO22vaQplcoKyBXbWRC"
952 | ],
953 | "fontSize": 20,
954 | "fontFamily": 1,
955 | "text": "worker 3",
956 | "baseline": 18,
957 | "textAlign": "center",
958 | "verticalAlign": "middle"
959 | },
960 | {
961 | "type": "rectangle",
962 | "version": 299,
963 | "versionNonce": 2035910467,
964 | "isDeleted": false,
965 | "id": "RcoOUjN-3ibbIV71_ozA6",
966 | "fillStyle": "hachure",
967 | "strokeWidth": 1,
968 | "strokeStyle": "solid",
969 | "roughness": 1,
970 | "opacity": 100,
971 | "angle": 0,
972 | "x": 629,
973 | "y": 426.5,
974 | "strokeColor": "#000000",
975 | "backgroundColor": "transparent",
976 | "width": 129,
977 | "height": 56,
978 | "seed": 954808749,
979 | "groupIds": [],
980 | "strokeSharpness": "sharp",
981 | "boundElementIds": [
982 | "BwLeUURxsJb0kYyPr25hY"
983 | ]
984 | },
985 | {
986 | "type": "diamond",
987 | "version": 427,
988 | "versionNonce": 139969133,
989 | "isDeleted": false,
990 | "id": "D01DM9Gzt47JacAhP--Cs",
991 | "fillStyle": "hachure",
992 | "strokeWidth": 2,
993 | "strokeStyle": "solid",
994 | "roughness": 0,
995 | "opacity": 100,
996 | "angle": 0,
997 | "x": 735.5,
998 | "y": 448.5,
999 | "strokeColor": "#000000",
1000 | "backgroundColor": "transparent",
1001 | "width": 16,
1002 | "height": 18,
1003 | "seed": 279069603,
1004 | "groupIds": [],
1005 | "strokeSharpness": "sharp",
1006 | "boundElementIds": [
1007 | "Sp9AvxDh8gwRvSC53VFKe",
1008 | "eU1gfEXnHSjxc-pEgv43A"
1009 | ]
1010 | },
1011 | {
1012 | "type": "text",
1013 | "version": 75,
1014 | "versionNonce": 466462435,
1015 | "isDeleted": false,
1016 | "id": "_Tyw0FsCuxYBWnTNAl2Ey",
1017 | "fillStyle": "hachure",
1018 | "strokeWidth": 1,
1019 | "strokeStyle": "solid",
1020 | "roughness": 1,
1021 | "opacity": 100,
1022 | "angle": 0,
1023 | "x": 477.5,
1024 | "y": 372.5,
1025 | "strokeColor": "#000000",
1026 | "backgroundColor": "transparent",
1027 | "width": 67,
1028 | "height": 26,
1029 | "seed": 1951366157,
1030 | "groupIds": [],
1031 | "strokeSharpness": "sharp",
1032 | "boundElementIds": [],
1033 | "fontSize": 20,
1034 | "fontFamily": 1,
1035 | "text": "master",
1036 | "baseline": 18,
1037 | "textAlign": "center",
1038 | "verticalAlign": "middle"
1039 | },
1040 | {
1041 | "type": "rectangle",
1042 | "version": 314,
1043 | "versionNonce": 242150605,
1044 | "isDeleted": false,
1045 | "id": "AEMAAc1yR1kMKbtgszrCZ",
1046 | "fillStyle": "hachure",
1047 | "strokeWidth": 1,
1048 | "strokeStyle": "solid",
1049 | "roughness": 1,
1050 | "opacity": 100,
1051 | "angle": 0,
1052 | "x": 444,
1053 | "y": 359.5,
1054 | "strokeColor": "#000000",
1055 | "backgroundColor": "transparent",
1056 | "width": 129,
1057 | "height": 56,
1058 | "seed": 1467995971,
1059 | "groupIds": [],
1060 | "strokeSharpness": "sharp",
1061 | "boundElementIds": [
1062 | "MEmprCJaM-n292s9xtiMc",
1063 | "wi3_pEzGG6Yyne5m3_yJi",
1064 | "BwLeUURxsJb0kYyPr25hY"
1065 | ]
1066 | },
1067 | {
1068 | "type": "arrow",
1069 | "version": 204,
1070 | "versionNonce": 98357891,
1071 | "isDeleted": false,
1072 | "id": "MEmprCJaM-n292s9xtiMc",
1073 | "fillStyle": "hachure",
1074 | "strokeWidth": 1,
1075 | "strokeStyle": "solid",
1076 | "roughness": 1,
1077 | "opacity": 100,
1078 | "angle": 0,
1079 | "x": 582.5,
1080 | "y": 380.5,
1081 | "strokeColor": "#000000",
1082 | "backgroundColor": "transparent",
1083 | "width": 34,
1084 | "height": 48,
1085 | "seed": 1115583085,
1086 | "groupIds": [],
1087 | "strokeSharpness": "round",
1088 | "boundElementIds": [],
1089 | "startBinding": {
1090 | "elementId": "AEMAAc1yR1kMKbtgszrCZ",
1091 | "focus": 0.8186758893280632,
1092 | "gap": 9.5
1093 | },
1094 | "endBinding": {
1095 | "elementId": "6QhcK7EmeSnlNA6mELnWw",
1096 | "focus": 0.7919960474308301,
1097 | "gap": 11.5
1098 | },
1099 | "points": [
1100 | [
1101 | 0,
1102 | 0
1103 | ],
1104 | [
1105 | 34,
1106 | -48
1107 | ]
1108 | ],
1109 | "lastCommittedPoint": null,
1110 | "startArrowhead": null,
1111 | "endArrowhead": "arrow"
1112 | },
1113 | {
1114 | "type": "arrow",
1115 | "version": 260,
1116 | "versionNonce": 1894894381,
1117 | "isDeleted": false,
1118 | "id": "wi3_pEzGG6Yyne5m3_yJi",
1119 | "fillStyle": "hachure",
1120 | "strokeWidth": 1,
1121 | "strokeStyle": "solid",
1122 | "roughness": 1,
1123 | "opacity": 100,
1124 | "angle": 0,
1125 | "x": 585.2063185837119,
1126 | "y": 387.00435436107216,
1127 | "strokeColor": "#000000",
1128 | "backgroundColor": "transparent",
1129 | "width": 32.383044731616906,
1130 | "height": 0.6793771122768604,
1131 | "seed": 11138787,
1132 | "groupIds": [],
1133 | "strokeSharpness": "round",
1134 | "boundElementIds": [],
1135 | "startBinding": {
1136 | "elementId": "AEMAAc1yR1kMKbtgszrCZ",
1137 | "focus": -0.071709415801483,
1138 | "gap": 12.20631858371189
1139 | },
1140 | "endBinding": {
1141 | "elementId": "ROA9477OMY_jpRWcfxUw6",
1142 | "focus": -0.02573187998110361,
1143 | "gap": 10.410636684671204
1144 | },
1145 | "points": [
1146 | [
1147 | 0,
1148 | 0
1149 | ],
1150 | [
1151 | 32.383044731616906,
1152 | 0.6793771122768604
1153 | ]
1154 | ],
1155 | "lastCommittedPoint": null,
1156 | "startArrowhead": null,
1157 | "endArrowhead": "arrow"
1158 | },
1159 | {
1160 | "type": "arrow",
1161 | "version": 315,
1162 | "versionNonce": 675645987,
1163 | "isDeleted": false,
1164 | "id": "BwLeUURxsJb0kYyPr25hY",
1165 | "fillStyle": "hachure",
1166 | "strokeWidth": 1,
1167 | "strokeStyle": "solid",
1168 | "roughness": 1,
1169 | "opacity": 100,
1170 | "angle": 0,
1171 | "x": 587.3084776341916,
1172 | "y": 399.1603114438616,
1173 | "strokeColor": "#000000",
1174 | "backgroundColor": "transparent",
1175 | "width": 32.40004203654814,
1176 | "height": 43.76823068360791,
1177 | "seed": 809475277,
1178 | "groupIds": [],
1179 | "strokeSharpness": "round",
1180 | "boundElementIds": [],
1181 | "startBinding": {
1182 | "elementId": "AEMAAc1yR1kMKbtgszrCZ",
1183 | "focus": -0.8234063011749818,
1184 | "gap": 14.308477634191604
1185 | },
1186 | "endBinding": {
1187 | "elementId": "RcoOUjN-3ibbIV71_ozA6",
1188 | "focus": -0.7653120403381727,
1189 | "gap": 9.291480329260253
1190 | },
1191 | "points": [
1192 | [
1193 | 0,
1194 | 0
1195 | ],
1196 | [
1197 | 32.40004203654814,
1198 | 43.76823068360791
1199 | ]
1200 | ],
1201 | "lastCommittedPoint": null,
1202 | "startArrowhead": null,
1203 | "endArrowhead": "arrow"
1204 | },
1205 | {
1206 | "type": "text",
1207 | "version": 46,
1208 | "versionNonce": 273276301,
1209 | "isDeleted": false,
1210 | "id": "YWZMjOMxTqcywTzWOi2Fd",
1211 | "fillStyle": "hachure",
1212 | "strokeWidth": 1,
1213 | "strokeStyle": "solid",
1214 | "roughness": 1,
1215 | "opacity": 100,
1216 | "angle": 0,
1217 | "x": 678,
1218 | "y": 170,
1219 | "strokeColor": "#000000",
1220 | "backgroundColor": "transparent",
1221 | "width": 16,
1222 | "height": 26,
1223 | "seed": 542615715,
1224 | "groupIds": [],
1225 | "strokeSharpness": "sharp",
1226 | "boundElementIds": [],
1227 | "fontSize": 20,
1228 | "fontFamily": 1,
1229 | "text": "...",
1230 | "baseline": 18,
1231 | "textAlign": "left",
1232 | "verticalAlign": "top"
1233 | },
1234 | {
1235 | "type": "text",
1236 | "version": 73,
1237 | "versionNonce": 1475759555,
1238 | "isDeleted": false,
1239 | "id": "ft8BfHmWU6cvt65MLclAF",
1240 | "fillStyle": "hachure",
1241 | "strokeWidth": 1,
1242 | "strokeStyle": "solid",
1243 | "roughness": 1,
1244 | "opacity": 100,
1245 | "angle": 0,
1246 | "x": 681,
1247 | "y": 503,
1248 | "strokeColor": "#000000",
1249 | "backgroundColor": "transparent",
1250 | "width": 16,
1251 | "height": 26,
1252 | "seed": 202755715,
1253 | "groupIds": [],
1254 | "strokeSharpness": "sharp",
1255 | "boundElementIds": [],
1256 | "fontSize": 20,
1257 | "fontFamily": 1,
1258 | "text": "...",
1259 | "baseline": 18,
1260 | "textAlign": "left",
1261 | "verticalAlign": "top"
1262 | },
1263 | {
1264 | "type": "arrow",
1265 | "version": 382,
1266 | "versionNonce": 61907949,
1267 | "isDeleted": false,
1268 | "id": "CKKC2fK8c7VggdJKNATSf",
1269 | "fillStyle": "hachure",
1270 | "strokeWidth": 2,
1271 | "strokeStyle": "solid",
1272 | "roughness": 0,
1273 | "opacity": 100,
1274 | "angle": 0,
1275 | "x": 864,
1276 | "y": 261,
1277 | "strokeColor": "#000000",
1278 | "backgroundColor": "transparent",
1279 | "width": 77,
1280 | "height": 39,
1281 | "seed": 1155983491,
1282 | "groupIds": [],
1283 | "strokeSharpness": "round",
1284 | "boundElementIds": [],
1285 | "startBinding": {
1286 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
1287 | "focus": 0.0932539046701243,
1288 | "gap": 14.753203494349187
1289 | },
1290 | "endBinding": {
1291 | "elementId": "Yp5Kpa1JPtKUjJlgEDAwU",
1292 | "focus": 0.04817924175177798,
1293 | "gap": 12.5
1294 | },
1295 | "points": [
1296 | [
1297 | 0,
1298 | 0
1299 | ],
1300 | [
1301 | -77,
1302 | 39
1303 | ]
1304 | ],
1305 | "lastCommittedPoint": null,
1306 | "startArrowhead": "arrow",
1307 | "endArrowhead": "arrow"
1308 | },
1309 | {
1310 | "type": "arrow",
1311 | "version": 440,
1312 | "versionNonce": 1470302275,
1313 | "isDeleted": false,
1314 | "id": "H6kPRLfMhpJHuNpq28DBh",
1315 | "fillStyle": "hachure",
1316 | "strokeWidth": 2,
1317 | "strokeStyle": "solid",
1318 | "roughness": 0,
1319 | "opacity": 100,
1320 | "angle": 0,
1321 | "x": 879.5,
1322 | "y": 284.5,
1323 | "strokeColor": "#000000",
1324 | "backgroundColor": "transparent",
1325 | "width": 87,
1326 | "height": 88,
1327 | "seed": 1138358531,
1328 | "groupIds": [],
1329 | "strokeSharpness": "round",
1330 | "boundElementIds": [],
1331 | "startBinding": {
1332 | "elementId": "EQmjbilyrf3OcSwGbMZrg",
1333 | "focus": -0.1142231163839854,
1334 | "gap": 18.76824885115778
1335 | },
1336 | "endBinding": {
1337 | "elementId": "Yp5Kpa1JPtKUjJlgEDAwU",
1338 | "focus": 0.5551491718480589,
1339 | "gap": 18
1340 | },
1341 | "points": [
1342 | [
1343 | 0,
1344 | 0
1345 | ],
1346 | [
1347 | -87,
1348 | 88
1349 | ]
1350 | ],
1351 | "lastCommittedPoint": null,
1352 | "startArrowhead": "arrow",
1353 | "endArrowhead": "arrow"
1354 | },
1355 | {
1356 | "type": "arrow",
1357 | "version": 494,
1358 | "versionNonce": 164316941,
1359 | "isDeleted": false,
1360 | "id": "s6bEUrOJ4kLZeJLk9dJST",
1361 | "fillStyle": "hachure",
1362 | "strokeWidth": 2,
1363 | "strokeStyle": "solid",
1364 | "roughness": 0,
1365 | "opacity": 100,
1366 | "angle": 0,
1367 | "x": 901.5,
1368 | "y": 297,
1369 | "strokeColor": "#000000",
1370 | "backgroundColor": "transparent",
1371 | "width": 109,
1372 | "height": 153,
1373 | "seed": 1853494147,
1374 | "groupIds": [],
1375 | "strokeSharpness": "round",
1376 | "boundElementIds": [],
1377 | "startBinding": null,
1378 | "endBinding": {
1379 | "elementId": "Yp5Kpa1JPtKUjJlgEDAwU",
1380 | "focus": 0.8434889945087904,
1381 | "gap": 18
1382 | },
1383 | "points": [
1384 | [
1385 | 0,
1386 | 0
1387 | ],
1388 | [
1389 | -109,
1390 | 153
1391 | ]
1392 | ],
1393 | "lastCommittedPoint": null,
1394 | "startArrowhead": "arrow",
1395 | "endArrowhead": "arrow"
1396 | },
1397 | {
1398 | "id": "2JYwvUtBLBneWYjVgsiLM",
1399 | "type": "text",
1400 | "x": 164,
1401 | "y": 186,
1402 | "width": 150,
1403 | "height": 52,
1404 | "angle": 0,
1405 | "strokeColor": "#000000",
1406 | "backgroundColor": "transparent",
1407 | "fillStyle": "hachure",
1408 | "strokeWidth": 2,
1409 | "strokeStyle": "solid",
1410 | "roughness": 1,
1411 | "opacity": 100,
1412 | "groupIds": [],
1413 | "strokeSharpness": "sharp",
1414 | "seed": 1208666435,
1415 | "version": 168,
1416 | "versionNonce": 1663726979,
1417 | "isDeleted": false,
1418 | "boundElementIds": null,
1419 | "text": "load-balancer\n(sticky session)",
1420 | "fontSize": 20,
1421 | "fontFamily": 1,
1422 | "textAlign": "center",
1423 | "verticalAlign": "top",
1424 | "baseline": 44
1425 | },
1426 | {
1427 | "id": "EBAsIqbyBZbbwEKEu4HSG",
1428 | "type": "diamond",
1429 | "x": 134,
1430 | "y": 138,
1431 | "width": 207,
1432 | "height": 149,
1433 | "angle": 0,
1434 | "strokeColor": "#000000",
1435 | "backgroundColor": "transparent",
1436 | "fillStyle": "hachure",
1437 | "strokeWidth": 2,
1438 | "strokeStyle": "solid",
1439 | "roughness": 1,
1440 | "opacity": 100,
1441 | "groupIds": [],
1442 | "strokeSharpness": "sharp",
1443 | "seed": 1371271043,
1444 | "version": 100,
1445 | "versionNonce": 439852355,
1446 | "isDeleted": false,
1447 | "boundElementIds": [
1448 | "zkLKnuWAYxJGCPBZp9UAB",
1449 | "SkslE91eN8Chjc7oKry2J"
1450 | ]
1451 | },
1452 | {
1453 | "id": "zkLKnuWAYxJGCPBZp9UAB",
1454 | "type": "arrow",
1455 | "x": 315,
1456 | "y": 166,
1457 | "width": 91,
1458 | "height": 80,
1459 | "angle": 0,
1460 | "strokeColor": "#000000",
1461 | "backgroundColor": "transparent",
1462 | "fillStyle": "hachure",
1463 | "strokeWidth": 1,
1464 | "strokeStyle": "solid",
1465 | "roughness": 1,
1466 | "opacity": 100,
1467 | "groupIds": [],
1468 | "strokeSharpness": "round",
1469 | "seed": 1134589091,
1470 | "version": 46,
1471 | "versionNonce": 2036575267,
1472 | "isDeleted": false,
1473 | "boundElementIds": null,
1474 | "points": [
1475 | [
1476 | 0,
1477 | 0
1478 | ],
1479 | [
1480 | 91,
1481 | -80
1482 | ]
1483 | ],
1484 | "lastCommittedPoint": null,
1485 | "startBinding": {
1486 | "elementId": "EBAsIqbyBZbbwEKEu4HSG",
1487 | "focus": 0.290360646065344,
1488 | "gap": 22.55056739709275
1489 | },
1490 | "endBinding": {
1491 | "elementId": "lmQ4o4New7xuXQLwavuSn",
1492 | "focus": 0.45414214414768966,
1493 | "gap": 22
1494 | },
1495 | "startArrowhead": "arrow",
1496 | "endArrowhead": "arrow"
1497 | },
1498 | {
1499 | "id": "SkslE91eN8Chjc7oKry2J",
1500 | "type": "arrow",
1501 | "x": 306.8498551402241,
1502 | "y": 257.2574737574905,
1503 | "width": 98.01361482879145,
1504 | "height": 128.02140059301632,
1505 | "angle": 0,
1506 | "strokeColor": "#000000",
1507 | "backgroundColor": "transparent",
1508 | "fillStyle": "hachure",
1509 | "strokeWidth": 1,
1510 | "strokeStyle": "solid",
1511 | "roughness": 1,
1512 | "opacity": 100,
1513 | "groupIds": [],
1514 | "strokeSharpness": "round",
1515 | "seed": 237887981,
1516 | "version": 93,
1517 | "versionNonce": 2089684077,
1518 | "isDeleted": false,
1519 | "boundElementIds": null,
1520 | "points": [
1521 | [
1522 | 0,
1523 | 0
1524 | ],
1525 | [
1526 | 98.01361482879145,
1527 | 128.02140059301632
1528 | ]
1529 | ],
1530 | "lastCommittedPoint": null,
1531 | "startBinding": {
1532 | "elementId": "EBAsIqbyBZbbwEKEu4HSG",
1533 | "focus": -0.3389698812804046,
1534 | "gap": 16.374991628092786
1535 | },
1536 | "endBinding": {
1537 | "elementId": "Yp5Kpa1JPtKUjJlgEDAwU",
1538 | "focus": -0.6847742800267905,
1539 | "gap": 24.63653003098443
1540 | },
1541 | "startArrowhead": "arrow",
1542 | "endArrowhead": "arrow"
1543 | }
1544 | ],
1545 | "appState": {
1546 | "gridSize": null,
1547 | "viewBackgroundColor": "#ffffff"
1548 | }
1549 | }
--------------------------------------------------------------------------------
/assets/socket.io-cluster-redis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-sticky/518bd0b989e20fadecbbb6b225578bfca82ad963/assets/socket.io-cluster-redis.png
--------------------------------------------------------------------------------
/assets/socket.io-cluster.excalidraw:
--------------------------------------------------------------------------------
1 | {
2 | "type": "excalidraw",
3 | "version": 2,
4 | "source": "https://excalidraw.com",
5 | "elements": [
6 | {
7 | "type": "text",
8 | "version": 287,
9 | "versionNonce": 624942413,
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": 1047,
19 | "y": 23.5,
20 | "strokeColor": "#000000",
21 | "backgroundColor": "transparent",
22 | "width": 78,
23 | "height": 26,
24 | "seed": 28708370,
25 | "groupIds": [],
26 | "strokeSharpness": "sharp",
27 | "boundElementIds": [
28 | "_wBO22vaQplcoKyBXbWRC"
29 | ],
30 | "fontSize": 20,
31 | "fontFamily": 1,
32 | "text": "worker 1",
33 | "baseline": 18,
34 | "textAlign": "center",
35 | "verticalAlign": "middle"
36 | },
37 | {
38 | "type": "rectangle",
39 | "version": 193,
40 | "versionNonce": 1953704131,
41 | "isDeleted": false,
42 | "id": "lmQ4o4New7xuXQLwavuSn",
43 | "fillStyle": "hachure",
44 | "strokeWidth": 1,
45 | "strokeStyle": "solid",
46 | "roughness": 1,
47 | "opacity": 100,
48 | "angle": 0,
49 | "x": 821,
50 | "y": -57,
51 | "strokeColor": "#000000",
52 | "backgroundColor": "transparent",
53 | "width": 345.00000000000006,
54 | "height": 311,
55 | "seed": 1594950354,
56 | "groupIds": [],
57 | "strokeSharpness": "sharp",
58 | "boundElementIds": [
59 | "_wBO22vaQplcoKyBXbWRC",
60 | "BZVwnsrGk9G-X87ZHkh-6",
61 | "eU1gfEXnHSjxc-pEgv43A",
62 | "XZpY0rnxgeDlxu5b8fgRQ",
63 | "4mjxZzapHnLuRx7KU2JeH",
64 | "mV8ZNfAcYrxGLJ7b9a_kn"
65 | ]
66 | },
67 | {
68 | "type": "text",
69 | "version": 132,
70 | "versionNonce": 1364241325,
71 | "isDeleted": false,
72 | "id": "ZQsZmj4NaTubBHMkVG2dl",
73 | "fillStyle": "hachure",
74 | "strokeWidth": 1,
75 | "strokeStyle": "solid",
76 | "roughness": 1,
77 | "opacity": 100,
78 | "angle": 0,
79 | "x": 841,
80 | "y": -47,
81 | "strokeColor": "#000000",
82 | "backgroundColor": "transparent",
83 | "width": 43,
84 | "height": 26,
85 | "seed": 126533902,
86 | "groupIds": [],
87 | "strokeSharpness": "sharp",
88 | "boundElementIds": [],
89 | "fontSize": 20,
90 | "fontFamily": 1,
91 | "text": "Host",
92 | "baseline": 18,
93 | "textAlign": "left",
94 | "verticalAlign": "top"
95 | },
96 | {
97 | "type": "rectangle",
98 | "version": 237,
99 | "versionNonce": 1477038563,
100 | "isDeleted": false,
101 | "id": "RRrk3Vsl-pM8Z1r8Fj3Vu",
102 | "fillStyle": "hachure",
103 | "strokeWidth": 1,
104 | "strokeStyle": "solid",
105 | "roughness": 1,
106 | "opacity": 100,
107 | "angle": 0,
108 | "x": 1019.5,
109 | "y": 8,
110 | "strokeColor": "#000000",
111 | "backgroundColor": "transparent",
112 | "width": 129,
113 | "height": 56,
114 | "seed": 1013161166,
115 | "groupIds": [],
116 | "strokeSharpness": "sharp",
117 | "boundElementIds": [
118 | "use4Bp2hbb77Fq5njtwBi"
119 | ]
120 | },
121 | {
122 | "type": "text",
123 | "version": 328,
124 | "versionNonce": 414893379,
125 | "isDeleted": false,
126 | "id": "qfQdcJHnwYnCMtLCV51X8",
127 | "fillStyle": "hachure",
128 | "strokeWidth": 1,
129 | "strokeStyle": "solid",
130 | "roughness": 1,
131 | "opacity": 100,
132 | "angle": 0,
133 | "x": 1043,
134 | "y": 94.5,
135 | "strokeColor": "#000000",
136 | "backgroundColor": "transparent",
137 | "width": 90,
138 | "height": 26,
139 | "seed": 1535426147,
140 | "groupIds": [],
141 | "strokeSharpness": "sharp",
142 | "boundElementIds": [
143 | "_wBO22vaQplcoKyBXbWRC",
144 | "2DIFacJXJtC5QIuMuo3pK"
145 | ],
146 | "fontSize": 20,
147 | "fontFamily": 1,
148 | "text": "worker 2",
149 | "baseline": 18,
150 | "textAlign": "center",
151 | "verticalAlign": "middle"
152 | },
153 | {
154 | "type": "rectangle",
155 | "version": 270,
156 | "versionNonce": 498267427,
157 | "isDeleted": false,
158 | "id": "IRd1nPQbv0PQdJQn_yLOs",
159 | "fillStyle": "hachure",
160 | "strokeWidth": 1,
161 | "strokeStyle": "solid",
162 | "roughness": 1,
163 | "opacity": 100,
164 | "angle": 0,
165 | "x": 1019.5,
166 | "y": 77,
167 | "strokeColor": "#000000",
168 | "backgroundColor": "transparent",
169 | "width": 129,
170 | "height": 56,
171 | "seed": 452398413,
172 | "groupIds": [],
173 | "strokeSharpness": "sharp",
174 | "boundElementIds": [
175 | "2DIFacJXJtC5QIuMuo3pK",
176 | "NhqDM6wVMhgbRvXrQJQge"
177 | ]
178 | },
179 | {
180 | "type": "text",
181 | "version": 316,
182 | "versionNonce": 935612109,
183 | "isDeleted": false,
184 | "id": "ENOSqQ4visNbCN7ZMZwxP",
185 | "fillStyle": "hachure",
186 | "strokeWidth": 1,
187 | "strokeStyle": "solid",
188 | "roughness": 1,
189 | "opacity": 100,
190 | "angle": 0,
191 | "x": 1040.5,
192 | "y": 161.5,
193 | "strokeColor": "#000000",
194 | "backgroundColor": "transparent",
195 | "width": 89,
196 | "height": 26,
197 | "seed": 1916984429,
198 | "groupIds": [],
199 | "strokeSharpness": "sharp",
200 | "boundElementIds": [
201 | "_wBO22vaQplcoKyBXbWRC"
202 | ],
203 | "fontSize": 20,
204 | "fontFamily": 1,
205 | "text": "worker 3",
206 | "baseline": 18,
207 | "textAlign": "center",
208 | "verticalAlign": "middle"
209 | },
210 | {
211 | "type": "rectangle",
212 | "version": 255,
213 | "versionNonce": 1264339043,
214 | "isDeleted": false,
215 | "id": "IqdB8EO7s50UY1EU9TVVP",
216 | "fillStyle": "hachure",
217 | "strokeWidth": 1,
218 | "strokeStyle": "solid",
219 | "roughness": 1,
220 | "opacity": 100,
221 | "angle": 0,
222 | "x": 1020.5,
223 | "y": 143,
224 | "strokeColor": "#000000",
225 | "backgroundColor": "transparent",
226 | "width": 129,
227 | "height": 56,
228 | "seed": 1832463587,
229 | "groupIds": [],
230 | "strokeSharpness": "sharp",
231 | "boundElementIds": [
232 | "NhqDM6wVMhgbRvXrQJQge"
233 | ]
234 | },
235 | {
236 | "id": "D8P7Bclj4xdmqfd3xlM9w",
237 | "type": "text",
238 | "x": 869,
239 | "y": 89,
240 | "width": 67,
241 | "height": 26,
242 | "angle": 0,
243 | "strokeColor": "#000000",
244 | "backgroundColor": "transparent",
245 | "fillStyle": "hachure",
246 | "strokeWidth": 1,
247 | "strokeStyle": "solid",
248 | "roughness": 1,
249 | "opacity": 100,
250 | "groupIds": [],
251 | "strokeSharpness": "sharp",
252 | "seed": 415223619,
253 | "version": 33,
254 | "versionNonce": 856131619,
255 | "isDeleted": false,
256 | "boundElementIds": null,
257 | "text": "master",
258 | "fontSize": 20,
259 | "fontFamily": 1,
260 | "textAlign": "center",
261 | "verticalAlign": "middle",
262 | "baseline": 18
263 | },
264 | {
265 | "type": "rectangle",
266 | "version": 268,
267 | "versionNonce": 847141059,
268 | "isDeleted": false,
269 | "id": "SlTRvTrZRavsPt44aEe3R",
270 | "fillStyle": "hachure",
271 | "strokeWidth": 1,
272 | "strokeStyle": "solid",
273 | "roughness": 1,
274 | "opacity": 100,
275 | "angle": 0,
276 | "x": 835.5,
277 | "y": 76,
278 | "strokeColor": "#000000",
279 | "backgroundColor": "transparent",
280 | "width": 129,
281 | "height": 56,
282 | "seed": 813326061,
283 | "groupIds": [],
284 | "strokeSharpness": "sharp",
285 | "boundElementIds": [
286 | "use4Bp2hbb77Fq5njtwBi",
287 | "2DIFacJXJtC5QIuMuo3pK",
288 | "NhqDM6wVMhgbRvXrQJQge"
289 | ]
290 | },
291 | {
292 | "id": "use4Bp2hbb77Fq5njtwBi",
293 | "type": "arrow",
294 | "x": 974,
295 | "y": 97,
296 | "width": 34,
297 | "height": 48,
298 | "angle": 0,
299 | "strokeColor": "#000000",
300 | "backgroundColor": "transparent",
301 | "fillStyle": "hachure",
302 | "strokeWidth": 1,
303 | "strokeStyle": "solid",
304 | "roughness": 1,
305 | "opacity": 100,
306 | "groupIds": [],
307 | "strokeSharpness": "round",
308 | "seed": 1423358221,
309 | "version": 73,
310 | "versionNonce": 1550083949,
311 | "isDeleted": false,
312 | "boundElementIds": null,
313 | "points": [
314 | [
315 | 0,
316 | 0
317 | ],
318 | [
319 | 34,
320 | -48
321 | ]
322 | ],
323 | "lastCommittedPoint": null,
324 | "startBinding": {
325 | "elementId": "SlTRvTrZRavsPt44aEe3R",
326 | "focus": 0.8186758893280632,
327 | "gap": 9.5
328 | },
329 | "endBinding": {
330 | "elementId": "RRrk3Vsl-pM8Z1r8Fj3Vu",
331 | "focus": 0.7919960474308301,
332 | "gap": 11.5
333 | },
334 | "startArrowhead": null,
335 | "endArrowhead": "arrow"
336 | },
337 | {
338 | "id": "2DIFacJXJtC5QIuMuo3pK",
339 | "type": "arrow",
340 | "x": 976.706318583712,
341 | "y": 103.50435436107217,
342 | "width": 32.383044731616906,
343 | "height": 0.6793771122768604,
344 | "angle": 0,
345 | "strokeColor": "#000000",
346 | "backgroundColor": "transparent",
347 | "fillStyle": "hachure",
348 | "strokeWidth": 2,
349 | "strokeStyle": "solid",
350 | "roughness": 1,
351 | "opacity": 100,
352 | "groupIds": [],
353 | "strokeSharpness": "round",
354 | "seed": 1764672259,
355 | "version": 144,
356 | "versionNonce": 1995450765,
357 | "isDeleted": false,
358 | "boundElementIds": null,
359 | "points": [
360 | [
361 | 0,
362 | 0
363 | ],
364 | [
365 | 32.383044731616906,
366 | 0.6793771122768604
367 | ]
368 | ],
369 | "lastCommittedPoint": null,
370 | "startBinding": {
371 | "elementId": "SlTRvTrZRavsPt44aEe3R",
372 | "focus": -0.07170941580148152,
373 | "gap": 12.206318583712005
374 | },
375 | "endBinding": {
376 | "elementId": "IRd1nPQbv0PQdJQn_yLOs",
377 | "focus": -0.025731879981102438,
378 | "gap": 10.41063668467109
379 | },
380 | "startArrowhead": null,
381 | "endArrowhead": "arrow"
382 | },
383 | {
384 | "id": "NhqDM6wVMhgbRvXrQJQge",
385 | "type": "arrow",
386 | "x": 978.8084776341915,
387 | "y": 115.66031144386157,
388 | "width": 32.40004203654814,
389 | "height": 43.76823068360791,
390 | "angle": 0,
391 | "strokeColor": "#000000",
392 | "backgroundColor": "transparent",
393 | "fillStyle": "hachure",
394 | "strokeWidth": 1,
395 | "strokeStyle": "solid",
396 | "roughness": 1,
397 | "opacity": 100,
398 | "groupIds": [],
399 | "strokeSharpness": "round",
400 | "seed": 1285959341,
401 | "version": 184,
402 | "versionNonce": 2109917421,
403 | "isDeleted": false,
404 | "boundElementIds": null,
405 | "points": [
406 | [
407 | 0,
408 | 0
409 | ],
410 | [
411 | 32.40004203654814,
412 | 43.76823068360791
413 | ]
414 | ],
415 | "lastCommittedPoint": null,
416 | "startBinding": {
417 | "elementId": "SlTRvTrZRavsPt44aEe3R",
418 | "focus": -0.8234063011749806,
419 | "gap": 14.30847763419149
420 | },
421 | "endBinding": {
422 | "elementId": "IqdB8EO7s50UY1EU9TVVP",
423 | "focus": -0.7653120403381738,
424 | "gap": 9.291480329260366
425 | },
426 | "startArrowhead": null,
427 | "endArrowhead": "arrow"
428 | },
429 | {
430 | "id": "YWZMjOMxTqcywTzWOi2Fd",
431 | "type": "text",
432 | "x": 1071,
433 | "y": 214,
434 | "width": 16,
435 | "height": 26,
436 | "angle": 0,
437 | "strokeColor": "#000000",
438 | "backgroundColor": "transparent",
439 | "fillStyle": "hachure",
440 | "strokeWidth": 1,
441 | "strokeStyle": "solid",
442 | "roughness": 1,
443 | "opacity": 100,
444 | "groupIds": [],
445 | "strokeSharpness": "sharp",
446 | "seed": 542615715,
447 | "version": 60,
448 | "versionNonce": 464314019,
449 | "isDeleted": false,
450 | "boundElementIds": null,
451 | "text": "...",
452 | "fontSize": 20,
453 | "fontFamily": 1,
454 | "textAlign": "left",
455 | "verticalAlign": "top",
456 | "baseline": 18
457 | },
458 | {
459 | "id": "9grXh8d6z3-WENQLWSBP6",
460 | "type": "rectangle",
461 | "x": 416,
462 | "y": 83,
463 | "width": 140,
464 | "height": 49,
465 | "angle": 0,
466 | "strokeColor": "#000000",
467 | "backgroundColor": "transparent",
468 | "fillStyle": "hachure",
469 | "strokeWidth": 1,
470 | "strokeStyle": "solid",
471 | "roughness": 1,
472 | "opacity": 100,
473 | "groupIds": [],
474 | "strokeSharpness": "sharp",
475 | "seed": 1667334019,
476 | "version": 56,
477 | "versionNonce": 799901037,
478 | "isDeleted": false,
479 | "boundElementIds": null
480 | },
481 | {
482 | "id": "uw4DcwoucyYZxQuvW-XdC",
483 | "type": "text",
484 | "x": 461,
485 | "y": 94.5,
486 | "width": 50,
487 | "height": 26,
488 | "angle": 0,
489 | "strokeColor": "#000000",
490 | "backgroundColor": "transparent",
491 | "fillStyle": "hachure",
492 | "strokeWidth": 1,
493 | "strokeStyle": "solid",
494 | "roughness": 1,
495 | "opacity": 100,
496 | "groupIds": [],
497 | "strokeSharpness": "sharp",
498 | "seed": 1216901411,
499 | "version": 36,
500 | "versionNonce": 266965987,
501 | "isDeleted": false,
502 | "boundElementIds": null,
503 | "text": "client",
504 | "fontSize": 20,
505 | "fontFamily": 1,
506 | "textAlign": "center",
507 | "verticalAlign": "middle",
508 | "baseline": 18
509 | },
510 | {
511 | "id": "mV8ZNfAcYrxGLJ7b9a_kn",
512 | "type": "arrow",
513 | "x": 574,
514 | "y": 105,
515 | "width": 229.6901474025101,
516 | "height": 1.3929567589983378,
517 | "angle": 0,
518 | "strokeColor": "#000000",
519 | "backgroundColor": "transparent",
520 | "fillStyle": "hachure",
521 | "strokeWidth": 2,
522 | "strokeStyle": "solid",
523 | "roughness": 1,
524 | "opacity": 100,
525 | "groupIds": [],
526 | "strokeSharpness": "round",
527 | "seed": 846315459,
528 | "version": 58,
529 | "versionNonce": 1002623629,
530 | "isDeleted": false,
531 | "boundElementIds": null,
532 | "points": [
533 | [
534 | 0,
535 | 0
536 | ],
537 | [
538 | 229.6901474025101,
539 | 1.3929567589983378
540 | ]
541 | ],
542 | "lastCommittedPoint": null,
543 | "startBinding": null,
544 | "endBinding": {
545 | "elementId": "lmQ4o4New7xuXQLwavuSn",
546 | "focus": -0.05777248853197267,
547 | "gap": 17.309852597489908
548 | },
549 | "startArrowhead": "arrow",
550 | "endArrowhead": "arrow"
551 | }
552 | ],
553 | "appState": {
554 | "gridSize": null,
555 | "viewBackgroundColor": "#ffffff"
556 | }
557 | }
--------------------------------------------------------------------------------
/assets/socket.io-cluster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-sticky/518bd0b989e20fadecbbb6b225578bfca82ad963/assets/socket.io-cluster.png
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { Server as HttpServer } from "http";
3 | import { Server } from "socket.io";
4 |
5 | interface Options {
6 | loadBalancingMethod?: "random" | "round-robin" | "least-connection";
7 | }
8 |
9 | export declare function setupMaster(httpServer: HttpServer, opts?: Options): void;
10 | export declare function setupWorker(io: Server): void;
11 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const cluster = require("cluster");
2 | const { randomBytes } = require("crypto");
3 |
4 | const randomId = () => randomBytes(8).toString("hex");
5 |
6 | function destroySocket() {
7 | this.destroy();
8 | }
9 |
10 | const setupMaster = (httpServer, opts) => {
11 | if (!cluster.isMaster) {
12 | throw new Error("not master");
13 | }
14 |
15 | const options = Object.assign(
16 | {
17 | loadBalancingMethod: "least-connection", // either "random", "round-robin" or "least-connection"
18 | },
19 | opts
20 | );
21 |
22 | const sessionIdToWorker = new Map();
23 | const sidRegex = /sid=([\w\-]{20})/;
24 | let currentIndex = 0; // for round-robin load balancing
25 |
26 | const computeWorkerId = (data) => {
27 | const match = sidRegex.exec(data);
28 | if (match) {
29 | const sid = match[1];
30 | const workerId = sessionIdToWorker.get(sid);
31 | if (workerId && cluster.workers[workerId]) {
32 | return workerId;
33 | }
34 | }
35 | switch (options.loadBalancingMethod) {
36 | case "random": {
37 | const workerIds = Object.keys(cluster.workers);
38 | return workerIds[Math.floor(Math.random() * workerIds.length)];
39 | }
40 | case "round-robin": {
41 | const workerIds = Object.keys(cluster.workers);
42 | currentIndex++;
43 | if (currentIndex >= workerIds.length) {
44 | currentIndex = 0;
45 | }
46 | return workerIds[currentIndex];
47 | }
48 | case "least-connection":
49 | let leastActiveWorker;
50 | for (const id in cluster.workers) {
51 | const worker = cluster.workers[id];
52 | if (leastActiveWorker === undefined) {
53 | leastActiveWorker = worker;
54 | } else {
55 | const c1 = worker.clientsCount || 0;
56 | const c2 = leastActiveWorker.clientsCount || 0;
57 | if (c1 < c2) {
58 | leastActiveWorker = worker;
59 | }
60 | }
61 | }
62 | return leastActiveWorker.id;
63 | }
64 | };
65 |
66 | httpServer.on("connection", (socket) => {
67 | let workerId, connectionId;
68 |
69 | const sendCallback = (err) => {
70 | if (err) {
71 | socket.destroy();
72 | }
73 | };
74 |
75 | socket.on("data", (buffer) => {
76 | if (Object.keys(cluster.workers).length === 0) {
77 | if (workerId) {
78 | // the socket was already assigned to a worker, so we destroy it directly
79 | socket.destroy();
80 | } else {
81 | socket.on("error", destroySocket);
82 | socket.once("finish", destroySocket);
83 |
84 | socket.end(`HTTP/1.1 503 Service Unavailable\r\n
85 | Connection: 'close'\r\n
86 | Content-Length: 0\r\n
87 | \r\n`);
88 | }
89 | return;
90 | }
91 | const data = buffer.toString();
92 | if (workerId && connectionId) {
93 | cluster.workers[workerId].send(
94 | { type: "sticky:http-chunk", data, connectionId },
95 | sendCallback
96 | );
97 | return;
98 | }
99 | workerId = computeWorkerId(data);
100 |
101 | const head = data.substring(0, data.indexOf("\r\n\r\n")).toLowerCase();
102 | const mayHaveMultipleChunks =
103 | head.includes("content-length:") || head.includes("transfer-encoding:");
104 |
105 | if (mayHaveMultipleChunks) {
106 | connectionId = randomId();
107 | }
108 | cluster.workers[workerId].send(
109 | { type: "sticky:connection", data, connectionId },
110 | socket,
111 | {
112 | keepOpen: mayHaveMultipleChunks,
113 | },
114 | sendCallback
115 | );
116 | });
117 | });
118 |
119 | // this is needed to properly detect the end of the HTTP request body
120 | httpServer.on("request", (req) => {
121 | req.on("data", () => {});
122 | });
123 |
124 | cluster.on("message", (worker, { type, data }) => {
125 | switch (type) {
126 | case "sticky:connection":
127 | sessionIdToWorker.set(data, worker.id);
128 | if (options.loadBalancingMethod === "least-connection") {
129 | worker.clientsCount = (worker.clientsCount || 0) + 1;
130 | }
131 | break;
132 | case "sticky:disconnection":
133 | sessionIdToWorker.delete(data);
134 | if (options.loadBalancingMethod === "least-connection") {
135 | worker.clientsCount--;
136 | }
137 | break;
138 | }
139 | });
140 |
141 | cluster.on("exit", (worker) => {
142 | sessionIdToWorker.forEach((value, key) => {
143 | if (value === worker.id) {
144 | sessionIdToWorker.delete(key);
145 | }
146 | });
147 | });
148 | };
149 |
150 | const setupWorker = (io) => {
151 | if (!cluster.isWorker) {
152 | throw new Error("not worker");
153 | }
154 |
155 | // store connections that may receive multiple chunks
156 | const sockets = new Map();
157 |
158 | process.on("message", ({ type, data, connectionId }, socket) => {
159 | switch (type) {
160 | case "sticky:connection":
161 | if (!socket) {
162 | // might happen if the socket is closed during the transfer to the worker
163 | // see https://nodejs.org/api/child_process.html#child_process_example_sending_a_socket_object
164 | return;
165 | }
166 | io.httpServer.emit("connection", socket); // inject connection
167 | socket.emit("data", Buffer.from(data)); // republish first chunk
168 | socket.resume();
169 |
170 | if (connectionId) {
171 | sockets.set(connectionId, socket);
172 |
173 | socket.on("close", () => {
174 | sockets.delete(connectionId);
175 | });
176 | }
177 |
178 | break;
179 |
180 | case "sticky:http-chunk": {
181 | const socket = sockets.get(connectionId);
182 | if (socket) {
183 | socket.emit("data", Buffer.from(data));
184 | }
185 | }
186 | }
187 | });
188 |
189 | const ignoreError = () => {}; // the next request will fail anyway
190 |
191 | io.engine.on("connection", (socket) => {
192 | process.send({ type: "sticky:connection", data: socket.id }, ignoreError);
193 |
194 | socket.once("close", () => {
195 | process.send(
196 | { type: "sticky:disconnection", data: socket.id },
197 | ignoreError
198 | );
199 | });
200 | });
201 | };
202 |
203 | module.exports = {
204 | setupMaster,
205 | setupWorker,
206 | };
207 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@socket.io/sticky",
3 | "version": "1.0.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@babel/code-frame": {
8 | "version": "7.12.11",
9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
11 | "dev": true,
12 | "requires": {
13 | "@babel/highlight": "^7.10.4"
14 | }
15 | },
16 | "@babel/core": {
17 | "version": "7.12.10",
18 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz",
19 | "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==",
20 | "dev": true,
21 | "requires": {
22 | "@babel/code-frame": "^7.10.4",
23 | "@babel/generator": "^7.12.10",
24 | "@babel/helper-module-transforms": "^7.12.1",
25 | "@babel/helpers": "^7.12.5",
26 | "@babel/parser": "^7.12.10",
27 | "@babel/template": "^7.12.7",
28 | "@babel/traverse": "^7.12.10",
29 | "@babel/types": "^7.12.10",
30 | "convert-source-map": "^1.7.0",
31 | "debug": "^4.1.0",
32 | "gensync": "^1.0.0-beta.1",
33 | "json5": "^2.1.2",
34 | "lodash": "^4.17.19",
35 | "semver": "^5.4.1",
36 | "source-map": "^0.5.0"
37 | },
38 | "dependencies": {
39 | "semver": {
40 | "version": "5.7.1",
41 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
42 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
43 | "dev": true
44 | }
45 | }
46 | },
47 | "@babel/generator": {
48 | "version": "7.12.11",
49 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz",
50 | "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==",
51 | "dev": true,
52 | "requires": {
53 | "@babel/types": "^7.12.11",
54 | "jsesc": "^2.5.1",
55 | "source-map": "^0.5.0"
56 | }
57 | },
58 | "@babel/helper-function-name": {
59 | "version": "7.12.11",
60 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz",
61 | "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==",
62 | "dev": true,
63 | "requires": {
64 | "@babel/helper-get-function-arity": "^7.12.10",
65 | "@babel/template": "^7.12.7",
66 | "@babel/types": "^7.12.11"
67 | }
68 | },
69 | "@babel/helper-get-function-arity": {
70 | "version": "7.12.10",
71 | "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz",
72 | "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==",
73 | "dev": true,
74 | "requires": {
75 | "@babel/types": "^7.12.10"
76 | }
77 | },
78 | "@babel/helper-member-expression-to-functions": {
79 | "version": "7.12.7",
80 | "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz",
81 | "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==",
82 | "dev": true,
83 | "requires": {
84 | "@babel/types": "^7.12.7"
85 | }
86 | },
87 | "@babel/helper-module-imports": {
88 | "version": "7.12.5",
89 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz",
90 | "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==",
91 | "dev": true,
92 | "requires": {
93 | "@babel/types": "^7.12.5"
94 | }
95 | },
96 | "@babel/helper-module-transforms": {
97 | "version": "7.12.1",
98 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz",
99 | "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==",
100 | "dev": true,
101 | "requires": {
102 | "@babel/helper-module-imports": "^7.12.1",
103 | "@babel/helper-replace-supers": "^7.12.1",
104 | "@babel/helper-simple-access": "^7.12.1",
105 | "@babel/helper-split-export-declaration": "^7.11.0",
106 | "@babel/helper-validator-identifier": "^7.10.4",
107 | "@babel/template": "^7.10.4",
108 | "@babel/traverse": "^7.12.1",
109 | "@babel/types": "^7.12.1",
110 | "lodash": "^4.17.19"
111 | }
112 | },
113 | "@babel/helper-optimise-call-expression": {
114 | "version": "7.12.10",
115 | "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz",
116 | "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==",
117 | "dev": true,
118 | "requires": {
119 | "@babel/types": "^7.12.10"
120 | }
121 | },
122 | "@babel/helper-replace-supers": {
123 | "version": "7.12.11",
124 | "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz",
125 | "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==",
126 | "dev": true,
127 | "requires": {
128 | "@babel/helper-member-expression-to-functions": "^7.12.7",
129 | "@babel/helper-optimise-call-expression": "^7.12.10",
130 | "@babel/traverse": "^7.12.10",
131 | "@babel/types": "^7.12.11"
132 | }
133 | },
134 | "@babel/helper-simple-access": {
135 | "version": "7.12.1",
136 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz",
137 | "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==",
138 | "dev": true,
139 | "requires": {
140 | "@babel/types": "^7.12.1"
141 | }
142 | },
143 | "@babel/helper-split-export-declaration": {
144 | "version": "7.12.11",
145 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz",
146 | "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==",
147 | "dev": true,
148 | "requires": {
149 | "@babel/types": "^7.12.11"
150 | }
151 | },
152 | "@babel/helper-validator-identifier": {
153 | "version": "7.12.11",
154 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
155 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
156 | "dev": true
157 | },
158 | "@babel/helpers": {
159 | "version": "7.12.5",
160 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz",
161 | "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==",
162 | "dev": true,
163 | "requires": {
164 | "@babel/template": "^7.10.4",
165 | "@babel/traverse": "^7.12.5",
166 | "@babel/types": "^7.12.5"
167 | }
168 | },
169 | "@babel/highlight": {
170 | "version": "7.10.4",
171 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
172 | "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
173 | "dev": true,
174 | "requires": {
175 | "@babel/helper-validator-identifier": "^7.10.4",
176 | "chalk": "^2.0.0",
177 | "js-tokens": "^4.0.0"
178 | },
179 | "dependencies": {
180 | "ansi-styles": {
181 | "version": "3.2.1",
182 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
183 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
184 | "dev": true,
185 | "requires": {
186 | "color-convert": "^1.9.0"
187 | }
188 | },
189 | "chalk": {
190 | "version": "2.4.2",
191 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
192 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
193 | "dev": true,
194 | "requires": {
195 | "ansi-styles": "^3.2.1",
196 | "escape-string-regexp": "^1.0.5",
197 | "supports-color": "^5.3.0"
198 | }
199 | },
200 | "color-convert": {
201 | "version": "1.9.3",
202 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
203 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
204 | "dev": true,
205 | "requires": {
206 | "color-name": "1.1.3"
207 | }
208 | },
209 | "color-name": {
210 | "version": "1.1.3",
211 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
212 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
213 | "dev": true
214 | },
215 | "escape-string-regexp": {
216 | "version": "1.0.5",
217 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
218 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
219 | "dev": true
220 | },
221 | "has-flag": {
222 | "version": "3.0.0",
223 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
224 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
225 | "dev": true
226 | },
227 | "supports-color": {
228 | "version": "5.5.0",
229 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
230 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
231 | "dev": true,
232 | "requires": {
233 | "has-flag": "^3.0.0"
234 | }
235 | }
236 | }
237 | },
238 | "@babel/parser": {
239 | "version": "7.12.11",
240 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
241 | "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==",
242 | "dev": true
243 | },
244 | "@babel/template": {
245 | "version": "7.12.7",
246 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz",
247 | "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==",
248 | "dev": true,
249 | "requires": {
250 | "@babel/code-frame": "^7.10.4",
251 | "@babel/parser": "^7.12.7",
252 | "@babel/types": "^7.12.7"
253 | }
254 | },
255 | "@babel/traverse": {
256 | "version": "7.12.12",
257 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz",
258 | "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==",
259 | "dev": true,
260 | "requires": {
261 | "@babel/code-frame": "^7.12.11",
262 | "@babel/generator": "^7.12.11",
263 | "@babel/helper-function-name": "^7.12.11",
264 | "@babel/helper-split-export-declaration": "^7.12.11",
265 | "@babel/parser": "^7.12.11",
266 | "@babel/types": "^7.12.12",
267 | "debug": "^4.1.0",
268 | "globals": "^11.1.0",
269 | "lodash": "^4.17.19"
270 | }
271 | },
272 | "@babel/types": {
273 | "version": "7.12.12",
274 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz",
275 | "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==",
276 | "dev": true,
277 | "requires": {
278 | "@babel/helper-validator-identifier": "^7.12.11",
279 | "lodash": "^4.17.19",
280 | "to-fast-properties": "^2.0.0"
281 | }
282 | },
283 | "@istanbuljs/load-nyc-config": {
284 | "version": "1.1.0",
285 | "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
286 | "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
287 | "dev": true,
288 | "requires": {
289 | "camelcase": "^5.3.1",
290 | "find-up": "^4.1.0",
291 | "get-package-type": "^0.1.0",
292 | "js-yaml": "^3.13.1",
293 | "resolve-from": "^5.0.0"
294 | },
295 | "dependencies": {
296 | "find-up": {
297 | "version": "4.1.0",
298 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
299 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
300 | "dev": true,
301 | "requires": {
302 | "locate-path": "^5.0.0",
303 | "path-exists": "^4.0.0"
304 | }
305 | },
306 | "locate-path": {
307 | "version": "5.0.0",
308 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
309 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
310 | "dev": true,
311 | "requires": {
312 | "p-locate": "^4.1.0"
313 | }
314 | },
315 | "p-limit": {
316 | "version": "2.3.0",
317 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
318 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
319 | "dev": true,
320 | "requires": {
321 | "p-try": "^2.0.0"
322 | }
323 | },
324 | "p-locate": {
325 | "version": "4.1.0",
326 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
327 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
328 | "dev": true,
329 | "requires": {
330 | "p-limit": "^2.2.0"
331 | }
332 | }
333 | }
334 | },
335 | "@istanbuljs/schema": {
336 | "version": "0.1.2",
337 | "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
338 | "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
339 | "dev": true
340 | },
341 | "@types/component-emitter": {
342 | "version": "1.2.10",
343 | "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
344 | "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==",
345 | "dev": true
346 | },
347 | "@types/cookie": {
348 | "version": "0.4.0",
349 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz",
350 | "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==",
351 | "dev": true
352 | },
353 | "@types/cors": {
354 | "version": "2.8.9",
355 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.9.tgz",
356 | "integrity": "sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg==",
357 | "dev": true
358 | },
359 | "@types/node": {
360 | "version": "14.14.22",
361 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
362 | "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==",
363 | "dev": true
364 | },
365 | "@ungap/promise-all-settled": {
366 | "version": "1.1.2",
367 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
368 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
369 | "dev": true
370 | },
371 | "accepts": {
372 | "version": "1.3.7",
373 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
374 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
375 | "dev": true,
376 | "requires": {
377 | "mime-types": "~2.1.24",
378 | "negotiator": "0.6.2"
379 | }
380 | },
381 | "aggregate-error": {
382 | "version": "3.1.0",
383 | "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
384 | "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
385 | "dev": true,
386 | "requires": {
387 | "clean-stack": "^2.0.0",
388 | "indent-string": "^4.0.0"
389 | }
390 | },
391 | "ansi-colors": {
392 | "version": "4.1.1",
393 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
394 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
395 | "dev": true
396 | },
397 | "ansi-regex": {
398 | "version": "3.0.0",
399 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
400 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
401 | "dev": true
402 | },
403 | "ansi-styles": {
404 | "version": "4.3.0",
405 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
406 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
407 | "dev": true,
408 | "requires": {
409 | "color-convert": "^2.0.1"
410 | }
411 | },
412 | "anymatch": {
413 | "version": "3.1.1",
414 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
415 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
416 | "dev": true,
417 | "requires": {
418 | "normalize-path": "^3.0.0",
419 | "picomatch": "^2.0.4"
420 | }
421 | },
422 | "append-transform": {
423 | "version": "2.0.0",
424 | "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
425 | "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
426 | "dev": true,
427 | "requires": {
428 | "default-require-extensions": "^3.0.0"
429 | }
430 | },
431 | "archy": {
432 | "version": "1.0.0",
433 | "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
434 | "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
435 | "dev": true
436 | },
437 | "argparse": {
438 | "version": "1.0.10",
439 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
440 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
441 | "dev": true,
442 | "requires": {
443 | "sprintf-js": "~1.0.2"
444 | }
445 | },
446 | "backo2": {
447 | "version": "1.0.2",
448 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
449 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
450 | "dev": true
451 | },
452 | "balanced-match": {
453 | "version": "1.0.0",
454 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
455 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
456 | "dev": true
457 | },
458 | "base64-arraybuffer": {
459 | "version": "0.1.4",
460 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
461 | "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=",
462 | "dev": true
463 | },
464 | "base64id": {
465 | "version": "2.0.0",
466 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
467 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
468 | "dev": true
469 | },
470 | "binary-extensions": {
471 | "version": "2.2.0",
472 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
473 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
474 | "dev": true
475 | },
476 | "brace-expansion": {
477 | "version": "1.1.11",
478 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
479 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
480 | "dev": true,
481 | "requires": {
482 | "balanced-match": "^1.0.0",
483 | "concat-map": "0.0.1"
484 | }
485 | },
486 | "braces": {
487 | "version": "3.0.2",
488 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
489 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
490 | "dev": true,
491 | "requires": {
492 | "fill-range": "^7.0.1"
493 | }
494 | },
495 | "browser-stdout": {
496 | "version": "1.3.1",
497 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
498 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
499 | "dev": true
500 | },
501 | "caching-transform": {
502 | "version": "4.0.0",
503 | "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
504 | "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
505 | "dev": true,
506 | "requires": {
507 | "hasha": "^5.0.0",
508 | "make-dir": "^3.0.0",
509 | "package-hash": "^4.0.0",
510 | "write-file-atomic": "^3.0.0"
511 | }
512 | },
513 | "camelcase": {
514 | "version": "5.3.1",
515 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
516 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
517 | "dev": true
518 | },
519 | "chalk": {
520 | "version": "4.1.0",
521 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
522 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
523 | "dev": true,
524 | "requires": {
525 | "ansi-styles": "^4.1.0",
526 | "supports-color": "^7.1.0"
527 | }
528 | },
529 | "chokidar": {
530 | "version": "3.4.3",
531 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
532 | "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
533 | "dev": true,
534 | "requires": {
535 | "anymatch": "~3.1.1",
536 | "braces": "~3.0.2",
537 | "fsevents": "~2.1.2",
538 | "glob-parent": "~5.1.0",
539 | "is-binary-path": "~2.1.0",
540 | "is-glob": "~4.0.1",
541 | "normalize-path": "~3.0.0",
542 | "readdirp": "~3.5.0"
543 | }
544 | },
545 | "clean-stack": {
546 | "version": "2.2.0",
547 | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
548 | "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
549 | "dev": true
550 | },
551 | "cliui": {
552 | "version": "5.0.0",
553 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
554 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
555 | "dev": true,
556 | "requires": {
557 | "string-width": "^3.1.0",
558 | "strip-ansi": "^5.2.0",
559 | "wrap-ansi": "^5.1.0"
560 | },
561 | "dependencies": {
562 | "ansi-regex": {
563 | "version": "4.1.0",
564 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
565 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
566 | "dev": true
567 | },
568 | "string-width": {
569 | "version": "3.1.0",
570 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
571 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
572 | "dev": true,
573 | "requires": {
574 | "emoji-regex": "^7.0.1",
575 | "is-fullwidth-code-point": "^2.0.0",
576 | "strip-ansi": "^5.1.0"
577 | }
578 | },
579 | "strip-ansi": {
580 | "version": "5.2.0",
581 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
582 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
583 | "dev": true,
584 | "requires": {
585 | "ansi-regex": "^4.1.0"
586 | }
587 | }
588 | }
589 | },
590 | "color-convert": {
591 | "version": "2.0.1",
592 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
593 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
594 | "dev": true,
595 | "requires": {
596 | "color-name": "~1.1.4"
597 | }
598 | },
599 | "color-name": {
600 | "version": "1.1.4",
601 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
602 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
603 | "dev": true
604 | },
605 | "commondir": {
606 | "version": "1.0.1",
607 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
608 | "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
609 | "dev": true
610 | },
611 | "component-emitter": {
612 | "version": "1.3.0",
613 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
614 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
615 | "dev": true
616 | },
617 | "concat-map": {
618 | "version": "0.0.1",
619 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
620 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
621 | "dev": true
622 | },
623 | "convert-source-map": {
624 | "version": "1.7.0",
625 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
626 | "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
627 | "dev": true,
628 | "requires": {
629 | "safe-buffer": "~5.1.1"
630 | },
631 | "dependencies": {
632 | "safe-buffer": {
633 | "version": "5.1.2",
634 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
635 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
636 | "dev": true
637 | }
638 | }
639 | },
640 | "cookie": {
641 | "version": "0.4.1",
642 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
643 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
644 | "dev": true
645 | },
646 | "cors": {
647 | "version": "2.8.5",
648 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
649 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
650 | "dev": true,
651 | "requires": {
652 | "object-assign": "^4",
653 | "vary": "^1"
654 | }
655 | },
656 | "cross-spawn": {
657 | "version": "7.0.3",
658 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
659 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
660 | "dev": true,
661 | "requires": {
662 | "path-key": "^3.1.0",
663 | "shebang-command": "^2.0.0",
664 | "which": "^2.0.1"
665 | }
666 | },
667 | "debug": {
668 | "version": "4.2.0",
669 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
670 | "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
671 | "dev": true,
672 | "requires": {
673 | "ms": "2.1.2"
674 | }
675 | },
676 | "decamelize": {
677 | "version": "1.2.0",
678 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
679 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
680 | "dev": true
681 | },
682 | "default-require-extensions": {
683 | "version": "3.0.0",
684 | "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
685 | "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
686 | "dev": true,
687 | "requires": {
688 | "strip-bom": "^4.0.0"
689 | }
690 | },
691 | "diff": {
692 | "version": "4.0.2",
693 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
694 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
695 | "dev": true
696 | },
697 | "emoji-regex": {
698 | "version": "7.0.3",
699 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
700 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
701 | "dev": true
702 | },
703 | "engine.io": {
704 | "version": "4.1.0",
705 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.1.0.tgz",
706 | "integrity": "sha512-vW7EAtn0HDQ4MtT5QbmCHF17TaYLONv2/JwdYsq9USPRZVM4zG7WB3k0Nc321z8EuSOlhGokrYlYx4176QhD0A==",
707 | "dev": true,
708 | "requires": {
709 | "accepts": "~1.3.4",
710 | "base64id": "2.0.0",
711 | "cookie": "~0.4.1",
712 | "cors": "~2.8.5",
713 | "debug": "~4.3.1",
714 | "engine.io-parser": "~4.0.0",
715 | "ws": "~7.4.2"
716 | },
717 | "dependencies": {
718 | "debug": {
719 | "version": "4.3.1",
720 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
721 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
722 | "dev": true,
723 | "requires": {
724 | "ms": "2.1.2"
725 | }
726 | }
727 | }
728 | },
729 | "engine.io-client": {
730 | "version": "4.1.0",
731 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.0.tgz",
732 | "integrity": "sha512-OUmn4m71/lW3ixICv4h3DuBRuh3ri0w3cDuepjsrINSbbqbni4Xw1shTFiKhl0v58lEtNpwJTpSKJJ3fondu5Q==",
733 | "dev": true,
734 | "requires": {
735 | "base64-arraybuffer": "0.1.4",
736 | "component-emitter": "~1.3.0",
737 | "debug": "~4.3.1",
738 | "engine.io-parser": "~4.0.1",
739 | "has-cors": "1.1.0",
740 | "parseqs": "0.0.6",
741 | "parseuri": "0.0.6",
742 | "ws": "~7.4.2",
743 | "xmlhttprequest-ssl": "~1.5.4",
744 | "yeast": "0.1.2"
745 | },
746 | "dependencies": {
747 | "debug": {
748 | "version": "4.3.1",
749 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
750 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
751 | "dev": true,
752 | "requires": {
753 | "ms": "2.1.2"
754 | }
755 | }
756 | }
757 | },
758 | "engine.io-parser": {
759 | "version": "4.0.2",
760 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz",
761 | "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==",
762 | "dev": true,
763 | "requires": {
764 | "base64-arraybuffer": "0.1.4"
765 | }
766 | },
767 | "es6-error": {
768 | "version": "4.1.1",
769 | "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
770 | "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
771 | "dev": true
772 | },
773 | "escape-string-regexp": {
774 | "version": "4.0.0",
775 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
776 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
777 | "dev": true
778 | },
779 | "esprima": {
780 | "version": "4.0.1",
781 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
782 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
783 | "dev": true
784 | },
785 | "fill-range": {
786 | "version": "7.0.1",
787 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
788 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
789 | "dev": true,
790 | "requires": {
791 | "to-regex-range": "^5.0.1"
792 | }
793 | },
794 | "find-cache-dir": {
795 | "version": "3.3.1",
796 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
797 | "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
798 | "dev": true,
799 | "requires": {
800 | "commondir": "^1.0.1",
801 | "make-dir": "^3.0.2",
802 | "pkg-dir": "^4.1.0"
803 | }
804 | },
805 | "find-up": {
806 | "version": "5.0.0",
807 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
808 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
809 | "dev": true,
810 | "requires": {
811 | "locate-path": "^6.0.0",
812 | "path-exists": "^4.0.0"
813 | }
814 | },
815 | "flat": {
816 | "version": "5.0.2",
817 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
818 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
819 | "dev": true
820 | },
821 | "foreground-child": {
822 | "version": "2.0.0",
823 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
824 | "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
825 | "dev": true,
826 | "requires": {
827 | "cross-spawn": "^7.0.0",
828 | "signal-exit": "^3.0.2"
829 | }
830 | },
831 | "fromentries": {
832 | "version": "1.3.2",
833 | "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
834 | "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
835 | "dev": true
836 | },
837 | "fs.realpath": {
838 | "version": "1.0.0",
839 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
840 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
841 | "dev": true
842 | },
843 | "fsevents": {
844 | "version": "2.1.3",
845 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
846 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
847 | "dev": true,
848 | "optional": true
849 | },
850 | "gensync": {
851 | "version": "1.0.0-beta.2",
852 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
853 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
854 | "dev": true
855 | },
856 | "get-caller-file": {
857 | "version": "2.0.5",
858 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
859 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
860 | "dev": true
861 | },
862 | "get-package-type": {
863 | "version": "0.1.0",
864 | "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
865 | "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
866 | "dev": true
867 | },
868 | "glob": {
869 | "version": "7.1.6",
870 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
871 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
872 | "dev": true,
873 | "requires": {
874 | "fs.realpath": "^1.0.0",
875 | "inflight": "^1.0.4",
876 | "inherits": "2",
877 | "minimatch": "^3.0.4",
878 | "once": "^1.3.0",
879 | "path-is-absolute": "^1.0.0"
880 | }
881 | },
882 | "glob-parent": {
883 | "version": "5.1.1",
884 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
885 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
886 | "dev": true,
887 | "requires": {
888 | "is-glob": "^4.0.1"
889 | }
890 | },
891 | "globals": {
892 | "version": "11.12.0",
893 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
894 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
895 | "dev": true
896 | },
897 | "graceful-fs": {
898 | "version": "4.2.4",
899 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
900 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
901 | "dev": true
902 | },
903 | "growl": {
904 | "version": "1.10.5",
905 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
906 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
907 | "dev": true
908 | },
909 | "has-cors": {
910 | "version": "1.1.0",
911 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
912 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
913 | "dev": true
914 | },
915 | "has-flag": {
916 | "version": "4.0.0",
917 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
918 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
919 | "dev": true
920 | },
921 | "hasha": {
922 | "version": "5.2.2",
923 | "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
924 | "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
925 | "dev": true,
926 | "requires": {
927 | "is-stream": "^2.0.0",
928 | "type-fest": "^0.8.0"
929 | }
930 | },
931 | "he": {
932 | "version": "1.2.0",
933 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
934 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
935 | "dev": true
936 | },
937 | "html-escaper": {
938 | "version": "2.0.2",
939 | "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
940 | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
941 | "dev": true
942 | },
943 | "imurmurhash": {
944 | "version": "0.1.4",
945 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
946 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
947 | "dev": true
948 | },
949 | "indent-string": {
950 | "version": "4.0.0",
951 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
952 | "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
953 | "dev": true
954 | },
955 | "inflight": {
956 | "version": "1.0.6",
957 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
958 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
959 | "dev": true,
960 | "requires": {
961 | "once": "^1.3.0",
962 | "wrappy": "1"
963 | }
964 | },
965 | "inherits": {
966 | "version": "2.0.4",
967 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
968 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
969 | "dev": true
970 | },
971 | "is-binary-path": {
972 | "version": "2.1.0",
973 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
974 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
975 | "dev": true,
976 | "requires": {
977 | "binary-extensions": "^2.0.0"
978 | }
979 | },
980 | "is-extglob": {
981 | "version": "2.1.1",
982 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
983 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
984 | "dev": true
985 | },
986 | "is-fullwidth-code-point": {
987 | "version": "2.0.0",
988 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
989 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
990 | "dev": true
991 | },
992 | "is-glob": {
993 | "version": "4.0.1",
994 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
995 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
996 | "dev": true,
997 | "requires": {
998 | "is-extglob": "^2.1.1"
999 | }
1000 | },
1001 | "is-number": {
1002 | "version": "7.0.0",
1003 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1004 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1005 | "dev": true
1006 | },
1007 | "is-plain-obj": {
1008 | "version": "2.1.0",
1009 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
1010 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
1011 | "dev": true
1012 | },
1013 | "is-stream": {
1014 | "version": "2.0.0",
1015 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
1016 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
1017 | "dev": true
1018 | },
1019 | "is-typedarray": {
1020 | "version": "1.0.0",
1021 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
1022 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
1023 | "dev": true
1024 | },
1025 | "is-windows": {
1026 | "version": "1.0.2",
1027 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
1028 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
1029 | "dev": true
1030 | },
1031 | "isexe": {
1032 | "version": "2.0.0",
1033 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1034 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1035 | "dev": true
1036 | },
1037 | "istanbul-lib-coverage": {
1038 | "version": "3.0.0",
1039 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
1040 | "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
1041 | "dev": true
1042 | },
1043 | "istanbul-lib-hook": {
1044 | "version": "3.0.0",
1045 | "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
1046 | "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
1047 | "dev": true,
1048 | "requires": {
1049 | "append-transform": "^2.0.0"
1050 | }
1051 | },
1052 | "istanbul-lib-instrument": {
1053 | "version": "4.0.3",
1054 | "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
1055 | "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
1056 | "dev": true,
1057 | "requires": {
1058 | "@babel/core": "^7.7.5",
1059 | "@istanbuljs/schema": "^0.1.2",
1060 | "istanbul-lib-coverage": "^3.0.0",
1061 | "semver": "^6.3.0"
1062 | }
1063 | },
1064 | "istanbul-lib-processinfo": {
1065 | "version": "2.0.2",
1066 | "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
1067 | "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==",
1068 | "dev": true,
1069 | "requires": {
1070 | "archy": "^1.0.0",
1071 | "cross-spawn": "^7.0.0",
1072 | "istanbul-lib-coverage": "^3.0.0-alpha.1",
1073 | "make-dir": "^3.0.0",
1074 | "p-map": "^3.0.0",
1075 | "rimraf": "^3.0.0",
1076 | "uuid": "^3.3.3"
1077 | }
1078 | },
1079 | "istanbul-lib-report": {
1080 | "version": "3.0.0",
1081 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
1082 | "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
1083 | "dev": true,
1084 | "requires": {
1085 | "istanbul-lib-coverage": "^3.0.0",
1086 | "make-dir": "^3.0.0",
1087 | "supports-color": "^7.1.0"
1088 | }
1089 | },
1090 | "istanbul-lib-source-maps": {
1091 | "version": "4.0.0",
1092 | "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
1093 | "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
1094 | "dev": true,
1095 | "requires": {
1096 | "debug": "^4.1.1",
1097 | "istanbul-lib-coverage": "^3.0.0",
1098 | "source-map": "^0.6.1"
1099 | },
1100 | "dependencies": {
1101 | "source-map": {
1102 | "version": "0.6.1",
1103 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1104 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1105 | "dev": true
1106 | }
1107 | }
1108 | },
1109 | "istanbul-reports": {
1110 | "version": "3.0.2",
1111 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
1112 | "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
1113 | "dev": true,
1114 | "requires": {
1115 | "html-escaper": "^2.0.0",
1116 | "istanbul-lib-report": "^3.0.0"
1117 | }
1118 | },
1119 | "js-tokens": {
1120 | "version": "4.0.0",
1121 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1122 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1123 | "dev": true
1124 | },
1125 | "js-yaml": {
1126 | "version": "3.14.0",
1127 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
1128 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
1129 | "dev": true,
1130 | "requires": {
1131 | "argparse": "^1.0.7",
1132 | "esprima": "^4.0.0"
1133 | }
1134 | },
1135 | "jsesc": {
1136 | "version": "2.5.2",
1137 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
1138 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
1139 | "dev": true
1140 | },
1141 | "json5": {
1142 | "version": "2.1.3",
1143 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
1144 | "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
1145 | "dev": true,
1146 | "requires": {
1147 | "minimist": "^1.2.5"
1148 | }
1149 | },
1150 | "locate-path": {
1151 | "version": "6.0.0",
1152 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
1153 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
1154 | "dev": true,
1155 | "requires": {
1156 | "p-locate": "^5.0.0"
1157 | }
1158 | },
1159 | "lodash": {
1160 | "version": "4.17.20",
1161 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
1162 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
1163 | "dev": true
1164 | },
1165 | "lodash.flattendeep": {
1166 | "version": "4.4.0",
1167 | "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
1168 | "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
1169 | "dev": true
1170 | },
1171 | "log-symbols": {
1172 | "version": "4.0.0",
1173 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
1174 | "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
1175 | "dev": true,
1176 | "requires": {
1177 | "chalk": "^4.0.0"
1178 | }
1179 | },
1180 | "make-dir": {
1181 | "version": "3.1.0",
1182 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
1183 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
1184 | "dev": true,
1185 | "requires": {
1186 | "semver": "^6.0.0"
1187 | }
1188 | },
1189 | "mime-db": {
1190 | "version": "1.45.0",
1191 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
1192 | "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
1193 | "dev": true
1194 | },
1195 | "mime-types": {
1196 | "version": "2.1.28",
1197 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
1198 | "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
1199 | "dev": true,
1200 | "requires": {
1201 | "mime-db": "1.45.0"
1202 | }
1203 | },
1204 | "minimatch": {
1205 | "version": "3.0.4",
1206 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1207 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1208 | "dev": true,
1209 | "requires": {
1210 | "brace-expansion": "^1.1.7"
1211 | }
1212 | },
1213 | "minimist": {
1214 | "version": "1.2.5",
1215 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
1216 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
1217 | "dev": true
1218 | },
1219 | "mocha": {
1220 | "version": "8.2.1",
1221 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz",
1222 | "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==",
1223 | "dev": true,
1224 | "requires": {
1225 | "@ungap/promise-all-settled": "1.1.2",
1226 | "ansi-colors": "4.1.1",
1227 | "browser-stdout": "1.3.1",
1228 | "chokidar": "3.4.3",
1229 | "debug": "4.2.0",
1230 | "diff": "4.0.2",
1231 | "escape-string-regexp": "4.0.0",
1232 | "find-up": "5.0.0",
1233 | "glob": "7.1.6",
1234 | "growl": "1.10.5",
1235 | "he": "1.2.0",
1236 | "js-yaml": "3.14.0",
1237 | "log-symbols": "4.0.0",
1238 | "minimatch": "3.0.4",
1239 | "ms": "2.1.2",
1240 | "nanoid": "3.1.12",
1241 | "serialize-javascript": "5.0.1",
1242 | "strip-json-comments": "3.1.1",
1243 | "supports-color": "7.2.0",
1244 | "which": "2.0.2",
1245 | "wide-align": "1.1.3",
1246 | "workerpool": "6.0.2",
1247 | "yargs": "13.3.2",
1248 | "yargs-parser": "13.1.2",
1249 | "yargs-unparser": "2.0.0"
1250 | }
1251 | },
1252 | "ms": {
1253 | "version": "2.1.2",
1254 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1255 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
1256 | "dev": true
1257 | },
1258 | "nanoid": {
1259 | "version": "3.1.12",
1260 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz",
1261 | "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==",
1262 | "dev": true
1263 | },
1264 | "negotiator": {
1265 | "version": "0.6.2",
1266 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
1267 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
1268 | "dev": true
1269 | },
1270 | "node-preload": {
1271 | "version": "0.2.1",
1272 | "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
1273 | "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
1274 | "dev": true,
1275 | "requires": {
1276 | "process-on-spawn": "^1.0.0"
1277 | }
1278 | },
1279 | "normalize-path": {
1280 | "version": "3.0.0",
1281 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1282 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1283 | "dev": true
1284 | },
1285 | "nyc": {
1286 | "version": "15.1.0",
1287 | "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
1288 | "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
1289 | "dev": true,
1290 | "requires": {
1291 | "@istanbuljs/load-nyc-config": "^1.0.0",
1292 | "@istanbuljs/schema": "^0.1.2",
1293 | "caching-transform": "^4.0.0",
1294 | "convert-source-map": "^1.7.0",
1295 | "decamelize": "^1.2.0",
1296 | "find-cache-dir": "^3.2.0",
1297 | "find-up": "^4.1.0",
1298 | "foreground-child": "^2.0.0",
1299 | "get-package-type": "^0.1.0",
1300 | "glob": "^7.1.6",
1301 | "istanbul-lib-coverage": "^3.0.0",
1302 | "istanbul-lib-hook": "^3.0.0",
1303 | "istanbul-lib-instrument": "^4.0.0",
1304 | "istanbul-lib-processinfo": "^2.0.2",
1305 | "istanbul-lib-report": "^3.0.0",
1306 | "istanbul-lib-source-maps": "^4.0.0",
1307 | "istanbul-reports": "^3.0.2",
1308 | "make-dir": "^3.0.0",
1309 | "node-preload": "^0.2.1",
1310 | "p-map": "^3.0.0",
1311 | "process-on-spawn": "^1.0.0",
1312 | "resolve-from": "^5.0.0",
1313 | "rimraf": "^3.0.0",
1314 | "signal-exit": "^3.0.2",
1315 | "spawn-wrap": "^2.0.0",
1316 | "test-exclude": "^6.0.0",
1317 | "yargs": "^15.0.2"
1318 | },
1319 | "dependencies": {
1320 | "ansi-regex": {
1321 | "version": "5.0.0",
1322 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
1323 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
1324 | "dev": true
1325 | },
1326 | "cliui": {
1327 | "version": "6.0.0",
1328 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
1329 | "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
1330 | "dev": true,
1331 | "requires": {
1332 | "string-width": "^4.2.0",
1333 | "strip-ansi": "^6.0.0",
1334 | "wrap-ansi": "^6.2.0"
1335 | }
1336 | },
1337 | "emoji-regex": {
1338 | "version": "8.0.0",
1339 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1340 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1341 | "dev": true
1342 | },
1343 | "find-up": {
1344 | "version": "4.1.0",
1345 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
1346 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
1347 | "dev": true,
1348 | "requires": {
1349 | "locate-path": "^5.0.0",
1350 | "path-exists": "^4.0.0"
1351 | }
1352 | },
1353 | "is-fullwidth-code-point": {
1354 | "version": "3.0.0",
1355 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1356 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1357 | "dev": true
1358 | },
1359 | "locate-path": {
1360 | "version": "5.0.0",
1361 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
1362 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
1363 | "dev": true,
1364 | "requires": {
1365 | "p-locate": "^4.1.0"
1366 | }
1367 | },
1368 | "p-limit": {
1369 | "version": "2.3.0",
1370 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
1371 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
1372 | "dev": true,
1373 | "requires": {
1374 | "p-try": "^2.0.0"
1375 | }
1376 | },
1377 | "p-locate": {
1378 | "version": "4.1.0",
1379 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1380 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1381 | "dev": true,
1382 | "requires": {
1383 | "p-limit": "^2.2.0"
1384 | }
1385 | },
1386 | "string-width": {
1387 | "version": "4.2.0",
1388 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
1389 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
1390 | "dev": true,
1391 | "requires": {
1392 | "emoji-regex": "^8.0.0",
1393 | "is-fullwidth-code-point": "^3.0.0",
1394 | "strip-ansi": "^6.0.0"
1395 | }
1396 | },
1397 | "strip-ansi": {
1398 | "version": "6.0.0",
1399 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
1400 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
1401 | "dev": true,
1402 | "requires": {
1403 | "ansi-regex": "^5.0.0"
1404 | }
1405 | },
1406 | "wrap-ansi": {
1407 | "version": "6.2.0",
1408 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
1409 | "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
1410 | "dev": true,
1411 | "requires": {
1412 | "ansi-styles": "^4.0.0",
1413 | "string-width": "^4.1.0",
1414 | "strip-ansi": "^6.0.0"
1415 | }
1416 | },
1417 | "yargs": {
1418 | "version": "15.4.1",
1419 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
1420 | "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
1421 | "dev": true,
1422 | "requires": {
1423 | "cliui": "^6.0.0",
1424 | "decamelize": "^1.2.0",
1425 | "find-up": "^4.1.0",
1426 | "get-caller-file": "^2.0.1",
1427 | "require-directory": "^2.1.1",
1428 | "require-main-filename": "^2.0.0",
1429 | "set-blocking": "^2.0.0",
1430 | "string-width": "^4.2.0",
1431 | "which-module": "^2.0.0",
1432 | "y18n": "^4.0.0",
1433 | "yargs-parser": "^18.1.2"
1434 | }
1435 | },
1436 | "yargs-parser": {
1437 | "version": "18.1.3",
1438 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
1439 | "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
1440 | "dev": true,
1441 | "requires": {
1442 | "camelcase": "^5.0.0",
1443 | "decamelize": "^1.2.0"
1444 | }
1445 | }
1446 | }
1447 | },
1448 | "object-assign": {
1449 | "version": "4.1.1",
1450 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1451 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
1452 | "dev": true
1453 | },
1454 | "once": {
1455 | "version": "1.4.0",
1456 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1457 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1458 | "dev": true,
1459 | "requires": {
1460 | "wrappy": "1"
1461 | }
1462 | },
1463 | "p-limit": {
1464 | "version": "3.1.0",
1465 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
1466 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
1467 | "dev": true,
1468 | "requires": {
1469 | "yocto-queue": "^0.1.0"
1470 | }
1471 | },
1472 | "p-locate": {
1473 | "version": "5.0.0",
1474 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
1475 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
1476 | "dev": true,
1477 | "requires": {
1478 | "p-limit": "^3.0.2"
1479 | }
1480 | },
1481 | "p-map": {
1482 | "version": "3.0.0",
1483 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
1484 | "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
1485 | "dev": true,
1486 | "requires": {
1487 | "aggregate-error": "^3.0.0"
1488 | }
1489 | },
1490 | "p-try": {
1491 | "version": "2.2.0",
1492 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
1493 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
1494 | "dev": true
1495 | },
1496 | "package-hash": {
1497 | "version": "4.0.0",
1498 | "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
1499 | "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
1500 | "dev": true,
1501 | "requires": {
1502 | "graceful-fs": "^4.1.15",
1503 | "hasha": "^5.0.0",
1504 | "lodash.flattendeep": "^4.4.0",
1505 | "release-zalgo": "^1.0.0"
1506 | }
1507 | },
1508 | "parseqs": {
1509 | "version": "0.0.6",
1510 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
1511 | "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
1512 | "dev": true
1513 | },
1514 | "parseuri": {
1515 | "version": "0.0.6",
1516 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
1517 | "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
1518 | "dev": true
1519 | },
1520 | "path-exists": {
1521 | "version": "4.0.0",
1522 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1523 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1524 | "dev": true
1525 | },
1526 | "path-is-absolute": {
1527 | "version": "1.0.1",
1528 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1529 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1530 | "dev": true
1531 | },
1532 | "path-key": {
1533 | "version": "3.1.1",
1534 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1535 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1536 | "dev": true
1537 | },
1538 | "picomatch": {
1539 | "version": "2.2.2",
1540 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
1541 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
1542 | "dev": true
1543 | },
1544 | "pkg-dir": {
1545 | "version": "4.2.0",
1546 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
1547 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
1548 | "dev": true,
1549 | "requires": {
1550 | "find-up": "^4.0.0"
1551 | },
1552 | "dependencies": {
1553 | "find-up": {
1554 | "version": "4.1.0",
1555 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
1556 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
1557 | "dev": true,
1558 | "requires": {
1559 | "locate-path": "^5.0.0",
1560 | "path-exists": "^4.0.0"
1561 | }
1562 | },
1563 | "locate-path": {
1564 | "version": "5.0.0",
1565 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
1566 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
1567 | "dev": true,
1568 | "requires": {
1569 | "p-locate": "^4.1.0"
1570 | }
1571 | },
1572 | "p-limit": {
1573 | "version": "2.3.0",
1574 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
1575 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
1576 | "dev": true,
1577 | "requires": {
1578 | "p-try": "^2.0.0"
1579 | }
1580 | },
1581 | "p-locate": {
1582 | "version": "4.1.0",
1583 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1584 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1585 | "dev": true,
1586 | "requires": {
1587 | "p-limit": "^2.2.0"
1588 | }
1589 | }
1590 | }
1591 | },
1592 | "prettier": {
1593 | "version": "2.2.1",
1594 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
1595 | "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
1596 | "dev": true
1597 | },
1598 | "process-on-spawn": {
1599 | "version": "1.0.0",
1600 | "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
1601 | "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
1602 | "dev": true,
1603 | "requires": {
1604 | "fromentries": "^1.2.0"
1605 | }
1606 | },
1607 | "randombytes": {
1608 | "version": "2.1.0",
1609 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1610 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1611 | "dev": true,
1612 | "requires": {
1613 | "safe-buffer": "^5.1.0"
1614 | }
1615 | },
1616 | "readdirp": {
1617 | "version": "3.5.0",
1618 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
1619 | "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
1620 | "dev": true,
1621 | "requires": {
1622 | "picomatch": "^2.2.1"
1623 | }
1624 | },
1625 | "release-zalgo": {
1626 | "version": "1.0.0",
1627 | "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
1628 | "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
1629 | "dev": true,
1630 | "requires": {
1631 | "es6-error": "^4.0.1"
1632 | }
1633 | },
1634 | "require-directory": {
1635 | "version": "2.1.1",
1636 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1637 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
1638 | "dev": true
1639 | },
1640 | "require-main-filename": {
1641 | "version": "2.0.0",
1642 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
1643 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
1644 | "dev": true
1645 | },
1646 | "resolve-from": {
1647 | "version": "5.0.0",
1648 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
1649 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
1650 | "dev": true
1651 | },
1652 | "rimraf": {
1653 | "version": "3.0.2",
1654 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1655 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1656 | "dev": true,
1657 | "requires": {
1658 | "glob": "^7.1.3"
1659 | }
1660 | },
1661 | "safe-buffer": {
1662 | "version": "5.2.1",
1663 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1664 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1665 | "dev": true
1666 | },
1667 | "semver": {
1668 | "version": "6.3.0",
1669 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
1670 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
1671 | "dev": true
1672 | },
1673 | "serialize-javascript": {
1674 | "version": "5.0.1",
1675 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
1676 | "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
1677 | "dev": true,
1678 | "requires": {
1679 | "randombytes": "^2.1.0"
1680 | }
1681 | },
1682 | "set-blocking": {
1683 | "version": "2.0.0",
1684 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
1685 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
1686 | "dev": true
1687 | },
1688 | "shebang-command": {
1689 | "version": "2.0.0",
1690 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1691 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1692 | "dev": true,
1693 | "requires": {
1694 | "shebang-regex": "^3.0.0"
1695 | }
1696 | },
1697 | "shebang-regex": {
1698 | "version": "3.0.0",
1699 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1700 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1701 | "dev": true
1702 | },
1703 | "signal-exit": {
1704 | "version": "3.0.3",
1705 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
1706 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
1707 | "dev": true
1708 | },
1709 | "socket.io": {
1710 | "version": "3.1.0",
1711 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.1.0.tgz",
1712 | "integrity": "sha512-Aqg2dlRh6xSJvRYK31ksG65q4kmBOqU4g+1ukhPcoT6wNGYoIwSYPlCPuRwOO9pgLUajojGFztl6+V2opmKcww==",
1713 | "dev": true,
1714 | "requires": {
1715 | "@types/cookie": "^0.4.0",
1716 | "@types/cors": "^2.8.8",
1717 | "@types/node": "^14.14.10",
1718 | "accepts": "~1.3.4",
1719 | "base64id": "~2.0.0",
1720 | "debug": "~4.3.1",
1721 | "engine.io": "~4.1.0",
1722 | "socket.io-adapter": "~2.1.0",
1723 | "socket.io-parser": "~4.0.3"
1724 | },
1725 | "dependencies": {
1726 | "debug": {
1727 | "version": "4.3.1",
1728 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
1729 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
1730 | "dev": true,
1731 | "requires": {
1732 | "ms": "2.1.2"
1733 | }
1734 | }
1735 | }
1736 | },
1737 | "socket.io-adapter": {
1738 | "version": "2.1.0",
1739 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.1.0.tgz",
1740 | "integrity": "sha512-+vDov/aTsLjViYTwS9fPy5pEtTkrbEKsw2M+oVSoFGw6OD1IpvlV1VPhUzNbofCQ8oyMbdYJqDtGdmHQK6TdPg==",
1741 | "dev": true
1742 | },
1743 | "socket.io-client": {
1744 | "version": "3.1.0",
1745 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-3.1.0.tgz",
1746 | "integrity": "sha512-T4qPOL80KnoBwkdR70zMpiR6aH6zv3ZqLNriofHqsO9wvQllNTOez0mpV4GdVqo1Y55Z+h8YOlBo7c8pOxDlHw==",
1747 | "dev": true,
1748 | "requires": {
1749 | "@types/component-emitter": "^1.2.10",
1750 | "backo2": "~1.0.2",
1751 | "component-emitter": "~1.3.0",
1752 | "debug": "~4.3.1",
1753 | "engine.io-client": "~4.1.0",
1754 | "parseuri": "0.0.6",
1755 | "socket.io-parser": "~4.0.4"
1756 | },
1757 | "dependencies": {
1758 | "debug": {
1759 | "version": "4.3.1",
1760 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
1761 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
1762 | "dev": true,
1763 | "requires": {
1764 | "ms": "2.1.2"
1765 | }
1766 | }
1767 | }
1768 | },
1769 | "socket.io-parser": {
1770 | "version": "4.0.4",
1771 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz",
1772 | "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==",
1773 | "dev": true,
1774 | "requires": {
1775 | "@types/component-emitter": "^1.2.10",
1776 | "component-emitter": "~1.3.0",
1777 | "debug": "~4.3.1"
1778 | },
1779 | "dependencies": {
1780 | "debug": {
1781 | "version": "4.3.1",
1782 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
1783 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
1784 | "dev": true,
1785 | "requires": {
1786 | "ms": "2.1.2"
1787 | }
1788 | }
1789 | }
1790 | },
1791 | "source-map": {
1792 | "version": "0.5.7",
1793 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
1794 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
1795 | "dev": true
1796 | },
1797 | "spawn-wrap": {
1798 | "version": "2.0.0",
1799 | "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
1800 | "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
1801 | "dev": true,
1802 | "requires": {
1803 | "foreground-child": "^2.0.0",
1804 | "is-windows": "^1.0.2",
1805 | "make-dir": "^3.0.0",
1806 | "rimraf": "^3.0.0",
1807 | "signal-exit": "^3.0.2",
1808 | "which": "^2.0.1"
1809 | }
1810 | },
1811 | "sprintf-js": {
1812 | "version": "1.0.3",
1813 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
1814 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
1815 | "dev": true
1816 | },
1817 | "string-width": {
1818 | "version": "2.1.1",
1819 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
1820 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
1821 | "dev": true,
1822 | "requires": {
1823 | "is-fullwidth-code-point": "^2.0.0",
1824 | "strip-ansi": "^4.0.0"
1825 | }
1826 | },
1827 | "strip-ansi": {
1828 | "version": "4.0.0",
1829 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
1830 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
1831 | "dev": true,
1832 | "requires": {
1833 | "ansi-regex": "^3.0.0"
1834 | }
1835 | },
1836 | "strip-bom": {
1837 | "version": "4.0.0",
1838 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
1839 | "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
1840 | "dev": true
1841 | },
1842 | "strip-json-comments": {
1843 | "version": "3.1.1",
1844 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
1845 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
1846 | "dev": true
1847 | },
1848 | "supports-color": {
1849 | "version": "7.2.0",
1850 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1851 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1852 | "dev": true,
1853 | "requires": {
1854 | "has-flag": "^4.0.0"
1855 | }
1856 | },
1857 | "test-exclude": {
1858 | "version": "6.0.0",
1859 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
1860 | "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
1861 | "dev": true,
1862 | "requires": {
1863 | "@istanbuljs/schema": "^0.1.2",
1864 | "glob": "^7.1.4",
1865 | "minimatch": "^3.0.4"
1866 | }
1867 | },
1868 | "to-fast-properties": {
1869 | "version": "2.0.0",
1870 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
1871 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
1872 | "dev": true
1873 | },
1874 | "to-regex-range": {
1875 | "version": "5.0.1",
1876 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1877 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1878 | "dev": true,
1879 | "requires": {
1880 | "is-number": "^7.0.0"
1881 | }
1882 | },
1883 | "type-fest": {
1884 | "version": "0.8.1",
1885 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
1886 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
1887 | "dev": true
1888 | },
1889 | "typedarray-to-buffer": {
1890 | "version": "3.1.5",
1891 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
1892 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
1893 | "dev": true,
1894 | "requires": {
1895 | "is-typedarray": "^1.0.0"
1896 | }
1897 | },
1898 | "uuid": {
1899 | "version": "3.4.0",
1900 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
1901 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
1902 | "dev": true
1903 | },
1904 | "vary": {
1905 | "version": "1.1.2",
1906 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1907 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
1908 | "dev": true
1909 | },
1910 | "which": {
1911 | "version": "2.0.2",
1912 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1913 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1914 | "dev": true,
1915 | "requires": {
1916 | "isexe": "^2.0.0"
1917 | }
1918 | },
1919 | "which-module": {
1920 | "version": "2.0.0",
1921 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
1922 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
1923 | "dev": true
1924 | },
1925 | "wide-align": {
1926 | "version": "1.1.3",
1927 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
1928 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
1929 | "dev": true,
1930 | "requires": {
1931 | "string-width": "^1.0.2 || 2"
1932 | }
1933 | },
1934 | "workerpool": {
1935 | "version": "6.0.2",
1936 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz",
1937 | "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==",
1938 | "dev": true
1939 | },
1940 | "wrap-ansi": {
1941 | "version": "5.1.0",
1942 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
1943 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
1944 | "dev": true,
1945 | "requires": {
1946 | "ansi-styles": "^3.2.0",
1947 | "string-width": "^3.0.0",
1948 | "strip-ansi": "^5.0.0"
1949 | },
1950 | "dependencies": {
1951 | "ansi-regex": {
1952 | "version": "4.1.0",
1953 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
1954 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
1955 | "dev": true
1956 | },
1957 | "ansi-styles": {
1958 | "version": "3.2.1",
1959 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
1960 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
1961 | "dev": true,
1962 | "requires": {
1963 | "color-convert": "^1.9.0"
1964 | }
1965 | },
1966 | "color-convert": {
1967 | "version": "1.9.3",
1968 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
1969 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
1970 | "dev": true,
1971 | "requires": {
1972 | "color-name": "1.1.3"
1973 | }
1974 | },
1975 | "color-name": {
1976 | "version": "1.1.3",
1977 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
1978 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
1979 | "dev": true
1980 | },
1981 | "string-width": {
1982 | "version": "3.1.0",
1983 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
1984 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
1985 | "dev": true,
1986 | "requires": {
1987 | "emoji-regex": "^7.0.1",
1988 | "is-fullwidth-code-point": "^2.0.0",
1989 | "strip-ansi": "^5.1.0"
1990 | }
1991 | },
1992 | "strip-ansi": {
1993 | "version": "5.2.0",
1994 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
1995 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
1996 | "dev": true,
1997 | "requires": {
1998 | "ansi-regex": "^4.1.0"
1999 | }
2000 | }
2001 | }
2002 | },
2003 | "wrappy": {
2004 | "version": "1.0.2",
2005 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2006 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
2007 | "dev": true
2008 | },
2009 | "write-file-atomic": {
2010 | "version": "3.0.3",
2011 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
2012 | "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
2013 | "dev": true,
2014 | "requires": {
2015 | "imurmurhash": "^0.1.4",
2016 | "is-typedarray": "^1.0.0",
2017 | "signal-exit": "^3.0.2",
2018 | "typedarray-to-buffer": "^3.1.5"
2019 | }
2020 | },
2021 | "ws": {
2022 | "version": "7.4.2",
2023 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
2024 | "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==",
2025 | "dev": true
2026 | },
2027 | "xmlhttprequest-ssl": {
2028 | "version": "1.5.5",
2029 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
2030 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
2031 | "dev": true
2032 | },
2033 | "y18n": {
2034 | "version": "4.0.1",
2035 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
2036 | "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
2037 | "dev": true
2038 | },
2039 | "yargs": {
2040 | "version": "13.3.2",
2041 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
2042 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
2043 | "dev": true,
2044 | "requires": {
2045 | "cliui": "^5.0.0",
2046 | "find-up": "^3.0.0",
2047 | "get-caller-file": "^2.0.1",
2048 | "require-directory": "^2.1.1",
2049 | "require-main-filename": "^2.0.0",
2050 | "set-blocking": "^2.0.0",
2051 | "string-width": "^3.0.0",
2052 | "which-module": "^2.0.0",
2053 | "y18n": "^4.0.0",
2054 | "yargs-parser": "^13.1.2"
2055 | },
2056 | "dependencies": {
2057 | "ansi-regex": {
2058 | "version": "4.1.0",
2059 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
2060 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2061 | "dev": true
2062 | },
2063 | "find-up": {
2064 | "version": "3.0.0",
2065 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
2066 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
2067 | "dev": true,
2068 | "requires": {
2069 | "locate-path": "^3.0.0"
2070 | }
2071 | },
2072 | "locate-path": {
2073 | "version": "3.0.0",
2074 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
2075 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
2076 | "dev": true,
2077 | "requires": {
2078 | "p-locate": "^3.0.0",
2079 | "path-exists": "^3.0.0"
2080 | }
2081 | },
2082 | "p-limit": {
2083 | "version": "2.3.0",
2084 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
2085 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
2086 | "dev": true,
2087 | "requires": {
2088 | "p-try": "^2.0.0"
2089 | }
2090 | },
2091 | "p-locate": {
2092 | "version": "3.0.0",
2093 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
2094 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
2095 | "dev": true,
2096 | "requires": {
2097 | "p-limit": "^2.0.0"
2098 | }
2099 | },
2100 | "path-exists": {
2101 | "version": "3.0.0",
2102 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
2103 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
2104 | "dev": true
2105 | },
2106 | "string-width": {
2107 | "version": "3.1.0",
2108 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2109 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2110 | "dev": true,
2111 | "requires": {
2112 | "emoji-regex": "^7.0.1",
2113 | "is-fullwidth-code-point": "^2.0.0",
2114 | "strip-ansi": "^5.1.0"
2115 | }
2116 | },
2117 | "strip-ansi": {
2118 | "version": "5.2.0",
2119 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
2120 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
2121 | "dev": true,
2122 | "requires": {
2123 | "ansi-regex": "^4.1.0"
2124 | }
2125 | }
2126 | }
2127 | },
2128 | "yargs-parser": {
2129 | "version": "13.1.2",
2130 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
2131 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
2132 | "dev": true,
2133 | "requires": {
2134 | "camelcase": "^5.0.0",
2135 | "decamelize": "^1.2.0"
2136 | }
2137 | },
2138 | "yargs-unparser": {
2139 | "version": "2.0.0",
2140 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
2141 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
2142 | "dev": true,
2143 | "requires": {
2144 | "camelcase": "^6.0.0",
2145 | "decamelize": "^4.0.0",
2146 | "flat": "^5.0.2",
2147 | "is-plain-obj": "^2.1.0"
2148 | },
2149 | "dependencies": {
2150 | "camelcase": {
2151 | "version": "6.2.0",
2152 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
2153 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
2154 | "dev": true
2155 | },
2156 | "decamelize": {
2157 | "version": "4.0.0",
2158 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
2159 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
2160 | "dev": true
2161 | }
2162 | }
2163 | },
2164 | "yeast": {
2165 | "version": "0.1.2",
2166 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
2167 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
2168 | "dev": true
2169 | },
2170 | "yocto-queue": {
2171 | "version": "0.1.0",
2172 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
2173 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
2174 | "dev": true
2175 | }
2176 | }
2177 | }
2178 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@socket.io/sticky",
3 | "version": "1.0.4",
4 | "description": "An alternative to the sticky-session package (https://github.com/indutny/sticky-session)",
5 | "main": "index.js",
6 | "types": "index.d.ts",
7 | "scripts": {
8 | "format:check": "prettier --check \"index.js\" \"test/**/*.js\"",
9 | "format:fix": "prettier --write \"index.js\" \"test/**/*.js\"",
10 | "test": "npm run format:check && nyc mocha --timeout 5000"
11 | },
12 | "files": [
13 | "index.js",
14 | "index.d.ts"
15 | ],
16 | "author": "Damien Arrachequesne ",
17 | "license": "MIT",
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/socketio/socket.io-sticky.git"
21 | },
22 | "homepage": "https://github.com/socketio/socket.io-sticky#readme",
23 | "devDependencies": {
24 | "mocha": "^8.2.1",
25 | "nyc": "^15.1.0",
26 | "prettier": "^2.2.1",
27 | "socket.io": "^3.1.0",
28 | "socket.io-client": "^3.1.0"
29 | },
30 | "keywords": [
31 | "socket.io",
32 | "websocket",
33 | "cluster",
34 | "node.js"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/test/fixtures/connection.js:
--------------------------------------------------------------------------------
1 | const cluster = require("cluster");
2 | const http = require("http");
3 | const { Server } = require("socket.io");
4 | const ioc = require("socket.io-client");
5 | const { setupMaster, setupWorker } = require("../..");
6 |
7 | if (cluster.isWorker) {
8 | const httpServer = http.createServer();
9 | const io = new Server(httpServer, {
10 | maxHttpBufferSize: 1.4 * 1e6, // to account for the base64 encoding of the binary payload
11 | });
12 | setupWorker(io);
13 |
14 | io.on("connection", (socket) => {
15 | socket.on("foo", (val) => {
16 | socket.emit("bar", val);
17 | });
18 | });
19 |
20 | return;
21 | }
22 |
23 | const WORKER_COUNT = 3;
24 |
25 | for (let i = 0; i < WORKER_COUNT; i++) {
26 | cluster.fork();
27 | }
28 |
29 | const httpServer = http.createServer();
30 |
31 | setupMaster(httpServer, {
32 | loadBalancingMethod: process.env.LB_METHOD || "least-connection",
33 | });
34 |
35 | const waitFor = (emitter, event) => {
36 | return new Promise((resolve) => {
37 | emitter.once(event, resolve);
38 | });
39 | };
40 |
41 | httpServer.listen(async () => {
42 | const port = httpServer.address().port;
43 |
44 | const socket = ioc(`http://localhost:${port}`, {
45 | transports: process.env.TRANSPORT
46 | ? [process.env.TRANSPORT]
47 | : ["polling", "websocket"],
48 | });
49 |
50 | await waitFor(socket, "connect");
51 |
52 | socket.disconnect().connect();
53 | await waitFor(socket, "connect");
54 |
55 | socket.disconnect().connect();
56 | await waitFor(socket, "connect");
57 |
58 | socket.emit("foo", "hello");
59 | await waitFor(socket, "bar");
60 |
61 | socket.emit("foo", Buffer.allocUnsafe(1e6));
62 | await waitFor(socket, "bar");
63 |
64 | // cleanup
65 | for (const id in cluster.workers) {
66 | cluster.workers[id].kill();
67 | }
68 | httpServer.close();
69 | socket.disconnect();
70 | });
71 |
--------------------------------------------------------------------------------
/test/fixtures/cors.js:
--------------------------------------------------------------------------------
1 | const cluster = require("cluster");
2 | const { createServer, request } = require("http");
3 | const { Server } = require("socket.io");
4 | const { setupMaster, setupWorker } = require("../..");
5 | const assert = require("assert").strict;
6 | const { sendRequest } = require("./util");
7 |
8 | if (cluster.isWorker) {
9 | const httpServer = createServer();
10 | const io = new Server(httpServer, {
11 | cors: {
12 | origin: true,
13 | },
14 | });
15 | setupWorker(io);
16 |
17 | io.on("connection", (socket) => {
18 | socket.on("foo", (val) => {
19 | socket.emit("bar", val);
20 | });
21 | });
22 |
23 | return;
24 | }
25 |
26 | const WORKER_COUNT = 3;
27 |
28 | for (let i = 0; i < WORKER_COUNT; i++) {
29 | cluster.fork();
30 | }
31 |
32 | const httpServer = createServer();
33 |
34 | setupMaster(httpServer, {
35 | loadBalancingMethod: process.env.LB_METHOD || "least-connection",
36 | });
37 |
38 | const waitFor = (emitter, event) => {
39 | return new Promise((resolve) => {
40 | emitter.once(event, resolve);
41 | });
42 | };
43 |
44 | httpServer.listen(async () => {
45 | const port = httpServer.address().port;
46 |
47 | const res = await sendRequest({
48 | port,
49 | method: "options",
50 | path: "/socket.io/",
51 | headers: {
52 | origin: "https://example.com",
53 | },
54 | });
55 |
56 | assert.equal(res.statusCode, 204);
57 |
58 | assert.equal(
59 | res.headers["access-control-allow-origin"],
60 | "https://example.com"
61 | );
62 |
63 | // cleanup
64 | for (const id in cluster.workers) {
65 | cluster.workers[id].kill();
66 | }
67 | httpServer.close();
68 | });
69 |
--------------------------------------------------------------------------------
/test/fixtures/failing.js:
--------------------------------------------------------------------------------
1 | const cluster = require("cluster");
2 | const { createServer, Agent } = require("http");
3 | const { Server } = require("socket.io");
4 | const { setupMaster, setupWorker } = require("../..");
5 | const assert = require("assert").strict;
6 | const { sendRequest } = require("./util");
7 |
8 | if (cluster.isWorker) {
9 | const httpServer = createServer();
10 | const io = new Server(httpServer);
11 | setupWorker(io);
12 |
13 | io.on("connection", (socket) => {
14 | socket.on("foo", (val) => {
15 | socket.emit("bar", val);
16 | });
17 | });
18 |
19 | return;
20 | }
21 |
22 | const WORKER_COUNT = 3;
23 |
24 | for (let i = 0; i < WORKER_COUNT; i++) {
25 | cluster.fork();
26 | }
27 |
28 | const httpServer = createServer();
29 |
30 | setupMaster(httpServer, {
31 | loadBalancingMethod: process.env.LB_METHOD || "least-connection",
32 | });
33 |
34 | httpServer.listen(async () => {
35 | const port = httpServer.address().port;
36 |
37 | const agent1 = new Agent({ keepAlive: true });
38 | const agent2 = new Agent({ keepAlive: true });
39 |
40 | // Engine.IO handshake on connection 1
41 | const res1 = await sendRequest({
42 | agent: agent1,
43 | port,
44 | method: "get",
45 | path: "/socket.io/?EIO=4&transport=polling",
46 | });
47 |
48 | assert.equal(res1.statusCode, 200);
49 |
50 | const sid = JSON.parse(res1.body.toString().substring(1)).sid;
51 |
52 | // Engine.IO handshake on connection 2
53 | const res2 = await sendRequest({
54 | agent: agent2,
55 | port,
56 | method: "get",
57 | path: "/socket.io/?EIO=4&transport=polling",
58 | });
59 |
60 | assert.equal(res2.statusCode, 200);
61 |
62 | // Socket.IO handshake on connection 2
63 | const res3 = await sendRequest(
64 | {
65 | agent: agent2,
66 | port,
67 | method: "post",
68 | path: `/socket.io/?EIO=4&transport=polling&sid=${sid}`,
69 | },
70 | "40"
71 | );
72 |
73 | // FIXME "session ID unknown"
74 | assert.equal(res3.statusCode, 400);
75 |
76 | // cleanup
77 | for (const id in cluster.workers) {
78 | cluster.workers[id].kill();
79 | }
80 | httpServer.close();
81 | });
82 |
--------------------------------------------------------------------------------
/test/fixtures/util.js:
--------------------------------------------------------------------------------
1 | const { request } = require("http");
2 |
3 | module.exports.sendRequest = function sendRequest(options, data) {
4 | return new Promise((resolve) => {
5 | if (data) {
6 | options.headers = options.headers || {};
7 | options.headers["content-length"] = Buffer.byteLength(data);
8 | }
9 |
10 | const req = request(options, (res) => {
11 | const chunks = [];
12 |
13 | res.on("data", (chunk) => {
14 | chunks.push(chunk);
15 | });
16 |
17 | res.on("end", () => {
18 | res.body = Buffer.concat(chunks);
19 | resolve(res);
20 | });
21 | });
22 |
23 | if (data) {
24 | req.write(data);
25 | }
26 |
27 | req.end();
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | const { join } = require("path");
2 | const { exec } = require("child_process");
3 | const { createServer } = require("http");
4 | const { setupMaster } = require("../index");
5 | const ioc = require("socket.io-client");
6 |
7 | const fixture = (filename) => {
8 | return (
9 | '"' + process.execPath + '" "' + join(__dirname, "fixtures", filename) + '"'
10 | );
11 | };
12 |
13 | function waitFor(emitter, event) {
14 | return new Promise((resolve) => {
15 | emitter.once(event, resolve);
16 | });
17 | }
18 |
19 | function success(done, httpServer, socket) {
20 | httpServer.close();
21 | socket.disconnect();
22 | done();
23 | }
24 |
25 | describe("@socket.io/sticky", () => {
26 | it("should work with least-connection load-balancing", (done) => {
27 | exec(fixture("connection.js"), done);
28 | });
29 |
30 | it("should work with round-robin load-balancing", (done) => {
31 | exec(fixture("connection.js"), { env: { LB_METHOD: "round-robin" } }, done);
32 | });
33 |
34 | it("should work with random load-balancing", (done) => {
35 | exec(fixture("connection.js"), { env: { LB_METHOD: "random" } }, done);
36 | });
37 |
38 | it("should work with WebSocket only", (done) => {
39 | exec(fixture("connection.js"), { env: { TRANSPORT: "websocket" } }, done);
40 | });
41 |
42 | it("should work with HTTP long-polling only", (done) => {
43 | exec(fixture("connection.js"), { env: { TRANSPORT: "polling" } }, done);
44 | });
45 |
46 | it("should work with CORS", (done) => {
47 | exec(fixture("cors.js"), done);
48 | });
49 |
50 | it("should return a 503 error when no worker is available (polling)", (done) => {
51 | const httpServer = createServer();
52 |
53 | setupMaster(httpServer, {
54 | loadBalancingMethod: "least-connection",
55 | });
56 |
57 | httpServer.listen(async () => {
58 | const { port } = httpServer.address();
59 |
60 | const socket = ioc(`http://localhost:${port}`, {
61 | transports: ["polling"],
62 | });
63 |
64 | await waitFor(socket, "connect_error");
65 |
66 | success(done, httpServer, socket);
67 | });
68 | });
69 |
70 | it("should return a 503 error when no worker is available (websocket)", (done) => {
71 | const httpServer = createServer();
72 |
73 | setupMaster(httpServer, {
74 | loadBalancingMethod: "least-connection",
75 | });
76 |
77 | httpServer.listen(async () => {
78 | const { port } = httpServer.address();
79 |
80 | const socket = ioc(`http://localhost:${port}`, {
81 | transports: ["websocket"],
82 | });
83 |
84 | await waitFor(socket, "connect_error");
85 |
86 | success(done, httpServer, socket);
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------