├── .github ├── actions │ └── bump-manifest-version.js └── workflows │ └── cd.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── fxmanifest.lua ├── game ├── client │ ├── bootstrap.ts │ ├── event.ts │ ├── tsconfig.json │ ├── types.ts │ └── utils.ts ├── nui │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── capture-stream.ts │ │ ├── capture.ts │ │ ├── main.ts │ │ ├── style.css │ │ ├── types.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.js ├── package.json ├── scripts │ ├── esbuild.config.js │ ├── handle-build.js │ └── node-paths.js └── server │ ├── bootstrap.ts │ ├── context.ts │ ├── event.ts │ ├── export.ts │ ├── koa-router.ts │ ├── multer.ts │ ├── tsconfig.json │ ├── types.ts │ └── upload-store.ts ├── package.json ├── packages ├── gameview │ ├── index.ts │ ├── package.json │ ├── tsconfig.json │ └── webgl.ts ├── react │ ├── index.ts │ ├── package.json │ ├── tsconfig.json │ ├── useCaptureScreen.ts │ └── utils.ts └── typescript-config │ ├── base.json │ ├── package.json │ └── react.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json /.github/actions/bump-manifest-version.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | const version = process.env.TGT_RELEASE_VERSION; 4 | const newVersion = version.replace("v", ""); 5 | 6 | const manifestFile = fs.readFileSync("fxmanifest.lua", { encoding: "utf8" }); 7 | 8 | const newFileContent = manifestFile.replace( 9 | /\bversion\s+(.*)$/gm, 10 | `version '${newVersion}'` 11 | ); 12 | 13 | fs.writeFileSync("fxmanifest.lua", newFileContent); -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | tags: 9 | - "v*.*.*" 10 | 11 | jobs: 12 | create-release: 13 | name: Build and Create Tagged release 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Install archive tools 18 | run: sudo apt install zip 19 | 20 | - name: Checkout source code 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | ref: ${{ github.event.repository.default_branch }} 25 | 26 | - name: Install pnpm 27 | uses: pnpm/action-setup@v4.0.0 28 | with: 29 | version: 9.11.0 30 | 31 | - name: Get variables 32 | id: get_vars 33 | run: | 34 | echo '::set-output name=SHORT_SHA::$(git rev-parse --short HEAD)' 35 | echo '::set-output name=DATE::$(date +'%D')' 36 | 37 | - name: Setup node 38 | uses: actions/setup-node@v4 39 | with: 40 | node-version: 21.x 41 | cache: "pnpm" 42 | 43 | - name: Install dependencies 44 | run: pnpm i --frozen-lockfile 45 | 46 | - name: Run build 47 | run: pnpm build 48 | env: 49 | CI: false 50 | 51 | - name: Bump manifest version 52 | run: node .github/actions/bump-manifest-version.js 53 | env: 54 | TGT_RELEASE_VERSION: ${{ github.ref_name }} 55 | 56 | - name: Push manifest change 57 | uses: EndBug/add-and-commit@v8 58 | with: 59 | add: fxmanifest.lua 60 | push: true 61 | author_name: Manifest Bumper 62 | message: "chore: bump manifest version to ${{ github.ref_name }}" 63 | 64 | - name: Update tag ref 65 | uses: EndBug/latest-tag@latest 66 | with: 67 | ref: ${{ github.ref_name }} 68 | 69 | - name: Bundle files 70 | run: | 71 | mkdir -p ./temp/screencapture 72 | mkdir -p ./temp/screencapture/game 73 | mkdir -p ./temp/screencapture/game/nui 74 | cp ./{README.md,LICENSE,fxmanifest.lua} ./temp/screencapture 75 | cp -r ./game/dist ./temp/screencapture/game/dist 76 | cp -r ./game/nui/dist ./temp/screencapture/game/nui/dist 77 | cd ./temp && zip -r ../screencapture.zip ./screencapture 78 | 79 | - name: Create Release 80 | uses: "marvinpinto/action-automatic-releases@v1.2.1" 81 | id: auto_release 82 | with: 83 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 84 | title: "${{ env.RELEASE_VERSION }}" 85 | prerelease: false 86 | files: screencapture.zip 87 | 88 | env: 89 | CI: false 90 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .turbo 4 | .idea 5 | router-local.ts -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsxSingleQuote": false, 3 | "singleQuote": true, 4 | "useTabs": false, 5 | "semi": true, 6 | "tabWidth": 2, 7 | "printWidth": 120, 8 | "bracketSpacing": true 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScreenCapture 2 | 3 | ScreenCapture is a being built as a replacement for screenshot-basic in FiveM. 4 | 5 | ## Why build something new? 6 | 7 | I'll explain this later, but breifly - Screenshot-Basic is no longer maintained, has it's issues. It's a nightmare for almost everyone to get up and running for some reason (blame FXServer yarn) and it's not up-to-date with anything. 8 | 9 | ## How to use 10 | 11 | You can use the server-side exports, or the `screenshot-basic` backwards compatiable client-export: `requestScreenshotUpload`. 12 | 13 | ### JavaScript / TypeScript 14 | 15 | Converting Base64 to Blob/Buffer is easy enough with Node, but Lua ScRT in FiveM doesn't really offer that functionality, so if you wish to use the `serverCapture` export, you'll need to use Base64. More on that later. 16 | 17 | ### serverCapture (server-side export) 18 | 19 | | Parameter | Type | Description | 20 | | ---------- | ------------------------ | ------------------------------------------------------------------------- | 21 | | `source` | string | Player to capture | 22 | | `options` | object/table | Configuration options for the capture | 23 | | `callback` | function | A function invoked with the captured data | 24 | | `dataType` | string (default: base64) | What data should be returned through the callback: `'base64'` or `'blob'` | 25 | 26 | #### Options 27 | 28 | The `options` argument accepts an object with the following fields: 29 | 30 | | Field | Type | Default | Description | 31 | | ----------- | -------------- | -------- | ------------------------------------------------------------------------- | 32 | | `headers` | `object/table` | `null` | Optional HTTP headers to include in the capture request. | 33 | | `formField` | `string` | `null` | The form field name to be used when uploading the captured data. | 34 | | `filename` | `string` | `null` | Specifies the name of the file when saving or transmitting captured data. | 35 | | `encoding` | `string` | `'webp'` | Specifies the encoding format for the captured image (e.g., `'webp'`). | 36 | 37 | ```ts 38 | RegisterCommand( 39 | 'capture', 40 | (_: string, args: string[]) => { 41 | exp.screencapture.serverCapture( 42 | args[0], 43 | { encoding: 'webp' }, 44 | (data: string | Buffer) => { 45 | data = Buffer.from(data as ArrayBuffer); 46 | 47 | fs.writeFileSync('./blob_image.webp', data); 48 | console.log(`File saved`); 49 | }, 50 | 'blob', 51 | ); 52 | }, 53 | false, 54 | ); 55 | ``` 56 | 57 | ### remoteUpload (server-side export) 58 | 59 | | Parameter | Type | Description | 60 | | ---------- | ------------------------ | ------------------------------------------------------------------------ | 61 | | `source` | string | Player to capture | 62 | | `url` | string | The upload URL | 63 | | `options` | object/table | Configuration options for the capture | 64 | | `callback` | function | Callback returning the HTTP response in JSON | 65 | | `dataType` | string (default: base64) | What data type should be used to upload the file: `'base64'` or `'blob'` | 66 | 67 | #### Options 68 | 69 | The `options` argument accepts an object with the following fields: 70 | 71 | | Field | Type | Default | Description | 72 | | ----------- | -------------- | -------- | ------------------------------------------------------------------------- | 73 | | `headers` | `object/table` | `null` | Optional HTTP headers to include in the capture request. | 74 | | `formField` | `string` | `null` | The form field name to be used when uploading the captured data. | 75 | | `filename` | `string` | `null` | Specifies the name of the file when saving or transmitting captured data. | 76 | | `encoding` | `string` | `'webp'` | Specifies the encoding format for the captured image (e.g., `'webp'`). | 77 | 78 | ```ts 79 | RegisterCommand( 80 | 'remoteCapture', 81 | (_: string, args: string[]) => { 82 | exp.screencapture.remoteUpload( 83 | args[0], 84 | 'https://api.fivemanage.com/api/image', 85 | { 86 | encoding: 'webp', 87 | headers: { 88 | Authorization: '', 89 | }, 90 | }, 91 | (data: any) => { 92 | console.log(data); 93 | }, 94 | 'blob', 95 | ); 96 | }, 97 | false, 98 | ); 99 | ``` 100 | 101 | ## Lua example with `remoteUpload` 102 | 103 | ```lua 104 | exports.screencapture:remoteUpload(args[1], "https://api.fivemanage.com/api/image", { 105 | encoding = "webp", 106 | headers = { 107 | ["Authorization"] = "" 108 | } 109 | }, function(data) 110 | print(data.url) 111 | end, "blob") 112 | ``` 113 | 114 | ## Screenshot Basic compatibility 115 | 116 | ### This is NOT recommend to use, as you risk expsoing tokens to clients. 117 | 118 | ### requestScreenshotUpload (client-side export) 119 | 120 | ```lua 121 | exports['screencapture']:requestScreenshotUpload('https://api.fivemanage.com/api/image', 'file', { 122 | headers = { 123 | ["Authorization"] = API_TOKEN 124 | }, 125 | encoding = "webp" 126 | }, function(data) 127 | local resp = json.decode(data) 128 | print(resp.url); 129 | TriggerEvent('chat:addMessage', { template = '', args = { resp.url } }) 130 | end) 131 | ``` 132 | 133 | ## What will this include? 134 | 135 | 1. Server exports both for getting image data and uploading images/videos from the server 136 | 2. Client exports (maybe) 137 | 3. Upload images or videos from NUI, just more secure. 138 | 4. React, Svelt and Vue packages + publishing all internal packages like @screencapture/gameview (SoonTM) 139 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'bodacious' 2 | 3 | version '0.3.2' 4 | 5 | game "gta5" 6 | 7 | client_script "game/dist/client.js" 8 | server_script "game/dist/server.js" 9 | 10 | ui_page "game/nui/dist/index.html" 11 | files { 12 | "game/nui/dist/index.html", 13 | "game/nui/dist/**/*", 14 | } -------------------------------------------------------------------------------- /game/client/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { netEventController } from './event'; 2 | import { CaptureRequest, RequestScreenshotUploadCB } from './types'; 3 | import { uuidv4 } from './utils'; 4 | 5 | const clientCaptureMap = new Map(); 6 | 7 | onNet('screencapture:captureScreen', (token: string, options: object, dataType: string) => { 8 | SendNUIMessage({ 9 | ...options, 10 | uploadToken: token, 11 | dataType, 12 | action: 'capture', 13 | serverEndpoint: `http://${GetCurrentServerEndpoint()}/${GetCurrentResourceName()}/image`, 14 | }); 15 | }); 16 | 17 | onNet('screencapture:INTERNAL_uploadComplete', (response: unknown, correlationId: string) => { 18 | const callback = clientCaptureMap.get(correlationId); 19 | if (callback) { 20 | callback(response); 21 | clientCaptureMap.delete(correlationId); 22 | } 23 | }); 24 | 25 | global.exports( 26 | 'requestScreenshotUpload', 27 | async ( 28 | url: string, 29 | formField: string, 30 | optionsOrCB: CaptureRequest | RequestScreenshotUploadCB, 31 | callback: RequestScreenshotUploadCB, 32 | ) => { 33 | // forgive me 34 | const isOptions = typeof optionsOrCB === 'object' && optionsOrCB !== null; 35 | const realOptions = isOptions 36 | ? (optionsOrCB as CaptureRequest) 37 | : ({ headers: {}, encoding: 'webp' } as CaptureRequest); 38 | const realCallback = isOptions 39 | ? (callback as RequestScreenshotUploadCB) 40 | : (optionsOrCB as RequestScreenshotUploadCB); 41 | 42 | const correlationId = uuidv4(); 43 | clientCaptureMap.set(correlationId, realCallback); 44 | 45 | const token = await netEventController('screencapture:INTERNAL_requestUploadToken', { 46 | ...realOptions, 47 | formField, 48 | url, 49 | correlationId, 50 | }); 51 | 52 | if (!token) { 53 | return console.error('Failed to get upload token'); 54 | } 55 | 56 | return createImageCaptureMessage({ 57 | ...realOptions, 58 | formField, 59 | url, 60 | uploadToken: token, 61 | dataType: 'blob', 62 | }); 63 | }, 64 | ); 65 | 66 | function createImageCaptureMessage(options: CaptureRequest) { 67 | SendNUIMessage({ 68 | ...options, 69 | action: 'capture', 70 | serverEndpoint: `http://${GetCurrentServerEndpoint()}/${GetCurrentResourceName()}/image`, 71 | }); 72 | } 73 | 74 | /* onNet("screencapture:captureStream", (token: string, options: object) => { 75 | SendNUIMessage({ 76 | ...options, 77 | uploadToken: token, 78 | action: 'capture-stream-start', 79 | serverEndpoint: `http://${GetCurrentServerEndpoint()}/${GetCurrentResourceName()}/stream`, 80 | }); 81 | }) */ 82 | 83 | /* onNet("screencapture:INTERNAL:stopCaptureStream", () => { 84 | SendNUIMessage({ 85 | action: 'capture-stream-stop', 86 | }) 87 | }) */ 88 | -------------------------------------------------------------------------------- /game/client/event.ts: -------------------------------------------------------------------------------- 1 | import { uuidv4 } from './utils'; 2 | 3 | export function uniqueId() { 4 | return uuidv4(); 5 | } 6 | 7 | export async function netEventController(event: string, ...args: any[]): Promise { 8 | return new Promise((resolve) => { 9 | const eventId = uniqueId(); 10 | const listenName = `${event}:${eventId}`; 11 | 12 | emitNet(event, listenName, ...args); 13 | 14 | const eventListener = (data: TResponse) => { 15 | removeEventListener(listenName, eventListener); 16 | resolve(data); 17 | }; 18 | 19 | onNet(listenName, eventListener); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /game/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@screencapture/typescript-config/base.json", 3 | "compilerOptions": { 4 | "types": ["@types/node", "@citizenfx/client"], 5 | "moduleResolution": "node", 6 | "module": "CommonJS" 7 | }, 8 | "include": ["**/*.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /game/client/types.ts: -------------------------------------------------------------------------------- 1 | export type RequestScreenshotUploadCB = (response: unknown) => void; 2 | 3 | type Encoding = 'webp' | 'jpg' | 'png'; 4 | 5 | export type CaptureRequest = { 6 | action: 'capture'; 7 | url: string; 8 | encoding: Encoding; 9 | quality: number; 10 | headers: Headers; 11 | uploadToken: string; 12 | serverEndpoint: string; 13 | filename: string; 14 | formField: string; 15 | dataType: 'blob' | 'base64'; 16 | }; 17 | 18 | export type RequestUploadToken = { 19 | url: string; 20 | encoding: Encoding; 21 | quality: number; 22 | headers: Headers; 23 | correlationId: string; 24 | }; 25 | -------------------------------------------------------------------------------- /game/client/utils.ts: -------------------------------------------------------------------------------- 1 | export const uuidv4 = (): string => { 2 | let uuid = ''; 3 | for (let ii = 0; ii < 32; ii += 1) { 4 | switch (ii) { 5 | case 8: 6 | case 20: 7 | uuid += '-'; 8 | uuid += ((Math.random() * 16) | 0).toString(16); 9 | break; 10 | case 12: 11 | uuid += '-'; 12 | uuid += '4'; 13 | break; 14 | case 16: 15 | uuid += '-'; 16 | uuid += ((Math.random() * 4) | 8).toString(16); 17 | break; 18 | default: 19 | uuid += ((Math.random() * 16) | 0).toString(16); 20 | } 21 | } 22 | return uuid; 23 | }; -------------------------------------------------------------------------------- /game/nui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /game/nui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ScreenCapture 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /game/nui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@screencapture/nui", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^5.5.3", 13 | "vite": "^5.4.1" 14 | }, 15 | "dependencies": { 16 | "@screencapture/gameview": "workspace:*" 17 | } 18 | } -------------------------------------------------------------------------------- /game/nui/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/nui/src/capture-stream.ts: -------------------------------------------------------------------------------- 1 | import { createGameView } from '@screencapture/gameview'; 2 | import { CaptureStreamActions } from './types'; 3 | 4 | type CaptureStreamRequest = { 5 | action: CaptureStreamActions; 6 | url: string; 7 | headers: Headers; 8 | uploadToken: string; 9 | serverEndpoint: string; 10 | formField: string; 11 | }; 12 | 13 | export class CaptureStream { 14 | #gameView: any; 15 | #canvas: HTMLCanvasElement | null = null; 16 | #mediaStream: MediaStream | null = null; 17 | #recorder: MediaRecorder | null = null; 18 | #chunks: Blob[] = []; 19 | 20 | start() { 21 | window.addEventListener('message', (event) => { 22 | const data = event.data as CaptureStreamRequest; 23 | 24 | if (data.action === CaptureStreamActions.Start) { 25 | console.log('got message to start streaming'); 26 | this.stream(data); 27 | } 28 | 29 | if (data.action === CaptureStreamActions.Stop) { 30 | this.stop(); 31 | } 32 | }); 33 | 34 | window.addEventListener('resize', () => { 35 | if (this.#gameView) { 36 | this.#gameView.resize(window.innerWidth, window.innerHeight); 37 | } 38 | }); 39 | } 40 | 41 | stream(request: CaptureStreamRequest) { 42 | this.#canvas = document.createElement('canvas'); 43 | this.#canvas.width = window.innerWidth; 44 | this.#canvas.height = window.innerHeight; 45 | 46 | this.#gameView = createGameView(this.#canvas); 47 | 48 | if (!this.#canvas) return console.error('Failed to find canvas'); 49 | 50 | this.#mediaStream = this.#canvas.captureStream(30); 51 | this.#recorder = new MediaRecorder(this.#mediaStream, { mimeType: 'video/webm' }); 52 | 53 | this.#recorder.ondataavailable = (ev) => { 54 | if (ev.data.size > 0) { 55 | console.log('data size', ev.data.size); 56 | this.#chunks.push(ev.data); 57 | // send chunk to http handler with corrID 58 | } 59 | }; 60 | 61 | this.#recorder.onerror = (err) => { 62 | console.error('oops', err); 63 | }; 64 | 65 | this.#recorder.onstop = async () => { 66 | console.log('rec stop'); 67 | await this.uploadVideo(request); 68 | if (this.#canvas) return this.#canvas.remove(); 69 | }; 70 | 71 | this.#recorder.start(500); 72 | } 73 | 74 | stop() { 75 | if (this.#recorder && this.#recorder.state !== 'inactive') { 76 | this.#recorder.stop(); 77 | 78 | if (this.#canvas) { 79 | this.#canvas?.remove(); 80 | } 81 | } 82 | } 83 | 84 | async uploadVideo(request: CaptureStreamRequest) { 85 | console.log('chunk len', this.#chunks.length); 86 | 87 | const blob = new Blob(this.#chunks, { type: this.#recorder?.mimeType }); 88 | console.log('blob size', blob.size); 89 | 90 | if (blob.size === 0) { 91 | console.error('Blob is empty, skipping upload'); 92 | return; 93 | } 94 | 95 | const formData = new FormData(); 96 | formData.append(request.formField || 'file', blob, 'capture.webm'); 97 | 98 | console.log('request', request); 99 | 100 | try { 101 | // Fetch without setting 'Content-Type' manually 102 | const response = await fetch(request.serverEndpoint, { 103 | method: 'POST', 104 | headers: { 105 | 'X-ScreenCapture-Token': request.uploadToken, // Add custom headers 106 | }, 107 | body: formData, // Browser handles Content-Type 108 | }); 109 | 110 | if (!response.ok) { 111 | throw new Error(`Failed to upload video. Status: ${response.status}`); 112 | } 113 | 114 | console.log('Video uploaded successfully'); 115 | } catch (err) { 116 | console.error('Error uploading video', err); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /game/nui/src/capture.ts: -------------------------------------------------------------------------------- 1 | import { createGameView } from '@screencapture/gameview'; 2 | 3 | type Encoding = 'webp' | 'jpg' | 'png'; 4 | 5 | type CaptureRequest = { 6 | action: 'capture'; 7 | url: string; 8 | encoding: Encoding; 9 | quality: number; 10 | headers: Headers; 11 | uploadToken: string; 12 | serverEndpoint: string; 13 | formField: string; 14 | dataType: 'blob' | 'base64'; 15 | }; 16 | 17 | export class Capture { 18 | #gameView: any; 19 | #canvas: HTMLCanvasElement | null = null; 20 | 21 | start() { 22 | window.addEventListener('message', async (event) => { 23 | const data = event.data as CaptureRequest; 24 | 25 | if (data.action === 'capture') { 26 | await this.captureScreen(data); 27 | } 28 | }); 29 | 30 | window.addEventListener('resize', () => { 31 | if (this.#gameView) { 32 | this.#gameView.resize(window.innerWidth, window.innerHeight); 33 | } 34 | }); 35 | } 36 | 37 | async captureScreen(request: CaptureRequest) { 38 | this.#canvas = document.createElement('canvas'); 39 | this.#canvas.width = window.innerWidth; 40 | this.#canvas.height = window.innerHeight; 41 | 42 | this.#gameView = createGameView(this.#canvas); 43 | 44 | const enc = request.encoding ?? 'png'; 45 | const qlty = request.quality ?? 0.5; 46 | let imageData: string | Blob; 47 | if (request.serverEndpoint || !request.formField) { 48 | // make sure we don't care about serverEndpoint, only the dataType 49 | imageData = await this.createBlob(this.#canvas, enc, qlty); 50 | } else { 51 | imageData = await this.createBlob(this.#canvas, enc, qlty); 52 | } 53 | 54 | if (!imageData) return console.error('No image available'); 55 | 56 | await this.httpUploadImage(request, imageData); 57 | this.#canvas.remove(); 58 | } 59 | 60 | async httpUploadImage(request: CaptureRequest, imageData: string | Blob) { 61 | const reqBody = this.createRequestBody(request, imageData); 62 | 63 | if (request.serverEndpoint) { 64 | try { 65 | await fetch(request.serverEndpoint, { 66 | method: 'POST', 67 | headers: { 68 | 'X-ScreenCapture-Token': request.uploadToken, 69 | }, 70 | body: reqBody, 71 | }); 72 | } catch (err) { 73 | console.error(err); 74 | } 75 | } 76 | } 77 | 78 | createRequestBody(request: CaptureRequest, imageData: string | Blob): BodyInit { 79 | if (imageData instanceof Blob) { 80 | const formData = new FormData(); 81 | formData.append(request.formField ?? 'file', imageData); 82 | 83 | return formData; 84 | } 85 | 86 | // dataType is just here in order to know what to do with the data when we get it back 87 | return JSON.stringify({ imageData: imageData, dataType: request.dataType }); 88 | } 89 | 90 | createDataURL(canvas: HTMLCanvasElement): Promise { 91 | return new Promise((resolve, reject) => { 92 | const url = canvas.toDataURL('image/webp', 0.7); 93 | if (!url) { 94 | reject('No data URL available'); 95 | } 96 | 97 | resolve(url); 98 | }); 99 | } 100 | 101 | createBlob(canvas: HTMLCanvasElement, enc: Encoding, quality = 0.7): Promise { 102 | return new Promise((resolve, reject) => { 103 | canvas.toBlob( 104 | (blob) => { 105 | if (blob) { 106 | resolve(blob); 107 | } else { 108 | reject('No blob available'); 109 | } 110 | }, 111 | `image/${enc}`, 112 | quality, 113 | ); 114 | }); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /game/nui/src/main.ts: -------------------------------------------------------------------------------- 1 | import { Capture } from "./capture"; 2 | import "./style.css"; 3 | 4 | const capture = new Capture(); 5 | capture.start(); 6 | 7 | /* const stream = new CaptureStream(); 8 | stream.start(); */ -------------------------------------------------------------------------------- /game/nui/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: transparent; 3 | background-color: transparent; 4 | } 5 | 6 | body { 7 | margin: 0; /* Remove default margin */ 8 | overflow: hidden; /* Prevent scrollbars */ 9 | } -------------------------------------------------------------------------------- /game/nui/src/types.ts: -------------------------------------------------------------------------------- 1 | export enum CaptureStreamActions { 2 | Start = "capture-stream-start", 3 | Stop = "capture-stream-stop" 4 | } -------------------------------------------------------------------------------- /game/nui/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /game/nui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src"] 23 | } 24 | -------------------------------------------------------------------------------- /game/nui/vite.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('vite').UserConfig} */ 2 | export default { 3 | base: "./", 4 | }; 5 | -------------------------------------------------------------------------------- /game/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@screencapture/game", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "node scripts/esbuild.config.js", 9 | "build:client": "esbuild client/client.ts --bundle --platform=neutral --outfile=dist/client.js", 10 | "build:server": "esbuild server/server.ts --bundle --platform=node --outfile=dist/server.js" 11 | }, 12 | "dependencies": { 13 | "@citizenfx/http-wrapper": "^0.2.2", 14 | "@koa/router": "^13.1.0", 15 | "form-data": "^4.0.1", 16 | "koa": "^2.15.4", 17 | "koa-body": "^6.0.1", 18 | "koa-router": "^13.0.1", 19 | "multer": "1.4.5-lts.1", 20 | "nanoid": "^5.0.8", 21 | "node-fetch": "^3.3.2" 22 | }, 23 | "devDependencies": { 24 | "@citizenfx/client": "2.0.10822-1", 25 | "@citizenfx/server": "2.0.7290-1", 26 | "@screencapture/typescript-config": "workspace:*", 27 | "@types/formidable": "^3.4.5", 28 | "@types/koa": "^2.15.0", 29 | "@types/koa-router": "^7.4.8", 30 | "@types/koa__router": "^12.0.4", 31 | "@types/multer": "^1.4.12", 32 | "@types/node": "^22.8.6", 33 | "colorette": "^2.0.20", 34 | "esbuild": "^0.24.0", 35 | "rcon": "^1.1.0", 36 | "tsup": "^8.3.0" 37 | }, 38 | "keywords": [], 39 | "author": "", 40 | "license": "MIT" 41 | } -------------------------------------------------------------------------------- /game/scripts/esbuild.config.js: -------------------------------------------------------------------------------- 1 | const { context } = require("esbuild"); 2 | const nodePaths = require("./node-paths"); 3 | 4 | 5 | const isWatchEnabled = process.argv.findIndex((arg) => arg === '--watch') !== -1; 6 | 7 | const shouldRestart = process.argv.findIndex((arg) => arg === '--restart') !== -1; 8 | 9 | const buildConfig = { 10 | server: { 11 | platform: 'node', 12 | target: ['node21'], 13 | format: 'cjs' 14 | }, 15 | client: { 16 | platform: 'browser', 17 | target: ['es2021'], 18 | format: 'iife', 19 | }, 20 | }; 21 | 22 | async function build() { 23 | for (const [targetProject, projectConfig] of Object.entries(buildConfig)) { 24 | const ctx = await context({ 25 | bundle: true, 26 | entryPoints: [`${targetProject}/bootstrap.ts`], 27 | outfile: `dist/${targetProject}.js`, 28 | minify: targetProject === 'client', 29 | plugins: [nodePaths], 30 | ...projectConfig, 31 | }); 32 | 33 | if (isWatchEnabled) { 34 | await ctx.watch(); 35 | } else { 36 | await ctx.rebuild(); 37 | await ctx.dispose(); 38 | } 39 | } 40 | } 41 | 42 | build(); 43 | -------------------------------------------------------------------------------- /game/scripts/handle-build.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const { 4 | blueBright, 5 | cyanBright, 6 | greenBright, 7 | red, 8 | yellowBright, 9 | } = require("colorette"); 10 | const RCon = require("rcon"); 11 | 12 | let isAuthing = false; 13 | const rcon = new RCon("127.0.0.1", 30120, "dev", { 14 | tcp: false, 15 | challenge: false, 16 | }); 17 | 18 | function log(level, log, domain, logData) { 19 | console.log( 20 | `[${yellowBright( 21 | new Date().toLocaleString().replace(",", "") 22 | )}] [${cyanBright(domain.toUpperCase())}] [${ 23 | level === "INFO" ? blueBright("INFO") : red("ERROR") 24 | }] - ${log}`, 25 | logData ?? "" 26 | ); 27 | } 28 | 29 | function handleYarnLock() { 30 | const resourcePath = path.resolve(__dirname, "../"); 31 | const packageJson = path.resolve(resourcePath, "package.json"); 32 | const yarnLock = path.resolve(resourcePath, ".yarn.installed"); 33 | 34 | if (!fs.existsSync(packageJson)) { 35 | log( 36 | "ERROR", 37 | "Root directory is missing a package.json file. How is this possible?", 38 | "node" 39 | ); 40 | return; 41 | } 42 | 43 | if (!fs.existsSync(yarnLock)) { 44 | log( 45 | "INFO", 46 | "Root directory is missing a .yarn.installed file. Creating it now...", 47 | "node" 48 | ); 49 | fs.closeSync(fs.openSync(yarnLock, "w")); 50 | return; 51 | } 52 | 53 | const packageStat = fs.statSync(packageJson); 54 | const yarnStat = fs.statSync(yarnLock); 55 | 56 | if (packageStat.mtimeMs > yarnStat.mtimeMs) { 57 | log( 58 | "INFO", 59 | "Root directory package.json change detected. Overwriting the .yarn.installed file now...", 60 | "node" 61 | ); 62 | fs.closeSync(fs.openSync(yarnLock, "w")); 63 | return; 64 | } 65 | } 66 | 67 | function debounce(func, delay) { 68 | let timeoutId; 69 | 70 | return (...args) => { 71 | clearTimeout(timeoutId); 72 | 73 | timeoutId = setTimeout(() => { 74 | timeoutId = null; 75 | func(...args); 76 | }, delay); 77 | }; 78 | } 79 | 80 | const restartResource = debounce(async () => { 81 | log("INFO", "Attempting to restart resource", "node"); 82 | rcon.send("ensure sdk"); 83 | }, 500); 84 | 85 | /** 86 | * @type {import('esbuild').Plugin} 87 | */ 88 | function handleBuild(domain, shouldRestart) { 89 | return { 90 | name: "handle-build", 91 | setup(build) { 92 | if (shouldRestart && !isAuthing) { 93 | isAuthing = true; 94 | rcon.connect(); 95 | } 96 | 97 | let buildCount = 0; 98 | let buildStart = 0; 99 | 100 | build.onStart(() => { 101 | buildStart = performance.now(); 102 | }); 103 | 104 | build.onEnd((res) => { 105 | const firstBuild = buildCount++ === 0; 106 | 107 | if (res.errors.length > 0) { 108 | log( 109 | "ERROR", 110 | "An error occurred during the build process.", 111 | domain, 112 | res.errors 113 | ); 114 | return; 115 | } 116 | 117 | log( 118 | "INFO", 119 | `Build completed ${ 120 | res.warnings.length > 0 121 | ? yellowBright("with warnings") 122 | : greenBright("successfully") 123 | } in ${(performance.now() - buildStart).toFixed(0)}ms`, 124 | domain, 125 | res.warnings.length > 0 ? res.warnings : undefined 126 | ); 127 | 128 | handleYarnLock(); 129 | 130 | if (!firstBuild && shouldRestart) { 131 | restartResource(); 132 | } 133 | }); 134 | }, 135 | }; 136 | } 137 | 138 | module.exports = handleBuild; -------------------------------------------------------------------------------- /game/scripts/node-paths.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | /** 4 | * @type {import('esbuild').Plugin} 5 | */ 6 | module.exports = { 7 | name: "node-paths", 8 | setup(build) { 9 | build.onLoad({ filter: /\.(js|ts)$/ }, async (args) => { 10 | const source = await require("fs/promises").readFile(args.path, "utf8"); 11 | 12 | const dirname = `const __dirname = ${JSON.stringify( 13 | path.dirname(args.path) 14 | )};`; 15 | 16 | const filename = `const __filename = ${JSON.stringify(args.path)};`; 17 | 18 | return { 19 | contents: `${dirname}\n${filename}\n${source}`, 20 | loader: args.path.endsWith(".ts") ? "ts" : "js", 21 | }; 22 | }); 23 | }, 24 | }; -------------------------------------------------------------------------------- /game/server/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { createServer } from './koa-router'; 2 | import './export'; 3 | import { eventController } from './event'; 4 | import { RequestUploadToken } from './types'; 5 | import { UploadStore } from './upload-store'; 6 | 7 | export const uploadStore = new UploadStore(); 8 | 9 | async function boot() { 10 | createServer(uploadStore); 11 | } 12 | 13 | boot(); 14 | 15 | eventController( 16 | 'screencapture:INTERNAL_requestUploadToken', 17 | async ({ ctx, body, send }) => { 18 | function uploadCallback( 19 | response: unknown, 20 | playerSource: number | undefined, 21 | correlationId: string | undefined, 22 | ): void { 23 | emitNet('screencapture:INTERNAL_uploadComplete', playerSource, JSON.stringify(response), correlationId); 24 | } 25 | 26 | const token = uploadStore.addUpload({ 27 | callback: uploadCallback, 28 | isRemote: true, 29 | remoteConfig: { 30 | filename: body ? body.filename : undefined, 31 | encoding: body.encoding, 32 | headers: body.headers, 33 | formField: 'file', 34 | }, 35 | url: body.url, 36 | dataType: 'blob', 37 | playerSource: ctx.source, 38 | correlationId: body.correlationId, 39 | }); 40 | 41 | return send(token); 42 | }, 43 | ); 44 | -------------------------------------------------------------------------------- /game/server/context.ts: -------------------------------------------------------------------------------- 1 | export type Context = { 2 | source: number; 3 | }; 4 | 5 | export function getEventContext(): Context { 6 | const _source = global.source; 7 | return { 8 | source: _source, 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /game/server/event.ts: -------------------------------------------------------------------------------- 1 | import { type Context, getEventContext } from './context'; 2 | 3 | type Event = { 4 | body: T; 5 | ctx: Context; 6 | send: (data: R) => void; 7 | }; 8 | 9 | export function eventController( 10 | event: string, 11 | callback: (req: Event) => Promise, 12 | ): void { 13 | onNet(event, async (responseEvent: string, data: TData) => { 14 | const ctx = getEventContext(); 15 | 16 | function send(data: TResponse): void { 17 | return emitNet(responseEvent, ctx.source, data); 18 | } 19 | 20 | // TODO: Add status codes or something to the response 21 | await callback({ 22 | body: data, 23 | ctx: ctx, 24 | send, 25 | }); 26 | //return emitNet(responseEvent, ctx.source, response); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /game/server/export.ts: -------------------------------------------------------------------------------- 1 | import { uploadStore } from './bootstrap'; 2 | import { CallbackFn, CaptureOptions, DataType } from './types'; 3 | 4 | /* global.exports("serverCaptureStream", (source: number) => { 5 | const token = router.addStream({ 6 | callback: null, 7 | isRemote: false, 8 | remoteConfig: null, 9 | }) 10 | 11 | emitNet("screencapture:captureStream", source, token, {}) 12 | }) 13 | 14 | // DO NOT USE 15 | global.exports("INTERNAL_stopServerCaptureStream", (source: number) => { 16 | emitNet("screencapture:INTERNAL:stopCaptureStream", source) 17 | }) */ 18 | 19 | // upload the file from the server and return the raw response 20 | global.exports( 21 | 'remoteUpload', 22 | (source: number, url: string, options: CaptureOptions, callback: CallbackFn, dataType: DataType = 'base64') => { 23 | if (!source) return console.error('source is required for serverCapture'); 24 | 25 | const token = uploadStore.addUpload({ 26 | callback: callback, 27 | isRemote: true, 28 | remoteConfig: { 29 | ...options, 30 | encoding: options.encoding ?? 'webp', 31 | }, 32 | url, 33 | dataType, 34 | }); 35 | 36 | emitNet('screencapture:captureScreen', source, token, options, dataType); 37 | }, 38 | ); 39 | 40 | // dataType here doesn't matter for NUI, its just for the server to know how to handle the data 41 | // when calling this export, the client will always send it back as base64 42 | global.exports( 43 | 'serverCapture', 44 | (source: number, options: CaptureOptions, callback: CallbackFn, dataType: DataType = 'base64') => { 45 | if (!source) return console.error('source is required for serverCapture'); 46 | 47 | const token = uploadStore.addUpload({ 48 | callback, 49 | isRemote: false, 50 | remoteConfig: null, 51 | dataType, 52 | }); 53 | 54 | const opts = { 55 | ...options, 56 | encoding: options.encoding ?? 'webp', 57 | }; 58 | 59 | emitNet('screencapture:captureScreen', source, token, opts, dataType); 60 | }, 61 | ); 62 | -------------------------------------------------------------------------------- /game/server/koa-router.ts: -------------------------------------------------------------------------------- 1 | import Koa from 'koa'; 2 | import Router from '@koa/router'; 3 | import { multer } from './multer' 4 | 5 | // @ts-ignore - no types 6 | import { setHttpCallback } from '@citizenfx/http-wrapper'; 7 | 8 | import FormData from 'form-data'; 9 | import fetch from 'node-fetch'; 10 | import { Blob } from 'node:buffer'; 11 | import { CaptureOptions, DataType } from './types'; 12 | import { UploadStore } from './upload-store'; 13 | 14 | export async function createServer(uploadStore: UploadStore) { 15 | const app = new Koa(); 16 | const router = new Router(); 17 | const upload = multer({ 18 | storage: multer.memoryStorage() 19 | }); 20 | 21 | router.post('/image', upload.single("file") as any, async (ctx) => { 22 | const token = ctx.request.headers['x-screencapture-token'] as string; 23 | if (!token) { 24 | ctx.status = 401; 25 | ctx.body = { status: 'error', message: 'No token provided' }; 26 | return; 27 | } 28 | 29 | const { callback, dataType, isRemote, remoteConfig, url, playerSource, correlationId } = 30 | uploadStore.getUpload(token); 31 | 32 | const file = ctx.file; 33 | if (!file) { 34 | ctx.status = 400; 35 | ctx.body = { status: 'error', message: 'No file provided' }; 36 | return; 37 | } 38 | 39 | try { 40 | 41 | const buf = await buffer(dataType, file.buffer); 42 | 43 | if (isRemote) { 44 | const response = await uploadFile(url, remoteConfig, buf, dataType); 45 | 46 | // this is only when we return data back to the client 47 | if (playerSource && correlationId) { 48 | callback(response, playerSource, correlationId); 49 | } else { 50 | callback(response); 51 | } 52 | } else { 53 | callback(buf); 54 | } 55 | 56 | ctx.status = 200; 57 | ctx.body = { status: 'success' }; 58 | } catch (err) { 59 | if (err instanceof Error) { 60 | ctx.status = 500; 61 | ctx.body = { status: 'error', message: err.message }; 62 | } else { 63 | ctx.status = 500; 64 | ctx.body = { status: 'error', message: 'An unknown error occurred' }; 65 | } 66 | } 67 | }); 68 | 69 | app.use(router.routes()).use(router.allowedMethods()); 70 | 71 | setHttpCallback(app.callback()); 72 | } 73 | 74 | async function uploadFile( 75 | url: string | undefined, 76 | config: CaptureOptions | null, 77 | buf: string | Buffer, 78 | dataType: DataType, 79 | ) { 80 | if (!url) throw new Error('No remote URL provided'); 81 | if (!config) throw new Error('No remote config provided'); 82 | 83 | try { 84 | const body = await createRequestBody(buf, dataType, config); 85 | 86 | let response; 87 | if (body instanceof FormData) { 88 | response = await fetch(url, { 89 | method: 'POST', 90 | headers: { 91 | ...body.getHeaders(), 92 | ...config.headers, 93 | }, 94 | body: body.getBuffer(), 95 | }); 96 | } else { 97 | response = await fetch(url, { 98 | method: 'POST', 99 | headers: config.headers || {}, 100 | // as soon as we get a node upgrade, we'll use Node's http module 101 | // we might be able to do it now, but if so I'll test that later 102 | body: body as any, 103 | }); 104 | } 105 | 106 | if (!response.ok) { 107 | const text = await response.text(); 108 | throw new Error(`Failed to upload file to ${url}. Status: ${response.status}. Response: ${text}`); 109 | } 110 | 111 | const res = await response.json(); 112 | return res; 113 | } catch (err) { 114 | if (err instanceof Error) { 115 | throw new Error(err.message); 116 | } 117 | } 118 | } 119 | 120 | function createRequestBody( 121 | buf: string | Buffer, 122 | dataType: DataType, 123 | config: CaptureOptions, 124 | ): Promise { 125 | return new Promise((resolve, reject) => { 126 | const { formField, filename } = config; 127 | 128 | const filenameExt = filename ? `${filename}.${config.encoding}` : `screenshot.${config.encoding}`; 129 | 130 | if (dataType === 'blob') { 131 | const formData = new FormData(); 132 | formData.append(formField || 'file', buf, filenameExt); 133 | if (filename) { 134 | formData.append('filename', filename); 135 | } 136 | 137 | return resolve(formData); 138 | } 139 | 140 | if (typeof buf === 'string' && dataType === 'base64') { 141 | return resolve(buf); 142 | } 143 | 144 | return reject('Invalid body data'); 145 | }); 146 | } 147 | 148 | async function buffer(dataType: DataType, imageData: Buffer): Promise { 149 | return new Promise(async (resolve, reject) => { 150 | if (dataType === 'base64') { 151 | const blob = new Blob([imageData]); 152 | const dateURL = await blobToBase64(blob); 153 | resolve(dateURL); 154 | } else { 155 | resolve(imageData); 156 | } 157 | }); 158 | } 159 | 160 | async function blobToBase64(blob: Blob): Promise { 161 | return new Promise(async (resolve, reject) => { 162 | try { 163 | const arrayBuffer = await blob.arrayBuffer(); 164 | const base64 = Buffer.from(arrayBuffer).toString('base64'); 165 | resolve(base64); 166 | } catch (err) { 167 | reject(err); 168 | } 169 | }); 170 | } 171 | -------------------------------------------------------------------------------- /game/server/multer.ts: -------------------------------------------------------------------------------- 1 | import originalMulter, { Options, Multer } from 'multer'; 2 | 3 | export function multer(options: Options): Multer { 4 | const m = originalMulter(options); 5 | 6 | makePromise(m, 'any'); 7 | makePromise(m, 'array'); 8 | makePromise(m, 'fields'); 9 | makePromise(m, 'none'); 10 | makePromise(m, 'single'); 11 | 12 | return m; 13 | } 14 | 15 | function makePromise(multer: any, name: any): any { 16 | if (!multer[name]) return; 17 | 18 | const fn = multer[name]; 19 | 20 | multer[name] = function () { 21 | const middleware = Reflect.apply(fn, this, arguments); 22 | 23 | return async (ctx: any, next: any) => { 24 | await new Promise((resolve, reject) => { 25 | middleware(ctx.req, ctx.res, (err: any) => { 26 | if (err) return reject(err); 27 | if ('request' in ctx) { 28 | if (ctx.req.body) { 29 | ctx.request.body = ctx.req.body; 30 | delete ctx.req.body; 31 | } 32 | 33 | if (ctx.req.file) { 34 | ctx.request.file = ctx.req.file; 35 | ctx.file = ctx.req.file; 36 | delete ctx.req.file; 37 | } 38 | 39 | if (ctx.req.files) { 40 | ctx.request.files = ctx.req.files; 41 | ctx.files = ctx.req.files; 42 | delete ctx.req.files; 43 | } 44 | } 45 | 46 | resolve(ctx); 47 | }); 48 | }); 49 | 50 | return next(); 51 | }; 52 | }; 53 | } 54 | 55 | multer.diskStorage = originalMulter.diskStorage; 56 | multer.memoryStorage = originalMulter.memoryStorage; -------------------------------------------------------------------------------- /game/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@screencapture/typescript-config/base.json", 3 | "compilerOptions": { 4 | "types": ["@types/node", "@citizenfx/server"], 5 | "moduleResolution": "node", 6 | "module": "CommonJS" 7 | }, 8 | "include": ["**/*.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /game/server/types.ts: -------------------------------------------------------------------------------- 1 | export type DataType = 'base64' | 'blob'; 2 | 3 | type Encoding = 'webp' | 'jpg' | 'png'; 4 | 5 | export interface UploadData { 6 | callback: CallbackFn; 7 | isRemote: boolean; 8 | remoteConfig: CaptureOptions | null; 9 | dataType: DataType; 10 | url?: string; 11 | playerSource?: number; 12 | correlationId?: string; 13 | } 14 | 15 | export interface StreamUploadData { 16 | callback: CallbackFn | null 17 | isRemote: boolean; 18 | remoteConfig: CaptureOptions | null; 19 | url?: string; 20 | } 21 | 22 | export interface RemoteConfig { 23 | url: string; 24 | headers?: HeadersInit; 25 | formField?: string; 26 | filename?: string; 27 | encoding?: string; 28 | } 29 | 30 | export interface CaptureOptions { 31 | headers?: HeadersInit; 32 | formField?: string; 33 | filename?: string; 34 | encoding?: string; 35 | } 36 | 37 | export type CallbackFn = (data: unknown, _playerSource?: number, correlationId?: string) => void; 38 | 39 | export interface CallbackData { 40 | imageData: string | Buffer; 41 | dataType: string; 42 | } 43 | 44 | export interface RequestBody { 45 | imageData: string; 46 | dataType: DataType; 47 | } 48 | 49 | export type RequestUploadToken = { 50 | url: string; 51 | encoding: Encoding; 52 | quality: number; 53 | headers: Headers; 54 | correlationId: string; 55 | filename: string; 56 | }; 57 | -------------------------------------------------------------------------------- /game/server/upload-store.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid'; 2 | import { UploadData } from './types'; 3 | 4 | export class UploadStore { 5 | #uploadMap: Map; 6 | //#streamUploadMap: Map; 7 | 8 | constructor() { 9 | this.#uploadMap = new Map(); 10 | //this.#streamUploadMap = new Map(); 11 | } 12 | 13 | addUpload(params: UploadData): string { 14 | const uploadToken = nanoid(24); 15 | 16 | this.#uploadMap.set(uploadToken, params); 17 | 18 | return uploadToken; 19 | } 20 | 21 | getUpload(uploadToken: string): UploadData { 22 | const exists = this.#uploadMap.has(uploadToken); 23 | if (!exists) { 24 | throw new Error('Upload data does not exist. Cancelling screen capture.'); 25 | } 26 | 27 | const data = this.#uploadMap.get(uploadToken); 28 | if (!data) throw new Error('Could not find upload data'); 29 | 30 | return data; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "screencapture", 3 | "version": "0.0.0", 4 | "description": "", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build:gameview": "pnpm --filter @screencapture/gameview build", 8 | "build:game": "pnpm --filter @screencapture/game build", 9 | "build:nui": "pnpm --filter @screencapture/nui build", 10 | "build": "pnpm turbo build" 11 | }, 12 | "keywords": [], 13 | "author": "itschip", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "prettier": "^3.3.3", 17 | "turbo": "^2.1.2", 18 | "typescript": "^5.5.3" 19 | }, 20 | "packageManager": "pnpm@9.11.0" 21 | } -------------------------------------------------------------------------------- /packages/gameview/index.ts: -------------------------------------------------------------------------------- 1 | export { createGameView } from './webgl'; -------------------------------------------------------------------------------- /packages/gameview/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@screencapture/gameview", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "build": "tsup index.ts --format esm,cjs --minify --dts" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "tsup": "^8.3.0", 17 | "@screencapture/typescript-config": "workspace:*" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/gameview/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@screencapture/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["**/*.ts"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/gameview/webgl.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/citizenfx/fivem/blob/538f9cc8310391417fd025febae6d1efb9558bc5/ext/cfx-ui/src/app/app.component.ts#L317 2 | const vertexShaderSrc = ` 3 | attribute vec2 a_position; 4 | attribute vec2 a_texcoord; 5 | uniform mat3 u_matrix; 6 | varying vec2 textureCoordinate; 7 | void main() { 8 | gl_Position = vec4(a_position, 0.0, 1.0); 9 | textureCoordinate = a_texcoord; 10 | } 11 | `; 12 | 13 | const fragmentShaderSrc = ` 14 | varying highp vec2 textureCoordinate; 15 | uniform sampler2D external_texture; 16 | void main() 17 | { 18 | gl_FragColor = texture2D(external_texture, textureCoordinate); 19 | } 20 | `; 21 | 22 | function makeShader(gl: WebGLRenderingContext, type: number, src: string) { 23 | const shader = gl.createShader(type); 24 | if (!shader) { 25 | throw new Error('Failed to create shader'); 26 | } 27 | 28 | gl.shaderSource(shader, src); 29 | gl.compileShader(shader); 30 | 31 | const infoLog = gl.getShaderInfoLog(shader); 32 | if (infoLog) { 33 | console.error(infoLog); 34 | } 35 | 36 | return shader; 37 | } 38 | 39 | function createTexture(gl: WebGLRenderingContext) { 40 | const tex = gl.createTexture(); 41 | 42 | const texPixels = new Uint8Array([0, 0, 255, 255]); 43 | 44 | gl.bindTexture(gl.TEXTURE_2D, tex); 45 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, texPixels); 46 | 47 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 48 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 49 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 50 | 51 | // Magic hook sequence 52 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 53 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT); 54 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); 55 | 56 | // Reset 57 | gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 58 | 59 | return tex; 60 | } 61 | 62 | function createBuffers(gl: WebGLRenderingContext) { 63 | const vertexBuff = gl.createBuffer(); 64 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuff); 65 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 66 | -1, -1, 67 | 1, -1, 68 | -1, 1, 69 | 1, 1, 70 | ]), gl.STATIC_DRAW); 71 | 72 | const texBuff = gl.createBuffer(); 73 | gl.bindBuffer(gl.ARRAY_BUFFER, texBuff); 74 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 75 | 0, 0, 76 | 1, 0, 77 | 0, 1, 78 | 1, 1, 79 | ]), gl.STATIC_DRAW); 80 | 81 | return { vertexBuff, texBuff }; 82 | } 83 | 84 | function createProgram(gl: WebGLRenderingContext) { 85 | const vertexShader = makeShader(gl, gl.VERTEX_SHADER, vertexShaderSrc); 86 | const fragmentShader = makeShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSrc); 87 | 88 | const program = gl.createProgram(); 89 | if (!program) { 90 | throw new Error('Failed to create program'); 91 | } 92 | 93 | gl.attachShader(program, vertexShader); 94 | gl.attachShader(program, fragmentShader); 95 | gl.linkProgram(program); 96 | gl.useProgram(program); 97 | 98 | const vloc = gl.getAttribLocation(program, 'a_position'); 99 | const tloc = gl.getAttribLocation(program, 'a_texcoord'); 100 | 101 | return { program, vloc, tloc }; 102 | } 103 | 104 | export function createGameView(canvas: HTMLCanvasElement) { 105 | const gl = canvas.getContext('webgl', { 106 | antialias: false, 107 | depth: false, 108 | stencil: false, 109 | alpha: false, 110 | desynchronized: true, 111 | failIfMajorPerformanceCaveat: false 112 | }) as WebGLRenderingContext; 113 | 114 | let render = () => { }; 115 | 116 | function createStuff() { 117 | const tex = createTexture(gl); 118 | const { program, vloc, tloc } = createProgram(gl); 119 | const { vertexBuff, texBuff } = createBuffers(gl); 120 | 121 | gl.useProgram(program); 122 | 123 | gl.bindTexture(gl.TEXTURE_2D, tex); 124 | 125 | gl.uniform1i(gl.getUniformLocation(program, 'external_texture'), 0); 126 | 127 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuff); 128 | gl.vertexAttribPointer(vloc, 2, gl.FLOAT, false, 0, 0); 129 | gl.enableVertexAttribArray(vloc); 130 | 131 | gl.bindBuffer(gl.ARRAY_BUFFER, texBuff); 132 | gl.vertexAttribPointer(tloc, 2, gl.FLOAT, false, 0, 0); 133 | gl.enableVertexAttribArray(tloc); 134 | 135 | gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 136 | 137 | render(); 138 | } 139 | 140 | const gameView = { 141 | canvas, 142 | gl, 143 | animationFrame: void 0, 144 | resize: (width: number, height: number) => { 145 | gl.viewport(0, 0, width, height); 146 | gl.canvas.width = width; 147 | gl.canvas.height = height; 148 | }, 149 | }; 150 | 151 | render = () => { 152 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 153 | gl.finish(); 154 | 155 | // @ts-ignore 156 | gameView.animationFrame = requestAnimationFrame(render); 157 | }; 158 | 159 | createStuff(); 160 | 161 | return gameView; 162 | } 163 | -------------------------------------------------------------------------------- /packages/react/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itschip/screencapture/091b63b59705af61bd6c09d667639af8796f14a2/packages/react/index.ts -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@screencapture/react", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": ["react", "fivem", "screenshot-basic", "screenshot", "webgl"], 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "tsup": "^8.3.0", 14 | "@screencapture/typescript-config": "workspace:*", 15 | "@screencapture/gameview": "workspace:*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@screencapture/typescript-config/react.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "jsx": "react-jsx" 6 | }, 7 | "include": ["**/*.ts", "**/*.tsx"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/react/useCaptureScreen.ts: -------------------------------------------------------------------------------- 1 | import { createGameView } from '@screencapture/gameview'; 2 | import { createBlob } from './utils'; 3 | 4 | export const useCaptureScreen = () => { 5 | const capture = async (canvas: HTMLCanvasElement) => { 6 | let localCanvas = false; 7 | if (!canvas) { 8 | localCanvas = true; 9 | canvas = document.createElement('canvas'); 10 | canvas.width = window.innerWidth; 11 | canvas.height = window.innerHeight; 12 | } 13 | 14 | const gameView = createGameView(canvas); 15 | 16 | // TODO: Use innerWidth and innerHeight from the game view unless the user has specified a custom size 17 | gameView.resize(window.innerWidth, window.innerHeight); 18 | 19 | // TODO: Option to choose between base64 and blob 20 | // TODO: Option for quality and encoding type 21 | const blob = await createBlob(canvas); 22 | 23 | if (!blob) { 24 | console.error('No blob available'); 25 | return; 26 | } 27 | 28 | if (localCanvas) { 29 | canvas.remove(); 30 | } 31 | 32 | return blob; 33 | }; 34 | 35 | return { capture }; 36 | }; -------------------------------------------------------------------------------- /packages/react/utils.ts: -------------------------------------------------------------------------------- 1 | export async function createBlob(canvas: HTMLCanvasElement): Promise { 2 | return new Promise((resolve, reject) => { 3 | canvas.toBlob( 4 | (blob) => { 5 | if (blob) { 6 | resolve(blob); 7 | } else { 8 | reject("No blob available"); 9 | } 10 | }, 11 | "image/webp", 12 | 0.5 13 | ); 14 | }); 15 | } -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "incremental": false, 9 | "isolatedModules": true, 10 | "lib": ["es2022", "DOM", "DOM.Iterable"], 11 | "module": "NodeNext", 12 | "moduleDetection": "force", 13 | "moduleResolution": "NodeNext", 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ES2022" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@screencapture/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "publishConfig": { 6 | "access": "public" 7 | }, 8 | "author": "itschip", 9 | "license": "MIT" 10 | } -------------------------------------------------------------------------------- /packages/typescript-config/react.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx" 7 | } 8 | } -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | prettier: 12 | specifier: ^3.3.3 13 | version: 3.3.3 14 | turbo: 15 | specifier: ^2.1.2 16 | version: 2.1.2 17 | typescript: 18 | specifier: ^5.5.3 19 | version: 5.6.2 20 | 21 | game: 22 | dependencies: 23 | '@citizenfx/http-wrapper': 24 | specifier: ^0.2.2 25 | version: 0.2.2 26 | '@koa/router': 27 | specifier: ^13.1.0 28 | version: 13.1.0 29 | form-data: 30 | specifier: ^4.0.1 31 | version: 4.0.1 32 | koa: 33 | specifier: ^2.15.4 34 | version: 2.15.4 35 | koa-body: 36 | specifier: ^6.0.1 37 | version: 6.0.1 38 | koa-router: 39 | specifier: ^13.0.1 40 | version: 13.0.1 41 | multer: 42 | specifier: 1.4.5-lts.1 43 | version: 1.4.5-lts.1 44 | nanoid: 45 | specifier: ^5.0.8 46 | version: 5.0.8 47 | node-fetch: 48 | specifier: ^3.3.2 49 | version: 3.3.2 50 | devDependencies: 51 | '@citizenfx/client': 52 | specifier: 2.0.10822-1 53 | version: 2.0.10822-1 54 | '@citizenfx/server': 55 | specifier: 2.0.7290-1 56 | version: 2.0.7290-1 57 | '@screencapture/typescript-config': 58 | specifier: workspace:* 59 | version: link:../packages/typescript-config 60 | '@types/formidable': 61 | specifier: ^3.4.5 62 | version: 3.4.5 63 | '@types/koa': 64 | specifier: ^2.15.0 65 | version: 2.15.0 66 | '@types/koa-router': 67 | specifier: ^7.4.8 68 | version: 7.4.8 69 | '@types/koa__router': 70 | specifier: ^12.0.4 71 | version: 12.0.4 72 | '@types/multer': 73 | specifier: ^1.4.12 74 | version: 1.4.12 75 | '@types/node': 76 | specifier: ^22.8.6 77 | version: 22.8.6 78 | colorette: 79 | specifier: ^2.0.20 80 | version: 2.0.20 81 | esbuild: 82 | specifier: ^0.24.0 83 | version: 0.24.0 84 | rcon: 85 | specifier: ^1.1.0 86 | version: 1.1.0 87 | tsup: 88 | specifier: ^8.3.0 89 | version: 8.3.0(postcss@8.4.47)(typescript@5.6.2) 90 | 91 | game/nui: 92 | dependencies: 93 | '@screencapture/gameview': 94 | specifier: workspace:* 95 | version: link:../../packages/gameview 96 | devDependencies: 97 | typescript: 98 | specifier: ^5.5.3 99 | version: 5.6.2 100 | vite: 101 | specifier: ^5.4.1 102 | version: 5.4.6(@types/node@22.8.6) 103 | 104 | packages/gameview: 105 | devDependencies: 106 | '@screencapture/typescript-config': 107 | specifier: workspace:* 108 | version: link:../typescript-config 109 | tsup: 110 | specifier: ^8.3.0 111 | version: 8.3.0(postcss@8.4.47)(typescript@5.6.2) 112 | 113 | packages/react: 114 | devDependencies: 115 | '@screencapture/gameview': 116 | specifier: workspace:* 117 | version: link:../gameview 118 | '@screencapture/typescript-config': 119 | specifier: workspace:* 120 | version: link:../typescript-config 121 | tsup: 122 | specifier: ^8.3.0 123 | version: 8.3.0(postcss@8.4.47)(typescript@5.6.2) 124 | 125 | packages/typescript-config: {} 126 | 127 | packages: 128 | 129 | '@citizenfx/client@2.0.10822-1': 130 | resolution: {integrity: sha512-9z8qf000oOsPw1lEn+KA2yxANGifcEn841YogOpQ2tjuwMRNy3jqqbIRg0kgnF3kTqNm2y45m+qM5i0CmHOCWw==} 131 | 132 | '@citizenfx/http-wrapper@0.2.2': 133 | resolution: {integrity: sha512-hFyrWN2U30KFRgYteyqs7PZ+9aXyiH3tsgOQL/vcOp9dGAZAyRSHDotJYZivTEpjRN4dMbgbZ2h9TgoDFRKi9w==} 134 | 135 | '@citizenfx/server@2.0.7290-1': 136 | resolution: {integrity: sha512-ZWuREJ7APkrUh2XOuREdVrZBPH7VNvOdz4DWlj1NVslwNi0atCk9cxiRtQ5yJpBTY9mZDQ5XwNeelQBlW64Yjg==} 137 | 138 | '@esbuild/aix-ppc64@0.21.5': 139 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 140 | engines: {node: '>=12'} 141 | cpu: [ppc64] 142 | os: [aix] 143 | 144 | '@esbuild/aix-ppc64@0.23.1': 145 | resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} 146 | engines: {node: '>=18'} 147 | cpu: [ppc64] 148 | os: [aix] 149 | 150 | '@esbuild/aix-ppc64@0.24.0': 151 | resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} 152 | engines: {node: '>=18'} 153 | cpu: [ppc64] 154 | os: [aix] 155 | 156 | '@esbuild/android-arm64@0.21.5': 157 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 158 | engines: {node: '>=12'} 159 | cpu: [arm64] 160 | os: [android] 161 | 162 | '@esbuild/android-arm64@0.23.1': 163 | resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} 164 | engines: {node: '>=18'} 165 | cpu: [arm64] 166 | os: [android] 167 | 168 | '@esbuild/android-arm64@0.24.0': 169 | resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} 170 | engines: {node: '>=18'} 171 | cpu: [arm64] 172 | os: [android] 173 | 174 | '@esbuild/android-arm@0.21.5': 175 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 176 | engines: {node: '>=12'} 177 | cpu: [arm] 178 | os: [android] 179 | 180 | '@esbuild/android-arm@0.23.1': 181 | resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} 182 | engines: {node: '>=18'} 183 | cpu: [arm] 184 | os: [android] 185 | 186 | '@esbuild/android-arm@0.24.0': 187 | resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} 188 | engines: {node: '>=18'} 189 | cpu: [arm] 190 | os: [android] 191 | 192 | '@esbuild/android-x64@0.21.5': 193 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 194 | engines: {node: '>=12'} 195 | cpu: [x64] 196 | os: [android] 197 | 198 | '@esbuild/android-x64@0.23.1': 199 | resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} 200 | engines: {node: '>=18'} 201 | cpu: [x64] 202 | os: [android] 203 | 204 | '@esbuild/android-x64@0.24.0': 205 | resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} 206 | engines: {node: '>=18'} 207 | cpu: [x64] 208 | os: [android] 209 | 210 | '@esbuild/darwin-arm64@0.21.5': 211 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 212 | engines: {node: '>=12'} 213 | cpu: [arm64] 214 | os: [darwin] 215 | 216 | '@esbuild/darwin-arm64@0.23.1': 217 | resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} 218 | engines: {node: '>=18'} 219 | cpu: [arm64] 220 | os: [darwin] 221 | 222 | '@esbuild/darwin-arm64@0.24.0': 223 | resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} 224 | engines: {node: '>=18'} 225 | cpu: [arm64] 226 | os: [darwin] 227 | 228 | '@esbuild/darwin-x64@0.21.5': 229 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 230 | engines: {node: '>=12'} 231 | cpu: [x64] 232 | os: [darwin] 233 | 234 | '@esbuild/darwin-x64@0.23.1': 235 | resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} 236 | engines: {node: '>=18'} 237 | cpu: [x64] 238 | os: [darwin] 239 | 240 | '@esbuild/darwin-x64@0.24.0': 241 | resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} 242 | engines: {node: '>=18'} 243 | cpu: [x64] 244 | os: [darwin] 245 | 246 | '@esbuild/freebsd-arm64@0.21.5': 247 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 248 | engines: {node: '>=12'} 249 | cpu: [arm64] 250 | os: [freebsd] 251 | 252 | '@esbuild/freebsd-arm64@0.23.1': 253 | resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} 254 | engines: {node: '>=18'} 255 | cpu: [arm64] 256 | os: [freebsd] 257 | 258 | '@esbuild/freebsd-arm64@0.24.0': 259 | resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} 260 | engines: {node: '>=18'} 261 | cpu: [arm64] 262 | os: [freebsd] 263 | 264 | '@esbuild/freebsd-x64@0.21.5': 265 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 266 | engines: {node: '>=12'} 267 | cpu: [x64] 268 | os: [freebsd] 269 | 270 | '@esbuild/freebsd-x64@0.23.1': 271 | resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} 272 | engines: {node: '>=18'} 273 | cpu: [x64] 274 | os: [freebsd] 275 | 276 | '@esbuild/freebsd-x64@0.24.0': 277 | resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} 278 | engines: {node: '>=18'} 279 | cpu: [x64] 280 | os: [freebsd] 281 | 282 | '@esbuild/linux-arm64@0.21.5': 283 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 284 | engines: {node: '>=12'} 285 | cpu: [arm64] 286 | os: [linux] 287 | 288 | '@esbuild/linux-arm64@0.23.1': 289 | resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} 290 | engines: {node: '>=18'} 291 | cpu: [arm64] 292 | os: [linux] 293 | 294 | '@esbuild/linux-arm64@0.24.0': 295 | resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} 296 | engines: {node: '>=18'} 297 | cpu: [arm64] 298 | os: [linux] 299 | 300 | '@esbuild/linux-arm@0.21.5': 301 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 302 | engines: {node: '>=12'} 303 | cpu: [arm] 304 | os: [linux] 305 | 306 | '@esbuild/linux-arm@0.23.1': 307 | resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} 308 | engines: {node: '>=18'} 309 | cpu: [arm] 310 | os: [linux] 311 | 312 | '@esbuild/linux-arm@0.24.0': 313 | resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} 314 | engines: {node: '>=18'} 315 | cpu: [arm] 316 | os: [linux] 317 | 318 | '@esbuild/linux-ia32@0.21.5': 319 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 320 | engines: {node: '>=12'} 321 | cpu: [ia32] 322 | os: [linux] 323 | 324 | '@esbuild/linux-ia32@0.23.1': 325 | resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} 326 | engines: {node: '>=18'} 327 | cpu: [ia32] 328 | os: [linux] 329 | 330 | '@esbuild/linux-ia32@0.24.0': 331 | resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} 332 | engines: {node: '>=18'} 333 | cpu: [ia32] 334 | os: [linux] 335 | 336 | '@esbuild/linux-loong64@0.21.5': 337 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 338 | engines: {node: '>=12'} 339 | cpu: [loong64] 340 | os: [linux] 341 | 342 | '@esbuild/linux-loong64@0.23.1': 343 | resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} 344 | engines: {node: '>=18'} 345 | cpu: [loong64] 346 | os: [linux] 347 | 348 | '@esbuild/linux-loong64@0.24.0': 349 | resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} 350 | engines: {node: '>=18'} 351 | cpu: [loong64] 352 | os: [linux] 353 | 354 | '@esbuild/linux-mips64el@0.21.5': 355 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 356 | engines: {node: '>=12'} 357 | cpu: [mips64el] 358 | os: [linux] 359 | 360 | '@esbuild/linux-mips64el@0.23.1': 361 | resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} 362 | engines: {node: '>=18'} 363 | cpu: [mips64el] 364 | os: [linux] 365 | 366 | '@esbuild/linux-mips64el@0.24.0': 367 | resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} 368 | engines: {node: '>=18'} 369 | cpu: [mips64el] 370 | os: [linux] 371 | 372 | '@esbuild/linux-ppc64@0.21.5': 373 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 374 | engines: {node: '>=12'} 375 | cpu: [ppc64] 376 | os: [linux] 377 | 378 | '@esbuild/linux-ppc64@0.23.1': 379 | resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} 380 | engines: {node: '>=18'} 381 | cpu: [ppc64] 382 | os: [linux] 383 | 384 | '@esbuild/linux-ppc64@0.24.0': 385 | resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} 386 | engines: {node: '>=18'} 387 | cpu: [ppc64] 388 | os: [linux] 389 | 390 | '@esbuild/linux-riscv64@0.21.5': 391 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 392 | engines: {node: '>=12'} 393 | cpu: [riscv64] 394 | os: [linux] 395 | 396 | '@esbuild/linux-riscv64@0.23.1': 397 | resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} 398 | engines: {node: '>=18'} 399 | cpu: [riscv64] 400 | os: [linux] 401 | 402 | '@esbuild/linux-riscv64@0.24.0': 403 | resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} 404 | engines: {node: '>=18'} 405 | cpu: [riscv64] 406 | os: [linux] 407 | 408 | '@esbuild/linux-s390x@0.21.5': 409 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 410 | engines: {node: '>=12'} 411 | cpu: [s390x] 412 | os: [linux] 413 | 414 | '@esbuild/linux-s390x@0.23.1': 415 | resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} 416 | engines: {node: '>=18'} 417 | cpu: [s390x] 418 | os: [linux] 419 | 420 | '@esbuild/linux-s390x@0.24.0': 421 | resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} 422 | engines: {node: '>=18'} 423 | cpu: [s390x] 424 | os: [linux] 425 | 426 | '@esbuild/linux-x64@0.21.5': 427 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 428 | engines: {node: '>=12'} 429 | cpu: [x64] 430 | os: [linux] 431 | 432 | '@esbuild/linux-x64@0.23.1': 433 | resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} 434 | engines: {node: '>=18'} 435 | cpu: [x64] 436 | os: [linux] 437 | 438 | '@esbuild/linux-x64@0.24.0': 439 | resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} 440 | engines: {node: '>=18'} 441 | cpu: [x64] 442 | os: [linux] 443 | 444 | '@esbuild/netbsd-x64@0.21.5': 445 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 446 | engines: {node: '>=12'} 447 | cpu: [x64] 448 | os: [netbsd] 449 | 450 | '@esbuild/netbsd-x64@0.23.1': 451 | resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} 452 | engines: {node: '>=18'} 453 | cpu: [x64] 454 | os: [netbsd] 455 | 456 | '@esbuild/netbsd-x64@0.24.0': 457 | resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} 458 | engines: {node: '>=18'} 459 | cpu: [x64] 460 | os: [netbsd] 461 | 462 | '@esbuild/openbsd-arm64@0.23.1': 463 | resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} 464 | engines: {node: '>=18'} 465 | cpu: [arm64] 466 | os: [openbsd] 467 | 468 | '@esbuild/openbsd-arm64@0.24.0': 469 | resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} 470 | engines: {node: '>=18'} 471 | cpu: [arm64] 472 | os: [openbsd] 473 | 474 | '@esbuild/openbsd-x64@0.21.5': 475 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 476 | engines: {node: '>=12'} 477 | cpu: [x64] 478 | os: [openbsd] 479 | 480 | '@esbuild/openbsd-x64@0.23.1': 481 | resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} 482 | engines: {node: '>=18'} 483 | cpu: [x64] 484 | os: [openbsd] 485 | 486 | '@esbuild/openbsd-x64@0.24.0': 487 | resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} 488 | engines: {node: '>=18'} 489 | cpu: [x64] 490 | os: [openbsd] 491 | 492 | '@esbuild/sunos-x64@0.21.5': 493 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 494 | engines: {node: '>=12'} 495 | cpu: [x64] 496 | os: [sunos] 497 | 498 | '@esbuild/sunos-x64@0.23.1': 499 | resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} 500 | engines: {node: '>=18'} 501 | cpu: [x64] 502 | os: [sunos] 503 | 504 | '@esbuild/sunos-x64@0.24.0': 505 | resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} 506 | engines: {node: '>=18'} 507 | cpu: [x64] 508 | os: [sunos] 509 | 510 | '@esbuild/win32-arm64@0.21.5': 511 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 512 | engines: {node: '>=12'} 513 | cpu: [arm64] 514 | os: [win32] 515 | 516 | '@esbuild/win32-arm64@0.23.1': 517 | resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} 518 | engines: {node: '>=18'} 519 | cpu: [arm64] 520 | os: [win32] 521 | 522 | '@esbuild/win32-arm64@0.24.0': 523 | resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} 524 | engines: {node: '>=18'} 525 | cpu: [arm64] 526 | os: [win32] 527 | 528 | '@esbuild/win32-ia32@0.21.5': 529 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 530 | engines: {node: '>=12'} 531 | cpu: [ia32] 532 | os: [win32] 533 | 534 | '@esbuild/win32-ia32@0.23.1': 535 | resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} 536 | engines: {node: '>=18'} 537 | cpu: [ia32] 538 | os: [win32] 539 | 540 | '@esbuild/win32-ia32@0.24.0': 541 | resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} 542 | engines: {node: '>=18'} 543 | cpu: [ia32] 544 | os: [win32] 545 | 546 | '@esbuild/win32-x64@0.21.5': 547 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 548 | engines: {node: '>=12'} 549 | cpu: [x64] 550 | os: [win32] 551 | 552 | '@esbuild/win32-x64@0.23.1': 553 | resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} 554 | engines: {node: '>=18'} 555 | cpu: [x64] 556 | os: [win32] 557 | 558 | '@esbuild/win32-x64@0.24.0': 559 | resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} 560 | engines: {node: '>=18'} 561 | cpu: [x64] 562 | os: [win32] 563 | 564 | '@hapi/bourne@3.0.0': 565 | resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} 566 | 567 | '@isaacs/cliui@8.0.2': 568 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 569 | engines: {node: '>=12'} 570 | 571 | '@jridgewell/gen-mapping@0.3.5': 572 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 573 | engines: {node: '>=6.0.0'} 574 | 575 | '@jridgewell/resolve-uri@3.1.2': 576 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 577 | engines: {node: '>=6.0.0'} 578 | 579 | '@jridgewell/set-array@1.2.1': 580 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 581 | engines: {node: '>=6.0.0'} 582 | 583 | '@jridgewell/sourcemap-codec@1.5.0': 584 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 585 | 586 | '@jridgewell/trace-mapping@0.3.25': 587 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 588 | 589 | '@koa/router@13.1.0': 590 | resolution: {integrity: sha512-mNVu1nvkpSd8Q8gMebGbCkDWJ51ODetrFvLKYusej+V0ByD4btqHYnPIzTBLXnQMVUlm/oxVwqmWBY3zQfZilw==} 591 | engines: {node: '>= 18'} 592 | 593 | '@pkgjs/parseargs@0.11.0': 594 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 595 | engines: {node: '>=14'} 596 | 597 | '@rollup/rollup-android-arm-eabi@4.22.0': 598 | resolution: {integrity: sha512-/IZQvg6ZR0tAkEi4tdXOraQoWeJy9gbQ/cx4I7k9dJaCk9qrXEcdouxRVz5kZXt5C2bQ9pILoAA+KB4C/d3pfw==} 599 | cpu: [arm] 600 | os: [android] 601 | 602 | '@rollup/rollup-android-arm64@4.22.0': 603 | resolution: {integrity: sha512-ETHi4bxrYnvOtXeM7d4V4kZWixib2jddFacJjsOjwbgYSRsyXYtZHC4ht134OsslPIcnkqT+TKV4eU8rNBKyyQ==} 604 | cpu: [arm64] 605 | os: [android] 606 | 607 | '@rollup/rollup-darwin-arm64@4.22.0': 608 | resolution: {integrity: sha512-ZWgARzhSKE+gVUX7QWaECoRQsPwaD8ZR0Oxb3aUpzdErTvlEadfQpORPXkKSdKbFci9v8MJfkTtoEHnnW9Ulng==} 609 | cpu: [arm64] 610 | os: [darwin] 611 | 612 | '@rollup/rollup-darwin-x64@4.22.0': 613 | resolution: {integrity: sha512-h0ZAtOfHyio8Az6cwIGS+nHUfRMWBDO5jXB8PQCARVF6Na/G6XS2SFxDl8Oem+S5ZsHQgtsI7RT4JQnI1qrlaw==} 614 | cpu: [x64] 615 | os: [darwin] 616 | 617 | '@rollup/rollup-linux-arm-gnueabihf@4.22.0': 618 | resolution: {integrity: sha512-9pxQJSPwFsVi0ttOmqLY4JJ9pg9t1gKhK0JDbV1yUEETSx55fdyCjt39eBQ54OQCzAF0nVGO6LfEH1KnCPvelA==} 619 | cpu: [arm] 620 | os: [linux] 621 | 622 | '@rollup/rollup-linux-arm-musleabihf@4.22.0': 623 | resolution: {integrity: sha512-YJ5Ku5BmNJZb58A4qSEo3JlIG4d3G2lWyBi13ABlXzO41SsdnUKi3HQHe83VpwBVG4jHFTW65jOQb8qyoR+qzg==} 624 | cpu: [arm] 625 | os: [linux] 626 | 627 | '@rollup/rollup-linux-arm64-gnu@4.22.0': 628 | resolution: {integrity: sha512-U4G4u7f+QCqHlVg1Nlx+qapZy+QoG+NV6ux+upo/T7arNGwKvKP2kmGM4W5QTbdewWFgudQxi3kDNST9GT1/mg==} 629 | cpu: [arm64] 630 | os: [linux] 631 | 632 | '@rollup/rollup-linux-arm64-musl@4.22.0': 633 | resolution: {integrity: sha512-aQpNlKmx3amwkA3a5J6nlXSahE1ijl0L9KuIjVOUhfOh7uw2S4piR3mtpxpRtbnK809SBtyPsM9q15CPTsY7HQ==} 634 | cpu: [arm64] 635 | os: [linux] 636 | 637 | '@rollup/rollup-linux-powerpc64le-gnu@4.22.0': 638 | resolution: {integrity: sha512-9fx6Zj/7vve/Fp4iexUFRKb5+RjLCff6YTRQl4CoDhdMfDoobWmhAxQWV3NfShMzQk1Q/iCnageFyGfqnsmeqQ==} 639 | cpu: [ppc64] 640 | os: [linux] 641 | 642 | '@rollup/rollup-linux-riscv64-gnu@4.22.0': 643 | resolution: {integrity: sha512-VWQiCcN7zBgZYLjndIEh5tamtnKg5TGxyZPWcN9zBtXBwfcGSZ5cHSdQZfQH/GB4uRxk0D3VYbOEe/chJhPGLQ==} 644 | cpu: [riscv64] 645 | os: [linux] 646 | 647 | '@rollup/rollup-linux-s390x-gnu@4.22.0': 648 | resolution: {integrity: sha512-EHmPnPWvyYqncObwqrosb/CpH3GOjE76vWVs0g4hWsDRUVhg61hBmlVg5TPXqF+g+PvIbqkC7i3h8wbn4Gp2Fg==} 649 | cpu: [s390x] 650 | os: [linux] 651 | 652 | '@rollup/rollup-linux-x64-gnu@4.22.0': 653 | resolution: {integrity: sha512-tsSWy3YQzmpjDKnQ1Vcpy3p9Z+kMFbSIesCdMNgLizDWFhrLZIoN21JSq01g+MZMDFF+Y1+4zxgrlqPjid5ohg==} 654 | cpu: [x64] 655 | os: [linux] 656 | 657 | '@rollup/rollup-linux-x64-musl@4.22.0': 658 | resolution: {integrity: sha512-anr1Y11uPOQrpuU8XOikY5lH4Qu94oS6j0xrulHk3NkLDq19MlX8Ng/pVipjxBJ9a2l3+F39REZYyWQFkZ4/fw==} 659 | cpu: [x64] 660 | os: [linux] 661 | 662 | '@rollup/rollup-win32-arm64-msvc@4.22.0': 663 | resolution: {integrity: sha512-7LB+Bh+Ut7cfmO0m244/asvtIGQr5pG5Rvjz/l1Rnz1kDzM02pSX9jPaS0p+90H5I1x4d1FkCew+B7MOnoatNw==} 664 | cpu: [arm64] 665 | os: [win32] 666 | 667 | '@rollup/rollup-win32-ia32-msvc@4.22.0': 668 | resolution: {integrity: sha512-+3qZ4rer7t/QsC5JwMpcvCVPRcJt1cJrYS/TMJZzXIJbxWFQEVhrIc26IhB+5Z9fT9umfVc+Es2mOZgl+7jdJQ==} 669 | cpu: [ia32] 670 | os: [win32] 671 | 672 | '@rollup/rollup-win32-x64-msvc@4.22.0': 673 | resolution: {integrity: sha512-YdicNOSJONVx/vuPkgPTyRoAPx3GbknBZRCOUkK84FJ/YTfs/F0vl/YsMscrB6Y177d+yDRcj+JWMPMCgshwrA==} 674 | cpu: [x64] 675 | os: [win32] 676 | 677 | '@types/accepts@1.3.7': 678 | resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} 679 | 680 | '@types/body-parser@1.19.5': 681 | resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} 682 | 683 | '@types/co-body@6.1.3': 684 | resolution: {integrity: sha512-UhuhrQ5hclX6UJctv5m4Rfp52AfG9o9+d9/HwjxhVB5NjXxr5t9oKgJxN8xRHgr35oo8meUEHUPFWiKg6y71aA==} 685 | 686 | '@types/connect@3.4.38': 687 | resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} 688 | 689 | '@types/content-disposition@0.5.8': 690 | resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==} 691 | 692 | '@types/cookies@0.9.0': 693 | resolution: {integrity: sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==} 694 | 695 | '@types/estree@1.0.5': 696 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 697 | 698 | '@types/express-serve-static-core@5.0.6': 699 | resolution: {integrity: sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==} 700 | 701 | '@types/express@5.0.0': 702 | resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==} 703 | 704 | '@types/formidable@2.0.6': 705 | resolution: {integrity: sha512-L4HcrA05IgQyNYJj6kItuIkXrInJvsXTPC5B1i64FggWKKqSL+4hgt7asiSNva75AoLQjq29oPxFfU4GAQ6Z2w==} 706 | 707 | '@types/formidable@3.4.5': 708 | resolution: {integrity: sha512-s7YPsNVfnsng5L8sKnG/Gbb2tiwwJTY1conOkJzTMRvJAlLFW1nEua+ADsJQu8N1c0oTHx9+d5nqg10WuT9gHQ==} 709 | 710 | '@types/http-assert@1.5.6': 711 | resolution: {integrity: sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw==} 712 | 713 | '@types/http-errors@2.0.4': 714 | resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} 715 | 716 | '@types/keygrip@1.0.6': 717 | resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} 718 | 719 | '@types/koa-compose@3.2.8': 720 | resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==} 721 | 722 | '@types/koa-router@7.4.8': 723 | resolution: {integrity: sha512-SkWlv4F9f+l3WqYNQHnWjYnyTxYthqt8W9az2RTdQW7Ay8bc00iRZcrb8MC75iEfPqnGcg2csEl8tTG1NQPD4A==} 724 | 725 | '@types/koa@2.15.0': 726 | resolution: {integrity: sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==} 727 | 728 | '@types/koa__router@12.0.4': 729 | resolution: {integrity: sha512-Y7YBbSmfXZpa/m5UGGzb7XadJIRBRnwNY9cdAojZGp65Cpe5MAP3mOZE7e3bImt8dfKS4UFcR16SLH8L/z7PBw==} 730 | 731 | '@types/mime@1.3.5': 732 | resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} 733 | 734 | '@types/multer@1.4.12': 735 | resolution: {integrity: sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==} 736 | 737 | '@types/node@22.8.6': 738 | resolution: {integrity: sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==} 739 | 740 | '@types/qs@6.9.18': 741 | resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} 742 | 743 | '@types/range-parser@1.2.7': 744 | resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} 745 | 746 | '@types/send@0.17.4': 747 | resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} 748 | 749 | '@types/serve-static@1.15.7': 750 | resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} 751 | 752 | accepts@1.3.8: 753 | resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} 754 | engines: {node: '>= 0.6'} 755 | 756 | ansi-regex@5.0.1: 757 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 758 | engines: {node: '>=8'} 759 | 760 | ansi-regex@6.1.0: 761 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 762 | engines: {node: '>=12'} 763 | 764 | ansi-styles@4.3.0: 765 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 766 | engines: {node: '>=8'} 767 | 768 | ansi-styles@6.2.1: 769 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 770 | engines: {node: '>=12'} 771 | 772 | any-promise@1.3.0: 773 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 774 | 775 | anymatch@3.1.3: 776 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 777 | engines: {node: '>= 8'} 778 | 779 | append-field@1.0.0: 780 | resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} 781 | 782 | asap@2.0.6: 783 | resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} 784 | 785 | asynckit@0.4.0: 786 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 787 | 788 | balanced-match@1.0.2: 789 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 790 | 791 | binary-extensions@2.3.0: 792 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 793 | engines: {node: '>=8'} 794 | 795 | brace-expansion@2.0.1: 796 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 797 | 798 | braces@3.0.3: 799 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 800 | engines: {node: '>=8'} 801 | 802 | buffer-from@1.1.2: 803 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 804 | 805 | bundle-require@5.0.0: 806 | resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==} 807 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 808 | peerDependencies: 809 | esbuild: '>=0.18' 810 | 811 | busboy@1.6.0: 812 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} 813 | engines: {node: '>=10.16.0'} 814 | 815 | bytes@3.1.2: 816 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 817 | engines: {node: '>= 0.8'} 818 | 819 | cac@6.7.14: 820 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 821 | engines: {node: '>=8'} 822 | 823 | cache-content-type@1.0.1: 824 | resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==} 825 | engines: {node: '>= 6.0.0'} 826 | 827 | call-bind-apply-helpers@1.0.2: 828 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 829 | engines: {node: '>= 0.4'} 830 | 831 | call-bound@1.0.3: 832 | resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} 833 | engines: {node: '>= 0.4'} 834 | 835 | chokidar@3.6.0: 836 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 837 | engines: {node: '>= 8.10.0'} 838 | 839 | co-body@6.2.0: 840 | resolution: {integrity: sha512-Kbpv2Yd1NdL1V/V4cwLVxraHDV6K8ayohr2rmH0J87Er8+zJjcTa6dAn9QMPC9CRgU8+aNajKbSf1TzDB1yKPA==} 841 | engines: {node: '>=8.0.0'} 842 | 843 | co@4.6.0: 844 | resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} 845 | engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} 846 | 847 | color-convert@2.0.1: 848 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 849 | engines: {node: '>=7.0.0'} 850 | 851 | color-name@1.1.4: 852 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 853 | 854 | colorette@2.0.20: 855 | resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} 856 | 857 | combined-stream@1.0.8: 858 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 859 | engines: {node: '>= 0.8'} 860 | 861 | commander@4.1.1: 862 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 863 | engines: {node: '>= 6'} 864 | 865 | concat-stream@1.6.2: 866 | resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} 867 | engines: {'0': node >= 0.8} 868 | 869 | consola@3.2.3: 870 | resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} 871 | engines: {node: ^14.18.0 || >=16.10.0} 872 | 873 | content-disposition@0.5.4: 874 | resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} 875 | engines: {node: '>= 0.6'} 876 | 877 | content-type@1.0.5: 878 | resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} 879 | engines: {node: '>= 0.6'} 880 | 881 | cookies@0.9.1: 882 | resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} 883 | engines: {node: '>= 0.8'} 884 | 885 | core-util-is@1.0.3: 886 | resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} 887 | 888 | cross-spawn@7.0.3: 889 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 890 | engines: {node: '>= 8'} 891 | 892 | data-uri-to-buffer@4.0.1: 893 | resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} 894 | engines: {node: '>= 12'} 895 | 896 | debug@4.3.7: 897 | resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} 898 | engines: {node: '>=6.0'} 899 | peerDependencies: 900 | supports-color: '*' 901 | peerDependenciesMeta: 902 | supports-color: 903 | optional: true 904 | 905 | deep-equal@1.0.1: 906 | resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==} 907 | 908 | delayed-stream@1.0.0: 909 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 910 | engines: {node: '>=0.4.0'} 911 | 912 | delegates@1.0.0: 913 | resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} 914 | 915 | depd@1.1.2: 916 | resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} 917 | engines: {node: '>= 0.6'} 918 | 919 | depd@2.0.0: 920 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 921 | engines: {node: '>= 0.8'} 922 | 923 | destroy@1.2.0: 924 | resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} 925 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} 926 | 927 | dezalgo@1.0.4: 928 | resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} 929 | 930 | dunder-proto@1.0.1: 931 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 932 | engines: {node: '>= 0.4'} 933 | 934 | eastasianwidth@0.2.0: 935 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 936 | 937 | ee-first@1.1.1: 938 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} 939 | 940 | emoji-regex@8.0.0: 941 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 942 | 943 | emoji-regex@9.2.2: 944 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 945 | 946 | encodeurl@1.0.2: 947 | resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} 948 | engines: {node: '>= 0.8'} 949 | 950 | es-define-property@1.0.1: 951 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 952 | engines: {node: '>= 0.4'} 953 | 954 | es-errors@1.3.0: 955 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 956 | engines: {node: '>= 0.4'} 957 | 958 | es-object-atoms@1.1.1: 959 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 960 | engines: {node: '>= 0.4'} 961 | 962 | esbuild@0.21.5: 963 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 964 | engines: {node: '>=12'} 965 | hasBin: true 966 | 967 | esbuild@0.23.1: 968 | resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} 969 | engines: {node: '>=18'} 970 | hasBin: true 971 | 972 | esbuild@0.24.0: 973 | resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} 974 | engines: {node: '>=18'} 975 | hasBin: true 976 | 977 | escape-html@1.0.3: 978 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 979 | 980 | execa@5.1.1: 981 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 982 | engines: {node: '>=10'} 983 | 984 | fdir@6.3.0: 985 | resolution: {integrity: sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==} 986 | peerDependencies: 987 | picomatch: ^3 || ^4 988 | peerDependenciesMeta: 989 | picomatch: 990 | optional: true 991 | 992 | fetch-blob@3.2.0: 993 | resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} 994 | engines: {node: ^12.20 || >= 14.13} 995 | 996 | fill-range@7.1.1: 997 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 998 | engines: {node: '>=8'} 999 | 1000 | foreground-child@3.3.0: 1001 | resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} 1002 | engines: {node: '>=14'} 1003 | 1004 | form-data@4.0.1: 1005 | resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} 1006 | engines: {node: '>= 6'} 1007 | 1008 | formdata-polyfill@4.0.10: 1009 | resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} 1010 | engines: {node: '>=12.20.0'} 1011 | 1012 | formidable@2.1.2: 1013 | resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} 1014 | 1015 | fresh@0.5.2: 1016 | resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} 1017 | engines: {node: '>= 0.6'} 1018 | 1019 | fsevents@2.3.3: 1020 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1021 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1022 | os: [darwin] 1023 | 1024 | function-bind@1.1.2: 1025 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1026 | 1027 | get-intrinsic@1.2.7: 1028 | resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} 1029 | engines: {node: '>= 0.4'} 1030 | 1031 | get-proto@1.0.1: 1032 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 1033 | engines: {node: '>= 0.4'} 1034 | 1035 | get-stream@6.0.1: 1036 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 1037 | engines: {node: '>=10'} 1038 | 1039 | glob-parent@5.1.2: 1040 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1041 | engines: {node: '>= 6'} 1042 | 1043 | glob@10.4.5: 1044 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 1045 | hasBin: true 1046 | 1047 | gopd@1.2.0: 1048 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 1049 | engines: {node: '>= 0.4'} 1050 | 1051 | has-symbols@1.1.0: 1052 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 1053 | engines: {node: '>= 0.4'} 1054 | 1055 | has-tostringtag@1.0.2: 1056 | resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} 1057 | engines: {node: '>= 0.4'} 1058 | 1059 | hasown@2.0.2: 1060 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 1061 | engines: {node: '>= 0.4'} 1062 | 1063 | hexoid@1.0.0: 1064 | resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} 1065 | engines: {node: '>=8'} 1066 | 1067 | http-assert@1.5.0: 1068 | resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==} 1069 | engines: {node: '>= 0.8'} 1070 | 1071 | http-errors@1.8.1: 1072 | resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} 1073 | engines: {node: '>= 0.6'} 1074 | 1075 | http-errors@2.0.0: 1076 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 1077 | engines: {node: '>= 0.8'} 1078 | 1079 | human-signals@2.1.0: 1080 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 1081 | engines: {node: '>=10.17.0'} 1082 | 1083 | iconv-lite@0.4.24: 1084 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 1085 | engines: {node: '>=0.10.0'} 1086 | 1087 | inflation@2.1.0: 1088 | resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==} 1089 | engines: {node: '>= 0.8.0'} 1090 | 1091 | inherits@2.0.4: 1092 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1093 | 1094 | is-binary-path@2.1.0: 1095 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1096 | engines: {node: '>=8'} 1097 | 1098 | is-extglob@2.1.1: 1099 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1100 | engines: {node: '>=0.10.0'} 1101 | 1102 | is-fullwidth-code-point@3.0.0: 1103 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1104 | engines: {node: '>=8'} 1105 | 1106 | is-generator-function@1.1.0: 1107 | resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} 1108 | engines: {node: '>= 0.4'} 1109 | 1110 | is-glob@4.0.3: 1111 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1112 | engines: {node: '>=0.10.0'} 1113 | 1114 | is-number@7.0.0: 1115 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1116 | engines: {node: '>=0.12.0'} 1117 | 1118 | is-regex@1.2.1: 1119 | resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} 1120 | engines: {node: '>= 0.4'} 1121 | 1122 | is-stream@2.0.1: 1123 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 1124 | engines: {node: '>=8'} 1125 | 1126 | isarray@1.0.0: 1127 | resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} 1128 | 1129 | isexe@2.0.0: 1130 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1131 | 1132 | jackspeak@3.4.3: 1133 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 1134 | 1135 | joycon@3.1.1: 1136 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 1137 | engines: {node: '>=10'} 1138 | 1139 | keygrip@1.1.0: 1140 | resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} 1141 | engines: {node: '>= 0.6'} 1142 | 1143 | koa-body@6.0.1: 1144 | resolution: {integrity: sha512-M8ZvMD8r+kPHy28aWP9VxL7kY8oPWA+C7ZgCljrCMeaU7uX6wsIQgDHskyrAr9sw+jqnIXyv4Mlxri5R4InIJg==} 1145 | 1146 | koa-compose@4.1.0: 1147 | resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} 1148 | 1149 | koa-convert@2.0.0: 1150 | resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==} 1151 | engines: {node: '>= 10'} 1152 | 1153 | koa-router@13.0.1: 1154 | resolution: {integrity: sha512-4/sijXdSxocIe2wv7RFFSxvo2ic1pDzPSmy11yCGztng1hx408qfw1wVmN3aqhQaU7U6nJ039JKC8ObE73Ohgw==} 1155 | engines: {node: '>= 18'} 1156 | 1157 | koa@2.15.4: 1158 | resolution: {integrity: sha512-7fNBIdrU2PEgLljXoPWoyY4r1e+ToWCmzS/wwMPbUNs7X+5MMET1ObhJBlUkF5uZG9B6QhM2zS1TsH6adegkiQ==} 1159 | engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4} 1160 | 1161 | lilconfig@3.1.2: 1162 | resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} 1163 | engines: {node: '>=14'} 1164 | 1165 | lines-and-columns@1.2.4: 1166 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 1167 | 1168 | load-tsconfig@0.2.5: 1169 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 1170 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1171 | 1172 | lodash.sortby@4.7.0: 1173 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 1174 | 1175 | lru-cache@10.4.3: 1176 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 1177 | 1178 | math-intrinsics@1.1.0: 1179 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 1180 | engines: {node: '>= 0.4'} 1181 | 1182 | media-typer@0.3.0: 1183 | resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} 1184 | engines: {node: '>= 0.6'} 1185 | 1186 | merge-stream@2.0.0: 1187 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 1188 | 1189 | mime-db@1.52.0: 1190 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 1191 | engines: {node: '>= 0.6'} 1192 | 1193 | mime-types@2.1.35: 1194 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 1195 | engines: {node: '>= 0.6'} 1196 | 1197 | mimic-fn@2.1.0: 1198 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 1199 | engines: {node: '>=6'} 1200 | 1201 | minimatch@9.0.5: 1202 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1203 | engines: {node: '>=16 || 14 >=14.17'} 1204 | 1205 | minimist@1.2.8: 1206 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1207 | 1208 | minipass@7.1.2: 1209 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 1210 | engines: {node: '>=16 || 14 >=14.17'} 1211 | 1212 | mkdirp@0.5.6: 1213 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} 1214 | hasBin: true 1215 | 1216 | ms@2.1.3: 1217 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1218 | 1219 | multer@1.4.5-lts.1: 1220 | resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} 1221 | engines: {node: '>= 6.0.0'} 1222 | 1223 | mz@2.7.0: 1224 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 1225 | 1226 | nanoid@3.3.7: 1227 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 1228 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1229 | hasBin: true 1230 | 1231 | nanoid@5.0.8: 1232 | resolution: {integrity: sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==} 1233 | engines: {node: ^18 || >=20} 1234 | hasBin: true 1235 | 1236 | negotiator@0.6.3: 1237 | resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} 1238 | engines: {node: '>= 0.6'} 1239 | 1240 | node-domexception@1.0.0: 1241 | resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} 1242 | engines: {node: '>=10.5.0'} 1243 | 1244 | node-fetch@3.3.2: 1245 | resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} 1246 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1247 | 1248 | normalize-path@3.0.0: 1249 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1250 | engines: {node: '>=0.10.0'} 1251 | 1252 | npm-run-path@4.0.1: 1253 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 1254 | engines: {node: '>=8'} 1255 | 1256 | object-assign@4.1.1: 1257 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1258 | engines: {node: '>=0.10.0'} 1259 | 1260 | object-inspect@1.13.4: 1261 | resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} 1262 | engines: {node: '>= 0.4'} 1263 | 1264 | on-finished@2.4.1: 1265 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} 1266 | engines: {node: '>= 0.8'} 1267 | 1268 | once@1.4.0: 1269 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1270 | 1271 | onetime@5.1.2: 1272 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} 1273 | engines: {node: '>=6'} 1274 | 1275 | only@0.0.2: 1276 | resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==} 1277 | 1278 | package-json-from-dist@1.0.0: 1279 | resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} 1280 | 1281 | parseurl@1.3.3: 1282 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} 1283 | engines: {node: '>= 0.8'} 1284 | 1285 | path-key@3.1.1: 1286 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1287 | engines: {node: '>=8'} 1288 | 1289 | path-scurry@1.11.1: 1290 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 1291 | engines: {node: '>=16 || 14 >=14.18'} 1292 | 1293 | path-to-regexp@6.3.0: 1294 | resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} 1295 | 1296 | path-to-regexp@8.2.0: 1297 | resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} 1298 | engines: {node: '>=16'} 1299 | 1300 | picocolors@1.1.0: 1301 | resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} 1302 | 1303 | picomatch@2.3.1: 1304 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1305 | engines: {node: '>=8.6'} 1306 | 1307 | picomatch@4.0.2: 1308 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 1309 | engines: {node: '>=12'} 1310 | 1311 | pirates@4.0.6: 1312 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} 1313 | engines: {node: '>= 6'} 1314 | 1315 | postcss-load-config@6.0.1: 1316 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} 1317 | engines: {node: '>= 18'} 1318 | peerDependencies: 1319 | jiti: '>=1.21.0' 1320 | postcss: '>=8.0.9' 1321 | tsx: ^4.8.1 1322 | yaml: ^2.4.2 1323 | peerDependenciesMeta: 1324 | jiti: 1325 | optional: true 1326 | postcss: 1327 | optional: true 1328 | tsx: 1329 | optional: true 1330 | yaml: 1331 | optional: true 1332 | 1333 | postcss@8.4.47: 1334 | resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} 1335 | engines: {node: ^10 || ^12 || >=14} 1336 | 1337 | prettier@3.3.3: 1338 | resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} 1339 | engines: {node: '>=14'} 1340 | hasBin: true 1341 | 1342 | process-nextick-args@2.0.1: 1343 | resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} 1344 | 1345 | punycode@2.3.1: 1346 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1347 | engines: {node: '>=6'} 1348 | 1349 | qs@6.14.0: 1350 | resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} 1351 | engines: {node: '>=0.6'} 1352 | 1353 | raw-body@2.5.2: 1354 | resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} 1355 | engines: {node: '>= 0.8'} 1356 | 1357 | rcon@1.1.0: 1358 | resolution: {integrity: sha512-eotwcApOBjfadTjqQlrZVR4jzlwGCMNxmHhnFZx+g4kouwwRstRHkk1ON7DzkqrHNIjADSh0cU3gThSsDolUpg==} 1359 | 1360 | readable-stream@2.3.8: 1361 | resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} 1362 | 1363 | readdirp@3.6.0: 1364 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1365 | engines: {node: '>=8.10.0'} 1366 | 1367 | resolve-from@5.0.0: 1368 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1369 | engines: {node: '>=8'} 1370 | 1371 | rollup@4.22.0: 1372 | resolution: {integrity: sha512-W21MUIFPZ4+O2Je/EU+GP3iz7PH4pVPUXSbEZdatQnxo29+3rsUjgrJmzuAZU24z7yRAnFN6ukxeAhZh/c7hzg==} 1373 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1374 | hasBin: true 1375 | 1376 | safe-buffer@5.1.2: 1377 | resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} 1378 | 1379 | safe-buffer@5.2.1: 1380 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1381 | 1382 | safe-regex-test@1.1.0: 1383 | resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} 1384 | engines: {node: '>= 0.4'} 1385 | 1386 | safer-buffer@2.1.2: 1387 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 1388 | 1389 | setprototypeof@1.2.0: 1390 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 1391 | 1392 | shebang-command@2.0.0: 1393 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1394 | engines: {node: '>=8'} 1395 | 1396 | shebang-regex@3.0.0: 1397 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1398 | engines: {node: '>=8'} 1399 | 1400 | side-channel-list@1.0.0: 1401 | resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} 1402 | engines: {node: '>= 0.4'} 1403 | 1404 | side-channel-map@1.0.1: 1405 | resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} 1406 | engines: {node: '>= 0.4'} 1407 | 1408 | side-channel-weakmap@1.0.2: 1409 | resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} 1410 | engines: {node: '>= 0.4'} 1411 | 1412 | side-channel@1.1.0: 1413 | resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} 1414 | engines: {node: '>= 0.4'} 1415 | 1416 | signal-exit@3.0.7: 1417 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1418 | 1419 | signal-exit@4.1.0: 1420 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1421 | engines: {node: '>=14'} 1422 | 1423 | source-map-js@1.2.1: 1424 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1425 | engines: {node: '>=0.10.0'} 1426 | 1427 | source-map@0.8.0-beta.0: 1428 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 1429 | engines: {node: '>= 8'} 1430 | 1431 | statuses@1.5.0: 1432 | resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} 1433 | engines: {node: '>= 0.6'} 1434 | 1435 | statuses@2.0.1: 1436 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 1437 | engines: {node: '>= 0.8'} 1438 | 1439 | streamsearch@1.1.0: 1440 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} 1441 | engines: {node: '>=10.0.0'} 1442 | 1443 | string-width@4.2.3: 1444 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1445 | engines: {node: '>=8'} 1446 | 1447 | string-width@5.1.2: 1448 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1449 | engines: {node: '>=12'} 1450 | 1451 | string_decoder@1.1.1: 1452 | resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} 1453 | 1454 | strip-ansi@6.0.1: 1455 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1456 | engines: {node: '>=8'} 1457 | 1458 | strip-ansi@7.1.0: 1459 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1460 | engines: {node: '>=12'} 1461 | 1462 | strip-final-newline@2.0.0: 1463 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 1464 | engines: {node: '>=6'} 1465 | 1466 | sucrase@3.35.0: 1467 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1468 | engines: {node: '>=16 || 14 >=14.17'} 1469 | hasBin: true 1470 | 1471 | thenify-all@1.6.0: 1472 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1473 | engines: {node: '>=0.8'} 1474 | 1475 | thenify@3.3.1: 1476 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1477 | 1478 | tinyglobby@0.2.6: 1479 | resolution: {integrity: sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g==} 1480 | engines: {node: '>=12.0.0'} 1481 | 1482 | to-regex-range@5.0.1: 1483 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1484 | engines: {node: '>=8.0'} 1485 | 1486 | toidentifier@1.0.1: 1487 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} 1488 | engines: {node: '>=0.6'} 1489 | 1490 | tr46@1.0.1: 1491 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 1492 | 1493 | tree-kill@1.2.2: 1494 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1495 | hasBin: true 1496 | 1497 | ts-interface-checker@0.1.13: 1498 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1499 | 1500 | tsscmp@1.0.6: 1501 | resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} 1502 | engines: {node: '>=0.6.x'} 1503 | 1504 | tsup@8.3.0: 1505 | resolution: {integrity: sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag==} 1506 | engines: {node: '>=18'} 1507 | hasBin: true 1508 | peerDependencies: 1509 | '@microsoft/api-extractor': ^7.36.0 1510 | '@swc/core': ^1 1511 | postcss: ^8.4.12 1512 | typescript: '>=4.5.0' 1513 | peerDependenciesMeta: 1514 | '@microsoft/api-extractor': 1515 | optional: true 1516 | '@swc/core': 1517 | optional: true 1518 | postcss: 1519 | optional: true 1520 | typescript: 1521 | optional: true 1522 | 1523 | turbo-darwin-64@2.1.2: 1524 | resolution: {integrity: sha512-3TEBxHWh99h2yIzkuIigMEOXt/ItYQp0aPiJjPd1xN4oDcsKK5AxiFKPH9pdtfIBzYsY59kQhZiFj0ELnSP7Bw==} 1525 | cpu: [x64] 1526 | os: [darwin] 1527 | 1528 | turbo-darwin-arm64@2.1.2: 1529 | resolution: {integrity: sha512-he0miWNq2WxJzsH82jS2Z4MXpnkzn9SH8a79iPXiJkq25QREImucscM4RPasXm8wARp91pyysJMq6aasD45CeA==} 1530 | cpu: [arm64] 1531 | os: [darwin] 1532 | 1533 | turbo-linux-64@2.1.2: 1534 | resolution: {integrity: sha512-fKUBcc0rK8Vdqv5a/E3CSpMBLG1bzwv+Q0Q83F8fG2ZfNCNKGbcEYABdonNZkkx141Rj03cZQFCgxu3MVEGU+A==} 1535 | cpu: [x64] 1536 | os: [linux] 1537 | 1538 | turbo-linux-arm64@2.1.2: 1539 | resolution: {integrity: sha512-sV8Bpmm0WiuxgbhxymcC7wSsuxfBBieI98GegSwbr/bs1ANAgzCg93urIrdKdQ3/b31zZxQwcaP4FBF1wx1Qdg==} 1540 | cpu: [arm64] 1541 | os: [linux] 1542 | 1543 | turbo-windows-64@2.1.2: 1544 | resolution: {integrity: sha512-wcmIJZI9ORT9ykHGliFE6kWRQrlH930QGSjSgWC8uFChFFuOyUlvC7ttcxuSvU9VqC7NF4C+GVAcFJQ8lTjN7g==} 1545 | cpu: [x64] 1546 | os: [win32] 1547 | 1548 | turbo-windows-arm64@2.1.2: 1549 | resolution: {integrity: sha512-zdnXjrhk7YO6CP+Q5wPueEvOCLH4lDa6C4rrwiakcWcPgcQGbVozJlo4uaQ6awo8HLWQEvOwu84RkWTdLAc/Hw==} 1550 | cpu: [arm64] 1551 | os: [win32] 1552 | 1553 | turbo@2.1.2: 1554 | resolution: {integrity: sha512-Jb0rbU4iHEVQ18An/YfakdIv9rKnd3zUfSE117EngrfWXFHo3RndVH96US3GsT8VHpwTncPePDBT2t06PaFLrw==} 1555 | hasBin: true 1556 | 1557 | type-is@1.6.18: 1558 | resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} 1559 | engines: {node: '>= 0.6'} 1560 | 1561 | typedarray@0.0.6: 1562 | resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} 1563 | 1564 | typescript@5.6.2: 1565 | resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} 1566 | engines: {node: '>=14.17'} 1567 | hasBin: true 1568 | 1569 | undici-types@6.19.8: 1570 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} 1571 | 1572 | unpipe@1.0.0: 1573 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} 1574 | engines: {node: '>= 0.8'} 1575 | 1576 | util-deprecate@1.0.2: 1577 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 1578 | 1579 | vary@1.1.2: 1580 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 1581 | engines: {node: '>= 0.8'} 1582 | 1583 | vite@5.4.6: 1584 | resolution: {integrity: sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==} 1585 | engines: {node: ^18.0.0 || >=20.0.0} 1586 | hasBin: true 1587 | peerDependencies: 1588 | '@types/node': ^18.0.0 || >=20.0.0 1589 | less: '*' 1590 | lightningcss: ^1.21.0 1591 | sass: '*' 1592 | sass-embedded: '*' 1593 | stylus: '*' 1594 | sugarss: '*' 1595 | terser: ^5.4.0 1596 | peerDependenciesMeta: 1597 | '@types/node': 1598 | optional: true 1599 | less: 1600 | optional: true 1601 | lightningcss: 1602 | optional: true 1603 | sass: 1604 | optional: true 1605 | sass-embedded: 1606 | optional: true 1607 | stylus: 1608 | optional: true 1609 | sugarss: 1610 | optional: true 1611 | terser: 1612 | optional: true 1613 | 1614 | web-streams-polyfill@3.3.3: 1615 | resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} 1616 | engines: {node: '>= 8'} 1617 | 1618 | webidl-conversions@4.0.2: 1619 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 1620 | 1621 | whatwg-url@7.1.0: 1622 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 1623 | 1624 | which@2.0.2: 1625 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1626 | engines: {node: '>= 8'} 1627 | hasBin: true 1628 | 1629 | wrap-ansi@7.0.0: 1630 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1631 | engines: {node: '>=10'} 1632 | 1633 | wrap-ansi@8.1.0: 1634 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1635 | engines: {node: '>=12'} 1636 | 1637 | wrappy@1.0.2: 1638 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1639 | 1640 | xtend@4.0.2: 1641 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} 1642 | engines: {node: '>=0.4'} 1643 | 1644 | ylru@1.4.0: 1645 | resolution: {integrity: sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==} 1646 | engines: {node: '>= 4.0.0'} 1647 | 1648 | zod@3.24.2: 1649 | resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} 1650 | 1651 | snapshots: 1652 | 1653 | '@citizenfx/client@2.0.10822-1': {} 1654 | 1655 | '@citizenfx/http-wrapper@0.2.2': {} 1656 | 1657 | '@citizenfx/server@2.0.7290-1': {} 1658 | 1659 | '@esbuild/aix-ppc64@0.21.5': 1660 | optional: true 1661 | 1662 | '@esbuild/aix-ppc64@0.23.1': 1663 | optional: true 1664 | 1665 | '@esbuild/aix-ppc64@0.24.0': 1666 | optional: true 1667 | 1668 | '@esbuild/android-arm64@0.21.5': 1669 | optional: true 1670 | 1671 | '@esbuild/android-arm64@0.23.1': 1672 | optional: true 1673 | 1674 | '@esbuild/android-arm64@0.24.0': 1675 | optional: true 1676 | 1677 | '@esbuild/android-arm@0.21.5': 1678 | optional: true 1679 | 1680 | '@esbuild/android-arm@0.23.1': 1681 | optional: true 1682 | 1683 | '@esbuild/android-arm@0.24.0': 1684 | optional: true 1685 | 1686 | '@esbuild/android-x64@0.21.5': 1687 | optional: true 1688 | 1689 | '@esbuild/android-x64@0.23.1': 1690 | optional: true 1691 | 1692 | '@esbuild/android-x64@0.24.0': 1693 | optional: true 1694 | 1695 | '@esbuild/darwin-arm64@0.21.5': 1696 | optional: true 1697 | 1698 | '@esbuild/darwin-arm64@0.23.1': 1699 | optional: true 1700 | 1701 | '@esbuild/darwin-arm64@0.24.0': 1702 | optional: true 1703 | 1704 | '@esbuild/darwin-x64@0.21.5': 1705 | optional: true 1706 | 1707 | '@esbuild/darwin-x64@0.23.1': 1708 | optional: true 1709 | 1710 | '@esbuild/darwin-x64@0.24.0': 1711 | optional: true 1712 | 1713 | '@esbuild/freebsd-arm64@0.21.5': 1714 | optional: true 1715 | 1716 | '@esbuild/freebsd-arm64@0.23.1': 1717 | optional: true 1718 | 1719 | '@esbuild/freebsd-arm64@0.24.0': 1720 | optional: true 1721 | 1722 | '@esbuild/freebsd-x64@0.21.5': 1723 | optional: true 1724 | 1725 | '@esbuild/freebsd-x64@0.23.1': 1726 | optional: true 1727 | 1728 | '@esbuild/freebsd-x64@0.24.0': 1729 | optional: true 1730 | 1731 | '@esbuild/linux-arm64@0.21.5': 1732 | optional: true 1733 | 1734 | '@esbuild/linux-arm64@0.23.1': 1735 | optional: true 1736 | 1737 | '@esbuild/linux-arm64@0.24.0': 1738 | optional: true 1739 | 1740 | '@esbuild/linux-arm@0.21.5': 1741 | optional: true 1742 | 1743 | '@esbuild/linux-arm@0.23.1': 1744 | optional: true 1745 | 1746 | '@esbuild/linux-arm@0.24.0': 1747 | optional: true 1748 | 1749 | '@esbuild/linux-ia32@0.21.5': 1750 | optional: true 1751 | 1752 | '@esbuild/linux-ia32@0.23.1': 1753 | optional: true 1754 | 1755 | '@esbuild/linux-ia32@0.24.0': 1756 | optional: true 1757 | 1758 | '@esbuild/linux-loong64@0.21.5': 1759 | optional: true 1760 | 1761 | '@esbuild/linux-loong64@0.23.1': 1762 | optional: true 1763 | 1764 | '@esbuild/linux-loong64@0.24.0': 1765 | optional: true 1766 | 1767 | '@esbuild/linux-mips64el@0.21.5': 1768 | optional: true 1769 | 1770 | '@esbuild/linux-mips64el@0.23.1': 1771 | optional: true 1772 | 1773 | '@esbuild/linux-mips64el@0.24.0': 1774 | optional: true 1775 | 1776 | '@esbuild/linux-ppc64@0.21.5': 1777 | optional: true 1778 | 1779 | '@esbuild/linux-ppc64@0.23.1': 1780 | optional: true 1781 | 1782 | '@esbuild/linux-ppc64@0.24.0': 1783 | optional: true 1784 | 1785 | '@esbuild/linux-riscv64@0.21.5': 1786 | optional: true 1787 | 1788 | '@esbuild/linux-riscv64@0.23.1': 1789 | optional: true 1790 | 1791 | '@esbuild/linux-riscv64@0.24.0': 1792 | optional: true 1793 | 1794 | '@esbuild/linux-s390x@0.21.5': 1795 | optional: true 1796 | 1797 | '@esbuild/linux-s390x@0.23.1': 1798 | optional: true 1799 | 1800 | '@esbuild/linux-s390x@0.24.0': 1801 | optional: true 1802 | 1803 | '@esbuild/linux-x64@0.21.5': 1804 | optional: true 1805 | 1806 | '@esbuild/linux-x64@0.23.1': 1807 | optional: true 1808 | 1809 | '@esbuild/linux-x64@0.24.0': 1810 | optional: true 1811 | 1812 | '@esbuild/netbsd-x64@0.21.5': 1813 | optional: true 1814 | 1815 | '@esbuild/netbsd-x64@0.23.1': 1816 | optional: true 1817 | 1818 | '@esbuild/netbsd-x64@0.24.0': 1819 | optional: true 1820 | 1821 | '@esbuild/openbsd-arm64@0.23.1': 1822 | optional: true 1823 | 1824 | '@esbuild/openbsd-arm64@0.24.0': 1825 | optional: true 1826 | 1827 | '@esbuild/openbsd-x64@0.21.5': 1828 | optional: true 1829 | 1830 | '@esbuild/openbsd-x64@0.23.1': 1831 | optional: true 1832 | 1833 | '@esbuild/openbsd-x64@0.24.0': 1834 | optional: true 1835 | 1836 | '@esbuild/sunos-x64@0.21.5': 1837 | optional: true 1838 | 1839 | '@esbuild/sunos-x64@0.23.1': 1840 | optional: true 1841 | 1842 | '@esbuild/sunos-x64@0.24.0': 1843 | optional: true 1844 | 1845 | '@esbuild/win32-arm64@0.21.5': 1846 | optional: true 1847 | 1848 | '@esbuild/win32-arm64@0.23.1': 1849 | optional: true 1850 | 1851 | '@esbuild/win32-arm64@0.24.0': 1852 | optional: true 1853 | 1854 | '@esbuild/win32-ia32@0.21.5': 1855 | optional: true 1856 | 1857 | '@esbuild/win32-ia32@0.23.1': 1858 | optional: true 1859 | 1860 | '@esbuild/win32-ia32@0.24.0': 1861 | optional: true 1862 | 1863 | '@esbuild/win32-x64@0.21.5': 1864 | optional: true 1865 | 1866 | '@esbuild/win32-x64@0.23.1': 1867 | optional: true 1868 | 1869 | '@esbuild/win32-x64@0.24.0': 1870 | optional: true 1871 | 1872 | '@hapi/bourne@3.0.0': {} 1873 | 1874 | '@isaacs/cliui@8.0.2': 1875 | dependencies: 1876 | string-width: 5.1.2 1877 | string-width-cjs: string-width@4.2.3 1878 | strip-ansi: 7.1.0 1879 | strip-ansi-cjs: strip-ansi@6.0.1 1880 | wrap-ansi: 8.1.0 1881 | wrap-ansi-cjs: wrap-ansi@7.0.0 1882 | 1883 | '@jridgewell/gen-mapping@0.3.5': 1884 | dependencies: 1885 | '@jridgewell/set-array': 1.2.1 1886 | '@jridgewell/sourcemap-codec': 1.5.0 1887 | '@jridgewell/trace-mapping': 0.3.25 1888 | 1889 | '@jridgewell/resolve-uri@3.1.2': {} 1890 | 1891 | '@jridgewell/set-array@1.2.1': {} 1892 | 1893 | '@jridgewell/sourcemap-codec@1.5.0': {} 1894 | 1895 | '@jridgewell/trace-mapping@0.3.25': 1896 | dependencies: 1897 | '@jridgewell/resolve-uri': 3.1.2 1898 | '@jridgewell/sourcemap-codec': 1.5.0 1899 | 1900 | '@koa/router@13.1.0': 1901 | dependencies: 1902 | http-errors: 2.0.0 1903 | koa-compose: 4.1.0 1904 | path-to-regexp: 6.3.0 1905 | 1906 | '@pkgjs/parseargs@0.11.0': 1907 | optional: true 1908 | 1909 | '@rollup/rollup-android-arm-eabi@4.22.0': 1910 | optional: true 1911 | 1912 | '@rollup/rollup-android-arm64@4.22.0': 1913 | optional: true 1914 | 1915 | '@rollup/rollup-darwin-arm64@4.22.0': 1916 | optional: true 1917 | 1918 | '@rollup/rollup-darwin-x64@4.22.0': 1919 | optional: true 1920 | 1921 | '@rollup/rollup-linux-arm-gnueabihf@4.22.0': 1922 | optional: true 1923 | 1924 | '@rollup/rollup-linux-arm-musleabihf@4.22.0': 1925 | optional: true 1926 | 1927 | '@rollup/rollup-linux-arm64-gnu@4.22.0': 1928 | optional: true 1929 | 1930 | '@rollup/rollup-linux-arm64-musl@4.22.0': 1931 | optional: true 1932 | 1933 | '@rollup/rollup-linux-powerpc64le-gnu@4.22.0': 1934 | optional: true 1935 | 1936 | '@rollup/rollup-linux-riscv64-gnu@4.22.0': 1937 | optional: true 1938 | 1939 | '@rollup/rollup-linux-s390x-gnu@4.22.0': 1940 | optional: true 1941 | 1942 | '@rollup/rollup-linux-x64-gnu@4.22.0': 1943 | optional: true 1944 | 1945 | '@rollup/rollup-linux-x64-musl@4.22.0': 1946 | optional: true 1947 | 1948 | '@rollup/rollup-win32-arm64-msvc@4.22.0': 1949 | optional: true 1950 | 1951 | '@rollup/rollup-win32-ia32-msvc@4.22.0': 1952 | optional: true 1953 | 1954 | '@rollup/rollup-win32-x64-msvc@4.22.0': 1955 | optional: true 1956 | 1957 | '@types/accepts@1.3.7': 1958 | dependencies: 1959 | '@types/node': 22.8.6 1960 | 1961 | '@types/body-parser@1.19.5': 1962 | dependencies: 1963 | '@types/connect': 3.4.38 1964 | '@types/node': 22.8.6 1965 | 1966 | '@types/co-body@6.1.3': 1967 | dependencies: 1968 | '@types/node': 22.8.6 1969 | '@types/qs': 6.9.18 1970 | 1971 | '@types/connect@3.4.38': 1972 | dependencies: 1973 | '@types/node': 22.8.6 1974 | 1975 | '@types/content-disposition@0.5.8': {} 1976 | 1977 | '@types/cookies@0.9.0': 1978 | dependencies: 1979 | '@types/connect': 3.4.38 1980 | '@types/express': 5.0.0 1981 | '@types/keygrip': 1.0.6 1982 | '@types/node': 22.8.6 1983 | 1984 | '@types/estree@1.0.5': {} 1985 | 1986 | '@types/express-serve-static-core@5.0.6': 1987 | dependencies: 1988 | '@types/node': 22.8.6 1989 | '@types/qs': 6.9.18 1990 | '@types/range-parser': 1.2.7 1991 | '@types/send': 0.17.4 1992 | 1993 | '@types/express@5.0.0': 1994 | dependencies: 1995 | '@types/body-parser': 1.19.5 1996 | '@types/express-serve-static-core': 5.0.6 1997 | '@types/qs': 6.9.18 1998 | '@types/serve-static': 1.15.7 1999 | 2000 | '@types/formidable@2.0.6': 2001 | dependencies: 2002 | '@types/node': 22.8.6 2003 | 2004 | '@types/formidable@3.4.5': 2005 | dependencies: 2006 | '@types/node': 22.8.6 2007 | 2008 | '@types/http-assert@1.5.6': {} 2009 | 2010 | '@types/http-errors@2.0.4': {} 2011 | 2012 | '@types/keygrip@1.0.6': {} 2013 | 2014 | '@types/koa-compose@3.2.8': 2015 | dependencies: 2016 | '@types/koa': 2.15.0 2017 | 2018 | '@types/koa-router@7.4.8': 2019 | dependencies: 2020 | '@types/koa': 2.15.0 2021 | 2022 | '@types/koa@2.15.0': 2023 | dependencies: 2024 | '@types/accepts': 1.3.7 2025 | '@types/content-disposition': 0.5.8 2026 | '@types/cookies': 0.9.0 2027 | '@types/http-assert': 1.5.6 2028 | '@types/http-errors': 2.0.4 2029 | '@types/keygrip': 1.0.6 2030 | '@types/koa-compose': 3.2.8 2031 | '@types/node': 22.8.6 2032 | 2033 | '@types/koa__router@12.0.4': 2034 | dependencies: 2035 | '@types/koa': 2.15.0 2036 | 2037 | '@types/mime@1.3.5': {} 2038 | 2039 | '@types/multer@1.4.12': 2040 | dependencies: 2041 | '@types/express': 5.0.0 2042 | 2043 | '@types/node@22.8.6': 2044 | dependencies: 2045 | undici-types: 6.19.8 2046 | 2047 | '@types/qs@6.9.18': {} 2048 | 2049 | '@types/range-parser@1.2.7': {} 2050 | 2051 | '@types/send@0.17.4': 2052 | dependencies: 2053 | '@types/mime': 1.3.5 2054 | '@types/node': 22.8.6 2055 | 2056 | '@types/serve-static@1.15.7': 2057 | dependencies: 2058 | '@types/http-errors': 2.0.4 2059 | '@types/node': 22.8.6 2060 | '@types/send': 0.17.4 2061 | 2062 | accepts@1.3.8: 2063 | dependencies: 2064 | mime-types: 2.1.35 2065 | negotiator: 0.6.3 2066 | 2067 | ansi-regex@5.0.1: {} 2068 | 2069 | ansi-regex@6.1.0: {} 2070 | 2071 | ansi-styles@4.3.0: 2072 | dependencies: 2073 | color-convert: 2.0.1 2074 | 2075 | ansi-styles@6.2.1: {} 2076 | 2077 | any-promise@1.3.0: {} 2078 | 2079 | anymatch@3.1.3: 2080 | dependencies: 2081 | normalize-path: 3.0.0 2082 | picomatch: 2.3.1 2083 | 2084 | append-field@1.0.0: {} 2085 | 2086 | asap@2.0.6: {} 2087 | 2088 | asynckit@0.4.0: {} 2089 | 2090 | balanced-match@1.0.2: {} 2091 | 2092 | binary-extensions@2.3.0: {} 2093 | 2094 | brace-expansion@2.0.1: 2095 | dependencies: 2096 | balanced-match: 1.0.2 2097 | 2098 | braces@3.0.3: 2099 | dependencies: 2100 | fill-range: 7.1.1 2101 | 2102 | buffer-from@1.1.2: {} 2103 | 2104 | bundle-require@5.0.0(esbuild@0.23.1): 2105 | dependencies: 2106 | esbuild: 0.23.1 2107 | load-tsconfig: 0.2.5 2108 | 2109 | busboy@1.6.0: 2110 | dependencies: 2111 | streamsearch: 1.1.0 2112 | 2113 | bytes@3.1.2: {} 2114 | 2115 | cac@6.7.14: {} 2116 | 2117 | cache-content-type@1.0.1: 2118 | dependencies: 2119 | mime-types: 2.1.35 2120 | ylru: 1.4.0 2121 | 2122 | call-bind-apply-helpers@1.0.2: 2123 | dependencies: 2124 | es-errors: 1.3.0 2125 | function-bind: 1.1.2 2126 | 2127 | call-bound@1.0.3: 2128 | dependencies: 2129 | call-bind-apply-helpers: 1.0.2 2130 | get-intrinsic: 1.2.7 2131 | 2132 | chokidar@3.6.0: 2133 | dependencies: 2134 | anymatch: 3.1.3 2135 | braces: 3.0.3 2136 | glob-parent: 5.1.2 2137 | is-binary-path: 2.1.0 2138 | is-glob: 4.0.3 2139 | normalize-path: 3.0.0 2140 | readdirp: 3.6.0 2141 | optionalDependencies: 2142 | fsevents: 2.3.3 2143 | 2144 | co-body@6.2.0: 2145 | dependencies: 2146 | '@hapi/bourne': 3.0.0 2147 | inflation: 2.1.0 2148 | qs: 6.14.0 2149 | raw-body: 2.5.2 2150 | type-is: 1.6.18 2151 | 2152 | co@4.6.0: {} 2153 | 2154 | color-convert@2.0.1: 2155 | dependencies: 2156 | color-name: 1.1.4 2157 | 2158 | color-name@1.1.4: {} 2159 | 2160 | colorette@2.0.20: {} 2161 | 2162 | combined-stream@1.0.8: 2163 | dependencies: 2164 | delayed-stream: 1.0.0 2165 | 2166 | commander@4.1.1: {} 2167 | 2168 | concat-stream@1.6.2: 2169 | dependencies: 2170 | buffer-from: 1.1.2 2171 | inherits: 2.0.4 2172 | readable-stream: 2.3.8 2173 | typedarray: 0.0.6 2174 | 2175 | consola@3.2.3: {} 2176 | 2177 | content-disposition@0.5.4: 2178 | dependencies: 2179 | safe-buffer: 5.2.1 2180 | 2181 | content-type@1.0.5: {} 2182 | 2183 | cookies@0.9.1: 2184 | dependencies: 2185 | depd: 2.0.0 2186 | keygrip: 1.1.0 2187 | 2188 | core-util-is@1.0.3: {} 2189 | 2190 | cross-spawn@7.0.3: 2191 | dependencies: 2192 | path-key: 3.1.1 2193 | shebang-command: 2.0.0 2194 | which: 2.0.2 2195 | 2196 | data-uri-to-buffer@4.0.1: {} 2197 | 2198 | debug@4.3.7: 2199 | dependencies: 2200 | ms: 2.1.3 2201 | 2202 | deep-equal@1.0.1: {} 2203 | 2204 | delayed-stream@1.0.0: {} 2205 | 2206 | delegates@1.0.0: {} 2207 | 2208 | depd@1.1.2: {} 2209 | 2210 | depd@2.0.0: {} 2211 | 2212 | destroy@1.2.0: {} 2213 | 2214 | dezalgo@1.0.4: 2215 | dependencies: 2216 | asap: 2.0.6 2217 | wrappy: 1.0.2 2218 | 2219 | dunder-proto@1.0.1: 2220 | dependencies: 2221 | call-bind-apply-helpers: 1.0.2 2222 | es-errors: 1.3.0 2223 | gopd: 1.2.0 2224 | 2225 | eastasianwidth@0.2.0: {} 2226 | 2227 | ee-first@1.1.1: {} 2228 | 2229 | emoji-regex@8.0.0: {} 2230 | 2231 | emoji-regex@9.2.2: {} 2232 | 2233 | encodeurl@1.0.2: {} 2234 | 2235 | es-define-property@1.0.1: {} 2236 | 2237 | es-errors@1.3.0: {} 2238 | 2239 | es-object-atoms@1.1.1: 2240 | dependencies: 2241 | es-errors: 1.3.0 2242 | 2243 | esbuild@0.21.5: 2244 | optionalDependencies: 2245 | '@esbuild/aix-ppc64': 0.21.5 2246 | '@esbuild/android-arm': 0.21.5 2247 | '@esbuild/android-arm64': 0.21.5 2248 | '@esbuild/android-x64': 0.21.5 2249 | '@esbuild/darwin-arm64': 0.21.5 2250 | '@esbuild/darwin-x64': 0.21.5 2251 | '@esbuild/freebsd-arm64': 0.21.5 2252 | '@esbuild/freebsd-x64': 0.21.5 2253 | '@esbuild/linux-arm': 0.21.5 2254 | '@esbuild/linux-arm64': 0.21.5 2255 | '@esbuild/linux-ia32': 0.21.5 2256 | '@esbuild/linux-loong64': 0.21.5 2257 | '@esbuild/linux-mips64el': 0.21.5 2258 | '@esbuild/linux-ppc64': 0.21.5 2259 | '@esbuild/linux-riscv64': 0.21.5 2260 | '@esbuild/linux-s390x': 0.21.5 2261 | '@esbuild/linux-x64': 0.21.5 2262 | '@esbuild/netbsd-x64': 0.21.5 2263 | '@esbuild/openbsd-x64': 0.21.5 2264 | '@esbuild/sunos-x64': 0.21.5 2265 | '@esbuild/win32-arm64': 0.21.5 2266 | '@esbuild/win32-ia32': 0.21.5 2267 | '@esbuild/win32-x64': 0.21.5 2268 | 2269 | esbuild@0.23.1: 2270 | optionalDependencies: 2271 | '@esbuild/aix-ppc64': 0.23.1 2272 | '@esbuild/android-arm': 0.23.1 2273 | '@esbuild/android-arm64': 0.23.1 2274 | '@esbuild/android-x64': 0.23.1 2275 | '@esbuild/darwin-arm64': 0.23.1 2276 | '@esbuild/darwin-x64': 0.23.1 2277 | '@esbuild/freebsd-arm64': 0.23.1 2278 | '@esbuild/freebsd-x64': 0.23.1 2279 | '@esbuild/linux-arm': 0.23.1 2280 | '@esbuild/linux-arm64': 0.23.1 2281 | '@esbuild/linux-ia32': 0.23.1 2282 | '@esbuild/linux-loong64': 0.23.1 2283 | '@esbuild/linux-mips64el': 0.23.1 2284 | '@esbuild/linux-ppc64': 0.23.1 2285 | '@esbuild/linux-riscv64': 0.23.1 2286 | '@esbuild/linux-s390x': 0.23.1 2287 | '@esbuild/linux-x64': 0.23.1 2288 | '@esbuild/netbsd-x64': 0.23.1 2289 | '@esbuild/openbsd-arm64': 0.23.1 2290 | '@esbuild/openbsd-x64': 0.23.1 2291 | '@esbuild/sunos-x64': 0.23.1 2292 | '@esbuild/win32-arm64': 0.23.1 2293 | '@esbuild/win32-ia32': 0.23.1 2294 | '@esbuild/win32-x64': 0.23.1 2295 | 2296 | esbuild@0.24.0: 2297 | optionalDependencies: 2298 | '@esbuild/aix-ppc64': 0.24.0 2299 | '@esbuild/android-arm': 0.24.0 2300 | '@esbuild/android-arm64': 0.24.0 2301 | '@esbuild/android-x64': 0.24.0 2302 | '@esbuild/darwin-arm64': 0.24.0 2303 | '@esbuild/darwin-x64': 0.24.0 2304 | '@esbuild/freebsd-arm64': 0.24.0 2305 | '@esbuild/freebsd-x64': 0.24.0 2306 | '@esbuild/linux-arm': 0.24.0 2307 | '@esbuild/linux-arm64': 0.24.0 2308 | '@esbuild/linux-ia32': 0.24.0 2309 | '@esbuild/linux-loong64': 0.24.0 2310 | '@esbuild/linux-mips64el': 0.24.0 2311 | '@esbuild/linux-ppc64': 0.24.0 2312 | '@esbuild/linux-riscv64': 0.24.0 2313 | '@esbuild/linux-s390x': 0.24.0 2314 | '@esbuild/linux-x64': 0.24.0 2315 | '@esbuild/netbsd-x64': 0.24.0 2316 | '@esbuild/openbsd-arm64': 0.24.0 2317 | '@esbuild/openbsd-x64': 0.24.0 2318 | '@esbuild/sunos-x64': 0.24.0 2319 | '@esbuild/win32-arm64': 0.24.0 2320 | '@esbuild/win32-ia32': 0.24.0 2321 | '@esbuild/win32-x64': 0.24.0 2322 | 2323 | escape-html@1.0.3: {} 2324 | 2325 | execa@5.1.1: 2326 | dependencies: 2327 | cross-spawn: 7.0.3 2328 | get-stream: 6.0.1 2329 | human-signals: 2.1.0 2330 | is-stream: 2.0.1 2331 | merge-stream: 2.0.0 2332 | npm-run-path: 4.0.1 2333 | onetime: 5.1.2 2334 | signal-exit: 3.0.7 2335 | strip-final-newline: 2.0.0 2336 | 2337 | fdir@6.3.0(picomatch@4.0.2): 2338 | optionalDependencies: 2339 | picomatch: 4.0.2 2340 | 2341 | fetch-blob@3.2.0: 2342 | dependencies: 2343 | node-domexception: 1.0.0 2344 | web-streams-polyfill: 3.3.3 2345 | 2346 | fill-range@7.1.1: 2347 | dependencies: 2348 | to-regex-range: 5.0.1 2349 | 2350 | foreground-child@3.3.0: 2351 | dependencies: 2352 | cross-spawn: 7.0.3 2353 | signal-exit: 4.1.0 2354 | 2355 | form-data@4.0.1: 2356 | dependencies: 2357 | asynckit: 0.4.0 2358 | combined-stream: 1.0.8 2359 | mime-types: 2.1.35 2360 | 2361 | formdata-polyfill@4.0.10: 2362 | dependencies: 2363 | fetch-blob: 3.2.0 2364 | 2365 | formidable@2.1.2: 2366 | dependencies: 2367 | dezalgo: 1.0.4 2368 | hexoid: 1.0.0 2369 | once: 1.4.0 2370 | qs: 6.14.0 2371 | 2372 | fresh@0.5.2: {} 2373 | 2374 | fsevents@2.3.3: 2375 | optional: true 2376 | 2377 | function-bind@1.1.2: {} 2378 | 2379 | get-intrinsic@1.2.7: 2380 | dependencies: 2381 | call-bind-apply-helpers: 1.0.2 2382 | es-define-property: 1.0.1 2383 | es-errors: 1.3.0 2384 | es-object-atoms: 1.1.1 2385 | function-bind: 1.1.2 2386 | get-proto: 1.0.1 2387 | gopd: 1.2.0 2388 | has-symbols: 1.1.0 2389 | hasown: 2.0.2 2390 | math-intrinsics: 1.1.0 2391 | 2392 | get-proto@1.0.1: 2393 | dependencies: 2394 | dunder-proto: 1.0.1 2395 | es-object-atoms: 1.1.1 2396 | 2397 | get-stream@6.0.1: {} 2398 | 2399 | glob-parent@5.1.2: 2400 | dependencies: 2401 | is-glob: 4.0.3 2402 | 2403 | glob@10.4.5: 2404 | dependencies: 2405 | foreground-child: 3.3.0 2406 | jackspeak: 3.4.3 2407 | minimatch: 9.0.5 2408 | minipass: 7.1.2 2409 | package-json-from-dist: 1.0.0 2410 | path-scurry: 1.11.1 2411 | 2412 | gopd@1.2.0: {} 2413 | 2414 | has-symbols@1.1.0: {} 2415 | 2416 | has-tostringtag@1.0.2: 2417 | dependencies: 2418 | has-symbols: 1.1.0 2419 | 2420 | hasown@2.0.2: 2421 | dependencies: 2422 | function-bind: 1.1.2 2423 | 2424 | hexoid@1.0.0: {} 2425 | 2426 | http-assert@1.5.0: 2427 | dependencies: 2428 | deep-equal: 1.0.1 2429 | http-errors: 1.8.1 2430 | 2431 | http-errors@1.8.1: 2432 | dependencies: 2433 | depd: 1.1.2 2434 | inherits: 2.0.4 2435 | setprototypeof: 1.2.0 2436 | statuses: 1.5.0 2437 | toidentifier: 1.0.1 2438 | 2439 | http-errors@2.0.0: 2440 | dependencies: 2441 | depd: 2.0.0 2442 | inherits: 2.0.4 2443 | setprototypeof: 1.2.0 2444 | statuses: 2.0.1 2445 | toidentifier: 1.0.1 2446 | 2447 | human-signals@2.1.0: {} 2448 | 2449 | iconv-lite@0.4.24: 2450 | dependencies: 2451 | safer-buffer: 2.1.2 2452 | 2453 | inflation@2.1.0: {} 2454 | 2455 | inherits@2.0.4: {} 2456 | 2457 | is-binary-path@2.1.0: 2458 | dependencies: 2459 | binary-extensions: 2.3.0 2460 | 2461 | is-extglob@2.1.1: {} 2462 | 2463 | is-fullwidth-code-point@3.0.0: {} 2464 | 2465 | is-generator-function@1.1.0: 2466 | dependencies: 2467 | call-bound: 1.0.3 2468 | get-proto: 1.0.1 2469 | has-tostringtag: 1.0.2 2470 | safe-regex-test: 1.1.0 2471 | 2472 | is-glob@4.0.3: 2473 | dependencies: 2474 | is-extglob: 2.1.1 2475 | 2476 | is-number@7.0.0: {} 2477 | 2478 | is-regex@1.2.1: 2479 | dependencies: 2480 | call-bound: 1.0.3 2481 | gopd: 1.2.0 2482 | has-tostringtag: 1.0.2 2483 | hasown: 2.0.2 2484 | 2485 | is-stream@2.0.1: {} 2486 | 2487 | isarray@1.0.0: {} 2488 | 2489 | isexe@2.0.0: {} 2490 | 2491 | jackspeak@3.4.3: 2492 | dependencies: 2493 | '@isaacs/cliui': 8.0.2 2494 | optionalDependencies: 2495 | '@pkgjs/parseargs': 0.11.0 2496 | 2497 | joycon@3.1.1: {} 2498 | 2499 | keygrip@1.1.0: 2500 | dependencies: 2501 | tsscmp: 1.0.6 2502 | 2503 | koa-body@6.0.1: 2504 | dependencies: 2505 | '@types/co-body': 6.1.3 2506 | '@types/formidable': 2.0.6 2507 | '@types/koa': 2.15.0 2508 | co-body: 6.2.0 2509 | formidable: 2.1.2 2510 | zod: 3.24.2 2511 | 2512 | koa-compose@4.1.0: {} 2513 | 2514 | koa-convert@2.0.0: 2515 | dependencies: 2516 | co: 4.6.0 2517 | koa-compose: 4.1.0 2518 | 2519 | koa-router@13.0.1: 2520 | dependencies: 2521 | http-errors: 2.0.0 2522 | koa-compose: 4.1.0 2523 | path-to-regexp: 8.2.0 2524 | 2525 | koa@2.15.4: 2526 | dependencies: 2527 | accepts: 1.3.8 2528 | cache-content-type: 1.0.1 2529 | content-disposition: 0.5.4 2530 | content-type: 1.0.5 2531 | cookies: 0.9.1 2532 | debug: 4.3.7 2533 | delegates: 1.0.0 2534 | depd: 2.0.0 2535 | destroy: 1.2.0 2536 | encodeurl: 1.0.2 2537 | escape-html: 1.0.3 2538 | fresh: 0.5.2 2539 | http-assert: 1.5.0 2540 | http-errors: 1.8.1 2541 | is-generator-function: 1.1.0 2542 | koa-compose: 4.1.0 2543 | koa-convert: 2.0.0 2544 | on-finished: 2.4.1 2545 | only: 0.0.2 2546 | parseurl: 1.3.3 2547 | statuses: 1.5.0 2548 | type-is: 1.6.18 2549 | vary: 1.1.2 2550 | transitivePeerDependencies: 2551 | - supports-color 2552 | 2553 | lilconfig@3.1.2: {} 2554 | 2555 | lines-and-columns@1.2.4: {} 2556 | 2557 | load-tsconfig@0.2.5: {} 2558 | 2559 | lodash.sortby@4.7.0: {} 2560 | 2561 | lru-cache@10.4.3: {} 2562 | 2563 | math-intrinsics@1.1.0: {} 2564 | 2565 | media-typer@0.3.0: {} 2566 | 2567 | merge-stream@2.0.0: {} 2568 | 2569 | mime-db@1.52.0: {} 2570 | 2571 | mime-types@2.1.35: 2572 | dependencies: 2573 | mime-db: 1.52.0 2574 | 2575 | mimic-fn@2.1.0: {} 2576 | 2577 | minimatch@9.0.5: 2578 | dependencies: 2579 | brace-expansion: 2.0.1 2580 | 2581 | minimist@1.2.8: {} 2582 | 2583 | minipass@7.1.2: {} 2584 | 2585 | mkdirp@0.5.6: 2586 | dependencies: 2587 | minimist: 1.2.8 2588 | 2589 | ms@2.1.3: {} 2590 | 2591 | multer@1.4.5-lts.1: 2592 | dependencies: 2593 | append-field: 1.0.0 2594 | busboy: 1.6.0 2595 | concat-stream: 1.6.2 2596 | mkdirp: 0.5.6 2597 | object-assign: 4.1.1 2598 | type-is: 1.6.18 2599 | xtend: 4.0.2 2600 | 2601 | mz@2.7.0: 2602 | dependencies: 2603 | any-promise: 1.3.0 2604 | object-assign: 4.1.1 2605 | thenify-all: 1.6.0 2606 | 2607 | nanoid@3.3.7: {} 2608 | 2609 | nanoid@5.0.8: {} 2610 | 2611 | negotiator@0.6.3: {} 2612 | 2613 | node-domexception@1.0.0: {} 2614 | 2615 | node-fetch@3.3.2: 2616 | dependencies: 2617 | data-uri-to-buffer: 4.0.1 2618 | fetch-blob: 3.2.0 2619 | formdata-polyfill: 4.0.10 2620 | 2621 | normalize-path@3.0.0: {} 2622 | 2623 | npm-run-path@4.0.1: 2624 | dependencies: 2625 | path-key: 3.1.1 2626 | 2627 | object-assign@4.1.1: {} 2628 | 2629 | object-inspect@1.13.4: {} 2630 | 2631 | on-finished@2.4.1: 2632 | dependencies: 2633 | ee-first: 1.1.1 2634 | 2635 | once@1.4.0: 2636 | dependencies: 2637 | wrappy: 1.0.2 2638 | 2639 | onetime@5.1.2: 2640 | dependencies: 2641 | mimic-fn: 2.1.0 2642 | 2643 | only@0.0.2: {} 2644 | 2645 | package-json-from-dist@1.0.0: {} 2646 | 2647 | parseurl@1.3.3: {} 2648 | 2649 | path-key@3.1.1: {} 2650 | 2651 | path-scurry@1.11.1: 2652 | dependencies: 2653 | lru-cache: 10.4.3 2654 | minipass: 7.1.2 2655 | 2656 | path-to-regexp@6.3.0: {} 2657 | 2658 | path-to-regexp@8.2.0: {} 2659 | 2660 | picocolors@1.1.0: {} 2661 | 2662 | picomatch@2.3.1: {} 2663 | 2664 | picomatch@4.0.2: {} 2665 | 2666 | pirates@4.0.6: {} 2667 | 2668 | postcss-load-config@6.0.1(postcss@8.4.47): 2669 | dependencies: 2670 | lilconfig: 3.1.2 2671 | optionalDependencies: 2672 | postcss: 8.4.47 2673 | 2674 | postcss@8.4.47: 2675 | dependencies: 2676 | nanoid: 3.3.7 2677 | picocolors: 1.1.0 2678 | source-map-js: 1.2.1 2679 | 2680 | prettier@3.3.3: {} 2681 | 2682 | process-nextick-args@2.0.1: {} 2683 | 2684 | punycode@2.3.1: {} 2685 | 2686 | qs@6.14.0: 2687 | dependencies: 2688 | side-channel: 1.1.0 2689 | 2690 | raw-body@2.5.2: 2691 | dependencies: 2692 | bytes: 3.1.2 2693 | http-errors: 2.0.0 2694 | iconv-lite: 0.4.24 2695 | unpipe: 1.0.0 2696 | 2697 | rcon@1.1.0: {} 2698 | 2699 | readable-stream@2.3.8: 2700 | dependencies: 2701 | core-util-is: 1.0.3 2702 | inherits: 2.0.4 2703 | isarray: 1.0.0 2704 | process-nextick-args: 2.0.1 2705 | safe-buffer: 5.1.2 2706 | string_decoder: 1.1.1 2707 | util-deprecate: 1.0.2 2708 | 2709 | readdirp@3.6.0: 2710 | dependencies: 2711 | picomatch: 2.3.1 2712 | 2713 | resolve-from@5.0.0: {} 2714 | 2715 | rollup@4.22.0: 2716 | dependencies: 2717 | '@types/estree': 1.0.5 2718 | optionalDependencies: 2719 | '@rollup/rollup-android-arm-eabi': 4.22.0 2720 | '@rollup/rollup-android-arm64': 4.22.0 2721 | '@rollup/rollup-darwin-arm64': 4.22.0 2722 | '@rollup/rollup-darwin-x64': 4.22.0 2723 | '@rollup/rollup-linux-arm-gnueabihf': 4.22.0 2724 | '@rollup/rollup-linux-arm-musleabihf': 4.22.0 2725 | '@rollup/rollup-linux-arm64-gnu': 4.22.0 2726 | '@rollup/rollup-linux-arm64-musl': 4.22.0 2727 | '@rollup/rollup-linux-powerpc64le-gnu': 4.22.0 2728 | '@rollup/rollup-linux-riscv64-gnu': 4.22.0 2729 | '@rollup/rollup-linux-s390x-gnu': 4.22.0 2730 | '@rollup/rollup-linux-x64-gnu': 4.22.0 2731 | '@rollup/rollup-linux-x64-musl': 4.22.0 2732 | '@rollup/rollup-win32-arm64-msvc': 4.22.0 2733 | '@rollup/rollup-win32-ia32-msvc': 4.22.0 2734 | '@rollup/rollup-win32-x64-msvc': 4.22.0 2735 | fsevents: 2.3.3 2736 | 2737 | safe-buffer@5.1.2: {} 2738 | 2739 | safe-buffer@5.2.1: {} 2740 | 2741 | safe-regex-test@1.1.0: 2742 | dependencies: 2743 | call-bound: 1.0.3 2744 | es-errors: 1.3.0 2745 | is-regex: 1.2.1 2746 | 2747 | safer-buffer@2.1.2: {} 2748 | 2749 | setprototypeof@1.2.0: {} 2750 | 2751 | shebang-command@2.0.0: 2752 | dependencies: 2753 | shebang-regex: 3.0.0 2754 | 2755 | shebang-regex@3.0.0: {} 2756 | 2757 | side-channel-list@1.0.0: 2758 | dependencies: 2759 | es-errors: 1.3.0 2760 | object-inspect: 1.13.4 2761 | 2762 | side-channel-map@1.0.1: 2763 | dependencies: 2764 | call-bound: 1.0.3 2765 | es-errors: 1.3.0 2766 | get-intrinsic: 1.2.7 2767 | object-inspect: 1.13.4 2768 | 2769 | side-channel-weakmap@1.0.2: 2770 | dependencies: 2771 | call-bound: 1.0.3 2772 | es-errors: 1.3.0 2773 | get-intrinsic: 1.2.7 2774 | object-inspect: 1.13.4 2775 | side-channel-map: 1.0.1 2776 | 2777 | side-channel@1.1.0: 2778 | dependencies: 2779 | es-errors: 1.3.0 2780 | object-inspect: 1.13.4 2781 | side-channel-list: 1.0.0 2782 | side-channel-map: 1.0.1 2783 | side-channel-weakmap: 1.0.2 2784 | 2785 | signal-exit@3.0.7: {} 2786 | 2787 | signal-exit@4.1.0: {} 2788 | 2789 | source-map-js@1.2.1: {} 2790 | 2791 | source-map@0.8.0-beta.0: 2792 | dependencies: 2793 | whatwg-url: 7.1.0 2794 | 2795 | statuses@1.5.0: {} 2796 | 2797 | statuses@2.0.1: {} 2798 | 2799 | streamsearch@1.1.0: {} 2800 | 2801 | string-width@4.2.3: 2802 | dependencies: 2803 | emoji-regex: 8.0.0 2804 | is-fullwidth-code-point: 3.0.0 2805 | strip-ansi: 6.0.1 2806 | 2807 | string-width@5.1.2: 2808 | dependencies: 2809 | eastasianwidth: 0.2.0 2810 | emoji-regex: 9.2.2 2811 | strip-ansi: 7.1.0 2812 | 2813 | string_decoder@1.1.1: 2814 | dependencies: 2815 | safe-buffer: 5.1.2 2816 | 2817 | strip-ansi@6.0.1: 2818 | dependencies: 2819 | ansi-regex: 5.0.1 2820 | 2821 | strip-ansi@7.1.0: 2822 | dependencies: 2823 | ansi-regex: 6.1.0 2824 | 2825 | strip-final-newline@2.0.0: {} 2826 | 2827 | sucrase@3.35.0: 2828 | dependencies: 2829 | '@jridgewell/gen-mapping': 0.3.5 2830 | commander: 4.1.1 2831 | glob: 10.4.5 2832 | lines-and-columns: 1.2.4 2833 | mz: 2.7.0 2834 | pirates: 4.0.6 2835 | ts-interface-checker: 0.1.13 2836 | 2837 | thenify-all@1.6.0: 2838 | dependencies: 2839 | thenify: 3.3.1 2840 | 2841 | thenify@3.3.1: 2842 | dependencies: 2843 | any-promise: 1.3.0 2844 | 2845 | tinyglobby@0.2.6: 2846 | dependencies: 2847 | fdir: 6.3.0(picomatch@4.0.2) 2848 | picomatch: 4.0.2 2849 | 2850 | to-regex-range@5.0.1: 2851 | dependencies: 2852 | is-number: 7.0.0 2853 | 2854 | toidentifier@1.0.1: {} 2855 | 2856 | tr46@1.0.1: 2857 | dependencies: 2858 | punycode: 2.3.1 2859 | 2860 | tree-kill@1.2.2: {} 2861 | 2862 | ts-interface-checker@0.1.13: {} 2863 | 2864 | tsscmp@1.0.6: {} 2865 | 2866 | tsup@8.3.0(postcss@8.4.47)(typescript@5.6.2): 2867 | dependencies: 2868 | bundle-require: 5.0.0(esbuild@0.23.1) 2869 | cac: 6.7.14 2870 | chokidar: 3.6.0 2871 | consola: 3.2.3 2872 | debug: 4.3.7 2873 | esbuild: 0.23.1 2874 | execa: 5.1.1 2875 | joycon: 3.1.1 2876 | picocolors: 1.1.0 2877 | postcss-load-config: 6.0.1(postcss@8.4.47) 2878 | resolve-from: 5.0.0 2879 | rollup: 4.22.0 2880 | source-map: 0.8.0-beta.0 2881 | sucrase: 3.35.0 2882 | tinyglobby: 0.2.6 2883 | tree-kill: 1.2.2 2884 | optionalDependencies: 2885 | postcss: 8.4.47 2886 | typescript: 5.6.2 2887 | transitivePeerDependencies: 2888 | - jiti 2889 | - supports-color 2890 | - tsx 2891 | - yaml 2892 | 2893 | turbo-darwin-64@2.1.2: 2894 | optional: true 2895 | 2896 | turbo-darwin-arm64@2.1.2: 2897 | optional: true 2898 | 2899 | turbo-linux-64@2.1.2: 2900 | optional: true 2901 | 2902 | turbo-linux-arm64@2.1.2: 2903 | optional: true 2904 | 2905 | turbo-windows-64@2.1.2: 2906 | optional: true 2907 | 2908 | turbo-windows-arm64@2.1.2: 2909 | optional: true 2910 | 2911 | turbo@2.1.2: 2912 | optionalDependencies: 2913 | turbo-darwin-64: 2.1.2 2914 | turbo-darwin-arm64: 2.1.2 2915 | turbo-linux-64: 2.1.2 2916 | turbo-linux-arm64: 2.1.2 2917 | turbo-windows-64: 2.1.2 2918 | turbo-windows-arm64: 2.1.2 2919 | 2920 | type-is@1.6.18: 2921 | dependencies: 2922 | media-typer: 0.3.0 2923 | mime-types: 2.1.35 2924 | 2925 | typedarray@0.0.6: {} 2926 | 2927 | typescript@5.6.2: {} 2928 | 2929 | undici-types@6.19.8: {} 2930 | 2931 | unpipe@1.0.0: {} 2932 | 2933 | util-deprecate@1.0.2: {} 2934 | 2935 | vary@1.1.2: {} 2936 | 2937 | vite@5.4.6(@types/node@22.8.6): 2938 | dependencies: 2939 | esbuild: 0.21.5 2940 | postcss: 8.4.47 2941 | rollup: 4.22.0 2942 | optionalDependencies: 2943 | '@types/node': 22.8.6 2944 | fsevents: 2.3.3 2945 | 2946 | web-streams-polyfill@3.3.3: {} 2947 | 2948 | webidl-conversions@4.0.2: {} 2949 | 2950 | whatwg-url@7.1.0: 2951 | dependencies: 2952 | lodash.sortby: 4.7.0 2953 | tr46: 1.0.1 2954 | webidl-conversions: 4.0.2 2955 | 2956 | which@2.0.2: 2957 | dependencies: 2958 | isexe: 2.0.0 2959 | 2960 | wrap-ansi@7.0.0: 2961 | dependencies: 2962 | ansi-styles: 4.3.0 2963 | string-width: 4.2.3 2964 | strip-ansi: 6.0.1 2965 | 2966 | wrap-ansi@8.1.0: 2967 | dependencies: 2968 | ansi-styles: 6.2.1 2969 | string-width: 5.1.2 2970 | strip-ansi: 7.1.0 2971 | 2972 | wrappy@1.0.2: {} 2973 | 2974 | xtend@4.0.2: {} 2975 | 2976 | ylru@1.4.0: {} 2977 | 2978 | zod@3.24.2: {} 2979 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'game/**' -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "tasks": { 4 | "build": { 5 | "dependsOn": ["^build"] 6 | }, 7 | "dev": { 8 | "persistent": true, 9 | "cache": false 10 | } 11 | } 12 | } --------------------------------------------------------------------------------