├── .gitignore
├── README.md
├── client
├── dist
│ └── assets
│ │ ├── License.txt
│ │ ├── ship_0000.png
│ │ ├── ship_0001.png
│ │ ├── ship_0002.png
│ │ ├── ship_0003.png
│ │ ├── ship_0004.png
│ │ ├── ship_0005.png
│ │ ├── ship_0006.png
│ │ ├── ship_0007.png
│ │ ├── ship_0008.png
│ │ ├── ship_0009.png
│ │ ├── ship_0010.png
│ │ ├── ship_0011.png
│ │ ├── ship_0012.png
│ │ ├── ship_0013.png
│ │ ├── ship_0014.png
│ │ ├── ship_0015.png
│ │ ├── ship_0016.png
│ │ ├── ship_0017.png
│ │ ├── ship_0018.png
│ │ ├── ship_0019.png
│ │ ├── ship_0020.png
│ │ ├── ship_0021.png
│ │ ├── ship_0022.png
│ │ └── ship_0023.png
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── backend.ts
│ ├── index.ts
│ └── scenes
│ │ ├── Part1Scene.ts
│ │ ├── Part2Scene.ts
│ │ ├── Part3Scene.ts
│ │ ├── Part4Scene.ts
│ │ └── SceneSelector.ts
└── tsconfig.json
└── server
├── .env.development
├── .env.production
├── .gitignore
├── README.md
├── loadtest
└── example.ts
├── package-lock.json
├── package.json
├── src
├── app.config.ts
├── index.ts
└── rooms
│ ├── Part1Room.ts
│ ├── Part2Room.ts
│ ├── Part3Room.ts
│ └── Part4Room.ts
├── test
└── MyRoom_test.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .parcel-cache
3 | client/dist/*.js
4 | client/dist/*.map
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Phaser: Real-time Multiplayer with Colyseus
2 |
3 | Full source-code for the step-by-step tutorial on how to use Phaser + Colyseus together.
4 |
5 | - [Live Demo](https://colyseus-phaser-tutorial.glitch.me/)
6 | - [See step-by-step Tutorial](https://colyseus.io/learn/phaser/)
7 | - [See Colyseus documentation](https://docs.colyseus.io/)
8 |
9 | ## How to run the **server**
10 |
11 | - Download and install [Node.js LTS](https://nodejs.org/en/download/)
12 | - Clone or download this repository.
13 | - Run the following commands:
14 |
15 | ```
16 | cd server
17 | npm install
18 | npm start
19 | ```
20 |
21 | The WebSocket server should be available locally at `ws://localhost:2567` ([http://localhost:2567](http://localhost:2567) should be accessible.)
22 |
23 | ## How to run the **client**
24 |
25 | In a new Terminal tab, run the following commands:
26 |
27 | ```
28 | cd client
29 | npm install
30 | npm start
31 | ```
32 |
33 | The client should be accessible at [`http://localhost:1234`](`http://localhost:1234`).
34 |
35 | ## License
36 |
37 | - Source-code is licensed under MIT License.
38 | - The [assets](https://www.kenney.nl/assets/pixel-shmup) are licensed under [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/).
39 |
--------------------------------------------------------------------------------
/client/dist/assets/License.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pixel Shmup (1.1)
4 |
5 | Created/distributed by Kenney (www.kenney.nl)
6 | Creation date: 01-11-2021
7 |
8 | ------------------------------
9 |
10 | License: (Creative Commons Zero, CC0)
11 | http://creativecommons.org/publicdomain/zero/1.0/
12 |
13 | This content is free to use in personal, educational and commercial projects.
14 |
15 | Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
16 |
17 | ------------------------------
18 |
19 | Donate: http://support.kenney.nl
20 | Patreon: http://patreon.com/kenney/
21 |
22 | Follow on Twitter for updates:
23 | http://twitter.com/KenneyNL
--------------------------------------------------------------------------------
/client/dist/assets/ship_0000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0000.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0001.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0002.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0003.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0004.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0005.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0006.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0007.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0008.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0009.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0009.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0010.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0010.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0011.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0011.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0012.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0012.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0013.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0013.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0014.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0014.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0015.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0015.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0016.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0016.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0017.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0017.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0018.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0018.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0019.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0019.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0020.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0020.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0021.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0022.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0022.png
--------------------------------------------------------------------------------
/client/dist/assets/ship_0023.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0023.png
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Colyseus + Phaser Example
8 |
18 |
19 |
20 |
21 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/client/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "client",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "colyseus.js": "^0.16.0",
13 | "phaser": "^3.55.2"
14 | },
15 | "devDependencies": {
16 | "buffer": "^6.0.3",
17 | "parcel": "^2.4.0",
18 | "process": "^0.11.10",
19 | "typescript": "^4.6.3"
20 | }
21 | },
22 | "node_modules/@babel/code-frame": {
23 | "version": "7.24.7",
24 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
25 | "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
26 | "dev": true,
27 | "dependencies": {
28 | "@babel/highlight": "^7.24.7",
29 | "picocolors": "^1.0.0"
30 | },
31 | "engines": {
32 | "node": ">=6.9.0"
33 | }
34 | },
35 | "node_modules/@babel/helper-validator-identifier": {
36 | "version": "7.24.7",
37 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
38 | "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
39 | "dev": true,
40 | "engines": {
41 | "node": ">=6.9.0"
42 | }
43 | },
44 | "node_modules/@babel/highlight": {
45 | "version": "7.24.7",
46 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
47 | "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
48 | "dev": true,
49 | "dependencies": {
50 | "@babel/helper-validator-identifier": "^7.24.7",
51 | "chalk": "^2.4.2",
52 | "js-tokens": "^4.0.0",
53 | "picocolors": "^1.0.0"
54 | },
55 | "engines": {
56 | "node": ">=6.9.0"
57 | }
58 | },
59 | "node_modules/@babel/highlight/node_modules/ansi-styles": {
60 | "version": "3.2.1",
61 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
62 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
63 | "dev": true,
64 | "dependencies": {
65 | "color-convert": "^1.9.0"
66 | },
67 | "engines": {
68 | "node": ">=4"
69 | }
70 | },
71 | "node_modules/@babel/highlight/node_modules/chalk": {
72 | "version": "2.4.2",
73 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
74 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
75 | "dev": true,
76 | "dependencies": {
77 | "ansi-styles": "^3.2.1",
78 | "escape-string-regexp": "^1.0.5",
79 | "supports-color": "^5.3.0"
80 | },
81 | "engines": {
82 | "node": ">=4"
83 | }
84 | },
85 | "node_modules/@babel/highlight/node_modules/color-convert": {
86 | "version": "1.9.3",
87 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
88 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
89 | "dev": true,
90 | "dependencies": {
91 | "color-name": "1.1.3"
92 | }
93 | },
94 | "node_modules/@babel/highlight/node_modules/color-name": {
95 | "version": "1.1.3",
96 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
97 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
98 | "dev": true
99 | },
100 | "node_modules/@babel/highlight/node_modules/has-flag": {
101 | "version": "3.0.0",
102 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
103 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
104 | "dev": true,
105 | "engines": {
106 | "node": ">=4"
107 | }
108 | },
109 | "node_modules/@babel/highlight/node_modules/supports-color": {
110 | "version": "5.5.0",
111 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
112 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
113 | "dev": true,
114 | "dependencies": {
115 | "has-flag": "^3.0.0"
116 | },
117 | "engines": {
118 | "node": ">=4"
119 | }
120 | },
121 | "node_modules/@colyseus/msgpackr": {
122 | "version": "1.10.5",
123 | "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.5.tgz",
124 | "integrity": "sha512-ZSWPpEEnSe/oMzifiLKkNdE5UR0B8STagWR1JcKV5qw6ISM/z8d7ArZgGstqBrrZAXAOIZDpvOyrTloiR9zRlg==",
125 | "license": "MIT",
126 | "optionalDependencies": {
127 | "msgpackr-extract": "^3.0.2"
128 | }
129 | },
130 | "node_modules/@colyseus/schema": {
131 | "version": "3.0.12",
132 | "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.12.tgz",
133 | "integrity": "sha512-KifxbFwljtMTyvcMF6XIFczgblmHa4CsGT9bzIv/n/YE6keXekrCagRlO87epQy/8kmN+EapBivjWrZbQdPKUA==",
134 | "license": "MIT",
135 | "bin": {
136 | "schema-codegen": "bin/schema-codegen",
137 | "schema-debug": "bin/schema-debug"
138 | }
139 | },
140 | "node_modules/@lezer/common": {
141 | "version": "1.2.1",
142 | "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
143 | "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==",
144 | "dev": true
145 | },
146 | "node_modules/@lezer/lr": {
147 | "version": "1.4.1",
148 | "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.1.tgz",
149 | "integrity": "sha512-CHsKq8DMKBf9b3yXPDIU4DbH+ZJd/sJdYOW2llbW/HudP5u0VS6Bfq1hLYfgU7uAYGFIyGGQIsSOXGPEErZiJw==",
150 | "dev": true,
151 | "dependencies": {
152 | "@lezer/common": "^1.0.0"
153 | }
154 | },
155 | "node_modules/@lmdb/lmdb-darwin-arm64": {
156 | "version": "2.8.5",
157 | "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.8.5.tgz",
158 | "integrity": "sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==",
159 | "cpu": [
160 | "arm64"
161 | ],
162 | "dev": true,
163 | "optional": true,
164 | "os": [
165 | "darwin"
166 | ]
167 | },
168 | "node_modules/@mischnic/json-sourcemap": {
169 | "version": "0.1.1",
170 | "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz",
171 | "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==",
172 | "dev": true,
173 | "dependencies": {
174 | "@lezer/common": "^1.0.0",
175 | "@lezer/lr": "^1.0.0",
176 | "json5": "^2.2.1"
177 | },
178 | "engines": {
179 | "node": ">=12.0.0"
180 | }
181 | },
182 | "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
183 | "version": "3.0.3",
184 | "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
185 | "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
186 | "cpu": [
187 | "arm64"
188 | ],
189 | "dev": true,
190 | "optional": true,
191 | "os": [
192 | "darwin"
193 | ]
194 | },
195 | "node_modules/@parcel/bundler-default": {
196 | "version": "2.12.0",
197 | "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.12.0.tgz",
198 | "integrity": "sha512-3ybN74oYNMKyjD6V20c9Gerdbh7teeNvVMwIoHIQMzuIFT6IGX53PyOLlOKRLbjxMc0TMimQQxIt2eQqxR5LsA==",
199 | "dev": true,
200 | "dependencies": {
201 | "@parcel/diagnostic": "2.12.0",
202 | "@parcel/graph": "3.2.0",
203 | "@parcel/plugin": "2.12.0",
204 | "@parcel/rust": "2.12.0",
205 | "@parcel/utils": "2.12.0",
206 | "nullthrows": "^1.1.1"
207 | },
208 | "engines": {
209 | "node": ">= 12.0.0",
210 | "parcel": "^2.12.0"
211 | },
212 | "funding": {
213 | "type": "opencollective",
214 | "url": "https://opencollective.com/parcel"
215 | }
216 | },
217 | "node_modules/@parcel/cache": {
218 | "version": "2.12.0",
219 | "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.12.0.tgz",
220 | "integrity": "sha512-FX5ZpTEkxvq/yvWklRHDESVRz+c7sLTXgFuzz6uEnBcXV38j6dMSikflNpHA6q/L4GKkCqRywm9R6XQwhwIMyw==",
221 | "dev": true,
222 | "dependencies": {
223 | "@parcel/fs": "2.12.0",
224 | "@parcel/logger": "2.12.0",
225 | "@parcel/utils": "2.12.0",
226 | "lmdb": "2.8.5"
227 | },
228 | "engines": {
229 | "node": ">= 12.0.0"
230 | },
231 | "funding": {
232 | "type": "opencollective",
233 | "url": "https://opencollective.com/parcel"
234 | },
235 | "peerDependencies": {
236 | "@parcel/core": "^2.12.0"
237 | }
238 | },
239 | "node_modules/@parcel/codeframe": {
240 | "version": "2.12.0",
241 | "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.12.0.tgz",
242 | "integrity": "sha512-v2VmneILFiHZJTxPiR7GEF1wey1/IXPdZMcUlNXBiPZyWDfcuNgGGVQkx/xW561rULLIvDPharOMdxz5oHOKQg==",
243 | "dev": true,
244 | "dependencies": {
245 | "chalk": "^4.1.0"
246 | },
247 | "engines": {
248 | "node": ">= 12.0.0"
249 | },
250 | "funding": {
251 | "type": "opencollective",
252 | "url": "https://opencollective.com/parcel"
253 | }
254 | },
255 | "node_modules/@parcel/compressor-raw": {
256 | "version": "2.12.0",
257 | "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.12.0.tgz",
258 | "integrity": "sha512-h41Q3X7ZAQ9wbQ2csP8QGrwepasLZdXiuEdpUryDce6rF9ZiHoJ97MRpdLxOhOPyASTw/xDgE1xyaPQr0Q3f5A==",
259 | "dev": true,
260 | "dependencies": {
261 | "@parcel/plugin": "2.12.0"
262 | },
263 | "engines": {
264 | "node": ">= 12.0.0",
265 | "parcel": "^2.12.0"
266 | },
267 | "funding": {
268 | "type": "opencollective",
269 | "url": "https://opencollective.com/parcel"
270 | }
271 | },
272 | "node_modules/@parcel/config-default": {
273 | "version": "2.12.0",
274 | "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.12.0.tgz",
275 | "integrity": "sha512-dPNe2n9eEsKRc1soWIY0yToMUPirPIa2QhxcCB3Z5RjpDGIXm0pds+BaiqY6uGLEEzsjhRO0ujd4v2Rmm0vuFg==",
276 | "dev": true,
277 | "dependencies": {
278 | "@parcel/bundler-default": "2.12.0",
279 | "@parcel/compressor-raw": "2.12.0",
280 | "@parcel/namer-default": "2.12.0",
281 | "@parcel/optimizer-css": "2.12.0",
282 | "@parcel/optimizer-htmlnano": "2.12.0",
283 | "@parcel/optimizer-image": "2.12.0",
284 | "@parcel/optimizer-svgo": "2.12.0",
285 | "@parcel/optimizer-swc": "2.12.0",
286 | "@parcel/packager-css": "2.12.0",
287 | "@parcel/packager-html": "2.12.0",
288 | "@parcel/packager-js": "2.12.0",
289 | "@parcel/packager-raw": "2.12.0",
290 | "@parcel/packager-svg": "2.12.0",
291 | "@parcel/packager-wasm": "2.12.0",
292 | "@parcel/reporter-dev-server": "2.12.0",
293 | "@parcel/resolver-default": "2.12.0",
294 | "@parcel/runtime-browser-hmr": "2.12.0",
295 | "@parcel/runtime-js": "2.12.0",
296 | "@parcel/runtime-react-refresh": "2.12.0",
297 | "@parcel/runtime-service-worker": "2.12.0",
298 | "@parcel/transformer-babel": "2.12.0",
299 | "@parcel/transformer-css": "2.12.0",
300 | "@parcel/transformer-html": "2.12.0",
301 | "@parcel/transformer-image": "2.12.0",
302 | "@parcel/transformer-js": "2.12.0",
303 | "@parcel/transformer-json": "2.12.0",
304 | "@parcel/transformer-postcss": "2.12.0",
305 | "@parcel/transformer-posthtml": "2.12.0",
306 | "@parcel/transformer-raw": "2.12.0",
307 | "@parcel/transformer-react-refresh-wrap": "2.12.0",
308 | "@parcel/transformer-svg": "2.12.0"
309 | },
310 | "funding": {
311 | "type": "opencollective",
312 | "url": "https://opencollective.com/parcel"
313 | },
314 | "peerDependencies": {
315 | "@parcel/core": "^2.12.0"
316 | }
317 | },
318 | "node_modules/@parcel/core": {
319 | "version": "2.12.0",
320 | "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.12.0.tgz",
321 | "integrity": "sha512-s+6pwEj+GfKf7vqGUzN9iSEPueUssCCQrCBUlcAfKrJe0a22hTUCjewpB0I7lNrCIULt8dkndD+sMdOrXsRl6Q==",
322 | "dev": true,
323 | "dependencies": {
324 | "@mischnic/json-sourcemap": "^0.1.0",
325 | "@parcel/cache": "2.12.0",
326 | "@parcel/diagnostic": "2.12.0",
327 | "@parcel/events": "2.12.0",
328 | "@parcel/fs": "2.12.0",
329 | "@parcel/graph": "3.2.0",
330 | "@parcel/logger": "2.12.0",
331 | "@parcel/package-manager": "2.12.0",
332 | "@parcel/plugin": "2.12.0",
333 | "@parcel/profiler": "2.12.0",
334 | "@parcel/rust": "2.12.0",
335 | "@parcel/source-map": "^2.1.1",
336 | "@parcel/types": "2.12.0",
337 | "@parcel/utils": "2.12.0",
338 | "@parcel/workers": "2.12.0",
339 | "abortcontroller-polyfill": "^1.1.9",
340 | "base-x": "^3.0.8",
341 | "browserslist": "^4.6.6",
342 | "clone": "^2.1.1",
343 | "dotenv": "^7.0.0",
344 | "dotenv-expand": "^5.1.0",
345 | "json5": "^2.2.0",
346 | "msgpackr": "^1.9.9",
347 | "nullthrows": "^1.1.1",
348 | "semver": "^7.5.2"
349 | },
350 | "engines": {
351 | "node": ">= 12.0.0"
352 | },
353 | "funding": {
354 | "type": "opencollective",
355 | "url": "https://opencollective.com/parcel"
356 | }
357 | },
358 | "node_modules/@parcel/diagnostic": {
359 | "version": "2.12.0",
360 | "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.12.0.tgz",
361 | "integrity": "sha512-8f1NOsSFK+F4AwFCKynyIu9Kr/uWHC+SywAv4oS6Bv3Acig0gtwUjugk0C9UaB8ztBZiW5TQZhw+uPZn9T/lJA==",
362 | "dev": true,
363 | "dependencies": {
364 | "@mischnic/json-sourcemap": "^0.1.0",
365 | "nullthrows": "^1.1.1"
366 | },
367 | "engines": {
368 | "node": ">= 12.0.0"
369 | },
370 | "funding": {
371 | "type": "opencollective",
372 | "url": "https://opencollective.com/parcel"
373 | }
374 | },
375 | "node_modules/@parcel/events": {
376 | "version": "2.12.0",
377 | "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.12.0.tgz",
378 | "integrity": "sha512-nmAAEIKLjW1kB2cUbCYSmZOGbnGj8wCzhqnK727zCCWaA25ogzAtt657GPOeFyqW77KyosU728Tl63Fc8hphIA==",
379 | "dev": true,
380 | "engines": {
381 | "node": ">= 12.0.0"
382 | },
383 | "funding": {
384 | "type": "opencollective",
385 | "url": "https://opencollective.com/parcel"
386 | }
387 | },
388 | "node_modules/@parcel/fs": {
389 | "version": "2.12.0",
390 | "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.12.0.tgz",
391 | "integrity": "sha512-NnFkuvou1YBtPOhTdZr44WN7I60cGyly2wpHzqRl62yhObyi1KvW0SjwOMa0QGNcBOIzp4G0CapoZ93hD0RG5Q==",
392 | "dev": true,
393 | "dependencies": {
394 | "@parcel/rust": "2.12.0",
395 | "@parcel/types": "2.12.0",
396 | "@parcel/utils": "2.12.0",
397 | "@parcel/watcher": "^2.0.7",
398 | "@parcel/workers": "2.12.0"
399 | },
400 | "engines": {
401 | "node": ">= 12.0.0"
402 | },
403 | "funding": {
404 | "type": "opencollective",
405 | "url": "https://opencollective.com/parcel"
406 | },
407 | "peerDependencies": {
408 | "@parcel/core": "^2.12.0"
409 | }
410 | },
411 | "node_modules/@parcel/graph": {
412 | "version": "3.2.0",
413 | "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.2.0.tgz",
414 | "integrity": "sha512-xlrmCPqy58D4Fg5umV7bpwDx5Vyt7MlnQPxW68vae5+BA4GSWetfZt+Cs5dtotMG2oCHzZxhIPt7YZ7NRyQzLA==",
415 | "dev": true,
416 | "dependencies": {
417 | "nullthrows": "^1.1.1"
418 | },
419 | "engines": {
420 | "node": ">= 12.0.0"
421 | },
422 | "funding": {
423 | "type": "opencollective",
424 | "url": "https://opencollective.com/parcel"
425 | }
426 | },
427 | "node_modules/@parcel/logger": {
428 | "version": "2.12.0",
429 | "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.12.0.tgz",
430 | "integrity": "sha512-cJ7Paqa7/9VJ7C+KwgJlwMqTQBOjjn71FbKk0G07hydUEBISU2aDfmc/52o60ErL9l+vXB26zTrIBanbxS8rVg==",
431 | "dev": true,
432 | "dependencies": {
433 | "@parcel/diagnostic": "2.12.0",
434 | "@parcel/events": "2.12.0"
435 | },
436 | "engines": {
437 | "node": ">= 12.0.0"
438 | },
439 | "funding": {
440 | "type": "opencollective",
441 | "url": "https://opencollective.com/parcel"
442 | }
443 | },
444 | "node_modules/@parcel/markdown-ansi": {
445 | "version": "2.12.0",
446 | "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.12.0.tgz",
447 | "integrity": "sha512-WZz3rzL8k0H3WR4qTHX6Ic8DlEs17keO9gtD4MNGyMNQbqQEvQ61lWJaIH0nAtgEetu0SOITiVqdZrb8zx/M7w==",
448 | "dev": true,
449 | "dependencies": {
450 | "chalk": "^4.1.0"
451 | },
452 | "engines": {
453 | "node": ">= 12.0.0"
454 | },
455 | "funding": {
456 | "type": "opencollective",
457 | "url": "https://opencollective.com/parcel"
458 | }
459 | },
460 | "node_modules/@parcel/namer-default": {
461 | "version": "2.12.0",
462 | "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.12.0.tgz",
463 | "integrity": "sha512-9DNKPDHWgMnMtqqZIMiEj/R9PNWW16lpnlHjwK3ciRlMPgjPJ8+UNc255teZODhX0T17GOzPdGbU/O/xbxVPzA==",
464 | "dev": true,
465 | "dependencies": {
466 | "@parcel/diagnostic": "2.12.0",
467 | "@parcel/plugin": "2.12.0",
468 | "nullthrows": "^1.1.1"
469 | },
470 | "engines": {
471 | "node": ">= 12.0.0",
472 | "parcel": "^2.12.0"
473 | },
474 | "funding": {
475 | "type": "opencollective",
476 | "url": "https://opencollective.com/parcel"
477 | }
478 | },
479 | "node_modules/@parcel/node-resolver-core": {
480 | "version": "3.3.0",
481 | "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.3.0.tgz",
482 | "integrity": "sha512-rhPW9DYPEIqQBSlYzz3S0AjXxjN6Ub2yS6tzzsW/4S3Gpsgk/uEq4ZfxPvoPf/6TgZndVxmKwpmxaKtGMmf3cA==",
483 | "dev": true,
484 | "dependencies": {
485 | "@mischnic/json-sourcemap": "^0.1.0",
486 | "@parcel/diagnostic": "2.12.0",
487 | "@parcel/fs": "2.12.0",
488 | "@parcel/rust": "2.12.0",
489 | "@parcel/utils": "2.12.0",
490 | "nullthrows": "^1.1.1",
491 | "semver": "^7.5.2"
492 | },
493 | "engines": {
494 | "node": ">= 12.0.0"
495 | },
496 | "funding": {
497 | "type": "opencollective",
498 | "url": "https://opencollective.com/parcel"
499 | }
500 | },
501 | "node_modules/@parcel/optimizer-css": {
502 | "version": "2.12.0",
503 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.12.0.tgz",
504 | "integrity": "sha512-ifbcC97fRzpruTjaa8axIFeX4MjjSIlQfem3EJug3L2AVqQUXnM1XO8L0NaXGNLTW2qnh1ZjIJ7vXT/QhsphsA==",
505 | "dev": true,
506 | "dependencies": {
507 | "@parcel/diagnostic": "2.12.0",
508 | "@parcel/plugin": "2.12.0",
509 | "@parcel/source-map": "^2.1.1",
510 | "@parcel/utils": "2.12.0",
511 | "browserslist": "^4.6.6",
512 | "lightningcss": "^1.22.1",
513 | "nullthrows": "^1.1.1"
514 | },
515 | "engines": {
516 | "node": ">= 12.0.0",
517 | "parcel": "^2.12.0"
518 | },
519 | "funding": {
520 | "type": "opencollective",
521 | "url": "https://opencollective.com/parcel"
522 | }
523 | },
524 | "node_modules/@parcel/optimizer-htmlnano": {
525 | "version": "2.12.0",
526 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.12.0.tgz",
527 | "integrity": "sha512-MfPMeCrT8FYiOrpFHVR+NcZQlXAptK2r4nGJjfT+ndPBhEEZp4yyL7n1y7HfX9geg5altc4WTb4Gug7rCoW8VQ==",
528 | "dev": true,
529 | "dependencies": {
530 | "@parcel/plugin": "2.12.0",
531 | "htmlnano": "^2.0.0",
532 | "nullthrows": "^1.1.1",
533 | "posthtml": "^0.16.5",
534 | "svgo": "^2.4.0"
535 | },
536 | "engines": {
537 | "node": ">= 12.0.0",
538 | "parcel": "^2.12.0"
539 | },
540 | "funding": {
541 | "type": "opencollective",
542 | "url": "https://opencollective.com/parcel"
543 | }
544 | },
545 | "node_modules/@parcel/optimizer-htmlnano/node_modules/css-select": {
546 | "version": "4.3.0",
547 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
548 | "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
549 | "dev": true,
550 | "dependencies": {
551 | "boolbase": "^1.0.0",
552 | "css-what": "^6.0.1",
553 | "domhandler": "^4.3.1",
554 | "domutils": "^2.8.0",
555 | "nth-check": "^2.0.1"
556 | },
557 | "funding": {
558 | "url": "https://github.com/sponsors/fb55"
559 | }
560 | },
561 | "node_modules/@parcel/optimizer-htmlnano/node_modules/css-tree": {
562 | "version": "1.1.3",
563 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
564 | "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
565 | "dev": true,
566 | "dependencies": {
567 | "mdn-data": "2.0.14",
568 | "source-map": "^0.6.1"
569 | },
570 | "engines": {
571 | "node": ">=8.0.0"
572 | }
573 | },
574 | "node_modules/@parcel/optimizer-htmlnano/node_modules/csso": {
575 | "version": "4.2.0",
576 | "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
577 | "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
578 | "dev": true,
579 | "dependencies": {
580 | "css-tree": "^1.1.2"
581 | },
582 | "engines": {
583 | "node": ">=8.0.0"
584 | }
585 | },
586 | "node_modules/@parcel/optimizer-htmlnano/node_modules/mdn-data": {
587 | "version": "2.0.14",
588 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
589 | "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
590 | "dev": true
591 | },
592 | "node_modules/@parcel/optimizer-htmlnano/node_modules/svgo": {
593 | "version": "2.8.0",
594 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
595 | "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
596 | "dev": true,
597 | "dependencies": {
598 | "@trysound/sax": "0.2.0",
599 | "commander": "^7.2.0",
600 | "css-select": "^4.1.3",
601 | "css-tree": "^1.1.3",
602 | "csso": "^4.2.0",
603 | "picocolors": "^1.0.0",
604 | "stable": "^0.1.8"
605 | },
606 | "bin": {
607 | "svgo": "bin/svgo"
608 | },
609 | "engines": {
610 | "node": ">=10.13.0"
611 | }
612 | },
613 | "node_modules/@parcel/optimizer-image": {
614 | "version": "2.12.0",
615 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.12.0.tgz",
616 | "integrity": "sha512-bo1O7raeAIbRU5nmNVtx8divLW9Xqn0c57GVNGeAK4mygnQoqHqRZ0mR9uboh64pxv6ijXZHPhKvU9HEpjPjBQ==",
617 | "dev": true,
618 | "dependencies": {
619 | "@parcel/diagnostic": "2.12.0",
620 | "@parcel/plugin": "2.12.0",
621 | "@parcel/rust": "2.12.0",
622 | "@parcel/utils": "2.12.0",
623 | "@parcel/workers": "2.12.0"
624 | },
625 | "engines": {
626 | "node": ">= 12.0.0",
627 | "parcel": "^2.12.0"
628 | },
629 | "funding": {
630 | "type": "opencollective",
631 | "url": "https://opencollective.com/parcel"
632 | },
633 | "peerDependencies": {
634 | "@parcel/core": "^2.12.0"
635 | }
636 | },
637 | "node_modules/@parcel/optimizer-svgo": {
638 | "version": "2.12.0",
639 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.12.0.tgz",
640 | "integrity": "sha512-Kyli+ZZXnoonnbeRQdoWwee9Bk2jm/49xvnfb+2OO8NN0d41lblBoRhOyFiScRnJrw7eVl1Xrz7NTkXCIO7XFQ==",
641 | "dev": true,
642 | "dependencies": {
643 | "@parcel/diagnostic": "2.12.0",
644 | "@parcel/plugin": "2.12.0",
645 | "@parcel/utils": "2.12.0",
646 | "svgo": "^2.4.0"
647 | },
648 | "engines": {
649 | "node": ">= 12.0.0",
650 | "parcel": "^2.12.0"
651 | },
652 | "funding": {
653 | "type": "opencollective",
654 | "url": "https://opencollective.com/parcel"
655 | }
656 | },
657 | "node_modules/@parcel/optimizer-svgo/node_modules/css-select": {
658 | "version": "4.3.0",
659 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
660 | "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
661 | "dev": true,
662 | "dependencies": {
663 | "boolbase": "^1.0.0",
664 | "css-what": "^6.0.1",
665 | "domhandler": "^4.3.1",
666 | "domutils": "^2.8.0",
667 | "nth-check": "^2.0.1"
668 | },
669 | "funding": {
670 | "url": "https://github.com/sponsors/fb55"
671 | }
672 | },
673 | "node_modules/@parcel/optimizer-svgo/node_modules/css-tree": {
674 | "version": "1.1.3",
675 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
676 | "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
677 | "dev": true,
678 | "dependencies": {
679 | "mdn-data": "2.0.14",
680 | "source-map": "^0.6.1"
681 | },
682 | "engines": {
683 | "node": ">=8.0.0"
684 | }
685 | },
686 | "node_modules/@parcel/optimizer-svgo/node_modules/csso": {
687 | "version": "4.2.0",
688 | "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
689 | "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
690 | "dev": true,
691 | "dependencies": {
692 | "css-tree": "^1.1.2"
693 | },
694 | "engines": {
695 | "node": ">=8.0.0"
696 | }
697 | },
698 | "node_modules/@parcel/optimizer-svgo/node_modules/mdn-data": {
699 | "version": "2.0.14",
700 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
701 | "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
702 | "dev": true
703 | },
704 | "node_modules/@parcel/optimizer-svgo/node_modules/svgo": {
705 | "version": "2.8.0",
706 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
707 | "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
708 | "dev": true,
709 | "dependencies": {
710 | "@trysound/sax": "0.2.0",
711 | "commander": "^7.2.0",
712 | "css-select": "^4.1.3",
713 | "css-tree": "^1.1.3",
714 | "csso": "^4.2.0",
715 | "picocolors": "^1.0.0",
716 | "stable": "^0.1.8"
717 | },
718 | "bin": {
719 | "svgo": "bin/svgo"
720 | },
721 | "engines": {
722 | "node": ">=10.13.0"
723 | }
724 | },
725 | "node_modules/@parcel/optimizer-swc": {
726 | "version": "2.12.0",
727 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.12.0.tgz",
728 | "integrity": "sha512-iBi6LZB3lm6WmbXfzi8J3DCVPmn4FN2lw7DGXxUXu7MouDPVWfTsM6U/5TkSHJRNRogZ2gqy5q9g34NPxHbJcw==",
729 | "dev": true,
730 | "dependencies": {
731 | "@parcel/diagnostic": "2.12.0",
732 | "@parcel/plugin": "2.12.0",
733 | "@parcel/source-map": "^2.1.1",
734 | "@parcel/utils": "2.12.0",
735 | "@swc/core": "^1.3.36",
736 | "nullthrows": "^1.1.1"
737 | },
738 | "engines": {
739 | "node": ">= 12.0.0",
740 | "parcel": "^2.12.0"
741 | },
742 | "funding": {
743 | "type": "opencollective",
744 | "url": "https://opencollective.com/parcel"
745 | }
746 | },
747 | "node_modules/@parcel/package-manager": {
748 | "version": "2.12.0",
749 | "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.12.0.tgz",
750 | "integrity": "sha512-0nvAezcjPx9FT+hIL+LS1jb0aohwLZXct7jAh7i0MLMtehOi0z1Sau+QpgMlA9rfEZZ1LIeFdnZZwqSy7Ccspw==",
751 | "dev": true,
752 | "dependencies": {
753 | "@parcel/diagnostic": "2.12.0",
754 | "@parcel/fs": "2.12.0",
755 | "@parcel/logger": "2.12.0",
756 | "@parcel/node-resolver-core": "3.3.0",
757 | "@parcel/types": "2.12.0",
758 | "@parcel/utils": "2.12.0",
759 | "@parcel/workers": "2.12.0",
760 | "@swc/core": "^1.3.36",
761 | "semver": "^7.5.2"
762 | },
763 | "engines": {
764 | "node": ">= 12.0.0"
765 | },
766 | "funding": {
767 | "type": "opencollective",
768 | "url": "https://opencollective.com/parcel"
769 | },
770 | "peerDependencies": {
771 | "@parcel/core": "^2.12.0"
772 | }
773 | },
774 | "node_modules/@parcel/packager-css": {
775 | "version": "2.12.0",
776 | "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.12.0.tgz",
777 | "integrity": "sha512-j3a/ODciaNKD19IYdWJT+TP+tnhhn5koBGBWWtrKSu0UxWpnezIGZetit3eE+Y9+NTePalMkvpIlit2eDhvfJA==",
778 | "dev": true,
779 | "dependencies": {
780 | "@parcel/diagnostic": "2.12.0",
781 | "@parcel/plugin": "2.12.0",
782 | "@parcel/source-map": "^2.1.1",
783 | "@parcel/utils": "2.12.0",
784 | "lightningcss": "^1.22.1",
785 | "nullthrows": "^1.1.1"
786 | },
787 | "engines": {
788 | "node": ">= 12.0.0",
789 | "parcel": "^2.12.0"
790 | },
791 | "funding": {
792 | "type": "opencollective",
793 | "url": "https://opencollective.com/parcel"
794 | }
795 | },
796 | "node_modules/@parcel/packager-html": {
797 | "version": "2.12.0",
798 | "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.12.0.tgz",
799 | "integrity": "sha512-PpvGB9hFFe+19NXGz2ApvPrkA9GwEqaDAninT+3pJD57OVBaxB8U+HN4a5LICKxjUppPPqmrLb6YPbD65IX4RA==",
800 | "dev": true,
801 | "dependencies": {
802 | "@parcel/plugin": "2.12.0",
803 | "@parcel/types": "2.12.0",
804 | "@parcel/utils": "2.12.0",
805 | "nullthrows": "^1.1.1",
806 | "posthtml": "^0.16.5"
807 | },
808 | "engines": {
809 | "node": ">= 12.0.0",
810 | "parcel": "^2.12.0"
811 | },
812 | "funding": {
813 | "type": "opencollective",
814 | "url": "https://opencollective.com/parcel"
815 | }
816 | },
817 | "node_modules/@parcel/packager-js": {
818 | "version": "2.12.0",
819 | "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.12.0.tgz",
820 | "integrity": "sha512-viMF+FszITRRr8+2iJyk+4ruGiL27Y6AF7hQ3xbJfzqnmbOhGFtLTQwuwhOLqN/mWR2VKdgbLpZSarWaO3yAMg==",
821 | "dev": true,
822 | "dependencies": {
823 | "@parcel/diagnostic": "2.12.0",
824 | "@parcel/plugin": "2.12.0",
825 | "@parcel/rust": "2.12.0",
826 | "@parcel/source-map": "^2.1.1",
827 | "@parcel/types": "2.12.0",
828 | "@parcel/utils": "2.12.0",
829 | "globals": "^13.2.0",
830 | "nullthrows": "^1.1.1"
831 | },
832 | "engines": {
833 | "node": ">= 12.0.0",
834 | "parcel": "^2.12.0"
835 | },
836 | "funding": {
837 | "type": "opencollective",
838 | "url": "https://opencollective.com/parcel"
839 | }
840 | },
841 | "node_modules/@parcel/packager-raw": {
842 | "version": "2.12.0",
843 | "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.12.0.tgz",
844 | "integrity": "sha512-tJZqFbHqP24aq1F+OojFbQIc09P/u8HAW5xfndCrFnXpW4wTgM3p03P0xfw3gnNq+TtxHJ8c3UFE5LnXNNKhYA==",
845 | "dev": true,
846 | "dependencies": {
847 | "@parcel/plugin": "2.12.0"
848 | },
849 | "engines": {
850 | "node": ">= 12.0.0",
851 | "parcel": "^2.12.0"
852 | },
853 | "funding": {
854 | "type": "opencollective",
855 | "url": "https://opencollective.com/parcel"
856 | }
857 | },
858 | "node_modules/@parcel/packager-svg": {
859 | "version": "2.12.0",
860 | "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.12.0.tgz",
861 | "integrity": "sha512-ldaGiacGb2lLqcXas97k8JiZRbAnNREmcvoY2W2dvW4loVuDT9B9fU777mbV6zODpcgcHWsLL3lYbJ5Lt3y9cg==",
862 | "dev": true,
863 | "dependencies": {
864 | "@parcel/plugin": "2.12.0",
865 | "@parcel/types": "2.12.0",
866 | "@parcel/utils": "2.12.0",
867 | "posthtml": "^0.16.4"
868 | },
869 | "engines": {
870 | "node": ">= 12.0.0",
871 | "parcel": "^2.12.0"
872 | },
873 | "funding": {
874 | "type": "opencollective",
875 | "url": "https://opencollective.com/parcel"
876 | }
877 | },
878 | "node_modules/@parcel/packager-wasm": {
879 | "version": "2.12.0",
880 | "resolved": "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.12.0.tgz",
881 | "integrity": "sha512-fYqZzIqO9fGYveeImzF8ll6KRo2LrOXfD+2Y5U3BiX/wp9wv17dz50QLDQm9hmTcKGWxK4yWqKQh+Evp/fae7A==",
882 | "dev": true,
883 | "dependencies": {
884 | "@parcel/plugin": "2.12.0"
885 | },
886 | "engines": {
887 | "node": ">=12.0.0",
888 | "parcel": "^2.12.0"
889 | },
890 | "funding": {
891 | "type": "opencollective",
892 | "url": "https://opencollective.com/parcel"
893 | }
894 | },
895 | "node_modules/@parcel/plugin": {
896 | "version": "2.12.0",
897 | "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.12.0.tgz",
898 | "integrity": "sha512-nc/uRA8DiMoe4neBbzV6kDndh/58a4wQuGKw5oEoIwBCHUvE2W8ZFSu7ollSXUGRzfacTt4NdY8TwS73ScWZ+g==",
899 | "dev": true,
900 | "dependencies": {
901 | "@parcel/types": "2.12.0"
902 | },
903 | "engines": {
904 | "node": ">= 12.0.0"
905 | },
906 | "funding": {
907 | "type": "opencollective",
908 | "url": "https://opencollective.com/parcel"
909 | }
910 | },
911 | "node_modules/@parcel/profiler": {
912 | "version": "2.12.0",
913 | "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.12.0.tgz",
914 | "integrity": "sha512-q53fvl5LDcFYzMUtSusUBZSjQrKjMlLEBgKeQHFwkimwR1mgoseaDBDuNz0XvmzDzF1UelJ02TUKCGacU8W2qA==",
915 | "dev": true,
916 | "dependencies": {
917 | "@parcel/diagnostic": "2.12.0",
918 | "@parcel/events": "2.12.0",
919 | "chrome-trace-event": "^1.0.2"
920 | },
921 | "engines": {
922 | "node": ">= 12.0.0"
923 | },
924 | "funding": {
925 | "type": "opencollective",
926 | "url": "https://opencollective.com/parcel"
927 | }
928 | },
929 | "node_modules/@parcel/reporter-cli": {
930 | "version": "2.12.0",
931 | "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.12.0.tgz",
932 | "integrity": "sha512-TqKsH4GVOLPSCanZ6tcTPj+rdVHERnt5y4bwTM82cajM21bCX1Ruwp8xOKU+03091oV2pv5ieB18pJyRF7IpIw==",
933 | "dev": true,
934 | "dependencies": {
935 | "@parcel/plugin": "2.12.0",
936 | "@parcel/types": "2.12.0",
937 | "@parcel/utils": "2.12.0",
938 | "chalk": "^4.1.0",
939 | "term-size": "^2.2.1"
940 | },
941 | "engines": {
942 | "node": ">= 12.0.0",
943 | "parcel": "^2.12.0"
944 | },
945 | "funding": {
946 | "type": "opencollective",
947 | "url": "https://opencollective.com/parcel"
948 | }
949 | },
950 | "node_modules/@parcel/reporter-dev-server": {
951 | "version": "2.12.0",
952 | "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.12.0.tgz",
953 | "integrity": "sha512-tIcDqRvAPAttRlTV28dHcbWT5K2r/MBFks7nM4nrEDHWtnrCwimkDmZTc1kD8QOCCjGVwRHcQybpHvxfwol6GA==",
954 | "dev": true,
955 | "dependencies": {
956 | "@parcel/plugin": "2.12.0",
957 | "@parcel/utils": "2.12.0"
958 | },
959 | "engines": {
960 | "node": ">= 12.0.0",
961 | "parcel": "^2.12.0"
962 | },
963 | "funding": {
964 | "type": "opencollective",
965 | "url": "https://opencollective.com/parcel"
966 | }
967 | },
968 | "node_modules/@parcel/reporter-tracer": {
969 | "version": "2.12.0",
970 | "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.12.0.tgz",
971 | "integrity": "sha512-g8rlu9GxB8Ut/F8WGx4zidIPQ4pcYFjU9bZO+fyRIPrSUFH2bKijCnbZcr4ntqzDGx74hwD6cCG4DBoleq2UlQ==",
972 | "dev": true,
973 | "dependencies": {
974 | "@parcel/plugin": "2.12.0",
975 | "@parcel/utils": "2.12.0",
976 | "chrome-trace-event": "^1.0.3",
977 | "nullthrows": "^1.1.1"
978 | },
979 | "engines": {
980 | "node": ">= 12.0.0",
981 | "parcel": "^2.12.0"
982 | },
983 | "funding": {
984 | "type": "opencollective",
985 | "url": "https://opencollective.com/parcel"
986 | }
987 | },
988 | "node_modules/@parcel/resolver-default": {
989 | "version": "2.12.0",
990 | "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.12.0.tgz",
991 | "integrity": "sha512-uuhbajTax37TwCxu7V98JtRLiT6hzE4VYSu5B7Qkauy14/WFt2dz6GOUXPgVsED569/hkxebPx3KCMtZW6cHHA==",
992 | "dev": true,
993 | "dependencies": {
994 | "@parcel/node-resolver-core": "3.3.0",
995 | "@parcel/plugin": "2.12.0"
996 | },
997 | "engines": {
998 | "node": ">= 12.0.0",
999 | "parcel": "^2.12.0"
1000 | },
1001 | "funding": {
1002 | "type": "opencollective",
1003 | "url": "https://opencollective.com/parcel"
1004 | }
1005 | },
1006 | "node_modules/@parcel/runtime-browser-hmr": {
1007 | "version": "2.12.0",
1008 | "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.12.0.tgz",
1009 | "integrity": "sha512-4ZLp2FWyD32r0GlTulO3+jxgsA3oO1P1b5oO2IWuWilfhcJH5LTiazpL5YdusUjtNn9PGN6QLAWfxmzRIfM+Ow==",
1010 | "dev": true,
1011 | "dependencies": {
1012 | "@parcel/plugin": "2.12.0",
1013 | "@parcel/utils": "2.12.0"
1014 | },
1015 | "engines": {
1016 | "node": ">= 12.0.0",
1017 | "parcel": "^2.12.0"
1018 | },
1019 | "funding": {
1020 | "type": "opencollective",
1021 | "url": "https://opencollective.com/parcel"
1022 | }
1023 | },
1024 | "node_modules/@parcel/runtime-js": {
1025 | "version": "2.12.0",
1026 | "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.12.0.tgz",
1027 | "integrity": "sha512-sBerP32Z1crX5PfLNGDSXSdqzlllM++GVnVQVeM7DgMKS8JIFG3VLi28YkX+dYYGtPypm01JoIHCkvwiZEcQJg==",
1028 | "dev": true,
1029 | "dependencies": {
1030 | "@parcel/diagnostic": "2.12.0",
1031 | "@parcel/plugin": "2.12.0",
1032 | "@parcel/utils": "2.12.0",
1033 | "nullthrows": "^1.1.1"
1034 | },
1035 | "engines": {
1036 | "node": ">= 12.0.0",
1037 | "parcel": "^2.12.0"
1038 | },
1039 | "funding": {
1040 | "type": "opencollective",
1041 | "url": "https://opencollective.com/parcel"
1042 | }
1043 | },
1044 | "node_modules/@parcel/runtime-react-refresh": {
1045 | "version": "2.12.0",
1046 | "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.12.0.tgz",
1047 | "integrity": "sha512-SCHkcczJIDFTFdLTzrHTkQ0aTrX3xH6jrA4UsCBL6ji61+w+ohy4jEEe9qCgJVXhnJfGLE43HNXek+0MStX+Mw==",
1048 | "dev": true,
1049 | "dependencies": {
1050 | "@parcel/plugin": "2.12.0",
1051 | "@parcel/utils": "2.12.0",
1052 | "react-error-overlay": "6.0.9",
1053 | "react-refresh": "^0.9.0"
1054 | },
1055 | "engines": {
1056 | "node": ">= 12.0.0",
1057 | "parcel": "^2.12.0"
1058 | },
1059 | "funding": {
1060 | "type": "opencollective",
1061 | "url": "https://opencollective.com/parcel"
1062 | }
1063 | },
1064 | "node_modules/@parcel/runtime-service-worker": {
1065 | "version": "2.12.0",
1066 | "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.12.0.tgz",
1067 | "integrity": "sha512-BXuMBsfiwpIEnssn+jqfC3jkgbS8oxeo3C7xhSQsuSv+AF2FwY3O3AO1c1RBskEW3XrBLNINOJujroNw80VTKA==",
1068 | "dev": true,
1069 | "dependencies": {
1070 | "@parcel/plugin": "2.12.0",
1071 | "@parcel/utils": "2.12.0",
1072 | "nullthrows": "^1.1.1"
1073 | },
1074 | "engines": {
1075 | "node": ">= 12.0.0",
1076 | "parcel": "^2.12.0"
1077 | },
1078 | "funding": {
1079 | "type": "opencollective",
1080 | "url": "https://opencollective.com/parcel"
1081 | }
1082 | },
1083 | "node_modules/@parcel/rust": {
1084 | "version": "2.12.0",
1085 | "resolved": "https://registry.npmjs.org/@parcel/rust/-/rust-2.12.0.tgz",
1086 | "integrity": "sha512-005cldMdFZFDPOjbDVEXcINQ3wT4vrxvSavRWI3Az0e3E18exO/x/mW9f648KtXugOXMAqCEqhFHcXECL9nmMw==",
1087 | "dev": true,
1088 | "engines": {
1089 | "node": ">= 12.0.0"
1090 | },
1091 | "funding": {
1092 | "type": "opencollective",
1093 | "url": "https://opencollective.com/parcel"
1094 | }
1095 | },
1096 | "node_modules/@parcel/source-map": {
1097 | "version": "2.1.1",
1098 | "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz",
1099 | "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==",
1100 | "dev": true,
1101 | "dependencies": {
1102 | "detect-libc": "^1.0.3"
1103 | },
1104 | "engines": {
1105 | "node": "^12.18.3 || >=14"
1106 | }
1107 | },
1108 | "node_modules/@parcel/source-map/node_modules/detect-libc": {
1109 | "version": "1.0.3",
1110 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
1111 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
1112 | "dev": true,
1113 | "bin": {
1114 | "detect-libc": "bin/detect-libc.js"
1115 | },
1116 | "engines": {
1117 | "node": ">=0.10"
1118 | }
1119 | },
1120 | "node_modules/@parcel/transformer-babel": {
1121 | "version": "2.12.0",
1122 | "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.12.0.tgz",
1123 | "integrity": "sha512-zQaBfOnf/l8rPxYGnsk/ufh/0EuqvmnxafjBIpKZ//j6rGylw5JCqXSb1QvvAqRYruKeccxGv7+HrxpqKU6V4A==",
1124 | "dev": true,
1125 | "dependencies": {
1126 | "@parcel/diagnostic": "2.12.0",
1127 | "@parcel/plugin": "2.12.0",
1128 | "@parcel/source-map": "^2.1.1",
1129 | "@parcel/utils": "2.12.0",
1130 | "browserslist": "^4.6.6",
1131 | "json5": "^2.2.0",
1132 | "nullthrows": "^1.1.1",
1133 | "semver": "^7.5.2"
1134 | },
1135 | "engines": {
1136 | "node": ">= 12.0.0",
1137 | "parcel": "^2.12.0"
1138 | },
1139 | "funding": {
1140 | "type": "opencollective",
1141 | "url": "https://opencollective.com/parcel"
1142 | }
1143 | },
1144 | "node_modules/@parcel/transformer-css": {
1145 | "version": "2.12.0",
1146 | "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.12.0.tgz",
1147 | "integrity": "sha512-vXhOqoAlQGATYyQ433Z1DXKmiKmzOAUmKysbYH3FD+LKEKLMEl/pA14goqp00TW+A/EjtSKKyeMyHlMIIUqj4Q==",
1148 | "dev": true,
1149 | "dependencies": {
1150 | "@parcel/diagnostic": "2.12.0",
1151 | "@parcel/plugin": "2.12.0",
1152 | "@parcel/source-map": "^2.1.1",
1153 | "@parcel/utils": "2.12.0",
1154 | "browserslist": "^4.6.6",
1155 | "lightningcss": "^1.22.1",
1156 | "nullthrows": "^1.1.1"
1157 | },
1158 | "engines": {
1159 | "node": ">= 12.0.0",
1160 | "parcel": "^2.12.0"
1161 | },
1162 | "funding": {
1163 | "type": "opencollective",
1164 | "url": "https://opencollective.com/parcel"
1165 | }
1166 | },
1167 | "node_modules/@parcel/transformer-html": {
1168 | "version": "2.12.0",
1169 | "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.12.0.tgz",
1170 | "integrity": "sha512-5jW4dFFBlYBvIQk4nrH62rfA/G/KzVzEDa6S+Nne0xXhglLjkm64Ci9b/d4tKZfuGWUbpm2ASAq8skti/nfpXw==",
1171 | "dev": true,
1172 | "dependencies": {
1173 | "@parcel/diagnostic": "2.12.0",
1174 | "@parcel/plugin": "2.12.0",
1175 | "@parcel/rust": "2.12.0",
1176 | "nullthrows": "^1.1.1",
1177 | "posthtml": "^0.16.5",
1178 | "posthtml-parser": "^0.10.1",
1179 | "posthtml-render": "^3.0.0",
1180 | "semver": "^7.5.2",
1181 | "srcset": "4"
1182 | },
1183 | "engines": {
1184 | "node": ">= 12.0.0",
1185 | "parcel": "^2.12.0"
1186 | },
1187 | "funding": {
1188 | "type": "opencollective",
1189 | "url": "https://opencollective.com/parcel"
1190 | }
1191 | },
1192 | "node_modules/@parcel/transformer-html/node_modules/srcset": {
1193 | "version": "4.0.0",
1194 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz",
1195 | "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==",
1196 | "dev": true,
1197 | "engines": {
1198 | "node": ">=12"
1199 | },
1200 | "funding": {
1201 | "url": "https://github.com/sponsors/sindresorhus"
1202 | }
1203 | },
1204 | "node_modules/@parcel/transformer-image": {
1205 | "version": "2.12.0",
1206 | "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.12.0.tgz",
1207 | "integrity": "sha512-8hXrGm2IRII49R7lZ0RpmNk27EhcsH+uNKsvxuMpXPuEnWgC/ha/IrjaI29xCng1uGur74bJF43NUSQhR4aTdw==",
1208 | "dev": true,
1209 | "dependencies": {
1210 | "@parcel/plugin": "2.12.0",
1211 | "@parcel/utils": "2.12.0",
1212 | "@parcel/workers": "2.12.0",
1213 | "nullthrows": "^1.1.1"
1214 | },
1215 | "engines": {
1216 | "node": ">= 12.0.0",
1217 | "parcel": "^2.12.0"
1218 | },
1219 | "peerDependencies": {
1220 | "@parcel/core": "^2.12.0"
1221 | }
1222 | },
1223 | "node_modules/@parcel/transformer-js": {
1224 | "version": "2.12.0",
1225 | "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.12.0.tgz",
1226 | "integrity": "sha512-OSZpOu+FGDbC/xivu24v092D9w6EGytB3vidwbdiJ2FaPgfV7rxS0WIUjH4I0OcvHAcitArRXL0a3+HrNTdQQw==",
1227 | "dev": true,
1228 | "dependencies": {
1229 | "@parcel/diagnostic": "2.12.0",
1230 | "@parcel/plugin": "2.12.0",
1231 | "@parcel/rust": "2.12.0",
1232 | "@parcel/source-map": "^2.1.1",
1233 | "@parcel/utils": "2.12.0",
1234 | "@parcel/workers": "2.12.0",
1235 | "@swc/helpers": "^0.5.0",
1236 | "browserslist": "^4.6.6",
1237 | "nullthrows": "^1.1.1",
1238 | "regenerator-runtime": "^0.13.7",
1239 | "semver": "^7.5.2"
1240 | },
1241 | "engines": {
1242 | "node": ">= 12.0.0",
1243 | "parcel": "^2.12.0"
1244 | },
1245 | "funding": {
1246 | "type": "opencollective",
1247 | "url": "https://opencollective.com/parcel"
1248 | },
1249 | "peerDependencies": {
1250 | "@parcel/core": "^2.12.0"
1251 | }
1252 | },
1253 | "node_modules/@parcel/transformer-json": {
1254 | "version": "2.12.0",
1255 | "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.12.0.tgz",
1256 | "integrity": "sha512-Utv64GLRCQILK5r0KFs4o7I41ixMPllwOLOhkdjJKvf1hZmN6WqfOmB1YLbWS/y5Zb/iB52DU2pWZm96vLFQZQ==",
1257 | "dev": true,
1258 | "dependencies": {
1259 | "@parcel/plugin": "2.12.0",
1260 | "json5": "^2.2.0"
1261 | },
1262 | "engines": {
1263 | "node": ">= 12.0.0",
1264 | "parcel": "^2.12.0"
1265 | },
1266 | "funding": {
1267 | "type": "opencollective",
1268 | "url": "https://opencollective.com/parcel"
1269 | }
1270 | },
1271 | "node_modules/@parcel/transformer-postcss": {
1272 | "version": "2.12.0",
1273 | "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.12.0.tgz",
1274 | "integrity": "sha512-FZqn+oUtiLfPOn67EZxPpBkfdFiTnF4iwiXPqvst3XI8H+iC+yNgzmtJkunOOuylpYY6NOU5jT8d7saqWSDv2Q==",
1275 | "dev": true,
1276 | "dependencies": {
1277 | "@parcel/diagnostic": "2.12.0",
1278 | "@parcel/plugin": "2.12.0",
1279 | "@parcel/rust": "2.12.0",
1280 | "@parcel/utils": "2.12.0",
1281 | "clone": "^2.1.1",
1282 | "nullthrows": "^1.1.1",
1283 | "postcss-value-parser": "^4.2.0",
1284 | "semver": "^7.5.2"
1285 | },
1286 | "engines": {
1287 | "node": ">= 12.0.0",
1288 | "parcel": "^2.12.0"
1289 | },
1290 | "funding": {
1291 | "type": "opencollective",
1292 | "url": "https://opencollective.com/parcel"
1293 | }
1294 | },
1295 | "node_modules/@parcel/transformer-posthtml": {
1296 | "version": "2.12.0",
1297 | "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.12.0.tgz",
1298 | "integrity": "sha512-z6Z7rav/pcaWdeD+2sDUcd0mmNZRUvtHaUGa50Y2mr+poxrKilpsnFMSiWBT+oOqPt7j71jzDvrdnAF4XkCljg==",
1299 | "dev": true,
1300 | "dependencies": {
1301 | "@parcel/plugin": "2.12.0",
1302 | "@parcel/utils": "2.12.0",
1303 | "nullthrows": "^1.1.1",
1304 | "posthtml": "^0.16.5",
1305 | "posthtml-parser": "^0.10.1",
1306 | "posthtml-render": "^3.0.0",
1307 | "semver": "^7.5.2"
1308 | },
1309 | "engines": {
1310 | "node": ">= 12.0.0",
1311 | "parcel": "^2.12.0"
1312 | },
1313 | "funding": {
1314 | "type": "opencollective",
1315 | "url": "https://opencollective.com/parcel"
1316 | }
1317 | },
1318 | "node_modules/@parcel/transformer-raw": {
1319 | "version": "2.12.0",
1320 | "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.12.0.tgz",
1321 | "integrity": "sha512-Ht1fQvXxix0NncdnmnXZsa6hra20RXYh1VqhBYZLsDfkvGGFnXIgO03Jqn4Z8MkKoa0tiNbDhpKIeTjyclbBxQ==",
1322 | "dev": true,
1323 | "dependencies": {
1324 | "@parcel/plugin": "2.12.0"
1325 | },
1326 | "engines": {
1327 | "node": ">= 12.0.0",
1328 | "parcel": "^2.12.0"
1329 | },
1330 | "funding": {
1331 | "type": "opencollective",
1332 | "url": "https://opencollective.com/parcel"
1333 | }
1334 | },
1335 | "node_modules/@parcel/transformer-react-refresh-wrap": {
1336 | "version": "2.12.0",
1337 | "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.12.0.tgz",
1338 | "integrity": "sha512-GE8gmP2AZtkpBIV5vSCVhewgOFRhqwdM5Q9jNPOY5PKcM3/Ff0qCqDiTzzGLhk0/VMBrdjssrfZkVx6S/lHdJw==",
1339 | "dev": true,
1340 | "dependencies": {
1341 | "@parcel/plugin": "2.12.0",
1342 | "@parcel/utils": "2.12.0",
1343 | "react-refresh": "^0.9.0"
1344 | },
1345 | "engines": {
1346 | "node": ">= 12.0.0",
1347 | "parcel": "^2.12.0"
1348 | },
1349 | "funding": {
1350 | "type": "opencollective",
1351 | "url": "https://opencollective.com/parcel"
1352 | }
1353 | },
1354 | "node_modules/@parcel/transformer-svg": {
1355 | "version": "2.12.0",
1356 | "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.12.0.tgz",
1357 | "integrity": "sha512-cZJqGRJ4JNdYcb+vj94J7PdOuTnwyy45dM9xqbIMH+HSiiIkfrMsdEwYft0GTyFTdsnf+hdHn3tau7Qa5hhX+A==",
1358 | "dev": true,
1359 | "dependencies": {
1360 | "@parcel/diagnostic": "2.12.0",
1361 | "@parcel/plugin": "2.12.0",
1362 | "@parcel/rust": "2.12.0",
1363 | "nullthrows": "^1.1.1",
1364 | "posthtml": "^0.16.5",
1365 | "posthtml-parser": "^0.10.1",
1366 | "posthtml-render": "^3.0.0",
1367 | "semver": "^7.5.2"
1368 | },
1369 | "engines": {
1370 | "node": ">= 12.0.0",
1371 | "parcel": "^2.12.0"
1372 | },
1373 | "funding": {
1374 | "type": "opencollective",
1375 | "url": "https://opencollective.com/parcel"
1376 | }
1377 | },
1378 | "node_modules/@parcel/types": {
1379 | "version": "2.12.0",
1380 | "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.12.0.tgz",
1381 | "integrity": "sha512-8zAFiYNCwNTQcglIObyNwKfRYQK5ELlL13GuBOrSMxueUiI5ylgsGbTS1N7J3dAGZixHO8KhHGv5a71FILn9rQ==",
1382 | "dev": true,
1383 | "dependencies": {
1384 | "@parcel/cache": "2.12.0",
1385 | "@parcel/diagnostic": "2.12.0",
1386 | "@parcel/fs": "2.12.0",
1387 | "@parcel/package-manager": "2.12.0",
1388 | "@parcel/source-map": "^2.1.1",
1389 | "@parcel/workers": "2.12.0",
1390 | "utility-types": "^3.10.0"
1391 | }
1392 | },
1393 | "node_modules/@parcel/utils": {
1394 | "version": "2.12.0",
1395 | "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.12.0.tgz",
1396 | "integrity": "sha512-z1JhLuZ8QmDaYoEIuUCVZlhcFrS7LMfHrb2OCRui5SQFntRWBH2fNM6H/fXXUkT9SkxcuFP2DUA6/m4+Gkz72g==",
1397 | "dev": true,
1398 | "dependencies": {
1399 | "@parcel/codeframe": "2.12.0",
1400 | "@parcel/diagnostic": "2.12.0",
1401 | "@parcel/logger": "2.12.0",
1402 | "@parcel/markdown-ansi": "2.12.0",
1403 | "@parcel/rust": "2.12.0",
1404 | "@parcel/source-map": "^2.1.1",
1405 | "chalk": "^4.1.0",
1406 | "nullthrows": "^1.1.1"
1407 | },
1408 | "engines": {
1409 | "node": ">= 12.0.0"
1410 | },
1411 | "funding": {
1412 | "type": "opencollective",
1413 | "url": "https://opencollective.com/parcel"
1414 | }
1415 | },
1416 | "node_modules/@parcel/watcher": {
1417 | "version": "2.4.1",
1418 | "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz",
1419 | "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==",
1420 | "dev": true,
1421 | "dependencies": {
1422 | "detect-libc": "^1.0.3",
1423 | "is-glob": "^4.0.3",
1424 | "micromatch": "^4.0.5",
1425 | "node-addon-api": "^7.0.0"
1426 | },
1427 | "engines": {
1428 | "node": ">= 10.0.0"
1429 | },
1430 | "funding": {
1431 | "type": "opencollective",
1432 | "url": "https://opencollective.com/parcel"
1433 | },
1434 | "optionalDependencies": {
1435 | "@parcel/watcher-android-arm64": "2.4.1",
1436 | "@parcel/watcher-darwin-arm64": "2.4.1",
1437 | "@parcel/watcher-darwin-x64": "2.4.1",
1438 | "@parcel/watcher-freebsd-x64": "2.4.1",
1439 | "@parcel/watcher-linux-arm-glibc": "2.4.1",
1440 | "@parcel/watcher-linux-arm64-glibc": "2.4.1",
1441 | "@parcel/watcher-linux-arm64-musl": "2.4.1",
1442 | "@parcel/watcher-linux-x64-glibc": "2.4.1",
1443 | "@parcel/watcher-linux-x64-musl": "2.4.1",
1444 | "@parcel/watcher-win32-arm64": "2.4.1",
1445 | "@parcel/watcher-win32-ia32": "2.4.1",
1446 | "@parcel/watcher-win32-x64": "2.4.1"
1447 | }
1448 | },
1449 | "node_modules/@parcel/watcher-darwin-arm64": {
1450 | "version": "2.4.1",
1451 | "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz",
1452 | "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==",
1453 | "cpu": [
1454 | "arm64"
1455 | ],
1456 | "dev": true,
1457 | "optional": true,
1458 | "os": [
1459 | "darwin"
1460 | ],
1461 | "engines": {
1462 | "node": ">= 10.0.0"
1463 | },
1464 | "funding": {
1465 | "type": "opencollective",
1466 | "url": "https://opencollective.com/parcel"
1467 | }
1468 | },
1469 | "node_modules/@parcel/watcher/node_modules/detect-libc": {
1470 | "version": "1.0.3",
1471 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
1472 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
1473 | "dev": true,
1474 | "bin": {
1475 | "detect-libc": "bin/detect-libc.js"
1476 | },
1477 | "engines": {
1478 | "node": ">=0.10"
1479 | }
1480 | },
1481 | "node_modules/@parcel/workers": {
1482 | "version": "2.12.0",
1483 | "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.12.0.tgz",
1484 | "integrity": "sha512-zv5We5Jmb+ZWXlU6A+AufyjY4oZckkxsZ8J4dvyWL0W8IQvGO1JB4FGeryyttzQv3RM3OxcN/BpTGPiDG6keBw==",
1485 | "dev": true,
1486 | "dependencies": {
1487 | "@parcel/diagnostic": "2.12.0",
1488 | "@parcel/logger": "2.12.0",
1489 | "@parcel/profiler": "2.12.0",
1490 | "@parcel/types": "2.12.0",
1491 | "@parcel/utils": "2.12.0",
1492 | "nullthrows": "^1.1.1"
1493 | },
1494 | "engines": {
1495 | "node": ">= 12.0.0"
1496 | },
1497 | "funding": {
1498 | "type": "opencollective",
1499 | "url": "https://opencollective.com/parcel"
1500 | },
1501 | "peerDependencies": {
1502 | "@parcel/core": "^2.12.0"
1503 | }
1504 | },
1505 | "node_modules/@swc/core": {
1506 | "version": "1.6.5",
1507 | "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.6.5.tgz",
1508 | "integrity": "sha512-tyVvUK/HDOUUsK6/GmWvnqUtD9oDpPUA4f7f7JCOV8hXxtfjMtAZeBKf93yrB1XZet69TDR7EN0hFC6i4MF0Ig==",
1509 | "dev": true,
1510 | "hasInstallScript": true,
1511 | "dependencies": {
1512 | "@swc/counter": "^0.1.3",
1513 | "@swc/types": "^0.1.9"
1514 | },
1515 | "engines": {
1516 | "node": ">=10"
1517 | },
1518 | "funding": {
1519 | "type": "opencollective",
1520 | "url": "https://opencollective.com/swc"
1521 | },
1522 | "optionalDependencies": {
1523 | "@swc/core-darwin-arm64": "1.6.5",
1524 | "@swc/core-darwin-x64": "1.6.5",
1525 | "@swc/core-linux-arm-gnueabihf": "1.6.5",
1526 | "@swc/core-linux-arm64-gnu": "1.6.5",
1527 | "@swc/core-linux-arm64-musl": "1.6.5",
1528 | "@swc/core-linux-x64-gnu": "1.6.5",
1529 | "@swc/core-linux-x64-musl": "1.6.5",
1530 | "@swc/core-win32-arm64-msvc": "1.6.5",
1531 | "@swc/core-win32-ia32-msvc": "1.6.5",
1532 | "@swc/core-win32-x64-msvc": "1.6.5"
1533 | },
1534 | "peerDependencies": {
1535 | "@swc/helpers": "*"
1536 | },
1537 | "peerDependenciesMeta": {
1538 | "@swc/helpers": {
1539 | "optional": true
1540 | }
1541 | }
1542 | },
1543 | "node_modules/@swc/core-darwin-arm64": {
1544 | "version": "1.6.5",
1545 | "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.5.tgz",
1546 | "integrity": "sha512-RGQhMdni2v1/ANQ/2K+F+QYdzaucekYBewZcX1ogqJ8G5sbPaBdYdDN1qQ4kHLCIkPtGP6qC7c71qPEqL2RidQ==",
1547 | "cpu": [
1548 | "arm64"
1549 | ],
1550 | "dev": true,
1551 | "optional": true,
1552 | "os": [
1553 | "darwin"
1554 | ],
1555 | "engines": {
1556 | "node": ">=10"
1557 | }
1558 | },
1559 | "node_modules/@swc/counter": {
1560 | "version": "0.1.3",
1561 | "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
1562 | "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
1563 | "dev": true
1564 | },
1565 | "node_modules/@swc/helpers": {
1566 | "version": "0.5.11",
1567 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz",
1568 | "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==",
1569 | "dev": true,
1570 | "dependencies": {
1571 | "tslib": "^2.4.0"
1572 | }
1573 | },
1574 | "node_modules/@swc/types": {
1575 | "version": "0.1.9",
1576 | "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.9.tgz",
1577 | "integrity": "sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==",
1578 | "dev": true,
1579 | "dependencies": {
1580 | "@swc/counter": "^0.1.3"
1581 | }
1582 | },
1583 | "node_modules/@trysound/sax": {
1584 | "version": "0.2.0",
1585 | "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
1586 | "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
1587 | "dev": true,
1588 | "engines": {
1589 | "node": ">=10.13.0"
1590 | }
1591 | },
1592 | "node_modules/abortcontroller-polyfill": {
1593 | "version": "1.7.5",
1594 | "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz",
1595 | "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==",
1596 | "dev": true
1597 | },
1598 | "node_modules/ansi-styles": {
1599 | "version": "4.3.0",
1600 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
1601 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
1602 | "dev": true,
1603 | "dependencies": {
1604 | "color-convert": "^2.0.1"
1605 | },
1606 | "engines": {
1607 | "node": ">=8"
1608 | },
1609 | "funding": {
1610 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
1611 | }
1612 | },
1613 | "node_modules/argparse": {
1614 | "version": "2.0.1",
1615 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
1616 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
1617 | "dev": true
1618 | },
1619 | "node_modules/base-x": {
1620 | "version": "3.0.9",
1621 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
1622 | "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
1623 | "dev": true,
1624 | "dependencies": {
1625 | "safe-buffer": "^5.0.1"
1626 | }
1627 | },
1628 | "node_modules/base64-js": {
1629 | "version": "1.5.1",
1630 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
1631 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
1632 | "dev": true,
1633 | "funding": [
1634 | {
1635 | "type": "github",
1636 | "url": "https://github.com/sponsors/feross"
1637 | },
1638 | {
1639 | "type": "patreon",
1640 | "url": "https://www.patreon.com/feross"
1641 | },
1642 | {
1643 | "type": "consulting",
1644 | "url": "https://feross.org/support"
1645 | }
1646 | ]
1647 | },
1648 | "node_modules/boolbase": {
1649 | "version": "1.0.0",
1650 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
1651 | "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
1652 | "dev": true
1653 | },
1654 | "node_modules/braces": {
1655 | "version": "3.0.3",
1656 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
1657 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
1658 | "dev": true,
1659 | "dependencies": {
1660 | "fill-range": "^7.1.1"
1661 | },
1662 | "engines": {
1663 | "node": ">=8"
1664 | }
1665 | },
1666 | "node_modules/browserslist": {
1667 | "version": "4.23.1",
1668 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz",
1669 | "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==",
1670 | "dev": true,
1671 | "funding": [
1672 | {
1673 | "type": "opencollective",
1674 | "url": "https://opencollective.com/browserslist"
1675 | },
1676 | {
1677 | "type": "tidelift",
1678 | "url": "https://tidelift.com/funding/github/npm/browserslist"
1679 | },
1680 | {
1681 | "type": "github",
1682 | "url": "https://github.com/sponsors/ai"
1683 | }
1684 | ],
1685 | "dependencies": {
1686 | "caniuse-lite": "^1.0.30001629",
1687 | "electron-to-chromium": "^1.4.796",
1688 | "node-releases": "^2.0.14",
1689 | "update-browserslist-db": "^1.0.16"
1690 | },
1691 | "bin": {
1692 | "browserslist": "cli.js"
1693 | },
1694 | "engines": {
1695 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1696 | }
1697 | },
1698 | "node_modules/buffer": {
1699 | "version": "6.0.3",
1700 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
1701 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
1702 | "dev": true,
1703 | "funding": [
1704 | {
1705 | "type": "github",
1706 | "url": "https://github.com/sponsors/feross"
1707 | },
1708 | {
1709 | "type": "patreon",
1710 | "url": "https://www.patreon.com/feross"
1711 | },
1712 | {
1713 | "type": "consulting",
1714 | "url": "https://feross.org/support"
1715 | }
1716 | ],
1717 | "dependencies": {
1718 | "base64-js": "^1.3.1",
1719 | "ieee754": "^1.2.1"
1720 | }
1721 | },
1722 | "node_modules/callsites": {
1723 | "version": "3.1.0",
1724 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
1725 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
1726 | "dev": true,
1727 | "engines": {
1728 | "node": ">=6"
1729 | }
1730 | },
1731 | "node_modules/caniuse-lite": {
1732 | "version": "1.0.30001636",
1733 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz",
1734 | "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==",
1735 | "dev": true,
1736 | "funding": [
1737 | {
1738 | "type": "opencollective",
1739 | "url": "https://opencollective.com/browserslist"
1740 | },
1741 | {
1742 | "type": "tidelift",
1743 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1744 | },
1745 | {
1746 | "type": "github",
1747 | "url": "https://github.com/sponsors/ai"
1748 | }
1749 | ]
1750 | },
1751 | "node_modules/chalk": {
1752 | "version": "4.1.2",
1753 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
1754 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
1755 | "dev": true,
1756 | "dependencies": {
1757 | "ansi-styles": "^4.1.0",
1758 | "supports-color": "^7.1.0"
1759 | },
1760 | "engines": {
1761 | "node": ">=10"
1762 | },
1763 | "funding": {
1764 | "url": "https://github.com/chalk/chalk?sponsor=1"
1765 | }
1766 | },
1767 | "node_modules/chrome-trace-event": {
1768 | "version": "1.0.4",
1769 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
1770 | "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
1771 | "dev": true,
1772 | "engines": {
1773 | "node": ">=6.0"
1774 | }
1775 | },
1776 | "node_modules/clone": {
1777 | "version": "2.1.2",
1778 | "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
1779 | "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
1780 | "dev": true,
1781 | "engines": {
1782 | "node": ">=0.8"
1783 | }
1784 | },
1785 | "node_modules/color-convert": {
1786 | "version": "2.0.1",
1787 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1788 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1789 | "dev": true,
1790 | "dependencies": {
1791 | "color-name": "~1.1.4"
1792 | },
1793 | "engines": {
1794 | "node": ">=7.0.0"
1795 | }
1796 | },
1797 | "node_modules/color-name": {
1798 | "version": "1.1.4",
1799 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1800 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1801 | "dev": true
1802 | },
1803 | "node_modules/colyseus.js": {
1804 | "version": "0.16.3",
1805 | "resolved": "https://registry.npmjs.org/colyseus.js/-/colyseus.js-0.16.3.tgz",
1806 | "integrity": "sha512-JyBz5D6Pmk10ACvivUc/WyMePmnSrC5DpYYBvM8bl4xfB3BQL7H5l94EPHA1VTII7rsjhXxew4OvbVr1viSA7g==",
1807 | "license": "MIT",
1808 | "dependencies": {
1809 | "@colyseus/msgpackr": "^1.10.5",
1810 | "@colyseus/schema": "^3.0.0",
1811 | "httpie": "^2.0.0-next.13",
1812 | "tslib": "^2.1.0",
1813 | "ws": "^8.13.0"
1814 | },
1815 | "engines": {
1816 | "node": ">= 12.x"
1817 | },
1818 | "funding": {
1819 | "url": "https://github.com/sponsors/endel"
1820 | }
1821 | },
1822 | "node_modules/commander": {
1823 | "version": "7.2.0",
1824 | "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
1825 | "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
1826 | "dev": true,
1827 | "engines": {
1828 | "node": ">= 10"
1829 | }
1830 | },
1831 | "node_modules/cosmiconfig": {
1832 | "version": "9.0.0",
1833 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
1834 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
1835 | "dev": true,
1836 | "dependencies": {
1837 | "env-paths": "^2.2.1",
1838 | "import-fresh": "^3.3.0",
1839 | "js-yaml": "^4.1.0",
1840 | "parse-json": "^5.2.0"
1841 | },
1842 | "engines": {
1843 | "node": ">=14"
1844 | },
1845 | "funding": {
1846 | "url": "https://github.com/sponsors/d-fischer"
1847 | },
1848 | "peerDependencies": {
1849 | "typescript": ">=4.9.5"
1850 | },
1851 | "peerDependenciesMeta": {
1852 | "typescript": {
1853 | "optional": true
1854 | }
1855 | }
1856 | },
1857 | "node_modules/css-select": {
1858 | "version": "5.1.0",
1859 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
1860 | "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
1861 | "dev": true,
1862 | "optional": true,
1863 | "peer": true,
1864 | "dependencies": {
1865 | "boolbase": "^1.0.0",
1866 | "css-what": "^6.1.0",
1867 | "domhandler": "^5.0.2",
1868 | "domutils": "^3.0.1",
1869 | "nth-check": "^2.0.1"
1870 | },
1871 | "funding": {
1872 | "url": "https://github.com/sponsors/fb55"
1873 | }
1874 | },
1875 | "node_modules/css-select/node_modules/dom-serializer": {
1876 | "version": "2.0.0",
1877 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
1878 | "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
1879 | "dev": true,
1880 | "optional": true,
1881 | "peer": true,
1882 | "dependencies": {
1883 | "domelementtype": "^2.3.0",
1884 | "domhandler": "^5.0.2",
1885 | "entities": "^4.2.0"
1886 | },
1887 | "funding": {
1888 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
1889 | }
1890 | },
1891 | "node_modules/css-select/node_modules/domhandler": {
1892 | "version": "5.0.3",
1893 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
1894 | "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
1895 | "dev": true,
1896 | "optional": true,
1897 | "peer": true,
1898 | "dependencies": {
1899 | "domelementtype": "^2.3.0"
1900 | },
1901 | "engines": {
1902 | "node": ">= 4"
1903 | },
1904 | "funding": {
1905 | "url": "https://github.com/fb55/domhandler?sponsor=1"
1906 | }
1907 | },
1908 | "node_modules/css-select/node_modules/domutils": {
1909 | "version": "3.1.0",
1910 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
1911 | "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
1912 | "dev": true,
1913 | "optional": true,
1914 | "peer": true,
1915 | "dependencies": {
1916 | "dom-serializer": "^2.0.0",
1917 | "domelementtype": "^2.3.0",
1918 | "domhandler": "^5.0.3"
1919 | },
1920 | "funding": {
1921 | "url": "https://github.com/fb55/domutils?sponsor=1"
1922 | }
1923 | },
1924 | "node_modules/css-select/node_modules/entities": {
1925 | "version": "4.5.0",
1926 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
1927 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
1928 | "dev": true,
1929 | "optional": true,
1930 | "peer": true,
1931 | "engines": {
1932 | "node": ">=0.12"
1933 | },
1934 | "funding": {
1935 | "url": "https://github.com/fb55/entities?sponsor=1"
1936 | }
1937 | },
1938 | "node_modules/css-tree": {
1939 | "version": "2.3.1",
1940 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
1941 | "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
1942 | "dev": true,
1943 | "optional": true,
1944 | "peer": true,
1945 | "dependencies": {
1946 | "mdn-data": "2.0.30",
1947 | "source-map-js": "^1.0.1"
1948 | },
1949 | "engines": {
1950 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
1951 | }
1952 | },
1953 | "node_modules/css-what": {
1954 | "version": "6.1.0",
1955 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
1956 | "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
1957 | "dev": true,
1958 | "engines": {
1959 | "node": ">= 6"
1960 | },
1961 | "funding": {
1962 | "url": "https://github.com/sponsors/fb55"
1963 | }
1964 | },
1965 | "node_modules/csso": {
1966 | "version": "5.0.5",
1967 | "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
1968 | "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
1969 | "dev": true,
1970 | "optional": true,
1971 | "peer": true,
1972 | "dependencies": {
1973 | "css-tree": "~2.2.0"
1974 | },
1975 | "engines": {
1976 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
1977 | "npm": ">=7.0.0"
1978 | }
1979 | },
1980 | "node_modules/csso/node_modules/css-tree": {
1981 | "version": "2.2.1",
1982 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
1983 | "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
1984 | "dev": true,
1985 | "optional": true,
1986 | "peer": true,
1987 | "dependencies": {
1988 | "mdn-data": "2.0.28",
1989 | "source-map-js": "^1.0.1"
1990 | },
1991 | "engines": {
1992 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
1993 | "npm": ">=7.0.0"
1994 | }
1995 | },
1996 | "node_modules/csso/node_modules/mdn-data": {
1997 | "version": "2.0.28",
1998 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
1999 | "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
2000 | "dev": true,
2001 | "optional": true,
2002 | "peer": true
2003 | },
2004 | "node_modules/detect-libc": {
2005 | "version": "2.0.3",
2006 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
2007 | "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
2008 | "devOptional": true,
2009 | "engines": {
2010 | "node": ">=8"
2011 | }
2012 | },
2013 | "node_modules/dom-serializer": {
2014 | "version": "1.4.1",
2015 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
2016 | "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
2017 | "dev": true,
2018 | "dependencies": {
2019 | "domelementtype": "^2.0.1",
2020 | "domhandler": "^4.2.0",
2021 | "entities": "^2.0.0"
2022 | },
2023 | "funding": {
2024 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
2025 | }
2026 | },
2027 | "node_modules/dom-serializer/node_modules/entities": {
2028 | "version": "2.2.0",
2029 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
2030 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
2031 | "dev": true,
2032 | "funding": {
2033 | "url": "https://github.com/fb55/entities?sponsor=1"
2034 | }
2035 | },
2036 | "node_modules/domelementtype": {
2037 | "version": "2.3.0",
2038 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
2039 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
2040 | "dev": true,
2041 | "funding": [
2042 | {
2043 | "type": "github",
2044 | "url": "https://github.com/sponsors/fb55"
2045 | }
2046 | ]
2047 | },
2048 | "node_modules/domhandler": {
2049 | "version": "4.3.1",
2050 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
2051 | "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
2052 | "dev": true,
2053 | "dependencies": {
2054 | "domelementtype": "^2.2.0"
2055 | },
2056 | "engines": {
2057 | "node": ">= 4"
2058 | },
2059 | "funding": {
2060 | "url": "https://github.com/fb55/domhandler?sponsor=1"
2061 | }
2062 | },
2063 | "node_modules/domutils": {
2064 | "version": "2.8.0",
2065 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
2066 | "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
2067 | "dev": true,
2068 | "dependencies": {
2069 | "dom-serializer": "^1.0.1",
2070 | "domelementtype": "^2.2.0",
2071 | "domhandler": "^4.2.0"
2072 | },
2073 | "funding": {
2074 | "url": "https://github.com/fb55/domutils?sponsor=1"
2075 | }
2076 | },
2077 | "node_modules/dotenv": {
2078 | "version": "7.0.0",
2079 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz",
2080 | "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==",
2081 | "dev": true,
2082 | "engines": {
2083 | "node": ">=6"
2084 | }
2085 | },
2086 | "node_modules/dotenv-expand": {
2087 | "version": "5.1.0",
2088 | "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
2089 | "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
2090 | "dev": true
2091 | },
2092 | "node_modules/electron-to-chromium": {
2093 | "version": "1.4.812",
2094 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.812.tgz",
2095 | "integrity": "sha512-7L8fC2Ey/b6SePDFKR2zHAy4mbdp1/38Yk5TsARO66W3hC5KEaeKMMHoxwtuH+jcu2AYLSn9QX04i95t6Fl1Hg==",
2096 | "dev": true
2097 | },
2098 | "node_modules/entities": {
2099 | "version": "3.0.1",
2100 | "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
2101 | "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
2102 | "dev": true,
2103 | "engines": {
2104 | "node": ">=0.12"
2105 | },
2106 | "funding": {
2107 | "url": "https://github.com/fb55/entities?sponsor=1"
2108 | }
2109 | },
2110 | "node_modules/env-paths": {
2111 | "version": "2.2.1",
2112 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
2113 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
2114 | "dev": true,
2115 | "engines": {
2116 | "node": ">=6"
2117 | }
2118 | },
2119 | "node_modules/error-ex": {
2120 | "version": "1.3.2",
2121 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
2122 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
2123 | "dev": true,
2124 | "dependencies": {
2125 | "is-arrayish": "^0.2.1"
2126 | }
2127 | },
2128 | "node_modules/escalade": {
2129 | "version": "3.1.2",
2130 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
2131 | "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
2132 | "dev": true,
2133 | "engines": {
2134 | "node": ">=6"
2135 | }
2136 | },
2137 | "node_modules/escape-string-regexp": {
2138 | "version": "1.0.5",
2139 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
2140 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
2141 | "dev": true,
2142 | "engines": {
2143 | "node": ">=0.8.0"
2144 | }
2145 | },
2146 | "node_modules/eventemitter3": {
2147 | "version": "5.0.1",
2148 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
2149 | "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
2150 | },
2151 | "node_modules/fill-range": {
2152 | "version": "7.1.1",
2153 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
2154 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
2155 | "dev": true,
2156 | "dependencies": {
2157 | "to-regex-range": "^5.0.1"
2158 | },
2159 | "engines": {
2160 | "node": ">=8"
2161 | }
2162 | },
2163 | "node_modules/get-port": {
2164 | "version": "4.2.0",
2165 | "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz",
2166 | "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==",
2167 | "dev": true,
2168 | "engines": {
2169 | "node": ">=6"
2170 | }
2171 | },
2172 | "node_modules/globals": {
2173 | "version": "13.24.0",
2174 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
2175 | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
2176 | "dev": true,
2177 | "dependencies": {
2178 | "type-fest": "^0.20.2"
2179 | },
2180 | "engines": {
2181 | "node": ">=8"
2182 | },
2183 | "funding": {
2184 | "url": "https://github.com/sponsors/sindresorhus"
2185 | }
2186 | },
2187 | "node_modules/has-flag": {
2188 | "version": "4.0.0",
2189 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
2190 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
2191 | "dev": true,
2192 | "engines": {
2193 | "node": ">=8"
2194 | }
2195 | },
2196 | "node_modules/htmlnano": {
2197 | "version": "2.1.1",
2198 | "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.1.tgz",
2199 | "integrity": "sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==",
2200 | "dev": true,
2201 | "dependencies": {
2202 | "cosmiconfig": "^9.0.0",
2203 | "posthtml": "^0.16.5",
2204 | "timsort": "^0.3.0"
2205 | },
2206 | "peerDependencies": {
2207 | "cssnano": "^7.0.0",
2208 | "postcss": "^8.3.11",
2209 | "purgecss": "^6.0.0",
2210 | "relateurl": "^0.2.7",
2211 | "srcset": "5.0.1",
2212 | "svgo": "^3.0.2",
2213 | "terser": "^5.10.0",
2214 | "uncss": "^0.17.3"
2215 | },
2216 | "peerDependenciesMeta": {
2217 | "cssnano": {
2218 | "optional": true
2219 | },
2220 | "postcss": {
2221 | "optional": true
2222 | },
2223 | "purgecss": {
2224 | "optional": true
2225 | },
2226 | "relateurl": {
2227 | "optional": true
2228 | },
2229 | "srcset": {
2230 | "optional": true
2231 | },
2232 | "svgo": {
2233 | "optional": true
2234 | },
2235 | "terser": {
2236 | "optional": true
2237 | },
2238 | "uncss": {
2239 | "optional": true
2240 | }
2241 | }
2242 | },
2243 | "node_modules/htmlparser2": {
2244 | "version": "7.2.0",
2245 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
2246 | "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
2247 | "dev": true,
2248 | "funding": [
2249 | "https://github.com/fb55/htmlparser2?sponsor=1",
2250 | {
2251 | "type": "github",
2252 | "url": "https://github.com/sponsors/fb55"
2253 | }
2254 | ],
2255 | "dependencies": {
2256 | "domelementtype": "^2.0.1",
2257 | "domhandler": "^4.2.2",
2258 | "domutils": "^2.8.0",
2259 | "entities": "^3.0.1"
2260 | }
2261 | },
2262 | "node_modules/httpie": {
2263 | "version": "2.0.0-next.13",
2264 | "resolved": "https://registry.npmjs.org/httpie/-/httpie-2.0.0-next.13.tgz",
2265 | "integrity": "sha512-KbKOnq8wt0hVEfteYCSnEsPgzaWxcVc4qZ4OaDU9mVOYLRo3XChjWs3MiuRgFu5y+4JDo7sDKdKzkAn1ljQYFA==",
2266 | "engines": {
2267 | "node": ">=10"
2268 | }
2269 | },
2270 | "node_modules/ieee754": {
2271 | "version": "1.2.1",
2272 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
2273 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
2274 | "dev": true,
2275 | "funding": [
2276 | {
2277 | "type": "github",
2278 | "url": "https://github.com/sponsors/feross"
2279 | },
2280 | {
2281 | "type": "patreon",
2282 | "url": "https://www.patreon.com/feross"
2283 | },
2284 | {
2285 | "type": "consulting",
2286 | "url": "https://feross.org/support"
2287 | }
2288 | ]
2289 | },
2290 | "node_modules/import-fresh": {
2291 | "version": "3.3.0",
2292 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
2293 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
2294 | "dev": true,
2295 | "dependencies": {
2296 | "parent-module": "^1.0.0",
2297 | "resolve-from": "^4.0.0"
2298 | },
2299 | "engines": {
2300 | "node": ">=6"
2301 | },
2302 | "funding": {
2303 | "url": "https://github.com/sponsors/sindresorhus"
2304 | }
2305 | },
2306 | "node_modules/is-arrayish": {
2307 | "version": "0.2.1",
2308 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
2309 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
2310 | "dev": true
2311 | },
2312 | "node_modules/is-extglob": {
2313 | "version": "2.1.1",
2314 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
2315 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
2316 | "dev": true,
2317 | "engines": {
2318 | "node": ">=0.10.0"
2319 | }
2320 | },
2321 | "node_modules/is-glob": {
2322 | "version": "4.0.3",
2323 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
2324 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
2325 | "dev": true,
2326 | "dependencies": {
2327 | "is-extglob": "^2.1.1"
2328 | },
2329 | "engines": {
2330 | "node": ">=0.10.0"
2331 | }
2332 | },
2333 | "node_modules/is-json": {
2334 | "version": "2.0.1",
2335 | "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
2336 | "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
2337 | "dev": true
2338 | },
2339 | "node_modules/is-number": {
2340 | "version": "7.0.0",
2341 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
2342 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
2343 | "dev": true,
2344 | "engines": {
2345 | "node": ">=0.12.0"
2346 | }
2347 | },
2348 | "node_modules/js-tokens": {
2349 | "version": "4.0.0",
2350 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
2351 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
2352 | "dev": true
2353 | },
2354 | "node_modules/js-yaml": {
2355 | "version": "4.1.0",
2356 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
2357 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
2358 | "dev": true,
2359 | "dependencies": {
2360 | "argparse": "^2.0.1"
2361 | },
2362 | "bin": {
2363 | "js-yaml": "bin/js-yaml.js"
2364 | }
2365 | },
2366 | "node_modules/json-parse-even-better-errors": {
2367 | "version": "2.3.1",
2368 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
2369 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
2370 | "dev": true
2371 | },
2372 | "node_modules/json5": {
2373 | "version": "2.2.3",
2374 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
2375 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
2376 | "dev": true,
2377 | "bin": {
2378 | "json5": "lib/cli.js"
2379 | },
2380 | "engines": {
2381 | "node": ">=6"
2382 | }
2383 | },
2384 | "node_modules/lightningcss": {
2385 | "version": "1.25.1",
2386 | "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.25.1.tgz",
2387 | "integrity": "sha512-V0RMVZzK1+rCHpymRv4URK2lNhIRyO8g7U7zOFwVAhJuat74HtkjIQpQRKNCwFEYkRGpafOpmXXLoaoBcyVtBg==",
2388 | "dev": true,
2389 | "dependencies": {
2390 | "detect-libc": "^1.0.3"
2391 | },
2392 | "engines": {
2393 | "node": ">= 12.0.0"
2394 | },
2395 | "funding": {
2396 | "type": "opencollective",
2397 | "url": "https://opencollective.com/parcel"
2398 | },
2399 | "optionalDependencies": {
2400 | "lightningcss-darwin-arm64": "1.25.1",
2401 | "lightningcss-darwin-x64": "1.25.1",
2402 | "lightningcss-freebsd-x64": "1.25.1",
2403 | "lightningcss-linux-arm-gnueabihf": "1.25.1",
2404 | "lightningcss-linux-arm64-gnu": "1.25.1",
2405 | "lightningcss-linux-arm64-musl": "1.25.1",
2406 | "lightningcss-linux-x64-gnu": "1.25.1",
2407 | "lightningcss-linux-x64-musl": "1.25.1",
2408 | "lightningcss-win32-x64-msvc": "1.25.1"
2409 | }
2410 | },
2411 | "node_modules/lightningcss-darwin-arm64": {
2412 | "version": "1.25.1",
2413 | "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.25.1.tgz",
2414 | "integrity": "sha512-G4Dcvv85bs5NLENcu/s1f7ehzE3D5ThnlWSDwE190tWXRQCQaqwcuHe+MGSVI/slm0XrxnaayXY+cNl3cSricw==",
2415 | "cpu": [
2416 | "arm64"
2417 | ],
2418 | "dev": true,
2419 | "optional": true,
2420 | "os": [
2421 | "darwin"
2422 | ],
2423 | "engines": {
2424 | "node": ">= 12.0.0"
2425 | },
2426 | "funding": {
2427 | "type": "opencollective",
2428 | "url": "https://opencollective.com/parcel"
2429 | }
2430 | },
2431 | "node_modules/lightningcss/node_modules/detect-libc": {
2432 | "version": "1.0.3",
2433 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
2434 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
2435 | "dev": true,
2436 | "bin": {
2437 | "detect-libc": "bin/detect-libc.js"
2438 | },
2439 | "engines": {
2440 | "node": ">=0.10"
2441 | }
2442 | },
2443 | "node_modules/lines-and-columns": {
2444 | "version": "1.2.4",
2445 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
2446 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
2447 | "dev": true
2448 | },
2449 | "node_modules/lmdb": {
2450 | "version": "2.8.5",
2451 | "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.8.5.tgz",
2452 | "integrity": "sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==",
2453 | "dev": true,
2454 | "hasInstallScript": true,
2455 | "dependencies": {
2456 | "msgpackr": "^1.9.5",
2457 | "node-addon-api": "^6.1.0",
2458 | "node-gyp-build-optional-packages": "5.1.1",
2459 | "ordered-binary": "^1.4.1",
2460 | "weak-lru-cache": "^1.2.2"
2461 | },
2462 | "bin": {
2463 | "download-lmdb-prebuilds": "bin/download-prebuilds.js"
2464 | },
2465 | "optionalDependencies": {
2466 | "@lmdb/lmdb-darwin-arm64": "2.8.5",
2467 | "@lmdb/lmdb-darwin-x64": "2.8.5",
2468 | "@lmdb/lmdb-linux-arm": "2.8.5",
2469 | "@lmdb/lmdb-linux-arm64": "2.8.5",
2470 | "@lmdb/lmdb-linux-x64": "2.8.5",
2471 | "@lmdb/lmdb-win32-x64": "2.8.5"
2472 | }
2473 | },
2474 | "node_modules/lmdb/node_modules/node-addon-api": {
2475 | "version": "6.1.0",
2476 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
2477 | "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==",
2478 | "dev": true
2479 | },
2480 | "node_modules/lmdb/node_modules/node-gyp-build-optional-packages": {
2481 | "version": "5.1.1",
2482 | "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz",
2483 | "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==",
2484 | "dev": true,
2485 | "dependencies": {
2486 | "detect-libc": "^2.0.1"
2487 | },
2488 | "bin": {
2489 | "node-gyp-build-optional-packages": "bin.js",
2490 | "node-gyp-build-optional-packages-optional": "optional.js",
2491 | "node-gyp-build-optional-packages-test": "build-test.js"
2492 | }
2493 | },
2494 | "node_modules/mdn-data": {
2495 | "version": "2.0.30",
2496 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
2497 | "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
2498 | "dev": true,
2499 | "optional": true,
2500 | "peer": true
2501 | },
2502 | "node_modules/micromatch": {
2503 | "version": "4.0.7",
2504 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
2505 | "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
2506 | "dev": true,
2507 | "dependencies": {
2508 | "braces": "^3.0.3",
2509 | "picomatch": "^2.3.1"
2510 | },
2511 | "engines": {
2512 | "node": ">=8.6"
2513 | }
2514 | },
2515 | "node_modules/msgpackr": {
2516 | "version": "1.10.2",
2517 | "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz",
2518 | "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==",
2519 | "dev": true,
2520 | "optionalDependencies": {
2521 | "msgpackr-extract": "^3.0.2"
2522 | }
2523 | },
2524 | "node_modules/msgpackr-extract": {
2525 | "version": "3.0.3",
2526 | "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
2527 | "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
2528 | "hasInstallScript": true,
2529 | "optional": true,
2530 | "dependencies": {
2531 | "node-gyp-build-optional-packages": "5.2.2"
2532 | },
2533 | "bin": {
2534 | "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
2535 | },
2536 | "optionalDependencies": {
2537 | "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
2538 | "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
2539 | "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
2540 | "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
2541 | "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
2542 | "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
2543 | }
2544 | },
2545 | "node_modules/node-addon-api": {
2546 | "version": "7.1.0",
2547 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz",
2548 | "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==",
2549 | "dev": true,
2550 | "engines": {
2551 | "node": "^16 || ^18 || >= 20"
2552 | }
2553 | },
2554 | "node_modules/node-gyp-build-optional-packages": {
2555 | "version": "5.2.2",
2556 | "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
2557 | "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
2558 | "optional": true,
2559 | "dependencies": {
2560 | "detect-libc": "^2.0.1"
2561 | },
2562 | "bin": {
2563 | "node-gyp-build-optional-packages": "bin.js",
2564 | "node-gyp-build-optional-packages-optional": "optional.js",
2565 | "node-gyp-build-optional-packages-test": "build-test.js"
2566 | }
2567 | },
2568 | "node_modules/node-releases": {
2569 | "version": "2.0.14",
2570 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
2571 | "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
2572 | "dev": true
2573 | },
2574 | "node_modules/nth-check": {
2575 | "version": "2.1.1",
2576 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
2577 | "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
2578 | "dev": true,
2579 | "dependencies": {
2580 | "boolbase": "^1.0.0"
2581 | },
2582 | "funding": {
2583 | "url": "https://github.com/fb55/nth-check?sponsor=1"
2584 | }
2585 | },
2586 | "node_modules/nullthrows": {
2587 | "version": "1.1.1",
2588 | "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
2589 | "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==",
2590 | "dev": true
2591 | },
2592 | "node_modules/ordered-binary": {
2593 | "version": "1.5.1",
2594 | "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz",
2595 | "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==",
2596 | "dev": true
2597 | },
2598 | "node_modules/parcel": {
2599 | "version": "2.12.0",
2600 | "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.12.0.tgz",
2601 | "integrity": "sha512-W+gxAq7aQ9dJIg/XLKGcRT0cvnStFAQHPaI0pvD0U2l6IVLueUAm3nwN7lkY62zZNmlvNx6jNtE4wlbS+CyqSg==",
2602 | "dev": true,
2603 | "dependencies": {
2604 | "@parcel/config-default": "2.12.0",
2605 | "@parcel/core": "2.12.0",
2606 | "@parcel/diagnostic": "2.12.0",
2607 | "@parcel/events": "2.12.0",
2608 | "@parcel/fs": "2.12.0",
2609 | "@parcel/logger": "2.12.0",
2610 | "@parcel/package-manager": "2.12.0",
2611 | "@parcel/reporter-cli": "2.12.0",
2612 | "@parcel/reporter-dev-server": "2.12.0",
2613 | "@parcel/reporter-tracer": "2.12.0",
2614 | "@parcel/utils": "2.12.0",
2615 | "chalk": "^4.1.0",
2616 | "commander": "^7.0.0",
2617 | "get-port": "^4.2.0"
2618 | },
2619 | "bin": {
2620 | "parcel": "lib/bin.js"
2621 | },
2622 | "engines": {
2623 | "node": ">= 12.0.0"
2624 | },
2625 | "funding": {
2626 | "type": "opencollective",
2627 | "url": "https://opencollective.com/parcel"
2628 | }
2629 | },
2630 | "node_modules/parent-module": {
2631 | "version": "1.0.1",
2632 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
2633 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
2634 | "dev": true,
2635 | "dependencies": {
2636 | "callsites": "^3.0.0"
2637 | },
2638 | "engines": {
2639 | "node": ">=6"
2640 | }
2641 | },
2642 | "node_modules/parse-json": {
2643 | "version": "5.2.0",
2644 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
2645 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
2646 | "dev": true,
2647 | "dependencies": {
2648 | "@babel/code-frame": "^7.0.0",
2649 | "error-ex": "^1.3.1",
2650 | "json-parse-even-better-errors": "^2.3.0",
2651 | "lines-and-columns": "^1.1.6"
2652 | },
2653 | "engines": {
2654 | "node": ">=8"
2655 | },
2656 | "funding": {
2657 | "url": "https://github.com/sponsors/sindresorhus"
2658 | }
2659 | },
2660 | "node_modules/phaser": {
2661 | "version": "3.80.1",
2662 | "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.80.1.tgz",
2663 | "integrity": "sha512-VQGAWoDOkEpAWYkI+PUADv5Ql+SM0xpLuAMBJHz9tBcOLqjJ2wd8bUhxJgOqclQlLTg97NmMd9MhS75w16x1Cw==",
2664 | "dependencies": {
2665 | "eventemitter3": "^5.0.1"
2666 | }
2667 | },
2668 | "node_modules/picocolors": {
2669 | "version": "1.0.1",
2670 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
2671 | "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
2672 | "dev": true
2673 | },
2674 | "node_modules/picomatch": {
2675 | "version": "2.3.1",
2676 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
2677 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
2678 | "dev": true,
2679 | "engines": {
2680 | "node": ">=8.6"
2681 | },
2682 | "funding": {
2683 | "url": "https://github.com/sponsors/jonschlinkert"
2684 | }
2685 | },
2686 | "node_modules/postcss-value-parser": {
2687 | "version": "4.2.0",
2688 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
2689 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
2690 | "dev": true
2691 | },
2692 | "node_modules/posthtml": {
2693 | "version": "0.16.6",
2694 | "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
2695 | "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
2696 | "dev": true,
2697 | "dependencies": {
2698 | "posthtml-parser": "^0.11.0",
2699 | "posthtml-render": "^3.0.0"
2700 | },
2701 | "engines": {
2702 | "node": ">=12.0.0"
2703 | }
2704 | },
2705 | "node_modules/posthtml-parser": {
2706 | "version": "0.10.2",
2707 | "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz",
2708 | "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==",
2709 | "dev": true,
2710 | "dependencies": {
2711 | "htmlparser2": "^7.1.1"
2712 | },
2713 | "engines": {
2714 | "node": ">=12"
2715 | }
2716 | },
2717 | "node_modules/posthtml-render": {
2718 | "version": "3.0.0",
2719 | "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
2720 | "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
2721 | "dev": true,
2722 | "dependencies": {
2723 | "is-json": "^2.0.1"
2724 | },
2725 | "engines": {
2726 | "node": ">=12"
2727 | }
2728 | },
2729 | "node_modules/posthtml/node_modules/posthtml-parser": {
2730 | "version": "0.11.0",
2731 | "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
2732 | "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
2733 | "dev": true,
2734 | "dependencies": {
2735 | "htmlparser2": "^7.1.1"
2736 | },
2737 | "engines": {
2738 | "node": ">=12"
2739 | }
2740 | },
2741 | "node_modules/process": {
2742 | "version": "0.11.10",
2743 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
2744 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
2745 | "dev": true,
2746 | "engines": {
2747 | "node": ">= 0.6.0"
2748 | }
2749 | },
2750 | "node_modules/react-error-overlay": {
2751 | "version": "6.0.9",
2752 | "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
2753 | "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==",
2754 | "dev": true
2755 | },
2756 | "node_modules/react-refresh": {
2757 | "version": "0.9.0",
2758 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz",
2759 | "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==",
2760 | "dev": true,
2761 | "engines": {
2762 | "node": ">=0.10.0"
2763 | }
2764 | },
2765 | "node_modules/regenerator-runtime": {
2766 | "version": "0.13.11",
2767 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
2768 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
2769 | "dev": true
2770 | },
2771 | "node_modules/resolve-from": {
2772 | "version": "4.0.0",
2773 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
2774 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
2775 | "dev": true,
2776 | "engines": {
2777 | "node": ">=4"
2778 | }
2779 | },
2780 | "node_modules/safe-buffer": {
2781 | "version": "5.2.1",
2782 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
2783 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
2784 | "dev": true,
2785 | "funding": [
2786 | {
2787 | "type": "github",
2788 | "url": "https://github.com/sponsors/feross"
2789 | },
2790 | {
2791 | "type": "patreon",
2792 | "url": "https://www.patreon.com/feross"
2793 | },
2794 | {
2795 | "type": "consulting",
2796 | "url": "https://feross.org/support"
2797 | }
2798 | ]
2799 | },
2800 | "node_modules/semver": {
2801 | "version": "7.6.2",
2802 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
2803 | "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
2804 | "dev": true,
2805 | "bin": {
2806 | "semver": "bin/semver.js"
2807 | },
2808 | "engines": {
2809 | "node": ">=10"
2810 | }
2811 | },
2812 | "node_modules/source-map": {
2813 | "version": "0.6.1",
2814 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
2815 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
2816 | "dev": true,
2817 | "engines": {
2818 | "node": ">=0.10.0"
2819 | }
2820 | },
2821 | "node_modules/source-map-js": {
2822 | "version": "1.2.0",
2823 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
2824 | "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
2825 | "dev": true,
2826 | "optional": true,
2827 | "peer": true,
2828 | "engines": {
2829 | "node": ">=0.10.0"
2830 | }
2831 | },
2832 | "node_modules/srcset": {
2833 | "version": "5.0.1",
2834 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz",
2835 | "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==",
2836 | "dev": true,
2837 | "optional": true,
2838 | "peer": true,
2839 | "engines": {
2840 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
2841 | },
2842 | "funding": {
2843 | "url": "https://github.com/sponsors/sindresorhus"
2844 | }
2845 | },
2846 | "node_modules/stable": {
2847 | "version": "0.1.8",
2848 | "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
2849 | "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
2850 | "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
2851 | "dev": true
2852 | },
2853 | "node_modules/supports-color": {
2854 | "version": "7.2.0",
2855 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
2856 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
2857 | "dev": true,
2858 | "dependencies": {
2859 | "has-flag": "^4.0.0"
2860 | },
2861 | "engines": {
2862 | "node": ">=8"
2863 | }
2864 | },
2865 | "node_modules/svgo": {
2866 | "version": "3.3.2",
2867 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz",
2868 | "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==",
2869 | "dev": true,
2870 | "optional": true,
2871 | "peer": true,
2872 | "dependencies": {
2873 | "@trysound/sax": "0.2.0",
2874 | "commander": "^7.2.0",
2875 | "css-select": "^5.1.0",
2876 | "css-tree": "^2.3.1",
2877 | "css-what": "^6.1.0",
2878 | "csso": "^5.0.5",
2879 | "picocolors": "^1.0.0"
2880 | },
2881 | "bin": {
2882 | "svgo": "bin/svgo"
2883 | },
2884 | "engines": {
2885 | "node": ">=14.0.0"
2886 | },
2887 | "funding": {
2888 | "type": "opencollective",
2889 | "url": "https://opencollective.com/svgo"
2890 | }
2891 | },
2892 | "node_modules/term-size": {
2893 | "version": "2.2.1",
2894 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
2895 | "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
2896 | "dev": true,
2897 | "engines": {
2898 | "node": ">=8"
2899 | },
2900 | "funding": {
2901 | "url": "https://github.com/sponsors/sindresorhus"
2902 | }
2903 | },
2904 | "node_modules/timsort": {
2905 | "version": "0.3.0",
2906 | "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
2907 | "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
2908 | "dev": true
2909 | },
2910 | "node_modules/to-regex-range": {
2911 | "version": "5.0.1",
2912 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
2913 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
2914 | "dev": true,
2915 | "dependencies": {
2916 | "is-number": "^7.0.0"
2917 | },
2918 | "engines": {
2919 | "node": ">=8.0"
2920 | }
2921 | },
2922 | "node_modules/tslib": {
2923 | "version": "2.6.3",
2924 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
2925 | "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
2926 | },
2927 | "node_modules/type-fest": {
2928 | "version": "0.20.2",
2929 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
2930 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
2931 | "dev": true,
2932 | "engines": {
2933 | "node": ">=10"
2934 | },
2935 | "funding": {
2936 | "url": "https://github.com/sponsors/sindresorhus"
2937 | }
2938 | },
2939 | "node_modules/typescript": {
2940 | "version": "4.9.5",
2941 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
2942 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
2943 | "dev": true,
2944 | "bin": {
2945 | "tsc": "bin/tsc",
2946 | "tsserver": "bin/tsserver"
2947 | },
2948 | "engines": {
2949 | "node": ">=4.2.0"
2950 | }
2951 | },
2952 | "node_modules/update-browserslist-db": {
2953 | "version": "1.0.16",
2954 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
2955 | "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
2956 | "dev": true,
2957 | "funding": [
2958 | {
2959 | "type": "opencollective",
2960 | "url": "https://opencollective.com/browserslist"
2961 | },
2962 | {
2963 | "type": "tidelift",
2964 | "url": "https://tidelift.com/funding/github/npm/browserslist"
2965 | },
2966 | {
2967 | "type": "github",
2968 | "url": "https://github.com/sponsors/ai"
2969 | }
2970 | ],
2971 | "dependencies": {
2972 | "escalade": "^3.1.2",
2973 | "picocolors": "^1.0.1"
2974 | },
2975 | "bin": {
2976 | "update-browserslist-db": "cli.js"
2977 | },
2978 | "peerDependencies": {
2979 | "browserslist": ">= 4.21.0"
2980 | }
2981 | },
2982 | "node_modules/utility-types": {
2983 | "version": "3.11.0",
2984 | "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz",
2985 | "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==",
2986 | "dev": true,
2987 | "engines": {
2988 | "node": ">= 4"
2989 | }
2990 | },
2991 | "node_modules/weak-lru-cache": {
2992 | "version": "1.2.2",
2993 | "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz",
2994 | "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==",
2995 | "dev": true
2996 | },
2997 | "node_modules/ws": {
2998 | "version": "8.17.1",
2999 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
3000 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
3001 | "engines": {
3002 | "node": ">=10.0.0"
3003 | },
3004 | "peerDependencies": {
3005 | "bufferutil": "^4.0.1",
3006 | "utf-8-validate": ">=5.0.2"
3007 | },
3008 | "peerDependenciesMeta": {
3009 | "bufferutil": {
3010 | "optional": true
3011 | },
3012 | "utf-8-validate": {
3013 | "optional": true
3014 | }
3015 | }
3016 | }
3017 | }
3018 | }
3019 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "1.0.0",
4 | "description": "Colyseus + Phaser: Client-side",
5 | "scripts": {
6 | "start": "parcel serve index.html",
7 | "build": "parcel build index.html",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [
11 | "colyseus",
12 | "phaser"
13 | ],
14 | "author": "Endel Dreyer",
15 | "license": "MIT",
16 | "devDependencies": {
17 | "buffer": "^6.0.3",
18 | "parcel": "^2.4.0",
19 | "process": "^0.11.10",
20 | "typescript": "^4.6.3"
21 | },
22 | "dependencies": {
23 | "colyseus.js": "^0.16.0",
24 | "phaser": "^3.55.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/src/backend.ts:
--------------------------------------------------------------------------------
1 | export const BACKEND_URL = (window.location.href.indexOf("localhost") === -1)
2 | ? `${window.location.protocol.replace("http", "ws")}//${window.location.hostname}${(window.location.port && `:${window.location.port}`)}`
3 | : "ws://localhost:2567"
4 |
5 | export const BACKEND_HTTP_URL = BACKEND_URL.replace("ws", "http");
--------------------------------------------------------------------------------
/client/src/index.ts:
--------------------------------------------------------------------------------
1 | import Phaser from "phaser";
2 |
3 | import { SceneSelector } from "./scenes/SceneSelector";
4 | import { Part1Scene } from "./scenes/Part1Scene";
5 | import { Part2Scene } from "./scenes/Part2Scene";
6 | import { Part3Scene } from "./scenes/Part3Scene";
7 | import { Part4Scene } from "./scenes/Part4Scene";
8 |
9 | import { BACKEND_HTTP_URL } from "./backend";
10 |
11 | const config: Phaser.Types.Core.GameConfig = {
12 | type: Phaser.AUTO,
13 | fps: {
14 | target: 60,
15 | forceSetTimeOut: true,
16 | smoothStep: false,
17 | },
18 | width: 800,
19 | height: 600,
20 | // height: 200,
21 | backgroundColor: '#b6d53c',
22 | parent: 'phaser-example',
23 | physics: {
24 | default: "arcade"
25 | },
26 | pixelArt: true,
27 | scene: [SceneSelector, Part1Scene, Part2Scene, Part3Scene, Part4Scene],
28 | };
29 |
30 | const game = new Phaser.Game(config);
31 |
32 | /**
33 | * Create FPS selector
34 | */
35 |
36 | // current fps label
37 | const fpsInput = document.querySelector("input#fps");
38 | const fpsValueLabel = document.querySelector("#fps-value");
39 | fpsValueLabel.innerText = fpsInput.value;
40 |
41 | fpsInput.oninput = function(event: InputEvent) {
42 | const value = (event.target as HTMLInputElement).value;
43 | fpsValueLabel.innerText = value;
44 |
45 | // destroy previous loop
46 | game.loop.destroy();
47 |
48 | // create new loop
49 | game.loop = new Phaser.Core.TimeStep(game, {
50 | target: parseInt(value),
51 | forceSetTimeOut: true,
52 | smoothStep: false,
53 | });
54 |
55 | // start new loop
56 | game.loop.start(game.step.bind(game));
57 | };
58 |
59 | /**
60 | * Create latency simulation selector
61 | */
62 | let fetchLatencySimulationInterval: number;
63 |
64 | // latency simulation label
65 | const latencyInput = document.querySelector("input#latency");
66 |
67 | if (latencyInput) {
68 | // current latency label
69 | const selectedLatencyLabel = document.querySelector("#latency-value")
70 | selectedLatencyLabel.innerText = `${latencyInput.value} ms`;
71 |
72 | latencyInput.onpointerdown = (event: PointerEvent) =>
73 | clearInterval(fetchLatencySimulationInterval);
74 |
75 | latencyInput.oninput = (event: InputEvent) =>
76 | selectedLatencyLabel.innerText = `${latencyInput.value} ms`;
77 |
78 | latencyInput.onchange = function (event: InputEvent) {
79 | // request server to update its latency simulation
80 | fetch(`${BACKEND_HTTP_URL}/simulate-latency/${latencyInput.value}`);
81 |
82 | setIntervalFetchLatencySimulation();
83 | };
84 |
85 | function setIntervalFetchLatencySimulation() {
86 | //
87 | // Keep fetching latency simulation number from server to keep all browser tabs in sync
88 | //
89 | fetchLatencySimulationInterval = setInterval(() => {
90 | fetch(`${BACKEND_HTTP_URL}/latency`)
91 | .then((response) => response.json())
92 | .then((value) => {
93 | latencyInput.value = value;
94 | latencyInput.oninput(undefined);
95 | });
96 | }, 1000);
97 | }
98 | setIntervalFetchLatencySimulation();
99 | }
--------------------------------------------------------------------------------
/client/src/scenes/Part1Scene.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ---------------------------
3 | * Phaser + Colyseus - Part 1.
4 | * ---------------------------
5 | * - Connecting with the room
6 | * - Sending inputs at the user's framerate
7 | * - Update each player's positions WITHOUT interpolation
8 | */
9 |
10 | import Phaser from "phaser";
11 | import { Room, Client, getStateCallbacks } from "colyseus.js";
12 | import { BACKEND_URL } from "../backend";
13 |
14 | // Import the state type from server-side code
15 | import type { MyRoomState } from "../../../server/src/rooms/Part1Room";
16 |
17 | export class Part1Scene extends Phaser.Scene {
18 | room: Room;
19 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {};
20 |
21 | debugFPS: Phaser.GameObjects.Text;
22 |
23 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys;
24 |
25 | inputPayload = {
26 | left: false,
27 | right: false,
28 | up: false,
29 | down: false,
30 | };
31 |
32 | constructor() {
33 | super({ key: "part1" });
34 | }
35 |
36 | async create() {
37 | this.cursorKeys = this.input.keyboard.createCursorKeys();
38 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", });
39 |
40 | // connect with the room
41 | await this.connect();
42 |
43 | const $ = getStateCallbacks(this.room);
44 |
45 | $(this.room.state).players.onAdd((player, sessionId) => {
46 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001');
47 | this.playerEntities[sessionId] = entity;
48 |
49 | // listening for server updates
50 | $(player).onChange(() => {
51 | //
52 | // update local position immediately
53 | // (WE WILL CHANGE THIS ON PART 2)
54 | //
55 | entity.x = player.x;
56 | entity.y = player.y;
57 | });
58 | });
59 |
60 | // remove local reference when entity is removed from the server
61 | $(this.room.state).players.onRemove((player, sessionId) => {
62 | const entity = this.playerEntities[sessionId];
63 | if (entity) {
64 | entity.destroy();
65 | delete this.playerEntities[sessionId]
66 | }
67 | });
68 |
69 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2);
70 | // this.cameras.main.setZoom(1);
71 | this.cameras.main.setBounds(0, 0, 800, 600);
72 | }
73 |
74 | async connect() {
75 | // add connection status text
76 | const connectionStatusText = this.add
77 | .text(0, 0, "Trying to connect with the server...")
78 | .setStyle({ color: "#ff0000" })
79 | .setPadding(4)
80 |
81 | const client = new Client(BACKEND_URL);
82 |
83 | try {
84 | this.room = await client.joinOrCreate("part1_room", {});
85 |
86 | // connection successful!
87 | connectionStatusText.destroy();
88 |
89 | } catch (e) {
90 | // couldn't connect
91 | connectionStatusText.text = "Could not connect with the server.";
92 | }
93 |
94 | }
95 |
96 | update(time: number, delta: number): void {
97 | // skip loop if not connected with room yet.
98 | if (!this.room) {
99 | return;
100 | }
101 |
102 | // send input to the server
103 | this.inputPayload.left = this.cursorKeys.left.isDown;
104 | this.inputPayload.right = this.cursorKeys.right.isDown;
105 | this.inputPayload.up = this.cursorKeys.up.isDown;
106 | this.inputPayload.down = this.cursorKeys.down.isDown;
107 | this.room.send(0, this.inputPayload);
108 |
109 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`;
110 | }
111 |
112 | }
--------------------------------------------------------------------------------
/client/src/scenes/Part2Scene.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ---------------------------
3 | * Phaser + Colyseus - Part 2.
4 | * ---------------------------
5 | * - Connecting with the room
6 | * - Sending inputs at the user's framerate
7 | * - Update each player's positions WITH interpolation
8 | */
9 |
10 | import Phaser from "phaser";
11 | import { Room, Client, getStateCallbacks } from "colyseus.js";
12 | import { BACKEND_URL } from "../backend";
13 |
14 | // Import the state type from server-side code
15 | import type { MyRoomState } from "../../../server/src/rooms/Part2Room";
16 |
17 | export class Part2Scene extends Phaser.Scene {
18 | room: Room;
19 |
20 | currentPlayer: Phaser.Types.Physics.Arcade.ImageWithDynamicBody;
21 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {};
22 |
23 | debugFPS: Phaser.GameObjects.Text;
24 |
25 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys;
26 |
27 | inputPayload = {
28 | left: false,
29 | right: false,
30 | up: false,
31 | down: false,
32 | };
33 |
34 | constructor() {
35 | super({ key: "part2" });
36 | }
37 |
38 | async create() {
39 | this.cursorKeys = this.input.keyboard.createCursorKeys();
40 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", });
41 |
42 | // connect with the room
43 | await this.connect();
44 |
45 | const $ = getStateCallbacks(this.room);
46 |
47 | $(this.room.state).players.onAdd((player, sessionId) => {
48 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001');
49 | this.playerEntities[sessionId] = entity;
50 |
51 | // listening for server updates
52 | $(player).onChange(() => {
53 | //
54 | // do not update local position immediately
55 | // we're going to LERP them during the render loop.
56 | //
57 | entity.setData('serverX', player.x);
58 | entity.setData('serverY', player.y);
59 | });
60 | });
61 |
62 | // remove local reference when entity is removed from the server
63 | $(this.room.state).players.onRemove((player, sessionId) => {
64 | const entity = this.playerEntities[sessionId];
65 | if (entity) {
66 | entity.destroy();
67 | delete this.playerEntities[sessionId]
68 | }
69 | });
70 |
71 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2);
72 | // this.cameras.main.setZoom(1);
73 | this.cameras.main.setBounds(0, 0, 800, 600);
74 | }
75 |
76 | async connect() {
77 | // add connection status text
78 | const connectionStatusText = this.add
79 | .text(0, 0, "Trying to connect with the server...")
80 | .setStyle({ color: "#ff0000" })
81 | .setPadding(4)
82 |
83 | const client = new Client(BACKEND_URL);
84 |
85 | try {
86 | this.room = await client.joinOrCreate("part2_room", {});
87 |
88 | // connection successful!
89 | connectionStatusText.destroy();
90 |
91 | } catch (e) {
92 | // couldn't connect
93 | connectionStatusText.text = "Could not connect with the server.";
94 | }
95 |
96 | }
97 |
98 | update(time: number, delta: number): void {
99 | // skip loop if not connected yet.
100 | if (!this.room) { return; }
101 |
102 | // send input to the server
103 | this.inputPayload.left = this.cursorKeys.left.isDown;
104 | this.inputPayload.right = this.cursorKeys.right.isDown;
105 | this.inputPayload.up = this.cursorKeys.up.isDown;
106 | this.inputPayload.down = this.cursorKeys.down.isDown;
107 | this.room.send(0, this.inputPayload);
108 |
109 | for (let sessionId in this.playerEntities) {
110 | // interpolate all player entities
111 | const entity = this.playerEntities[sessionId];
112 | const { serverX, serverY } = entity.data.values;
113 |
114 | entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2);
115 | entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2);
116 |
117 | // entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2);
118 | // entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2);
119 |
120 | }
121 |
122 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`;
123 | }
124 |
125 | fixedTick(time, delta) {
126 | }
127 |
128 | }
--------------------------------------------------------------------------------
/client/src/scenes/Part3Scene.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ---------------------------
3 | * Phaser + Colyseus - Part 3.
4 | * ---------------------------
5 | * - Connecting with the room
6 | * - Sending inputs at the user's framerate
7 | * - Update other player's positions WITH interpolation (for other players)
8 | * - Client-predicted input for local (current) player
9 | */
10 |
11 | import Phaser from "phaser";
12 | import { Room, Client, getStateCallbacks } from "colyseus.js";
13 | import { BACKEND_URL } from "../backend";
14 |
15 | // Import the state type from server-side code
16 | import type { MyRoomState } from "../../../server/src/rooms/Part3Room";
17 |
18 | export class Part3Scene extends Phaser.Scene {
19 | room: Room;
20 |
21 | currentPlayer: Phaser.Types.Physics.Arcade.ImageWithDynamicBody;
22 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {};
23 |
24 | debugFPS: Phaser.GameObjects.Text;
25 |
26 | localRef: Phaser.GameObjects.Rectangle;
27 | remoteRef: Phaser.GameObjects.Rectangle;
28 |
29 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys;
30 |
31 | inputPayload = {
32 | left: false,
33 | right: false,
34 | up: false,
35 | down: false,
36 | };
37 |
38 | constructor() {
39 | super({ key: "part3" });
40 | }
41 |
42 | async create() {
43 | this.cursorKeys = this.input.keyboard.createCursorKeys();
44 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", });
45 |
46 | // connect with the room
47 | await this.connect();
48 |
49 | const $ = getStateCallbacks(this.room);
50 |
51 | $(this.room.state).players.onAdd((player, sessionId) => {
52 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001');
53 | this.playerEntities[sessionId] = entity;
54 |
55 | // is current player
56 | if (sessionId === this.room.sessionId) {
57 | this.currentPlayer = entity;
58 |
59 | this.localRef = this.add.rectangle(0, 0, entity.width, entity.height);
60 | this.localRef.setStrokeStyle(1, 0x00ff00);
61 |
62 | this.remoteRef = this.add.rectangle(0, 0, entity.width, entity.height);
63 | this.remoteRef.setStrokeStyle(1, 0xff0000);
64 |
65 | $(player).onChange(() => {
66 | this.remoteRef.x = player.x;
67 | this.remoteRef.y = player.y;
68 | });
69 |
70 | } else {
71 | // listening for server updates
72 | $(player).onChange(() => {
73 | //
74 | // we're going to LERP the positions during the render loop.
75 | //
76 | entity.setData('serverX', player.x);
77 | entity.setData('serverY', player.y);
78 | });
79 |
80 | }
81 |
82 | });
83 |
84 | // remove local reference when entity is removed from the server
85 | $(this.room.state).players.onRemove((player, sessionId) => {
86 | const entity = this.playerEntities[sessionId];
87 | if (entity) {
88 | entity.destroy();
89 | delete this.playerEntities[sessionId]
90 | }
91 | });
92 |
93 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2);
94 | // this.cameras.main.setZoom(1);
95 | this.cameras.main.setBounds(0, 0, 800, 600);
96 | }
97 |
98 | async connect() {
99 | // add connection status text
100 | const connectionStatusText = this.add
101 | .text(0, 0, "Trying to connect with the server...")
102 | .setStyle({ color: "#ff0000" })
103 | .setPadding(4)
104 |
105 | const client = new Client(BACKEND_URL);
106 |
107 | try {
108 | this.room = await client.joinOrCreate("part3_room", {});
109 |
110 | // connection successful!
111 | connectionStatusText.destroy();
112 |
113 | } catch (e) {
114 | // couldn't connect
115 | connectionStatusText.text = "Could not connect with the server.";
116 | }
117 |
118 | }
119 |
120 | update(time: number, delta: number): void {
121 | // skip loop if not connected yet.
122 | if (!this.currentPlayer) { return; }
123 |
124 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`;
125 |
126 | const velocity = 2;
127 | this.inputPayload.left = this.cursorKeys.left.isDown;
128 | this.inputPayload.right = this.cursorKeys.right.isDown;
129 | this.inputPayload.up = this.cursorKeys.up.isDown;
130 | this.inputPayload.down = this.cursorKeys.down.isDown;
131 | this.room.send(0, this.inputPayload);
132 |
133 | if (this.inputPayload.left) {
134 | this.currentPlayer.x -= velocity;
135 |
136 | } else if (this.inputPayload.right) {
137 | this.currentPlayer.x += velocity;
138 | }
139 |
140 | if (this.inputPayload.up) {
141 | this.currentPlayer.y -= velocity;
142 |
143 | } else if (this.inputPayload.down) {
144 | this.currentPlayer.y += velocity;
145 | }
146 |
147 | this.localRef.x = this.currentPlayer.x;
148 | this.localRef.y = this.currentPlayer.y;
149 |
150 | for (let sessionId in this.playerEntities) {
151 | // interpolate all player entities
152 | // (except the current player)
153 | if (sessionId === this.room.sessionId) {
154 | continue;
155 | }
156 |
157 | const entity = this.playerEntities[sessionId];
158 | const { serverX, serverY } = entity.data.values;
159 |
160 | entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2);
161 | entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2);
162 | }
163 |
164 | }
165 |
166 | }
--------------------------------------------------------------------------------
/client/src/scenes/Part4Scene.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ---------------------------
3 | * Phaser + Colyseus - Part 4.
4 | * ---------------------------
5 | * - Connecting with the room
6 | * - Sending inputs at the user's framerate
7 | * - Update other player's positions WITH interpolation (for other players)
8 | * - Client-predicted input for local (current) player
9 | * - Fixed tickrate on both client and server
10 | */
11 |
12 | import Phaser from "phaser";
13 | import { Room, Client, getStateCallbacks } from "colyseus.js";
14 | import { BACKEND_URL } from "../backend";
15 |
16 | // Import the state type from server-side code
17 | import type { MyRoomState } from "../../../server/src/rooms/Part4Room";
18 |
19 | export class Part4Scene extends Phaser.Scene {
20 | room: Room;
21 |
22 | currentPlayer: Phaser.Types.Physics.Arcade.ImageWithDynamicBody;
23 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {};
24 |
25 | debugFPS: Phaser.GameObjects.Text;
26 |
27 | localRef: Phaser.GameObjects.Rectangle;
28 | remoteRef: Phaser.GameObjects.Rectangle;
29 |
30 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys;
31 |
32 | inputPayload = {
33 | left: false,
34 | right: false,
35 | up: false,
36 | down: false,
37 | tick: undefined,
38 | };
39 |
40 | elapsedTime = 0;
41 | fixedTimeStep = 1000 / 60;
42 |
43 | currentTick: number = 0;
44 |
45 | constructor() {
46 | super({ key: "part4" });
47 | }
48 |
49 | async create() {
50 | this.cursorKeys = this.input.keyboard.createCursorKeys();
51 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", });
52 |
53 | // connect with the room
54 | await this.connect();
55 |
56 | const $ = getStateCallbacks(this.room);
57 |
58 | $(this.room.state).players.onAdd((player, sessionId) => {
59 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001');
60 | this.playerEntities[sessionId] = entity;
61 |
62 | // is current player
63 | if (sessionId === this.room.sessionId) {
64 | this.currentPlayer = entity;
65 |
66 | this.localRef = this.add.rectangle(0, 0, entity.width, entity.height);
67 | this.localRef.setStrokeStyle(1, 0x00ff00);
68 |
69 | this.remoteRef = this.add.rectangle(0, 0, entity.width, entity.height);
70 | this.remoteRef.setStrokeStyle(1, 0xff0000);
71 |
72 | $(player).onChange(() => {
73 | this.remoteRef.x = player.x;
74 | this.remoteRef.y = player.y;
75 | });
76 |
77 | } else {
78 | // listening for server updates
79 | $(player).onChange(() => {
80 | //
81 | // we're going to LERP the positions during the render loop.
82 | //
83 | entity.setData('serverX', player.x);
84 | entity.setData('serverY', player.y);
85 | });
86 |
87 | }
88 |
89 | });
90 |
91 | // remove local reference when entity is removed from the server
92 | $(this.room.state).players.onRemove((player, sessionId) => {
93 | const entity = this.playerEntities[sessionId];
94 | if (entity) {
95 | entity.destroy();
96 | delete this.playerEntities[sessionId]
97 | }
98 | });
99 |
100 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2);
101 | // this.cameras.main.setZoom(1);
102 | this.cameras.main.setBounds(0, 0, 800, 600);
103 | }
104 |
105 | async connect() {
106 | // add connection status text
107 | const connectionStatusText = this.add
108 | .text(0, 0, "Trying to connect with the server...")
109 | .setStyle({ color: "#ff0000" })
110 | .setPadding(4)
111 |
112 | const client = new Client(BACKEND_URL);
113 |
114 | try {
115 | this.room = await client.joinOrCreate("part4_room", {});
116 |
117 | // connection successful!
118 | connectionStatusText.destroy();
119 |
120 | } catch (e) {
121 | // couldn't connect
122 | connectionStatusText.text = "Could not connect with the server.";
123 | }
124 |
125 | }
126 |
127 | update(time: number, delta: number): void {
128 | // skip loop if not connected yet.
129 | if (!this.currentPlayer) { return; }
130 |
131 | this.elapsedTime += delta;
132 | while (this.elapsedTime >= this.fixedTimeStep) {
133 | this.elapsedTime -= this.fixedTimeStep;
134 | this.fixedTick(time, this.fixedTimeStep);
135 | }
136 |
137 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`;
138 | }
139 |
140 | fixedTick(time, delta) {
141 | this.currentTick++;
142 |
143 | // const currentPlayerRemote = this.room.state.players.get(this.room.sessionId);
144 | // const ticksBehind = this.currentTick - currentPlayerRemote.tick;
145 | // console.log({ ticksBehind });
146 |
147 | const velocity = 2;
148 | this.inputPayload.left = this.cursorKeys.left.isDown;
149 | this.inputPayload.right = this.cursorKeys.right.isDown;
150 | this.inputPayload.up = this.cursorKeys.up.isDown;
151 | this.inputPayload.down = this.cursorKeys.down.isDown;
152 | this.inputPayload.tick = this.currentTick;
153 | this.room.send(0, this.inputPayload);
154 |
155 | if (this.inputPayload.left) {
156 | this.currentPlayer.x -= velocity;
157 |
158 | } else if (this.inputPayload.right) {
159 | this.currentPlayer.x += velocity;
160 | }
161 |
162 | if (this.inputPayload.up) {
163 | this.currentPlayer.y -= velocity;
164 |
165 | } else if (this.inputPayload.down) {
166 | this.currentPlayer.y += velocity;
167 | }
168 |
169 | this.localRef.x = this.currentPlayer.x;
170 | this.localRef.y = this.currentPlayer.y;
171 |
172 | for (let sessionId in this.playerEntities) {
173 | // interpolate all player entities
174 | // (except the current player)
175 | if (sessionId === this.room.sessionId) {
176 | continue;
177 | }
178 |
179 | const entity = this.playerEntities[sessionId];
180 | const { serverX, serverY } = entity.data.values;
181 |
182 | entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2);
183 | entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2);
184 | }
185 |
186 | }
187 |
188 | }
--------------------------------------------------------------------------------
/client/src/scenes/SceneSelector.ts:
--------------------------------------------------------------------------------
1 | import Phaser from "phaser";
2 |
3 | export class SceneSelector extends Phaser.Scene {
4 |
5 | parts = {
6 | '1': "Basic Player Movement",
7 | '2': "Interpolation",
8 | '3': "Client-predicted Input",
9 | '4': "Fixed Tickrate",
10 | };
11 |
12 | constructor() {
13 | super({ key: "selector", active: true });
14 | }
15 |
16 | preload() {
17 | // update menu background color
18 | this.cameras.main.setBackgroundColor(0x000000);
19 |
20 | // preload demo assets
21 | // this.load.image('ship_0001', 'assets/ship_0001.png');
22 | this.load.image('ship_0001', 'https://cdn.glitch.global/3e033dcd-d5be-4db4-99e8-086ae90969ec/ship_0001.png?v=1649945243288');
23 | }
24 |
25 | create() {
26 | // automatically navigate to hash scene if provided
27 | if (window.location.hash) {
28 | this.runScene(window.location.hash.substring(1));
29 | return;
30 | }
31 |
32 | const textStyle: Phaser.Types.GameObjects.Text.TextStyle = {
33 | color: "#ff0000",
34 | fontSize: "32px",
35 | // fontSize: "24px",
36 | fontFamily: "Arial"
37 | };
38 |
39 | for (let partNum in this.parts) {
40 | const index = parseInt(partNum) - 1;
41 | const label = this.parts[partNum];
42 |
43 | // this.add.text(32, 32 + 32 * index, `Part ${partNum}: ${label}`, textStyle)
44 | this.add.text(130, 150 + 70 * index, `Part ${partNum}: ${label}`, textStyle)
45 | .setInteractive()
46 | .setPadding(6)
47 | .on("pointerdown", () => {
48 | this.runScene(`part${partNum}`);
49 | });
50 | }
51 | }
52 |
53 | runScene(key: string) {
54 | this.game.scene.switch("selector", key)
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Enable incremental compilation */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 |
26 | /* Modules */
27 | "module": "commonjs", /* Specify what module code is generated. */
28 | // "rootDir": "./", /* Specify the root folder within your source files. */
29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
36 | // "resolveJsonModule": true, /* Enable importing .json files */
37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */
38 |
39 | /* JavaScript Support */
40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
43 |
44 | /* Emit */
45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50 | // "outDir": "./", /* Specify an output folder for all emitted files. */
51 | // "removeComments": true, /* Disable emitting comments. */
52 | // "noEmit": true, /* Disable emitting files from a compilation. */
53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
61 | // "newLine": "crlf", /* Set the newline character for emitting files. */
62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
68 |
69 | /* Interop Constraints */
70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
72 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
74 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
75 |
76 | /* Type Checking */
77 | "strict": false, /* Enable all strict type-checking options. */
78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
96 |
97 | /* Completeness */
98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/server/.env.development:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
--------------------------------------------------------------------------------
/server/.env.production:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/server/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to Colyseus!
2 |
3 | This project has been created using [⚔️ `create-colyseus-app`](https://github.com/colyseus/create-colyseus-app/) - an npm init template for kick starting a Colyseus project in TypeScript.
4 |
5 | [Documentation](http://docs.colyseus.io/)
6 |
7 | ## :crossed_swords: Usage
8 |
9 | ```
10 | npm start
11 | ```
12 |
13 | ## Structure
14 |
15 | - `index.ts`: main entry point, register an empty room handler and attach [`@colyseus/monitor`](https://github.com/colyseus/colyseus-monitor)
16 | - `src/rooms/MyRoom.ts`: an empty room handler for you to implement your logic
17 | - `src/rooms/schema/MyRoomState.ts`: an empty schema used on your room's state.
18 | - `loadtest/example.ts`: scriptable client for the loadtest tool (see `npm run loadtest`)
19 | - `package.json`:
20 | - `scripts`:
21 | - `npm start`: runs `ts-node-dev index.ts`
22 | - `npm test`: runs mocha test suite
23 | - `npm run loadtest`: runs the [`@colyseus/loadtest`](https://github.com/colyseus/colyseus-loadtest/) tool for testing the connection, using the `loadtest/example.ts` script.
24 | - `tsconfig.json`: TypeScript configuration file
25 |
26 |
27 | ## License
28 |
29 | MIT
30 |
--------------------------------------------------------------------------------
/server/loadtest/example.ts:
--------------------------------------------------------------------------------
1 | import { Room, Client } from "colyseus.js";
2 |
3 | export function requestJoinOptions (this: Client, i: number) {
4 | return { requestNumber: i };
5 | }
6 |
7 | export function onJoin(this: Room) {
8 | console.log(this.sessionId, "joined.");
9 |
10 | this.onMessage("*", (type, message) => {
11 | console.log(this.sessionId, "received:", type, message);
12 | });
13 | }
14 |
15 | export function onLeave(this: Room) {
16 | console.log(this.sessionId, "left.");
17 | }
18 |
19 | export function onError(this: Room, err: any) {
20 | console.log(this.sessionId, "!! ERROR !!", err.message);
21 | }
22 |
23 | export function onStateChange(this: Room, state: any) {
24 | console.log(this.sessionId, "new state:", state);
25 | }
26 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "my-app",
4 | "version": "1.0.0",
5 | "description": "npm init template for bootstrapping an empty Colyseus project",
6 | "main": "lib/index.js",
7 | "scripts": {
8 | "start": "tsx watch src/index.ts",
9 | "loadtest": "colyseus-loadtest loadtest/example.ts --room my_room --numClients 2",
10 | "build": "npm run clean && tsc",
11 | "clean": "node node_modules/rimraf/bin lib",
12 | "test": "mocha -r tsx test/**_test.ts --exit --timeout 15000"
13 | },
14 | "author": "",
15 | "license": "UNLICENSED",
16 | "bugs": {
17 | "url": "https://github.com/colyseus/create-colyseus/issues"
18 | },
19 | "homepage": "https://github.com/colyseus/create-colyseus#readme",
20 | "devDependencies": {
21 | "@colyseus/loadtest": "^0.16.0",
22 | "@colyseus/testing": "^0.16.0",
23 | "@types/cors": "^2.8.6",
24 | "@types/express": "^4.17.1",
25 | "@types/mocha": "^8.2.3",
26 | "copyfiles": "^2.4.1",
27 | "mocha": "^9.0.2",
28 | "rimraf": "^2.7.1",
29 | "tsx": "^3.12.7",
30 | "typescript": "^4.6.3"
31 | },
32 | "dependencies": {
33 | "@colyseus/core": "^0.16.0",
34 | "@colyseus/monitor": "^0.16.0",
35 | "@colyseus/playground": "^0.16.0",
36 | "@colyseus/tools": "^0.16.0",
37 | "colyseus": "^0.16.0",
38 | "cors": "^2.8.5",
39 | "express": "^4.16.4"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/server/src/app.config.ts:
--------------------------------------------------------------------------------
1 | import config from "@colyseus/tools";
2 | import { Server } from "@colyseus/core";
3 | import { monitor } from "@colyseus/monitor";
4 | import { playground } from "@colyseus/playground";
5 |
6 | /**
7 | * Import your Room files
8 | */
9 | import { Part1Room } from "./rooms/Part1Room";
10 | import { Part2Room } from "./rooms/Part2Room";
11 | import { Part3Room } from "./rooms/Part3Room";
12 | import { Part4Room } from "./rooms/Part4Room";
13 |
14 | let gameServerRef: Server;
15 | let latencySimulationMs: number = 0;
16 |
17 | export default config({
18 | options: {
19 | // devMode: true,
20 | },
21 |
22 | initializeGameServer: (gameServer) => {
23 | /**
24 | * Define your room handlers:
25 | */
26 | gameServer.define('part1_room', Part1Room);
27 | gameServer.define('part2_room', Part2Room);
28 | gameServer.define('part3_room', Part3Room);
29 | gameServer.define('part4_room', Part4Room);
30 |
31 | //
32 | // keep gameServer reference, so we can
33 | // call `.simulateLatency()` later through an http route
34 | //
35 | gameServerRef = gameServer;
36 | },
37 |
38 | initializeExpress: (app) => {
39 | /**
40 | * Bind your custom express routes here:
41 | */
42 | app.get("/hello", (req, res) => {
43 | res.send("It's time to kick ass and chew bubblegum!");
44 | });
45 |
46 | // these latency methods are for development purpose only.
47 | app.get("/latency", (req, res) => res.json(latencySimulationMs));
48 | app.get("/simulate-latency/:milliseconds", (req, res) => {
49 | latencySimulationMs = parseInt(req.params.milliseconds || "100");
50 |
51 | // enable latency simulation
52 | gameServerRef.simulateLatency(latencySimulationMs);
53 |
54 | res.json({ success: true });
55 | });
56 |
57 | if (process.env.NODE_ENV !== "production") {
58 | app.use("/", playground());
59 | }
60 |
61 | /**
62 | * Bind @colyseus/monitor
63 | * It is recommended to protect this route with a password.
64 | * Read more: https://docs.colyseus.io/tools/monitor/
65 | */
66 | app.use("/colyseus", monitor());
67 | },
68 |
69 |
70 | beforeListen: () => {
71 | /**
72 | * Before before gameServer.listen() is called.
73 | */
74 | }
75 | });
76 |
--------------------------------------------------------------------------------
/server/src/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * IMPORTANT:
3 | * ---------
4 | * Do not manually edit this file if you'd like to use Colyseus Cloud
5 | *
6 | * If you're self-hosting (without Colyseus Cloud), you can manually instantiate a
7 | * Colyseus Server as documented here: 👉 https://docs.colyseus.io/server/api/#constructor-options
8 | */
9 | import { listen } from "@colyseus/tools";
10 |
11 | // Import arena config
12 | import appConfig from "./app.config";
13 |
14 | // Create and listen on 2567 (or PORT environment variable.)
15 | listen(appConfig);
16 |
--------------------------------------------------------------------------------
/server/src/rooms/Part1Room.ts:
--------------------------------------------------------------------------------
1 | import { Room, Client } from "colyseus";
2 | import { Schema, type, MapSchema } from "@colyseus/schema";
3 |
4 | export class Player extends Schema {
5 | @type("number") x: number;
6 | @type("number") y: number;
7 | }
8 |
9 | export class MyRoomState extends Schema {
10 | @type("number") mapWidth: number;
11 | @type("number") mapHeight: number;
12 | @type({ map: Player }) players = new MapSchema();
13 | }
14 |
15 | export class Part1Room extends Room {
16 | state = new MyRoomState();
17 |
18 | onCreate (options: any) {
19 | // set map dimensions
20 | this.state.mapWidth = 800;
21 | this.state.mapHeight = 600;
22 |
23 | // handle player input
24 | this.onMessage(0, (client, input) => {
25 | const player = this.state.players.get(client.sessionId);
26 | const velocity = 2;
27 |
28 | if (input.left) {
29 | player.x -= velocity;
30 |
31 | } else if (input.right) {
32 | player.x += velocity;
33 | }
34 |
35 | if (input.up) {
36 | player.y -= velocity;
37 |
38 | } else if (input.down) {
39 | player.y += velocity;
40 | }
41 |
42 | });
43 | }
44 |
45 | onJoin (client: Client, options: any) {
46 | console.log(client.sessionId, "joined!");
47 |
48 | // create player at random position.
49 | const player = new Player();
50 | player.x = Math.random() * this.state.mapWidth;
51 | player.y = Math.random() * this.state.mapHeight;
52 |
53 | this.state.players.set(client.sessionId, player);
54 | }
55 |
56 | onLeave (client: Client, consented: boolean) {
57 | console.log(client.sessionId, "left!");
58 | this.state.players.delete(client.sessionId);
59 | }
60 |
61 | onDispose() {
62 | console.log("room", this.roomId, "disposing...");
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/server/src/rooms/Part2Room.ts:
--------------------------------------------------------------------------------
1 | import { Room, Client } from "colyseus";
2 | import { Schema, type, MapSchema } from "@colyseus/schema";
3 |
4 | export class Player extends Schema {
5 | @type("number") x: number;
6 | @type("number") y: number;
7 | }
8 |
9 | export class MyRoomState extends Schema {
10 | @type("number") mapWidth: number;
11 | @type("number") mapHeight: number;
12 | @type({ map: Player }) players = new MapSchema();
13 | }
14 |
15 | export class Part2Room extends Room {
16 | state = new MyRoomState();
17 |
18 | onCreate (options: any) {
19 | // set map dimensions
20 | this.state.mapWidth = 800;
21 | this.state.mapHeight = 600;
22 |
23 | this.onMessage(0, (client, input) => {
24 | // handle player input
25 | const player = this.state.players.get(client.sessionId);
26 | const velocity = 2;
27 |
28 | if (input.left) {
29 | player.x -= velocity;
30 |
31 | } else if (input.right) {
32 | player.x += velocity;
33 | }
34 |
35 | if (input.up) {
36 | player.y -= velocity;
37 |
38 | } else if (input.down) {
39 | player.y += velocity;
40 | }
41 |
42 | });
43 | }
44 |
45 | onJoin (client: Client, options: any) {
46 | console.log(client.sessionId, "joined!");
47 |
48 | // create player at random position.
49 | const player = new Player();
50 | player.x = Math.random() * this.state.mapWidth;
51 | player.y = Math.random() * this.state.mapHeight;
52 |
53 | this.state.players.set(client.sessionId, player);
54 | }
55 |
56 | onLeave (client: Client, consented: boolean) {
57 | console.log(client.sessionId, "left!");
58 | this.state.players.delete(client.sessionId);
59 | }
60 |
61 | onDispose() {
62 | console.log("room", this.roomId, "disposing...");
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/server/src/rooms/Part3Room.ts:
--------------------------------------------------------------------------------
1 | import { Room, Client } from "colyseus";
2 | import { Schema, type, MapSchema } from "@colyseus/schema";
3 |
4 | export interface InputData {
5 | left: false;
6 | right: false;
7 | up: false;
8 | down: false;
9 | tick: number;
10 | }
11 |
12 | export class Player extends Schema {
13 | @type("number") x: number;
14 | @type("number") y: number;
15 | @type("number") tick: number;
16 |
17 | inputQueue: InputData[] = [];
18 | }
19 |
20 | export class MyRoomState extends Schema {
21 | @type("number") mapWidth: number;
22 | @type("number") mapHeight: number;
23 | @type({ map: Player }) players = new MapSchema();
24 | }
25 |
26 | export class Part3Room extends Room {
27 | state = new MyRoomState();
28 | fixedTimeStep = 1000 / 60;
29 |
30 | onCreate (options: any) {
31 | // set map dimensions
32 | this.state.mapWidth = 800;
33 | this.state.mapHeight = 600;
34 |
35 | this.onMessage(0, (client, input) => {
36 | // handle player input
37 | const player = this.state.players.get(client.sessionId);
38 |
39 | // enqueue input to user input buffer.
40 | player.inputQueue.push(input);
41 | });
42 |
43 | this.setSimulationInterval((deltaTime) => {
44 | this.update(deltaTime);
45 | });
46 | }
47 |
48 | update(deltaTime: number) {
49 | const velocity = 2;
50 |
51 | this.state.players.forEach(player => {
52 | let input: InputData;
53 |
54 | // dequeue player inputs
55 | while (input = player.inputQueue.shift()) {
56 | if (input.left) {
57 | player.x -= velocity;
58 |
59 | } else if (input.right) {
60 | player.x += velocity;
61 | }
62 |
63 | if (input.up) {
64 | player.y -= velocity;
65 |
66 | } else if (input.down) {
67 | player.y += velocity;
68 | }
69 |
70 | player.tick = input.tick;
71 | }
72 | });
73 | }
74 |
75 | onJoin (client: Client, options: any) {
76 | console.log(client.sessionId, "joined!");
77 |
78 | const player = new Player();
79 | player.x = Math.random() * this.state.mapWidth;
80 | player.y = Math.random() * this.state.mapHeight;
81 |
82 | this.state.players.set(client.sessionId, player);
83 | }
84 |
85 | onLeave (client: Client, consented: boolean) {
86 | console.log(client.sessionId, "left!");
87 | this.state.players.delete(client.sessionId);
88 | }
89 |
90 | onDispose() {
91 | console.log("room", this.roomId, "disposing...");
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/server/src/rooms/Part4Room.ts:
--------------------------------------------------------------------------------
1 | import { Room, Client } from "colyseus";
2 | import { Schema, type, MapSchema } from "@colyseus/schema";
3 |
4 | export interface InputData {
5 | left: false;
6 | right: false;
7 | up: false;
8 | down: false;
9 | tick: number;
10 | }
11 |
12 | export class Player extends Schema {
13 | @type("number") x: number;
14 | @type("number") y: number;
15 | @type("number") tick: number;
16 | inputQueue: InputData[] = [];
17 | }
18 |
19 | export class MyRoomState extends Schema {
20 | @type("number") mapWidth: number;
21 | @type("number") mapHeight: number;
22 | @type({ map: Player }) players = new MapSchema();
23 | }
24 |
25 | export class Part4Room extends Room {
26 | state = new MyRoomState();
27 | fixedTimeStep = 1000 / 60;
28 |
29 | onCreate (options: any) {
30 | // set map dimensions
31 | this.state.mapWidth = 800;
32 | this.state.mapHeight = 600;
33 |
34 | this.onMessage(0, (client, input) => {
35 | // handle player input
36 | const player = this.state.players.get(client.sessionId);
37 |
38 | // enqueue input to user input buffer.
39 | player.inputQueue.push(input);
40 | });
41 |
42 | let elapsedTime = 0;
43 | this.setSimulationInterval((deltaTime) => {
44 | elapsedTime += deltaTime;
45 |
46 | while (elapsedTime >= this.fixedTimeStep) {
47 | elapsedTime -= this.fixedTimeStep;
48 | this.fixedTick(this.fixedTimeStep);
49 | }
50 | });
51 | }
52 |
53 | fixedTick(timeStep: number) {
54 | const velocity = 2;
55 |
56 | this.state.players.forEach(player => {
57 | let input: InputData;
58 |
59 | // dequeue player inputs
60 | while (input = player.inputQueue.shift()) {
61 | if (input.left) {
62 | player.x -= velocity;
63 |
64 | } else if (input.right) {
65 | player.x += velocity;
66 | }
67 |
68 | if (input.up) {
69 | player.y -= velocity;
70 |
71 | } else if (input.down) {
72 | player.y += velocity;
73 | }
74 |
75 | player.tick = input.tick;
76 | }
77 | });
78 | }
79 |
80 | onJoin (client: Client, options: any) {
81 | console.log(client.sessionId, "joined!");
82 |
83 | const player = new Player();
84 | player.x = Math.random() * this.state.mapWidth;
85 | player.y = Math.random() * this.state.mapHeight;
86 |
87 | this.state.players.set(client.sessionId, player);
88 | }
89 |
90 | onLeave (client: Client, consented: boolean) {
91 | console.log(client.sessionId, "left!");
92 | this.state.players.delete(client.sessionId);
93 | }
94 |
95 | onDispose() {
96 | console.log("room", this.roomId, "disposing...");
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/server/test/MyRoom_test.ts:
--------------------------------------------------------------------------------
1 | import assert from "assert";
2 | import { ColyseusTestServer, boot } from "@colyseus/testing";
3 |
4 | // import your "arena.config.ts" file here.
5 | import appConfig from "../src/arena.config";
6 | import { MyRoomState } from "../src/rooms/schema/MyRoomState";
7 |
8 | describe("testing your Colyseus app", () => {
9 | let colyseus: ColyseusTestServer;
10 |
11 | before(async () => colyseus = await boot(appConfig));
12 | after(async () => colyseus.shutdown());
13 |
14 | beforeEach(async () => await colyseus.cleanup());
15 |
16 | it("connecting into a room", async () => {
17 | // `room` is the server-side Room instance reference.
18 | const room = await colyseus.createRoom("my_room", {});
19 |
20 | // `client1` is the client-side `Room` instance reference (same as JavaScript SDK)
21 | const client1 = await colyseus.connectTo(room);
22 |
23 | // make your assertions
24 | assert.strictEqual(client1.sessionId, room.clients[0].sessionId);
25 |
26 | // wait for state sync
27 | await room.waitForNextPatch();
28 |
29 | assert.deepStrictEqual({ mySynchronizedProperty: "Hello world" }, client1.state.toJSON());
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/server/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "build",
4 | "target": "ESNext",
5 | "resolveJsonModule":true,
6 | "module": "ESNext",
7 | "moduleResolution": "node",
8 | "strict": true,
9 | "allowJs": true,
10 | "strictNullChecks": false,
11 | "esModuleInterop": true,
12 | "experimentalDecorators": true,
13 | "skipLibCheck": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "useDefineForClassFields": false
16 | },
17 | "include": [
18 | "src"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------