├── .dockerignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml └── workflows │ └── docker-publish.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── config.example.js ├── docker_start.sh ├── errors.js ├── index.js ├── lib ├── bot.js ├── bot_controller.js ├── game_data.js ├── inspect_url.js ├── job.js ├── postgres.js ├── queue.js └── utils.js ├── package-lock.json ├── package.json └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "node": true, 4 | "es6": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "rules": { 8 | "indent": [ 9 | "error", 10 | 4 11 | ], 12 | "linebreak-style": [ 13 | "error", 14 | "unix" 15 | ], 16 | "quotes": [ 17 | "error", 18 | "single" 19 | ], 20 | "semi": [ 21 | "error", 22 | "always" 23 | ], 24 | "no-console": 0, 25 | "linebreak-style": 0 26 | } 27 | }; -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | # This workflow uses actions that are not certified by GitHub. 4 | # They are provided by a third-party and are governed by 5 | # separate terms of service, privacy policy, and support 6 | # documentation. 7 | 8 | on: 9 | push: 10 | branches: [ master, beta ] 11 | # Publish semver tags as releases. 12 | tags: [ 'v*.*.*' ] 13 | pull_request: 14 | branches: [ master, beta ] 15 | 16 | env: 17 | # Use docker.io for Docker Hub if empty 18 | REGISTRY: docker.io 19 | # github.repository as / 20 | IMAGE_NAME: step7750/csgofloat 21 | 22 | 23 | jobs: 24 | build: 25 | 26 | runs-on: ubuntu-latest 27 | permissions: 28 | contents: read 29 | packages: write 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | 35 | # Login against a Docker registry except on PR 36 | # https://github.com/docker/login-action 37 | - name: Log into registry ${{ env.REGISTRY }} 38 | if: github.event_name != 'pull_request' 39 | uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c 40 | with: 41 | registry: ${{ env.REGISTRY }} 42 | username: ${{ secrets.DOCKER_USERNAME }} 43 | password: ${{ secrets.DOCKER_PASSWORD }} 44 | 45 | # Extract metadata (tags, labels) for Docker 46 | # https://github.com/docker/metadata-action 47 | - name: Extract Docker metadata 48 | id: meta 49 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 50 | with: 51 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 52 | 53 | # Build and push Docker image with Buildx (don't push on PR) 54 | # https://github.com/docker/build-push-action 55 | - name: Build and push Docker image 56 | uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc 57 | with: 58 | context: . 59 | push: ${{ github.event_name != 'pull_request' }} 60 | tags: ${{ steps.meta.outputs.tags }} 61 | labels: ${{ steps.meta.outputs.labels }} 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config.js 3 | /config 4 | sentry 5 | game_files 6 | .DS_Store 7 | .idea 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.15 2 | 3 | # Create app directory 4 | WORKDIR /usr/src/csgofloat 5 | 6 | # Install app dependencies 7 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 8 | # where available (npm@5+) 9 | COPY package*.json ./ 10 | 11 | RUN npm install 12 | 13 | # Bundle app source 14 | COPY . . 15 | 16 | EXPOSE 80 17 | EXPOSE 443 18 | VOLUME /config 19 | 20 | CMD [ "/bin/bash", "docker_start.sh" ] 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Stepan Fedorko-Bartos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 | [![GitHub stars](https://img.shields.io/github/stars/Step7750/CSGOFloat.svg)](https://github.com/Step7750/CSGOFloat/stargazers) 8 | [![GitHub forks](https://img.shields.io/github/forks/Step7750/CSGOFloat.svg)](https://github.com/Step7750/CSGOFloat/network) 9 | [![GitHub issues](https://img.shields.io/github/issues/Step7750/CSGOFloat.svg)](https://github.com/Step7750/CSGOFloat/issues) 10 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Step7750/CSGOFloat/LICENSE) 11 | [![Website](https://img.shields.io/website-up-down-green-red/https/csgofloat.com.svg)](https://csgofloat.com) 12 | [![Chrome Web Store](https://img.shields.io/chrome-web-store/d/jjicbefpemnphinccgikpdaagjebbnhg.svg)](https://chrome.google.com/webstore/detail/csgofloat-market-checker/jjicbefpemnphinccgikpdaagjebbnhg) 13 | [![Docker](https://img.shields.io/docker/pulls/step7750/csgofloat.svg)](https://hub.docker.com/r/step7750/csgofloat) 14 | 15 | CSGOFloat is a free and open source API service that allows you to obtain the float and paint seed of any CSGO item using its inspect link. 16 | 17 | ### Repo Links 18 | 19 | [CSGOFloat-Extension](https://github.com/Step7750/CSGOFloat-Extension) 20 | 21 | [CSGOFloat-Website](https://github.com/Step7750/CSGOFloat-Website) 22 | 23 | ## Table of Contents 24 | * [API](https://github.com/Step7750/CSGOFloat#api) 25 | * [`GET /`](https://github.com/Step7750/CSGOFloat#get-) 26 | * [Examples](https://github.com/Step7750/CSGOFloat#examples) 27 | * [`GET /` (Using an Inspect URL)](https://github.com/Step7750/CSGOFloat#get--using-an-inspect-url) 28 | * [Examples](https://github.com/Step7750/CSGOFloat#examples-1) 29 | * [Reply](https://github.com/Step7750/CSGOFloat#reply) 30 | * [Errors](https://github.com/Step7750/CSGOFloat#errors) 31 | * [How to Install](https://github.com/Step7750/CSGOFloat#how-to-install) 32 | * [Docker](https://github.com/Step7750/CSGOFloat#docker) 33 | * [Manual](https://github.com/Step7750/CSGOFloat#manual) 34 | * [Steps](https://github.com/Step7750/CSGOFloat#steps) 35 | * [How to First Login a Bot](https://github.com/Step7750/CSGOFloat#how-to-first-login-a-bot) 36 | * [Breaking Changes](https://github.com/Step7750/CSGOFloat#breaking-changes) 37 | * [Args](https://github.com/Step7750/CSGOFloat#args) 38 | 39 | 40 | # API 41 | 42 | ### `GET /` 43 | 44 | Parameters s, a, d, m can be found in the inspect link of a csgo item. 45 | 46 | | Parameter | Description | 47 | |:-------------:|:-------------| 48 | | s | Optional: If an inventory item, fill out this parameter from the inspect URL | 49 | | a | Required: Inspect URL "a" param | 50 | | d | Required: Inspect URL "d" param | 51 | | m | Optional: If a market item, fill out this parameter from the inspect URL | 52 | 53 | ##### Examples 54 | 55 | `http://:/?m=563330426657599553&a=6710760926&d=9406593057029549017` 56 | 57 | `http://:/?s=76561198084749846&a=6777992090&d=3378412659870065794` 58 | 59 | 60 | 61 | ### `GET /` (Using an Inspect URL) 62 | 63 | | Parameter | Description | 64 | |:-------------:|:-------------| 65 | | url | Required: Inspect URL of the CSGO item | 66 | 67 | ##### Examples 68 | 69 | `http://:/?url=steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20S76561198084749846A698323590D7935523998312483177` 70 | 71 | `http://:/?url=steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20M625254122282020305A6760346663D30614827701953021` 72 | 73 | 74 | ### Reply 75 | 76 | The reply of this API is based upon [this CSGO protobuf](https://github.com/SteamDatabase/GameTracking-CSGO/blob/a00b71ec84b24e0773c5fbd595eb91e17fa57f8f/Protobufs/cstrike15_gcmessages.proto#L729). 77 | 78 | | Attribute | Data Type | Description | 79 | |:-------------:|:-------------:|:--------------| 80 | | itemid | uint32 | Item ID | 81 | | defindex | uint32 | Weapon ID | 82 | | paintindex | uint32 | Paint ID of the weapon (skin) | 83 | | rarity | uint32 | Rarity value of the weapon | 84 | | quality | uint32 | Quality of the weapon | 85 | | paintwear | uint32 | Wear of the exterior of the skin | 86 | | paintseed | uint32 | Seed for the RNG that defines how to place the skin texture | 87 | | killeatervalue | uint32 | If the item is StatTrak, this is the amount of kills | 88 | | customname | string | If the item has a nametag, this is the custom name | 89 | | stickers | array | Contains data on the placement of stickers | 90 | | origin | uint32 | Origin ID of the weapon | 91 | | floatvalue | float | Exterior wear of the skin in its float representation | 92 | | imageurl | string | Optional: Image of the item | 93 | | min | float | Minimum wear of the skin | 94 | | max | float | Maximum wear of the skin | 95 | | item_name | uint32 | Optional: Name of the skin | 96 | | weapon_type | string | Weapon type name | 97 | | origin_name | string | Origin name (Trade-Up, Dropped, etc...) | 98 | | quality_name | string | Quality name (Souvenir, Stattrak, etc...) | 99 | | rarity_name | string | Rarity name (Covert, Mil-Spec, etc...) | 100 | | wear_name | string | Wear name (Factory New, Minimal Wear, etc...) | 101 | | full_item_name | string | Full Item Name (ex. SSG 08 Blue Spruce (Minimal Wear)) | 102 | 103 | 104 | ```json 105 | { 106 | "iteminfo": { 107 | "accountid": null, 108 | "itemid": "13874827217", 109 | "defindex": 7, 110 | "paintindex": 282, 111 | "rarity": 5, 112 | "quality": 4, 113 | "paintseed": 361, 114 | "killeaterscoretype": null, 115 | "killeatervalue": null, 116 | "customname": null, 117 | "stickers": [], 118 | "inventory": 11, 119 | "origin": 8, 120 | "questid": null, 121 | "dropreason": null, 122 | "musicindex": null, 123 | "s": "0", 124 | "a": "13874827217", 125 | "d": "4649025583329100061", 126 | "m": "2608048286785948758", 127 | "floatvalue": 0.22740158438682556, 128 | "imageurl": "http://media.steampowered.com/apps/730/icons/econ/default_generated/weapon_ak47_cu_ak47_cobra_light_large.7494bfdf4855fd4e6a2dbd983ed0a243c80ef830.png", 129 | "min": 0.1, 130 | "max": 0.7, 131 | "weapon_type": "AK-47", 132 | "item_name": "Redline", 133 | "rarity_name": "Classified", 134 | "quality_name": "Unique", 135 | "origin_name": "Found in Crate", 136 | "wear_name": "Field-Tested", 137 | "full_item_name": "AK-47 | Redline (Field-Tested)" 138 | } 139 | } 140 | ``` 141 | 142 | ### `POST /bulk` 143 | 144 | Allows you to request the inspect link data for multiple items at once. 145 | 146 | NOTE: Ensure that you send proper `Content-Type: application/json` headers 147 | 148 | Request Body: 149 | 150 | ```json 151 | { 152 | "links": [ 153 | {"link": "steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20M2906459769049600931A18971892678D9403672490970763167"}, 154 | {"link": "steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20M2907585668964658722A17231546984D5353704955732169451"} 155 | ] 156 | } 157 | ``` 158 | 159 | Example Response: 160 | 161 | ```json 162 | { 163 | "18971892678": { 164 | "origin": 8, 165 | "quality": 4, 166 | "rarity": 5, 167 | "a": "18971892678", 168 | "d": "9403672490970763167", 169 | "paintseed": 49, 170 | "defindex": 7, 171 | "paintindex": 282, 172 | // STUB... 173 | }, 174 | "17231546984": { 175 | "origin": 4, 176 | "quality": 4, 177 | "rarity": 4, 178 | "a": "17231546984", 179 | "d": "5353704955732169451", 180 | "paintseed": 597, 181 | "defindex": 9, 182 | "paintindex": 838, 183 | // STUB... 184 | }, 185 | ... 186 | } 187 | ``` 188 | 189 | ### `GET /stats` 190 | 191 | Gives some data on the current status of your bots and queue. 192 | 193 | Example: 194 | ```json 195 | {"bots_online":100,"bots_total":100,"queue_size":20,"queue_concurrency":100} 196 | ``` 197 | 198 | ## Errors 199 | 200 | ##### Error Codes 201 | 202 | | Code | Description | 203 | |:-------------:|:-------------| 204 | | 1 | Improper Parameter Structure | 205 | | 2 | Invalid Inspect Link Structure | 206 | | 3 | You may only have X pending request(s) at a time | 207 | | 4 | Valve's servers didn't reply in time | 208 | | 5 | Valve's servers appear to be offline, please try again later! | 209 | | 6 | Something went wrong on our end, please try again | 210 | | 7 | Improper body format | 211 | | 8 | Bad Secret | 212 | 213 | ##### Example Error 214 | 215 | ```json 216 | { 217 | "error": "Valve's servers didn't reply in time", 218 | "code": 4 219 | } 220 | ``` 221 | 222 | If using a `/bulk` request and the error only applies to a specific inspect link, the returned response for it will be 223 | replaced while other inspect links will be processed normally. If the error applies to the entire request (ie. bad post body), 224 | it will return a root-level error as shown above. 225 | 226 | Example: 227 | 228 | ``` 229 | { 230 | "18971892678": { 231 | "origin": 8, 232 | "quality": 4, 233 | "rarity": 5, 234 | "a": "18971892678", 235 | "d": "9403672490970763167", 236 | "paintseed": 49, 237 | "defindex": 7, 238 | "paintindex": 282, 239 | // STUB... 240 | }, 241 | "16231546984": { 242 | "error": "Valve's servers didn't reply in time", 243 | "code": 4, 244 | "status": 500 245 | } 246 | } 247 | ``` 248 | 249 | 250 | # How to Install 251 | 252 | In order to retrieve float values for weapons in this way, you must have Steam account(s) with a copy of CS:GO. Each account can request 1 float per second. CSGOFloat allows you to have as many bots as you'd like by inputting the login info into config.js. 253 | 254 | Each instance of CSGOFloat can operate around 300 accounts. It is recommended to either configure a Postgres server or setup another cache such as Varnish or Nginx in front of your server. 255 | 256 | ## Docker 257 | 258 | Pull the [image](https://hub.docker.com/r/step7750/csgofloat) from docker and mount the config directory 259 | 260 | ``` 261 | docker pull step7750/csgofloat:master 262 | docker run -d --name csgofloat -v /host/config:/config -p 80:80 -p 443:443 step7750/csgofloat:master 263 | ``` 264 | 265 | The first time you start the docker container, it'll copy the `config.js` file to the config directory and stop. You'll need to edit this file and include your bots login information and then start the docker again. See the section [How to First Login a Bot](https://github.com/Step7750/CSGOFloat#how-to-first-login-a-bot) for further info. 266 | 267 | **Make sure you configure a Postgres server to use for caching!** 268 | 269 | ## Manual 270 | 271 | Requires Node.js v14+! 272 | 273 | Clone the repo (or `npm install csgofloat`) and install the Node.js dependencies using `npm install` or `yarn install` in the root directory. 274 | 275 | #### Steps: 276 | 277 | 1. Copy `config.example.js` to `config.js` 278 | 2. Add your bot(s) login information to `config.js` 279 | 3. Edit `config.js` with your desired settings 280 | 4. Ensure Postgres is running if you've set it's database url 281 | 5. Run `node index.js` in the main directory 282 | 6. [How to First Login a Bot](https://github.com/Step7750/CSGOFloat#how-to-first-login-a-bot) 283 | 7. Navigate to the IP that the server is hosted on and query the API using the docs above! 284 | 285 | ## How to First Login a Bot 286 | 287 | **Note**: If the bot has never logged into the steam client before and doesn't have Mobile 2FA enabled (fresh account), you can just input the username and password and it should successfully log in without email 2FA 288 | 289 | If your bot doesn't own CS:GO, CSGOFloat will automatically try to obtain a license for it during startup. 290 | 291 | * Using Email 2FA 292 | * Only fill in the `user` and `pass` fields for the bot (make sure the `auth` field is empty or removed) 293 | * Start up CSGOFloat 294 | * It will tell you that an auth code was sent to your email 295 | * Input the code from your email into the `auth` field for the bot 296 | * Restart CSGOFloat 297 | * It should successfully login and create machine auth token files for each account in the current [node-steam-user config directory](https://github.com/DoctorMcKay/node-steam-user#datadirectory) 298 | * The `auth` field can now be optionally removed in your login file for further logins 299 | * Using Mobile 2FA 300 | * Fill in the `user` and `pass` fields for the bot 301 | * Fill in the `auth` field with the `shared_secret` for the bot 302 | * Start up CSGOFloat 303 | * It should successfully login and create machine auth token files for each account in the current [node-steam-user config directory](https://github.com/DoctorMcKay/node-steam-user#datadirectory) 304 | * You'll need to keep the `auth` field filled in for future logins 305 | 306 | ## Breaking Changes 307 | 308 | ### v3.0 -> v4.0 309 | 310 | * MongoDB is no longer supported, use Postgres instead 311 | * Socket.io access is no longer supported 312 | * Built-in HTTPS handling has been removed, reverse proxy to HTTP instead 313 | 314 | ### v2.0 -> v3.0 315 | 316 | * Since we now use node-steam-user instead of node-steam, the sentry folder location now [depends on your system](https://github.com/DoctorMcKay/node-steam-user#datadirectory). If you'd like to migrate sentry files from v2.0 rather than having to reauthenticate email 2FA accounts, you'll need to copy your sentry files and rename them to match node-steam-user's format 317 | * `allow_simultaneous_requests` has now been replaced by `max_simultaneous_requests`. You can set `max_simultaneous_requests` to `-1` to allow an infinite amount of simultaneous requests by the same IP. 318 | 319 | ## Args 320 | 321 | ### `-c`/`--config` (default `./config.js`) 322 | 323 | CSGOFloat config file location 324 | 325 | ### `-s`/`--steam_data` (default [node-steam-user config directory](https://github.com/DoctorMcKay/node-steam-user#datadirectory)) 326 | 327 | node-steam-user config directory 328 | -------------------------------------------------------------------------------- /config.example.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Configuration for the HTTP API server 3 | 'http': { 4 | 'port': 80 5 | }, 6 | // Whether to trust a forwarding proxy's IP (trust X-Forwarded-For) 7 | 'trust_proxy': false, 8 | // List of usernames and passwords for the Steam accounts 9 | 'logins': [ 10 | { 11 | 'user': 'USERNAME', 12 | 'pass': 'PASSWORD', 13 | // You can either use a 2FA email/mobile token (5 letters/digits), or the shared_secret of mobile 2FA 14 | 'auth': '2FA_TOKEN' 15 | }, 16 | { 17 | 'user': 'USERNAME_2', 18 | 'pass': 'PASSWORD_2', 19 | 'auth': '2FA_TOKEN_2' 20 | } 21 | ], 22 | // Optional HTTP/SOCKS5 proxies to auto-rotate for each bot in a round-robin 23 | 'proxies': [], 24 | // Bot settings 25 | 'bot_settings': { 26 | // Amount of attempts for each request to Valve 27 | 'max_attempts': 1, 28 | // Amount of milliseconds to wait between subsequent requests to Valve (per bot) 29 | 'request_delay': 1100, 30 | // Amount of milliseconds to wait until a request to Valve is timed out 31 | 'request_ttl': 2000, 32 | // OPTIONAL: Settings for Steam User (https://github.com/DoctorMcKay/node-steam-user#options-) 33 | 'steam_user': {} 34 | }, 35 | // Origins allowed to connect to the HTTP/HTTPS API 36 | 'allowed_origins': [ 37 | 'http://example.com', 38 | 'https://example.com', 39 | 'chrome-extension://jjicbefpemnphinccgikpdaagjebbnhg', 40 | 'http://steamcommunity.com', 41 | 'https://steamcommunity.com' 42 | ], 43 | // Origins allowed to connect to the HTTP/HTTPS API with Regex 44 | 'allowed_regex_origins': [ 45 | 'https://.*\\.steamcommunity\\.com' 46 | ], 47 | // Optionally configure a global rate limit across all endpoints 48 | 'rate_limit': { 49 | 'enable': false, 50 | 'window_ms': 60 * 60 * 1000, // 60 min 51 | 'max': 10000 52 | }, 53 | // Logging Level (error, warn, info, verbose, debug, silly) 54 | 'logLevel': 'debug', 55 | // Max amount of simultaneous requests from the same IP (incl. WS and HTTP/HTTPS), -1 for unlimited 56 | 'max_simultaneous_requests': 1, 57 | // Bool to enable game file updates from the SteamDB Github tracker (updated item definitions, images, names) 58 | 'enable_game_file_updates': true, 59 | // Amount of seconds to wait between updating game files (0 = No Interval Updates) 60 | 'game_files_update_interval': 3600, 61 | // Postgres connection string to store results in (ex. postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable) 62 | 'database_url': '', 63 | // OPTIONAL: Enable bulk inserts, may improve performance with many requests 64 | 'enable_bulk_inserts': false, 65 | // OPTIONAL: Key by the caller to allow inserting price information, required to use the feature 66 | 'price_key': '', 67 | // OPTIONAL: Key by the caller to allow placing bulk searches 68 | 'bulk_key': '', 69 | // OPTIONAL: Maximum queue size allowed before dropping requests 70 | 'max_queue_size': -1, 71 | }; 72 | -------------------------------------------------------------------------------- /docker_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f /config/config.js ]; then 4 | cp /usr/src/csgofloat/config.example.js /config/config.js 5 | echo "Copied example config file to /config/config.js, please edit this file and restart" 6 | exit 1 7 | fi 8 | 9 | if [ ! -d /config/steam_data ]; then 10 | mkdir /config/steam_data 11 | fi 12 | 13 | node index.js -c /config/config.js -s /config/steam_data 14 | -------------------------------------------------------------------------------- /errors.js: -------------------------------------------------------------------------------- 1 | class Error { 2 | constructor(message, internalCode, statusCode) { 3 | this.message = message; 4 | this.code = internalCode; 5 | this.statusCode = statusCode; // HTTP Status Code 6 | } 7 | 8 | getJSON() { 9 | return {error: this.message, code: this.code, status: this.statusCode}; 10 | } 11 | 12 | respond(res) { 13 | res.status(this.statusCode).json(this.getJSON()); 14 | } 15 | 16 | toString() { 17 | return `[Code ${this.code}] - ${this.message}`; 18 | } 19 | } 20 | 21 | module.exports = { 22 | Error: Error, 23 | BadParams: new Error('Improper Parameter Structure', 1, 400), 24 | InvalidInspect: new Error('Invalid Inspect Link Structure', 2, 400), 25 | MaxRequests: new Error('You have too many pending requests', 3, 400), 26 | TTLExceeded: new Error('Valve\'s servers didn\'t reply in time', 4, 500), 27 | SteamOffline: new Error('Valve\'s servers appear to be offline, please try again later', 5, 503), 28 | GenericBad: new Error('Something went wrong on our end, please try again', 6, 500), 29 | BadBody: new Error('Improper body format', 7, 400), 30 | BadSecret: new Error('Bad Secret', 8, 400), 31 | NoBotsAvailable: new Error('No bots available to fulfill this request', 9, 500), 32 | RateLimit: new Error('Rate limit exceeded, too many requests', 10, 429), 33 | MaxQueueSize: new Error('Queue size is full, please try again later', 11, 500), 34 | }; 35 | 36 | 37 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | global._mckay_statistics_opt_out = true; // Opt out of node-steam-user stats 2 | 3 | const optionDefinitions = [ 4 | { name: 'config', alias: 'c', type: String, defaultValue: './config.js' }, // Config file location 5 | { name: 'steam_data', alias: 's', type: String } // Steam data directory 6 | ]; 7 | 8 | const winston = require('winston'), 9 | args = require('command-line-args')(optionDefinitions), 10 | bodyParser = require('body-parser'), 11 | rateLimit = require('express-rate-limit'), 12 | utils = require('./lib/utils'), 13 | queue = new (require('./lib/queue'))(), 14 | InspectURL = require('./lib/inspect_url'), 15 | botController = new (require('./lib/bot_controller'))(), 16 | CONFIG = require(args.config), 17 | postgres = new (require('./lib/postgres'))(CONFIG.database_url, CONFIG.enable_bulk_inserts), 18 | gameData = new (require('./lib/game_data'))(CONFIG.game_files_update_interval, CONFIG.enable_game_file_updates), 19 | errors = require('./errors'), 20 | Job = require('./lib/job'); 21 | 22 | if (CONFIG.max_simultaneous_requests === undefined) { 23 | CONFIG.max_simultaneous_requests = 1; 24 | } 25 | 26 | winston.level = CONFIG.logLevel || 'debug'; 27 | 28 | if (CONFIG.logins.length === 0) { 29 | console.log('There are no bot logins. Please add some in config.json'); 30 | process.exit(1); 31 | } 32 | 33 | if (args.steam_data) { 34 | CONFIG.bot_settings.steam_user.dataDirectory = args.steam_data; 35 | } 36 | 37 | for (let [i, loginData] of CONFIG.logins.entries()) { 38 | const settings = Object.assign({}, CONFIG.bot_settings); 39 | if (CONFIG.proxies && CONFIG.proxies.length > 0) { 40 | const proxy = CONFIG.proxies[i % CONFIG.proxies.length]; 41 | 42 | if (proxy.startsWith('http://')) { 43 | settings.steam_user = Object.assign({}, settings.steam_user, {httpProxy: proxy}); 44 | } else if (proxy.startsWith('socks5://')) { 45 | settings.steam_user = Object.assign({}, settings.steam_user, {socksProxy: proxy}); 46 | } else { 47 | console.log(`Invalid proxy '${proxy}' in config, must prefix with http:// or socks5://`); 48 | process.exit(1); 49 | } 50 | } 51 | 52 | botController.addBot(loginData, settings); 53 | } 54 | 55 | postgres.connect(); 56 | 57 | // Setup and configure express 58 | const app = require('express')(); 59 | app.use(function (req, res, next) { 60 | if (req.method === 'POST') { 61 | // Default content-type 62 | req.headers['content-type'] = 'application/json'; 63 | } 64 | next(); 65 | }); 66 | app.use(bodyParser.json({limit: '5mb'})); 67 | 68 | app.use(function (error, req, res, next) { 69 | // Handle bodyParser errors 70 | if (error instanceof SyntaxError) { 71 | errors.BadBody.respond(res); 72 | } 73 | else next(); 74 | }); 75 | 76 | 77 | if (CONFIG.trust_proxy === true) { 78 | app.enable('trust proxy'); 79 | } 80 | 81 | CONFIG.allowed_regex_origins = CONFIG.allowed_regex_origins || []; 82 | CONFIG.allowed_origins = CONFIG.allowed_origins || []; 83 | const allowedRegexOrigins = CONFIG.allowed_regex_origins.map((origin) => new RegExp(origin)); 84 | 85 | 86 | async function handleJob(job) { 87 | // See which items have already been cached 88 | const itemData = await postgres.getItemData(job.getRemainingLinks().map(e => e.link)); 89 | for (let item of itemData) { 90 | const link = job.getLink(item.a); 91 | 92 | if (!item.price && link.price) { 93 | postgres.updateItemPrice(item.a, link.price); 94 | } 95 | 96 | gameData.addAdditionalItemProperties(item); 97 | item = utils.removeNullValues(item); 98 | 99 | job.setResponse(item.a, item); 100 | } 101 | 102 | if (!botController.hasBotOnline()) { 103 | return job.setResponseRemaining(errors.SteamOffline); 104 | } 105 | 106 | if (CONFIG.max_simultaneous_requests > 0 && 107 | (queue.getUserQueuedAmt(job.ip) + job.remainingSize()) > CONFIG.max_simultaneous_requests) { 108 | return job.setResponseRemaining(errors.MaxRequests); 109 | } 110 | 111 | if (CONFIG.max_queue_size > 0 && (queue.size() + job.remainingSize()) > CONFIG.max_queue_size) { 112 | return job.setResponseRemaining(errors.MaxQueueSize); 113 | } 114 | 115 | if (job.remainingSize() > 0) { 116 | queue.addJob(job, CONFIG.bot_settings.max_attempts); 117 | } 118 | } 119 | 120 | function canSubmitPrice(key, link, price) { 121 | return CONFIG.price_key && key === CONFIG.price_key && price && link.isMarketLink() && utils.isOnlyDigits(price); 122 | } 123 | 124 | app.use(function (req, res, next) { 125 | if (CONFIG.allowed_origins.length > 0 && req.get('origin') != undefined) { 126 | // check to see if its a valid domain 127 | const allowed = CONFIG.allowed_origins.indexOf(req.get('origin')) > -1 || 128 | allowedRegexOrigins.findIndex((reg) => reg.test(req.get('origin'))) > -1; 129 | 130 | if (allowed) { 131 | res.header('Access-Control-Allow-Origin', req.get('origin')); 132 | res.header('Access-Control-Allow-Methods', 'GET'); 133 | } 134 | } 135 | next() 136 | }); 137 | 138 | if (CONFIG.rate_limit && CONFIG.rate_limit.enable) { 139 | app.use(rateLimit({ 140 | windowMs: CONFIG.rate_limit.window_ms, 141 | max: CONFIG.rate_limit.max, 142 | headers: false, 143 | handler: function (req, res) { 144 | errors.RateLimit.respond(res); 145 | } 146 | })) 147 | } 148 | 149 | app.get('/', function(req, res) { 150 | // Get and parse parameters 151 | let link; 152 | 153 | if ('url' in req.query) { 154 | link = new InspectURL(req.query.url); 155 | } 156 | else if ('a' in req.query && 'd' in req.query && ('s' in req.query || 'm' in req.query)) { 157 | link = new InspectURL(req.query); 158 | } 159 | 160 | if (!link || !link.getParams()) { 161 | return errors.InvalidInspect.respond(res); 162 | } 163 | 164 | const job = new Job(req, res, /* bulk */ false); 165 | 166 | let price; 167 | 168 | if (canSubmitPrice(req.query.priceKey, link, req.query.price)) { 169 | price = parseInt(req.query.price); 170 | } 171 | 172 | job.add(link, price); 173 | 174 | try { 175 | handleJob(job); 176 | } catch (e) { 177 | winston.warn(e); 178 | errors.GenericBad.respond(res); 179 | } 180 | }); 181 | 182 | app.post('/bulk', (req, res) => { 183 | if (!req.body || (CONFIG.bulk_key && req.body.bulk_key != CONFIG.bulk_key)) { 184 | return errors.BadSecret.respond(res); 185 | } 186 | 187 | if (!req.body.links || req.body.links.length === 0) { 188 | return errors.BadBody.respond(res); 189 | } 190 | 191 | if (CONFIG.max_simultaneous_requests > 0 && req.body.links.length > CONFIG.max_simultaneous_requests) { 192 | return errors.MaxRequests.respond(res); 193 | } 194 | 195 | const job = new Job(req, res, /* bulk */ true); 196 | 197 | for (const data of req.body.links) { 198 | const link = new InspectURL(data.link); 199 | if (!link.valid) { 200 | return errors.InvalidInspect.respond(res); 201 | } 202 | 203 | let price; 204 | 205 | if (canSubmitPrice(req.body.priceKey, link, data.price)) { 206 | price = parseInt(req.query.price); 207 | } 208 | 209 | job.add(link, price); 210 | } 211 | 212 | try { 213 | handleJob(job); 214 | } catch (e) { 215 | winston.warn(e); 216 | errors.GenericBad.respond(res); 217 | } 218 | }); 219 | 220 | app.get('/stats', (req, res) => { 221 | res.json({ 222 | bots_online: botController.getReadyAmount(), 223 | bots_total: botController.bots.length, 224 | queue_size: queue.queue.length, 225 | queue_concurrency: queue.concurrency, 226 | }); 227 | }); 228 | 229 | const http_server = require('http').Server(app); 230 | http_server.listen(CONFIG.http.port); 231 | winston.info('Listening for HTTP on port: ' + CONFIG.http.port); 232 | 233 | queue.process(CONFIG.logins.length, botController, async (job) => { 234 | const itemData = await botController.lookupFloat(job.data.link); 235 | winston.debug(`Received itemData for ${job.data.link.getParams().a}`); 236 | 237 | // Save and remove the delay attribute 238 | let delay = itemData.delay; 239 | delete itemData.delay; 240 | 241 | // add the item info to the DB 242 | await postgres.insertItemData(itemData.iteminfo, job.data.price); 243 | 244 | // Get rank, annotate with game files 245 | itemData.iteminfo = Object.assign(itemData.iteminfo, await postgres.getItemRank(itemData.iteminfo.a)); 246 | gameData.addAdditionalItemProperties(itemData.iteminfo); 247 | 248 | itemData.iteminfo = utils.removeNullValues(itemData.iteminfo); 249 | itemData.iteminfo.stickers = itemData.iteminfo.stickers.map((s) => utils.removeNullValues(s)); 250 | itemData.iteminfo.keychains = itemData.iteminfo.keychains.map((s) => utils.removeNullValues(s)); 251 | 252 | job.data.job.setResponse(job.data.link.getParams().a, itemData.iteminfo); 253 | 254 | return delay; 255 | }); 256 | 257 | queue.on('job failed', (job, err) => { 258 | const params = job.data.link.getParams(); 259 | winston.warn(`Job Failed! S: ${params.s} A: ${params.a} D: ${params.d} M: ${params.m} IP: ${job.ip}, Err: ${(err || '').toString()}`); 260 | 261 | job.data.job.setResponse(params.a, errors.TTLExceeded); 262 | }); 263 | -------------------------------------------------------------------------------- /lib/bot.js: -------------------------------------------------------------------------------- 1 | const winston = require('winston'), 2 | SteamUser = require('steam-user'), 3 | GlobalOffensive = require('globaloffensive'), 4 | SteamTotp = require('steam-totp'), 5 | EventEmitter = require('events').EventEmitter; 6 | 7 | class Bot extends EventEmitter { 8 | /** 9 | * Sets the ready status and sends a 'ready' or 'unready' event if it has changed 10 | * @param {*|boolean} val New ready status 11 | */ 12 | set ready(val) { 13 | const prev = this.ready; 14 | this.ready_ = val; 15 | 16 | if (val !== prev) { 17 | this.emit(val ? 'ready' : 'unready'); 18 | } 19 | } 20 | 21 | /** 22 | * Returns the current ready status 23 | * @return {*|boolean} Ready status 24 | */ 25 | get ready() { 26 | return this.ready_ || false; 27 | } 28 | 29 | constructor(settings) { 30 | super(); 31 | 32 | this.settings = settings; 33 | this.busy = false; 34 | 35 | this.steamClient = new SteamUser(Object.assign({ 36 | promptSteamGuardCode: false, 37 | enablePicsCache: true // Required to check if we own CSGO with ownsApp 38 | }, this.settings.steam_user)); 39 | 40 | this.csgoClient = new GlobalOffensive(this.steamClient); 41 | 42 | // set up event handlers 43 | this.bindEventHandlers(); 44 | 45 | // Variance to apply so that each bot relogins at different times 46 | const variance = parseInt(Math.random() * 4 * 60 * 1000); 47 | 48 | // As of 7/10/2020, GC inspect calls can timeout repeatedly for whatever reason 49 | setInterval(() => { 50 | if (this.csgoClient.haveGCSession) { 51 | this.relogin = true; 52 | this.steamClient.relog(); 53 | } 54 | }, 30 * 60 * 1000 + variance); 55 | } 56 | 57 | logIn(username, password, auth) { 58 | this.ready = false; 59 | 60 | // Save these parameters if we login later 61 | if (arguments.length === 3) { 62 | this.username = username; 63 | this.password = password; 64 | this.auth = auth; 65 | } 66 | 67 | winston.info(`Logging in ${this.username}`); 68 | 69 | // If there is a steam client, make sure it is disconnected 70 | if (this.steamClient) this.steamClient.logOff(); 71 | 72 | this.loginData = { 73 | accountName: this.username, 74 | password: this.password, 75 | rememberPassword: true, 76 | }; 77 | 78 | if (this.auth && this.auth !== '') { 79 | // Check if it is a shared_secret 80 | if (this.auth.length <= 5) this.loginData.authCode = this.auth; 81 | else { 82 | // Generate the code from the shared_secret 83 | winston.debug(`${this.username} Generating TOTP Code from shared_secret`); 84 | this.loginData.twoFactorCode = SteamTotp.getAuthCode(this.auth); 85 | } 86 | } 87 | 88 | winston.debug(`${this.username} About to connect`); 89 | this.steamClient.logOn(this.loginData); 90 | } 91 | 92 | bindEventHandlers() { 93 | this.steamClient.on('error', (err) => { 94 | winston.error(`Error logging in ${this.username}:`, err); 95 | 96 | let login_error_msgs = { 97 | 61: 'Invalid Password', 98 | 63: 'Account login denied due to 2nd factor authentication failure. ' + 99 | 'If using email auth, an email has been sent.', 100 | 65: 'Account login denied due to auth code being invalid', 101 | 66: 'Account login denied due to 2nd factor auth failure and no mail has been sent' 102 | }; 103 | 104 | if (err.eresult && login_error_msgs[err.eresult] !== undefined) { 105 | winston.error(this.username + ': ' + login_error_msgs[err.eresult]); 106 | } 107 | 108 | // Yes, checking for string errors sucks, but we have no other attributes to check 109 | // this error against. 110 | if (err.toString().includes('Proxy connection timed out')) { 111 | this.logIn(); 112 | } 113 | }); 114 | 115 | this.steamClient.on('disconnected', (eresult, msg) => { 116 | winston.warn(`${this.username} Logged off, reconnecting! (${eresult}, ${msg})`); 117 | }); 118 | 119 | this.steamClient.on('loggedOn', (details, parental) => { 120 | winston.info(`${this.username} Log on OK`); 121 | 122 | // Fixes reconnecting to CS:GO GC since node-steam-user still assumes we're playing 730 123 | // and never sends the appLaunched event to node-globaloffensive 124 | this.steamClient.gamesPlayed([], true); 125 | 126 | if (this.relogin) { 127 | // Don't check ownership cache since the event isn't always emitted on relogin 128 | winston.info(`${this.username} Initiating GC Connection, Relogin`); 129 | this.steamClient.gamesPlayed([730], true); 130 | return; 131 | } 132 | 133 | // Ensure we own CSGO 134 | // We have to wait until app ownership is cached to safely check 135 | this.steamClient.once('ownershipCached', () => { 136 | if (!this.steamClient.ownsApp(730)) { 137 | winston.info(`${this.username} doesn't own CS:GO, retrieving free license`); 138 | 139 | // Request a license for CS:GO 140 | this.steamClient.requestFreeLicense([730], (err, grantedPackages, grantedAppIDs) => { 141 | winston.debug(`${this.username} Granted Packages`, grantedPackages); 142 | winston.debug(`${this.username} Granted App IDs`, grantedAppIDs); 143 | 144 | if (err) { 145 | winston.error(`${this.username} Failed to obtain free CS:GO license`); 146 | } else { 147 | winston.info(`${this.username} Initiating GC Connection`); 148 | this.steamClient.gamesPlayed([730], true); 149 | } 150 | }); 151 | } else { 152 | winston.info(`${this.username} Initiating GC Connection`); 153 | this.steamClient.gamesPlayed([730], true); 154 | } 155 | }); 156 | }); 157 | 158 | this.csgoClient.on('inspectItemInfo', (itemData) => { 159 | if (this.resolve && this.currentRequest) { 160 | itemData = {iteminfo: itemData}; 161 | 162 | // Ensure the received itemid is the same as what we want 163 | if (itemData.iteminfo.itemid !== this.currentRequest.a) return; 164 | 165 | // Clear any TTL timeout 166 | if (this.ttlTimeout) { 167 | clearTimeout(this.ttlTimeout); 168 | this.ttlTimeout = false; 169 | } 170 | 171 | // GC requires a delay between subsequent requests 172 | // Figure out how long to delay until this bot isn't busy anymore 173 | let offset = new Date().getTime() - this.currentRequest.time; 174 | let delay = this.settings.request_delay - offset; 175 | 176 | // If we're past the request delay, don't delay 177 | if (delay < 0) delay = 0; 178 | 179 | itemData.delay = delay; 180 | itemData.iteminfo.s = this.currentRequest.s; 181 | itemData.iteminfo.a = this.currentRequest.a; 182 | itemData.iteminfo.d = this.currentRequest.d; 183 | itemData.iteminfo.m = this.currentRequest.m; 184 | 185 | // If the paintseed is 0, the proto returns null, force 0 186 | itemData.iteminfo.paintseed = itemData.iteminfo.paintseed || 0; 187 | 188 | // paintwear -> floatvalue to match previous API version response 189 | itemData.iteminfo.floatvalue = itemData.iteminfo.paintwear; 190 | delete itemData.iteminfo.paintwear; 191 | 192 | // Backwards compatibility with previous node-globaloffensive versions 193 | for (const sticker of itemData.iteminfo.stickers) { 194 | sticker.stickerId = sticker.sticker_id; 195 | delete sticker.sticker_id; 196 | } 197 | 198 | this.resolve(itemData); 199 | this.resolve = false; 200 | this.currentRequest = false; 201 | 202 | setTimeout(() => { 203 | // We're no longer busy (satisfied request delay) 204 | this.busy = false; 205 | }, delay); 206 | } 207 | }); 208 | 209 | this.csgoClient.on('connectedToGC', () => { 210 | winston.info(`${this.username} CSGO Client Ready!`); 211 | 212 | this.ready = true; 213 | }); 214 | 215 | this.csgoClient.on('disconnectedFromGC', (reason) => { 216 | winston.warn(`${this.username} CSGO unready (${reason}), trying to reconnect!`); 217 | this.ready = false; 218 | 219 | // node-globaloffensive will automatically try to reconnect 220 | }); 221 | 222 | this.csgoClient.on('connectionStatus', (status) => { 223 | winston.debug(`${this.username} GC Connection Status Update ${status}`); 224 | }); 225 | 226 | this.csgoClient.on('debug', (msg) => { 227 | winston.debug(msg); 228 | }); 229 | } 230 | 231 | sendFloatRequest(link) { 232 | return new Promise((resolve, reject) => { 233 | this.resolve = resolve; 234 | this.busy = true; 235 | 236 | const params = link.getParams(); 237 | winston.debug(`${this.username} Fetching for ${params.a}`); 238 | 239 | this.currentRequest = {s: params.s, a: params.a, d: params.d, m: params.m, time: new Date().getTime()}; 240 | 241 | if (!this.ready) { 242 | reject('This bot is not ready'); 243 | } 244 | else { 245 | // The first param (owner) depends on the type of inspect link 246 | this.csgoClient.inspectItem(params.s !== '0' ? params.s : params.m, params.a, params.d); 247 | } 248 | 249 | // Set a timeout in case the GC takes too long to respond 250 | this.ttlTimeout = setTimeout(() => { 251 | // GC didn't respond in time, reset and reject 252 | this.busy = false; 253 | this.currentRequest = false; 254 | reject('ttl exceeded'); 255 | }, this.settings.request_ttl); 256 | }); 257 | } 258 | } 259 | 260 | module.exports = Bot; 261 | -------------------------------------------------------------------------------- /lib/bot_controller.js: -------------------------------------------------------------------------------- 1 | const Bot = require('./bot'), 2 | utils = require('./utils'), 3 | EventEmitter = require('events').EventEmitter, 4 | errors = require('../errors'); 5 | 6 | class BotController extends EventEmitter { 7 | constructor() { 8 | super(); 9 | 10 | this.readyEvent = false; 11 | this.bots = []; 12 | } 13 | 14 | addBot(loginData, settings) { 15 | let bot = new Bot(settings); 16 | bot.logIn(loginData.user, loginData.pass, loginData.auth); 17 | 18 | bot.on('ready', () => { 19 | if (!this.readyEvent && this.hasBotOnline()) { 20 | this.readyEvent = true; 21 | this.emit('ready'); 22 | } 23 | }); 24 | 25 | bot.on('unready', () => { 26 | if (this.readyEvent && this.hasBotOnline() === false) { 27 | this.readyEvent = false; 28 | this.emit('unready'); 29 | } 30 | }); 31 | 32 | this.bots.push(bot); 33 | } 34 | 35 | getFreeBot() { 36 | // Shuffle array to evenly distribute requests 37 | for (let bot of utils.shuffleArray(this.bots)) { 38 | if (!bot.busy && bot.ready) return bot; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | hasBotOnline() { 45 | for (let bot of this.bots) { 46 | if (bot.ready) return true; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | getReadyAmount() { 53 | let amount = 0; 54 | for (const bot of this.bots) { 55 | if (bot.ready) { 56 | amount++; 57 | } 58 | } 59 | return amount; 60 | } 61 | 62 | lookupFloat(data) { 63 | let freeBot = this.getFreeBot(); 64 | 65 | if (freeBot) return freeBot.sendFloatRequest(data); 66 | else return Promise.reject(errors.NoBotsAvailable); 67 | } 68 | } 69 | 70 | module.exports = BotController; 71 | -------------------------------------------------------------------------------- /lib/game_data.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'), 2 | winston = require('winston'), 3 | vdf = require('simple-vdf'), 4 | utils = require('./utils'); 5 | 6 | const floatNames = [{ 7 | range: [0, 0.07], 8 | name: 'SFUI_InvTooltip_Wear_Amount_0' 9 | },{ 10 | range: [0.07, 0.15], 11 | name: 'SFUI_InvTooltip_Wear_Amount_1' 12 | },{ 13 | range: [0.15, 0.38], 14 | name: 'SFUI_InvTooltip_Wear_Amount_2' 15 | },{ 16 | range: [0.38, 0.45], 17 | name: 'SFUI_InvTooltip_Wear_Amount_3' 18 | },{ 19 | range: [0.45, 1.00], 20 | name: 'SFUI_InvTooltip_Wear_Amount_4' 21 | }]; 22 | 23 | 24 | const LanguageHandler = { 25 | get: function(obj, prop) { 26 | return obj[prop.toLowerCase()]; 27 | }, 28 | has: function (obj, prop) { 29 | return prop.toLowerCase() in obj; 30 | } 31 | }; 32 | 33 | class GameData { 34 | constructor(update_interval, enable_update) { 35 | this.items_game_url = 'https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/scripts/items/items_game.txt'; 36 | this.items_game_cdn_url = 'https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/scripts/items/items_game_cdn.txt'; 37 | this.csgo_english_url = 'https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/resource/csgo_english.txt'; 38 | this.schema_url = 'https://raw.githubusercontent.com/SteamDatabase/SteamTracking/b5cba7a22ab899d6d423380cff21cec707b7c947/ItemSchema/CounterStrikeGlobalOffensive.json'; 39 | 40 | this.items_game = false; 41 | this.items_game_cdn = false; 42 | this.csgo_english = false; 43 | this.schema = false; 44 | 45 | // Create the game data folder if it doesn't exist 46 | if (!utils.isValidDir('game_files')) { 47 | winston.info('Creating game files directory'); 48 | fs.mkdirSync('game_files'); 49 | } 50 | else { 51 | // check if we can load the files from disk 52 | this.loadFiles(); 53 | } 54 | 55 | if (enable_update) { 56 | // Update the files 57 | this.update(); 58 | 59 | // Setup interval 60 | if (update_interval && update_interval > 0) setInterval(() => {this.update();}, update_interval*1000); 61 | } 62 | } 63 | 64 | /* 65 | Loads items_game, csgo_english, and items_game_cdn from disk 66 | */ 67 | loadFiles() { 68 | if (fs.existsSync('game_files/items_game.txt')) { 69 | this.items_game = vdf.parse(fs.readFileSync('game_files/items_game.txt', 'utf8'))['items_game']; 70 | } 71 | 72 | if (fs.existsSync('game_files/csgo_english.txt')) { 73 | const f = fs.readFileSync('game_files/csgo_english.txt', 'utf8'); 74 | this.csgo_english = this.objectKeysToLowerCase(vdf.parse(f)['lang']['Tokens']); 75 | this.csgo_english = new Proxy(this.csgo_english, LanguageHandler); 76 | } 77 | 78 | if (fs.existsSync('game_files/items_game_cdn.txt')) { 79 | let data = fs.readFileSync('game_files/items_game_cdn.txt', 'utf8'); 80 | this.items_game_cdn = this.parseItemsCDN(data); 81 | } 82 | 83 | if (fs.existsSync('game_files/schema.json')) { 84 | let data = fs.readFileSync('game_files/schema.json', 'utf8'); 85 | this.schema = JSON.parse(data)['result']; 86 | } 87 | } 88 | 89 | /* 90 | Parses the data of items_game_cdn 91 | */ 92 | parseItemsCDN(data) { 93 | let lines = data.split('\n'); 94 | 95 | const result = {}; 96 | 97 | for (let line of lines) { 98 | let kv = line.split('='); 99 | 100 | if (kv[1]) { 101 | result[kv[0]] = kv[1]; 102 | } 103 | } 104 | 105 | return result; 106 | } 107 | 108 | /* 109 | Calls toLowerCase on all object shallow keys, modifies in-place, not pure 110 | */ 111 | objectKeysToLowerCase(obj) { 112 | const keys = Object.keys(obj); 113 | let n = keys.length; 114 | while (n--) { 115 | const key = keys[n]; 116 | const lower = key.toLowerCase(); 117 | if (key !== lower) { 118 | obj[lower] = obj[key]; 119 | delete obj[key]; 120 | } 121 | } 122 | 123 | return obj; 124 | } 125 | 126 | /* 127 | Updates and saves the most recent versions of csgo_english, items_game, and items_game_cdn from the SteamDB Github 128 | */ 129 | update() { 130 | winston.info('Updating Game Files...'); 131 | 132 | utils.downloadFile(this.items_game_url, (data) => { 133 | if (data) { 134 | winston.debug('Fetched items_game.txt'); 135 | this.items_game = vdf.parse(data)['items_game']; 136 | fs.writeFileSync('game_files/items_game.txt', data, 'utf8'); 137 | } 138 | else winston.error('Failed to fetch items_game.txt'); 139 | }); 140 | 141 | utils.downloadFile(this.csgo_english_url, (data) => { 142 | if (data) { 143 | winston.debug('Fetched csgo_english.txt'); 144 | this.csgo_english = this.objectKeysToLowerCase(vdf.parse(data)['lang']['Tokens']); 145 | this.csgo_english = new Proxy(this.csgo_english, LanguageHandler); 146 | 147 | fs.writeFileSync('game_files/csgo_english.txt', data, 'utf8'); 148 | } 149 | else winston.error('Failed to fetch csgo_english.txt'); 150 | }); 151 | 152 | utils.downloadFile(this.items_game_cdn_url, (data) => { 153 | if (data) { 154 | winston.debug('Fetched items_game_cdn.txt'); 155 | this.items_game_cdn = this.parseItemsCDN(data); 156 | fs.writeFileSync('game_files/items_game_cdn.txt', data, 'utf8'); 157 | } 158 | else winston.error('Failed to fetch items_game_cdn.txt'); 159 | }); 160 | 161 | utils.downloadFile(this.schema_url, (data) => { 162 | if (data) { 163 | winston.debug('Fetched schema.json'); 164 | this.schema = JSON.parse(data)['result']; 165 | fs.writeFileSync('game_files/schema.json', data, 'utf8'); 166 | } 167 | else winston.error('Failed to fetch schema.json'); 168 | }); 169 | } 170 | 171 | /* 172 | Given returned iteminfo, finds the item's min/max float, name, weapon type, and image url using CSGO game data 173 | */ 174 | addAdditionalItemProperties(iteminfo) { 175 | if (!this.items_game || !this.items_game_cdn || !this.csgo_english) return; 176 | 177 | // Get sticker codename/name 178 | const stickerKits = this.items_game.sticker_kits; 179 | for (const sticker of iteminfo.stickers || []) { 180 | const kit = stickerKits[sticker.stickerId]; 181 | 182 | if (!kit) continue; 183 | 184 | sticker.codename = kit.name; 185 | sticker.material = kit.sticker_material; 186 | 187 | let name = this.csgo_english[kit.item_name.replace('#', '')]; 188 | 189 | if (sticker.tintId) { 190 | name += ` (${this.csgo_english[`Attrib_SprayTintValue_${sticker.tintId}`]})`; 191 | } 192 | 193 | if (name) sticker.name = name; 194 | } 195 | // Get keychain name 196 | const keychainDefinitions = this.items_game.keychain_definitions; 197 | for (const keychain of iteminfo.keychains || []) { 198 | const kit = keychainDefinitions[keychain.sticker_id]; 199 | 200 | if (!kit) continue; 201 | 202 | let name = this.csgo_english[kit.loc_name.replace('#', '')]; 203 | 204 | if (name) keychain.name = name; 205 | } 206 | 207 | // Get the skin name 208 | let skin_name = ''; 209 | 210 | if (iteminfo.paintindex in this.items_game['paint_kits']) { 211 | skin_name = '_' + this.items_game['paint_kits'][iteminfo.paintindex]['name']; 212 | 213 | if (skin_name == '_default') { 214 | skin_name = ''; 215 | } 216 | } 217 | 218 | // Get the weapon name 219 | let weapon_name; 220 | 221 | if (iteminfo.defindex in this.items_game['items']) { 222 | weapon_name = this.items_game['items'][iteminfo.defindex]['name']; 223 | } 224 | 225 | // Get the image url 226 | let image_name = weapon_name + skin_name; 227 | 228 | if (image_name in this.items_game_cdn) { 229 | iteminfo['imageurl'] = this.items_game_cdn[image_name]; 230 | } 231 | 232 | // Get the paint data and code name 233 | let code_name; 234 | let paint_data; 235 | 236 | if (iteminfo.paintindex in this.items_game['paint_kits']) { 237 | code_name = this.items_game['paint_kits'][iteminfo.paintindex]['description_tag'].replace('#', ''); 238 | paint_data = this.items_game['paint_kits'][iteminfo.paintindex]; 239 | } 240 | 241 | // Get the min float 242 | if (paint_data && 'wear_remap_min' in paint_data) { 243 | iteminfo['min'] = parseFloat(paint_data['wear_remap_min']); 244 | } 245 | else iteminfo['min'] = 0.06; 246 | 247 | // Get the max float 248 | if (paint_data && 'wear_remap_max' in paint_data) { 249 | iteminfo['max'] = parseFloat(paint_data['wear_remap_max']); 250 | } 251 | else iteminfo['max'] = 0.8; 252 | 253 | let weapon_data = ''; 254 | 255 | if (iteminfo.defindex in this.items_game['items']) { 256 | weapon_data = this.items_game['items'][iteminfo.defindex]; 257 | } 258 | 259 | // Get the weapon_hud 260 | let weapon_hud; 261 | 262 | if (weapon_data !== '' && 'item_name' in weapon_data) { 263 | weapon_hud = weapon_data['item_name'].replace('#', ''); 264 | } 265 | else { 266 | // need to find the weapon hud from the prefab 267 | if (iteminfo.defindex in this.items_game['items']) { 268 | let prefab_val = this.items_game['items'][iteminfo.defindex]['prefab']; 269 | weapon_hud = this.items_game['prefabs'][prefab_val]['item_name'].replace('#', ''); 270 | } 271 | } 272 | 273 | // Get the skin name if we can 274 | if (weapon_hud in this.csgo_english && code_name in this.csgo_english) { 275 | iteminfo['weapon_type'] = this.csgo_english[weapon_hud]; 276 | iteminfo['item_name'] = this.csgo_english[code_name]; 277 | } 278 | 279 | // Get the rarity name (Mil-Spec Grade, Covert etc...) 280 | const rarityKey = Object.keys(this.items_game['rarities']).find((key) => { 281 | return parseInt(this.items_game['rarities'][key]['value']) === iteminfo.rarity; 282 | }); 283 | 284 | if (rarityKey) { 285 | const rarity = this.items_game['rarities'][rarityKey]; 286 | 287 | // Assumes weapons always have a float above 0 and that other items don't 288 | // TODO: Improve weapon check if this isn't robust 289 | iteminfo['rarity_name'] = this.csgo_english 290 | [rarity[iteminfo.floatvalue > 0 ? 'loc_key_weapon' : 'loc_key']]; 291 | } 292 | 293 | // Get the quality name (Souvenir, Stattrak, etc...) 294 | const qualityKey = Object.keys(this.items_game['qualities']).find((key) => { 295 | return parseInt(this.items_game['qualities'][key]['value']) === iteminfo.quality; 296 | }); 297 | 298 | iteminfo['quality_name'] = this.csgo_english[qualityKey]; 299 | 300 | // Get the origin name 301 | const origin = this.schema['originNames'].find((o) => o.origin === iteminfo.origin); 302 | 303 | if (origin) { 304 | iteminfo['origin_name'] = origin['name']; 305 | } 306 | 307 | // Get the wear name 308 | const wearName = this.getWearName(iteminfo.floatvalue); 309 | if (wearName) { 310 | iteminfo['wear_name'] = wearName; 311 | } 312 | 313 | const itemName = this.getFullItemName(iteminfo); 314 | if (itemName) { 315 | iteminfo['full_item_name'] = itemName; 316 | } 317 | } 318 | 319 | getWearName(float) { 320 | const f = floatNames.find((f) => float > f.range[0] && float <= f.range[1]); 321 | 322 | if (f) { 323 | return this.csgo_english[f['name']]; 324 | } 325 | } 326 | 327 | getFullItemName(iteminfo) { 328 | let name = ''; 329 | 330 | // Default items have the "unique" quality 331 | if (iteminfo.quality !== 4) { 332 | name += `${iteminfo.quality_name} `; 333 | } 334 | 335 | // Patch for items that are stattrak and unusual (ex. Stattrak Karambit) 336 | if (iteminfo.killeatervalue !== null && iteminfo.quality !== 9) { 337 | name += `${this.csgo_english['strange']} `; 338 | } 339 | 340 | name += `${iteminfo.weapon_type} `; 341 | 342 | if (iteminfo.weapon_type === 'Sticker' || iteminfo.weapon_type === 'Sealed Graffiti') { 343 | name += `| ${iteminfo.stickers[0].name}`; 344 | } else if (iteminfo.weapon_type === 'Charm') { 345 | name += `| ${iteminfo.keychains[0].name}`; 346 | } 347 | 348 | // Vanilla items have an item_name of '-' 349 | if (iteminfo.item_name && iteminfo.item_name !== '-') { 350 | name += `| ${iteminfo.item_name} `; 351 | 352 | if (iteminfo.wear_name) { 353 | name += `(${iteminfo.wear_name})`; 354 | } 355 | } 356 | 357 | return name.trim(); 358 | } 359 | } 360 | 361 | module.exports = GameData; 362 | -------------------------------------------------------------------------------- /lib/inspect_url.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils'); 2 | 3 | class InspectURL { 4 | constructor() { 5 | this.requiredParams = ['s', 'a', 'd', 'm']; 6 | 7 | if (arguments.length === 1 && typeof arguments[0] === 'string') { 8 | // parse the inspect link 9 | this.parseLink(arguments[0]); 10 | } 11 | else if (arguments.length === 1 && typeof arguments[0] === 'object') { 12 | // parse object with the requiredParams 13 | 14 | for (let param of this.requiredParams) { 15 | if (arguments[0][param] && typeof arguments[0][param] === 'string' && arguments[0][param].length > 0) { 16 | this[param] = arguments[0][param]; 17 | } 18 | else this[param] = '0'; 19 | } 20 | } 21 | else if (arguments.length === 4) { 22 | // parse each arg 23 | 24 | // Ensure each arg is a string 25 | for (let param in this.requiredParams) { 26 | if (typeof arguments[param] === 'string') { 27 | this[this.requiredParams[param]] = arguments[param]; 28 | } 29 | else return; 30 | } 31 | } 32 | } 33 | 34 | get valid() { 35 | // Ensure each param exists and only contains digits 36 | for (let param of this.requiredParams) { 37 | if (!this[param] || !utils.isOnlyDigits(this[param])) return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | parseLink(link) { 44 | try { 45 | link = decodeURI(link); 46 | } catch (e) { 47 | // Catch URI Malformed exceptions 48 | return; 49 | } 50 | 51 | let groups = /^steam:\/\/rungame\/730\/\d+\/[+ ]csgo_econ_action_preview ([SM])(\d+)A(\d+)D(\d+)$/.exec(link); 52 | 53 | if (groups) { 54 | if (groups[1] === 'S') { 55 | this.s = groups[2]; 56 | this.m = '0'; 57 | } 58 | else if (groups[1] === 'M') { 59 | this.m = groups[2]; 60 | this.s = '0'; 61 | } 62 | 63 | this.a = groups[3]; 64 | this.d = groups[4]; 65 | } 66 | } 67 | 68 | getParams() { 69 | if (this.valid) return {s: this.s, a: this.a, d: this.d, m: this.m}; 70 | } 71 | 72 | isMarketLink() { 73 | return this.valid && this.m !== '0'; 74 | } 75 | 76 | getLink() { 77 | if (!this.valid) return; 78 | 79 | if (this.s === '0' && this.m) { 80 | return `steam://rungame/730/76561202255233023/+csgo_econ_action_preview M${this.m}A${this.a}D${this.d}`; 81 | } 82 | else { 83 | return `steam://rungame/730/76561202255233023/+csgo_econ_action_preview S${this.s}A${this.a}D${this.d}`; 84 | } 85 | } 86 | } 87 | 88 | module.exports = InspectURL; 89 | -------------------------------------------------------------------------------- /lib/job.js: -------------------------------------------------------------------------------- 1 | const errors = require('./../errors'); 2 | 3 | // A Job encapsulates fetching multiple links for a single request 4 | class Job { 5 | get ip() { 6 | return this.req.ip; 7 | } 8 | 9 | constructor(req, res, isBulk) { 10 | this.req = req; 11 | this.res = res; 12 | this.isBulk = isBulk; 13 | this.remainingLinks = []; 14 | 15 | this.index = 0; 16 | 17 | this.responses = {}; 18 | } 19 | 20 | add(link, price) { 21 | this.remainingLinks.push({ 22 | link, 23 | price, 24 | job: this, 25 | }); 26 | } 27 | 28 | getRemainingLinks() { 29 | return this.remainingLinks; 30 | } 31 | 32 | remainingSize() { 33 | return this.remainingLinks.length; 34 | } 35 | 36 | getLink(aParam) { 37 | return this.remainingLinks.find(e => e.link.getParams().a == aParam); 38 | } 39 | 40 | setResponseRemaining(response) { 41 | // Prevent operating on mutating list size 42 | for (const link of [...this.remainingLinks]) { 43 | this.setResponse(link.link.getParams().a, response); 44 | } 45 | } 46 | 47 | setResponse(assetId, response) { 48 | const index = this.remainingLinks.findIndex(e => e.link.getParams().a == assetId); 49 | if (index === -1) { 50 | return; 51 | } 52 | 53 | if (response instanceof errors.Error) { 54 | response = response.getJSON(); 55 | } 56 | 57 | this.responses[assetId.toString()] = response; 58 | this.remainingLinks.splice(index, 1); 59 | 60 | if (this.remainingLinks.length === 0) { 61 | this._reply(); 62 | } 63 | } 64 | 65 | _reply() { 66 | const keys = Object.keys(this.responses); 67 | 68 | if (keys.length === 0) { 69 | return; 70 | } 71 | 72 | if (this.isBulk || keys.length > 1) { 73 | this.res.json(this.responses); 74 | } else { 75 | const response = this.responses[keys[0]]; 76 | if (response.error) { 77 | this.res.status(response.status).json(response); 78 | } else { 79 | this.res.json({iteminfo: response}); 80 | } 81 | } 82 | } 83 | } 84 | 85 | module.exports = Job; 86 | -------------------------------------------------------------------------------- /lib/postgres.js: -------------------------------------------------------------------------------- 1 | const { Pool } = require('pg'), 2 | utils = require('./utils'), 3 | winston = require('winston'); 4 | 5 | 6 | function flatten(arr){ 7 | const newArr = []; 8 | arr.forEach(v => v.forEach(p => newArr.push(p))); 9 | return newArr 10 | } 11 | 12 | class Postgres { 13 | constructor(url, enableBulkInserts) { 14 | this.pool = new Pool({ 15 | connectionString: url 16 | }); 17 | 18 | this.enableBulkInserts = enableBulkInserts || false; 19 | 20 | if (enableBulkInserts) { 21 | this.queuedInserts = []; 22 | 23 | setInterval(() => { 24 | if (this.queuedInserts.length > 0) { 25 | const copy = [...this.queuedInserts]; 26 | this.queuedInserts = []; 27 | this.handleBulkInsert(copy); 28 | } 29 | }, 1000); 30 | } 31 | } 32 | 33 | connect() { 34 | return this.pool.connect().then(() => this.ensureSchema()); 35 | } 36 | 37 | /* 38 | Returns the following properties in a 32 bit integer 39 | rarity quality origin 40 | 0000000000 00000000 00000000 00000000 41 | 8 bits 8 bits 8 bits 42 | */ 43 | static storeProperties(origin, quality, rarity) { 44 | return origin | (quality << 8) | (rarity << 16); 45 | } 46 | 47 | static extractProperties(prop) { 48 | return { 49 | origin: prop & ((1 << 8) - 1), 50 | quality: (prop >> 8) & ((1 << 8) - 1), 51 | rarity: (prop >> 16) & ((1 << 8) - 1) 52 | } 53 | } 54 | 55 | async ensureSchema() { 56 | await this.pool.query(`CREATE TABLE IF NOT EXISTS items ( 57 | ms bigint NOT NULL, 58 | a bigint NOT NULL, 59 | d bigint NOT NULL, 60 | paintseed smallint NOT NULL, 61 | paintwear integer NOT NULL, 62 | defindex smallint NOT NULL, 63 | paintindex smallint NOT NULL, 64 | stattrak boolean NOT NULL, 65 | souvenir boolean NOT NULL, 66 | props integer NOT NULL, 67 | stickers jsonb, 68 | updated timestamp NOT NULL, 69 | rarity smallint NOT NULL, 70 | floatid bigint NOT NULL, 71 | price integer, 72 | PRIMARY KEY (a) 73 | ); 74 | 75 | CREATE TABLE IF NOT EXISTS history ( 76 | floatid bigint NOT NULL, 77 | a bigint NOT NULL, 78 | steamid bigint NOT NULL, 79 | created_at timestamp NOT NULL, 80 | price integer, 81 | PRIMARY KEY (floatid, a) 82 | ); 83 | 84 | ALTER TABLE items ADD COLUMN IF NOT EXISTS floatid BIGINT; 85 | ALTER TABLE items ADD COLUMN IF NOT EXISTS price INTEGER; 86 | ALTER TABLE items ADD COLUMN IF NOT EXISTS listed_price INTEGER; 87 | ALTER TABLE items ADD COLUMN IF NOT EXISTS keychains JSONB; 88 | ALTER TABLE history ADD COLUMN IF NOT EXISTS price INTEGER; 89 | 90 | -- Float ID is defined as the first asset id we've seen for an item 91 | 92 | CREATE OR REPLACE FUNCTION is_steamid(IN val bigint) 93 | RETURNS boolean 94 | LANGUAGE 'plpgsql' 95 | IMMUTABLE 96 | PARALLEL SAFE 97 | AS $BODY$BEGIN 98 | IF val < 76561197960265728 THEN 99 | RETURN FALSE; 100 | ELSIF (val >> 56) > 5 THEN 101 | RETURN FALSE; 102 | ELSIF ((val >> 32) & ((1 << 20) - 1)) > 32 THEN 103 | RETURN FALSE; 104 | END IF; 105 | 106 | RETURN TRUE; 107 | END;$BODY$; 108 | 109 | CREATE OR REPLACE FUNCTION extend_history() 110 | RETURNS TRIGGER 111 | AS $$ 112 | BEGIN 113 | -- Handle cases where the floatid isn't there 114 | IF NEW.floatid IS NULL THEN 115 | NEW.floatid = OLD.a; 116 | END IF; 117 | 118 | IF NEW.a = OLD.a THEN 119 | -- Ignore handling, no new item details, updating existing 120 | RETURN NEW; 121 | END IF; 122 | 123 | IF NEW.a < OLD.a THEN 124 | -- If we find an older asset id than the current, still want to add it to history if not there 125 | INSERT INTO history VALUES (NEW.floatid, NEW.a, NEW.ms, NEW.updated, NULL) ON CONFLICT DO NOTHING; 126 | 127 | -- Prevent update to this row 128 | RETURN NULL; 129 | END IF; 130 | 131 | IF (is_steamid(OLD.ms) AND OLD.ms != NEW.ms) OR OLD.price IS NOT NULL THEN 132 | -- We care about history for inventory changes or market listings that had price data 133 | INSERT INTO history VALUES (NEW.floatid, OLD.a, OLD.ms, OLD.updated, OLD.price); 134 | END IF; 135 | 136 | -- Reset the price if it is the same, it is possible that the item was sold for the exact same amount in a row 137 | -- and we clear it here, but that isn't too much of a concern for the application of the data 138 | -- This ensures that outdated instances contributing to the same db don't conflict state 139 | IF NEW.price = OLD.price OR NEW.listed_price = OLD.listed_price OR is_steamid(NEW.ms) THEN 140 | NEW.price = NULL; 141 | NEW.listed_price = NULL; 142 | END IF; 143 | 144 | RETURN NEW; 145 | END; 146 | $$ 147 | LANGUAGE 'plpgsql'; 148 | 149 | DROP TRIGGER IF EXISTS extend_history_trigger 150 | ON items; 151 | 152 | CREATE TRIGGER extend_history_trigger 153 | BEFORE UPDATE ON items 154 | FOR EACH ROW 155 | EXECUTE PROCEDURE extend_history(); 156 | 157 | CREATE OR REPLACE FUNCTION ensure_floatid() 158 | RETURNS TRIGGER 159 | AS $$ 160 | BEGIN 161 | IF NEW.floatid IS NULL THEN 162 | NEW.floatid = NEW.a; 163 | END IF; 164 | 165 | RETURN NEW; 166 | END; 167 | $$ 168 | LANGUAGE 'plpgsql'; 169 | 170 | DROP TRIGGER IF EXISTS ensure_floatid_trigger 171 | ON items; 172 | 173 | CREATE TRIGGER ensure_floatid_trigger 174 | BEFORE INSERT ON items 175 | FOR EACH ROW 176 | EXECUTE PROCEDURE ensure_floatid(); 177 | `); 178 | 179 | await this.pool.query(`CREATE INDEX IF NOT EXISTS i_stickers ON items USING gin (stickers jsonb_path_ops) 180 | WHERE stickers IS NOT NULL`); 181 | await this.pool.query(`CREATE INDEX IF NOT EXISTS i_paintwear ON items (paintwear)`); 182 | await this.pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS i_unique_item ON 183 | items (defindex, paintindex, paintwear, paintseed)`); 184 | await this.pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS i_unique_fid ON items (floatid)`); 185 | } 186 | 187 | async insertItemData(item, price) { 188 | if (this.enableBulkInserts) { 189 | this.queuedInserts.push([item, price]); 190 | } else { 191 | await this.handleBulkInsert([[item, price]]); 192 | } 193 | } 194 | 195 | /** 196 | * Bulk handler to improve insert performance with 300+ rows at once 197 | * @param data [[item, price]] 198 | * @returns {Promise} 199 | */ 200 | async handleBulkInsert(data) { 201 | const values = []; 202 | const uniqueItems = new Set(); 203 | 204 | for (let [item, price] of data) { 205 | item = Object.assign({}, item); 206 | 207 | // Store float as int32 to prevent float rounding errors 208 | // Postgres doesn't support unsigned types, so we use signed here 209 | const buf = Buffer.alloc(4); 210 | buf.writeFloatBE(item.floatvalue, 0); 211 | item.paintwear = buf.readInt32BE(0); 212 | 213 | if (item.floatvalue <= 0 && item.defindex !== 507) { 214 | // Only insert weapons, naive check 215 | // Special case for the 0 float Karambit 216 | continue; 217 | } 218 | 219 | // Postgres doesn't support unsigned 64 bit ints, so we convert them to signed 220 | item.s = utils.unsigned64ToSigned(item.s).toString(); 221 | item.a = utils.unsigned64ToSigned(item.a).toString(); 222 | item.d = utils.unsigned64ToSigned(item.d).toString(); 223 | item.m = utils.unsigned64ToSigned(item.m).toString(); 224 | 225 | const stickers = item.stickers.length > 0 ? item.stickers.map((s) => { 226 | const res = {s: s.slot, i: s.stickerId}; 227 | if (s.wear) { 228 | res.w = s.wear; 229 | } 230 | if (s.rotation) { 231 | res.r = s.rotation; 232 | } 233 | if (s.offset_x) { 234 | res.x = s.offset_x; 235 | } 236 | if (s.offset_y) { 237 | res.y = s.offset_y; 238 | } 239 | return res; 240 | }) : null; 241 | 242 | if (stickers) { 243 | // Add a property on stickers with duplicates that signifies how many dupes there are 244 | // Only add this property to one of the dupe stickers in the array 245 | for (const sticker of stickers) { 246 | const matching = stickers.filter((s) => s.i === sticker.i); 247 | if (matching.length > 1 && !matching.find((s) => s.d > 1)) { 248 | sticker.d = matching.length; 249 | } 250 | } 251 | } 252 | 253 | const keychains = item.keychains.length > 0 ? item.keychains.map((s) => { 254 | const res = {s: s.slot, i: s.sticker_id}; 255 | if (s.wear) { 256 | res.w = s.wear; 257 | } 258 | if (s.scale) { 259 | res.sc = s.scale; 260 | } 261 | if (s.rotation) { 262 | res.r = s.rotation; 263 | } 264 | if (s.tint_id) { 265 | res.t = s.tint_id; 266 | } 267 | if (s.offset_x) { 268 | res.x = s.offset_x; 269 | } 270 | if (s.offset_y) { 271 | res.y = s.offset_y; 272 | } 273 | if (s.offset_z) { 274 | res.z = s.offset_z; 275 | } 276 | if (s.pattern) { 277 | res.p = s.pattern; 278 | } 279 | return res; 280 | }) : null; 281 | 282 | const ms = item.s !== '0' ? item.s : item.m; 283 | const isStattrak = item.killeatervalue !== null; 284 | const isSouvenir = item.quality === 12; 285 | 286 | const props = Postgres.storeProperties(item.origin, item.quality, item.rarity); 287 | 288 | price = price || null; 289 | 290 | // Prevent two of the same item from being inserted in the same statement (causes postgres to get angry) 291 | const key = `${item.defindex}_${item.paintindex}_${item.paintwear}_${item.paintseed}`; 292 | if (uniqueItems.has(key)) { 293 | continue; 294 | } else { 295 | uniqueItems.add(key); 296 | } 297 | 298 | values.push([ms, item.a, item.d, item.paintseed, item.paintwear, item.defindex, item.paintindex, isStattrak, 299 | isSouvenir, props, JSON.stringify(stickers), JSON.stringify(keychains), item.rarity, price]); 300 | } 301 | 302 | if (values.length === 0) { 303 | return; 304 | } 305 | 306 | try { 307 | const query = Postgres.buildQuery(values.length); 308 | await this.pool.query(query, flatten(values)); 309 | winston.debug(`Inserted/updated ${values.length} items`) 310 | } catch (e) { 311 | winston.warn(e); 312 | } 313 | } 314 | 315 | static buildQuery(itemCount) { 316 | const values = []; 317 | let i = 1; 318 | 319 | // Builds binding pattern such as ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11::jsonb, $12::jsonb, now(), $13, NULL, $14) 320 | for (let c = 0; c < itemCount; c++) { 321 | values.push(`($${i++}, $${i++}, $${i++}, $${i++}, $${i++}, $${i++}, $${i++}, $${i++}, $${i++}, $${i++}, $${i++}::jsonb, $${i++}::jsonb, now(), $${i++}, NULL, $${i++})`); 322 | } 323 | 324 | return `INSERT INTO items (ms, a, d, paintseed, paintwear, defindex, paintindex, stattrak, souvenir, props, stickers, keychains, updated, rarity, floatid, price) 325 | VALUES ${values.join(', ')} ON CONFLICT(defindex, paintindex, paintwear, paintseed) DO UPDATE SET ms=excluded.ms, a=excluded.a, d=excluded.d, stickers=excluded.stickers, keychains=excluded.keychains, updated=now()`; 326 | } 327 | 328 | updateItemPrice(assetId, price) { 329 | return this.pool.query(`UPDATE items SET price = $1 WHERE a = $2`, [price, assetId]); 330 | } 331 | 332 | async getItemData(links) { 333 | // Chunking into db calls of 100 each is more performant 334 | const chunked = utils.chunkArray(links, 100); 335 | const promises = chunked.map(e => this._getItemData(e)); 336 | const results = await Promise.all(promises); 337 | 338 | // Flatten results 339 | return results.reduce((acc, val) => acc.concat(val), []); 340 | } 341 | 342 | async _getItemData(links) { 343 | const aValues = links.map(e => utils.unsigned64ToSigned(e.getParams().a)); 344 | 345 | const result = await this.pool.query(` 346 | SELECT *, 347 | (SELECT Count(*)+1 348 | FROM (SELECT * 349 | FROM items T 350 | WHERE T.paintwear < S.paintwear 351 | AND T.defindex = S.defindex 352 | AND T.paintindex = S.paintindex 353 | AND T.stattrak = S.stattrak 354 | AND T.souvenir = S.souvenir 355 | ORDER BY T.paintwear 356 | LIMIT 1000) as a) AS low_rank, 357 | (SELECT Count(*)+1 358 | FROM (SELECT * 359 | FROM items J 360 | WHERE J.paintwear > S.paintwear 361 | AND J.defindex = S.defindex 362 | AND J.paintindex = S.paintindex 363 | AND J.stattrak = S.stattrak 364 | AND J.souvenir = S.souvenir 365 | ORDER BY J.paintwear DESC 366 | LIMIT 1000) as b) AS high_rank 367 | FROM items S 368 | WHERE a= ANY($1::bigint[])`, [aValues]); 369 | 370 | return result.rows.map((item) => { 371 | delete item.updated; 372 | 373 | // Correspond to existing API, ensure we can still recreate the full item name 374 | if (item.stattrak) { 375 | item.killeatervalue = 0; 376 | } else { 377 | item.killeatervalue = null; 378 | } 379 | 380 | item.stickers = item.stickers || []; 381 | item.stickers = item.stickers.map((s) => { 382 | return { 383 | stickerId: s.i, 384 | slot: s.s, 385 | wear: s.w, 386 | rotation: s.r, 387 | offset_x: s.x, 388 | offset_y: s.y, 389 | } 390 | }); 391 | 392 | item.keychains = item.keychains || []; 393 | item.keychains = item.keychains.map((s) => { 394 | return { 395 | sticker_id: s.i, 396 | slot: s.s, 397 | wear: s.w, 398 | scale: s.sc, 399 | rotation: s.r, 400 | tint_id: s.t, 401 | offset_x: s.x, 402 | offset_y: s.y, 403 | offset_z: s.z, 404 | pattern: s.p, 405 | } 406 | }); 407 | 408 | item = Object.assign(Postgres.extractProperties(item.props), item); 409 | 410 | const buf = Buffer.alloc(4); 411 | buf.writeInt32BE(item.paintwear, 0); 412 | item.floatvalue = buf.readFloatBE(0); 413 | 414 | item.a = utils.signed64ToUnsigned(item.a).toString(); 415 | item.d = utils.signed64ToUnsigned(item.d).toString(); 416 | item.ms = utils.signed64ToUnsigned(item.ms).toString(); 417 | 418 | if (utils.isSteamId64(item.ms)){ 419 | item.s = item.ms; 420 | item.m = '0'; 421 | } else { 422 | item.m = item.ms; 423 | item.s = '0'; 424 | } 425 | 426 | item.high_rank = parseInt(item.high_rank); 427 | item.low_rank = parseInt(item.low_rank); 428 | 429 | // Delete the rank if above 1000 (we don't get ranking above that) 430 | if (item.high_rank === 1001) { 431 | delete item.high_rank; 432 | } 433 | 434 | if (item.low_rank === 1001) { 435 | delete item.low_rank; 436 | } 437 | 438 | delete item.souvenir; 439 | delete item.stattrak; 440 | delete item.paintwear; 441 | delete item.ms; 442 | delete item.props; 443 | delete item.price; 444 | delete item.listed_price; 445 | delete item.dupe_count; 446 | 447 | return item; 448 | }); 449 | } 450 | 451 | getItemRank(id) { 452 | return this.pool.query(`SELECT (SELECT Count(*)+1 453 | FROM (SELECT * 454 | FROM items T 455 | WHERE T.paintwear < S.paintwear 456 | AND T.defindex = S.defindex 457 | AND T.paintindex = S.paintindex 458 | AND T.stattrak = S.stattrak 459 | AND T.souvenir = S.souvenir 460 | ORDER BY T.paintwear 461 | LIMIT 1000) as a) AS low_rank, 462 | (SELECT Count(*)+1 463 | FROM (SELECT * 464 | FROM items J 465 | WHERE J.paintwear > S.paintwear 466 | AND J.defindex = S.defindex 467 | AND J.paintindex = S.paintindex 468 | AND J.stattrak = S.stattrak 469 | AND J.souvenir = S.souvenir 470 | ORDER BY J.paintwear DESC 471 | LIMIT 1000) as b) AS high_rank 472 | FROM items S 473 | WHERE a=$1`, 474 | [id]).then((res) => { 475 | if (res.rows.length > 0) { 476 | const item = res.rows[0]; 477 | const result = {}; 478 | 479 | if (item.high_rank != 1001) { 480 | result.high_rank = parseInt(item.high_rank); 481 | } 482 | if (item.low_rank != 1001) { 483 | result.low_rank = parseInt(item.low_rank); 484 | } 485 | 486 | return result; 487 | } else { 488 | return {}; 489 | } 490 | }); 491 | } 492 | } 493 | 494 | module.exports = Postgres; 495 | -------------------------------------------------------------------------------- /lib/queue.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require('events').EventEmitter; 2 | const errors = require('../errors'); 3 | 4 | class Queue extends EventEmitter { 5 | constructor() { 6 | super(); 7 | 8 | this.queue = []; 9 | this.users = {}; 10 | this.running = false; 11 | } 12 | 13 | size() { 14 | return this.queue.length; 15 | } 16 | 17 | process(concurrency, controller, handler) { 18 | this.handler = handler; 19 | this.concurrency = concurrency; 20 | this.processing = 0; 21 | 22 | this.start(); 23 | 24 | // Monkey patch to ensure queue processing size is roughly equal to amount of bots ready 25 | setInterval(() => { 26 | // Update concurrency level, possible bots went offline or otherwise 27 | const oldConcurrency = this.concurrency; 28 | this.concurrency = controller.getReadyAmount(); 29 | 30 | if (this.concurrency > oldConcurrency) { 31 | for (let i = 0; i < this.concurrency - oldConcurrency; i++) { 32 | this.checkQueue(); 33 | } 34 | } 35 | 36 | }, 50); 37 | } 38 | 39 | addJob(job, max_attempts) { 40 | if (!(job.ip in this.users)) { 41 | this.users[job.ip] = 0; 42 | } 43 | 44 | for (const link of job.getRemainingLinks()) { 45 | this.queue.push({ 46 | data: link, 47 | max_attempts: max_attempts, 48 | attempts: 0, 49 | ip: job.ip, 50 | }); 51 | 52 | this.users[job.ip]++; 53 | this.checkQueue(); 54 | } 55 | } 56 | 57 | checkQueue() { 58 | if (!this.running) return; 59 | 60 | if (this.queue.length > 0 && this.processing < this.concurrency) { 61 | // there is a free bot, process the job 62 | let job = this.queue.shift(); 63 | 64 | this.processing += 1; 65 | 66 | this.handler(job).then((delay) => { 67 | if (!delay) delay = 0; 68 | 69 | // Allow users to request again before the promise resolve delay 70 | this.users[job.ip]--; 71 | 72 | return new Promise((resolve, reject) => { 73 | setTimeout(() => { 74 | resolve(); 75 | }, delay); 76 | }); 77 | }).catch((err) => { 78 | if (err !== errors.NoBotsAvailable) { 79 | job.attempts++; 80 | } 81 | 82 | if (job.attempts === job.max_attempts) { 83 | // job failed 84 | this.emit('job failed', job, err); 85 | this.users[job.ip]--; 86 | } 87 | else { 88 | // try again 89 | this.queue.unshift(job); 90 | } 91 | }).then(() => { 92 | this.processing -= 1; 93 | this.checkQueue(); 94 | }); 95 | } 96 | } 97 | 98 | start() { 99 | if (!this.running) { 100 | this.running = true; 101 | this.checkQueue(); 102 | } 103 | } 104 | 105 | pause() { 106 | if (this.running) this.running = false; 107 | } 108 | 109 | /** 110 | * Returns number of requests the ip currently has queued 111 | */ 112 | getUserQueuedAmt(ip) { 113 | return this.users[ip] || 0; 114 | } 115 | } 116 | 117 | module.exports = Queue; 118 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | const https = require('https'), 2 | fs = require('fs'); 3 | 4 | /* 5 | Downloads the given HTTPS file 6 | */ 7 | exports.downloadFile = function(url, cb) { 8 | https.get(url, function(res) { 9 | let errored = false; 10 | 11 | if (res.statusCode !== 200 && !errored) { 12 | cb(); 13 | return; 14 | } 15 | 16 | res.setEncoding('utf8'); 17 | let data = ''; 18 | 19 | res.on('error', function(err) { 20 | cb(); 21 | errored = true; 22 | }); 23 | 24 | res.on('data', function(chunk) { 25 | data += chunk; 26 | }); 27 | 28 | res.on('end', function() { 29 | cb(data); 30 | }); 31 | }); 32 | }; 33 | 34 | /* 35 | Returns a boolean as to whether the specified path is a directory and exists 36 | */ 37 | exports.isValidDir = function(path) { 38 | try { 39 | return fs.statSync(path).isDirectory(); 40 | } catch (e) { 41 | return false; 42 | } 43 | }; 44 | 45 | /* 46 | Returns a boolean as to whether the string only contains numbers 47 | */ 48 | exports.isOnlyDigits = function (num) { 49 | return /^\d+$/.test(num); 50 | }; 51 | 52 | /* 53 | Filters the keys in the given object and returns new one 54 | */ 55 | exports.filterKeys = function (keys, obj) { 56 | return keys.reduce((result, key) => { 57 | if (key in obj) result[key] = obj[key]; 58 | return result; 59 | }, {}); 60 | }; 61 | 62 | /* 63 | Removes keys with null values 64 | */ 65 | exports.removeNullValues = function (obj) { 66 | return Object.keys(obj).reduce((result, key) => { 67 | if (key in obj && obj[key] !== null) { 68 | result[key] = obj[key]; 69 | } 70 | 71 | return result; 72 | }, {}); 73 | }; 74 | 75 | /* 76 | Converts the given unsigned 64 bit integer into a signed 64 bit integer 77 | */ 78 | exports.unsigned64ToSigned = function (num) { 79 | const mask = 1n << 63n; 80 | return (BigInt(num)^mask) - mask; 81 | }; 82 | 83 | /* 84 | Converts the given signed 64 bit integer into an unsigned 64 bit integer 85 | */ 86 | exports.signed64ToUnsigned = function (num) { 87 | const mask = 1n << 63n; 88 | return (BigInt(num)+mask) ^ mask; 89 | }; 90 | 91 | /* 92 | Checks whether the given ID is a SteamID64 93 | */ 94 | exports.isSteamId64 = function (id) { 95 | id = BigInt(id); 96 | const universe = id >> 56n; 97 | if (universe > 5n) return false; 98 | 99 | const instance = (id >> 32n) & (1n << 20n)-1n; 100 | 101 | // There are currently no documented instances above 4, but this is for good measure 102 | return instance <= 32n; 103 | }; 104 | 105 | /* 106 | Chunks array into sub-arrays of the given size 107 | */ 108 | exports.chunkArray = function (arr, size) { 109 | return new Array(Math.ceil(arr.length / size)).fill().map(_ => arr.splice(0,size)); 110 | }; 111 | 112 | /* 113 | Shuffle array - O(N LOG N) so it shouldn't be used for super-large arrays 114 | */ 115 | exports.shuffleArray = function (arr) { 116 | return arr.map(value => ({ value, sort: Math.random() })) 117 | .sort((a, b) => a.sort - b.sort) 118 | .map(({ value }) => value) 119 | } 120 | 121 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "csgofloat", 3 | "version": "4.0.0", 4 | "description": "Source Code that Powers the CSGOFloat API", 5 | "author": "Step7750", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/Step7750/CSGOFloat.git" 11 | }, 12 | "scripts": { 13 | "start": "node index.js" 14 | }, 15 | "dependencies": { 16 | "body-parser": "^1.19.0", 17 | "command-line-args": "^5.1.1", 18 | "express": "^4.17.1", 19 | "express-rate-limit": "^5.2.6", 20 | "globaloffensive": "^3.2.0", 21 | "long": "^3.2.0", 22 | "mongodb": "^2.2.36", 23 | "pg": "^8.10.0", 24 | "simple-vdf": "^1.1.1", 25 | "socket.io": "^2.4.0", 26 | "steam-totp": "^2.1.2", 27 | "steam-user": "^5.2.0", 28 | "winston": "^2.4.5" 29 | }, 30 | "devDependencies": { 31 | "eslint": "^8.56.0", 32 | "eslint-config-google": "^0.7.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@aashutoshrathi/word-wrap@^1.2.3": 6 | version "1.2.6" 7 | resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" 8 | integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== 9 | 10 | "@bbob/parser@^2.2.0": 11 | version "2.9.0" 12 | resolved "https://registry.npmjs.org/@bbob/parser/-/parser-2.9.0.tgz" 13 | integrity sha512-tldSYsMoEclke/B1nqL7+HbYMWZHTKvpbEHRSHuY+sZvS1o7Jpdfjb+KPpwP9wLI3p3r7GPv69/wGy+Xibs9yA== 14 | dependencies: 15 | "@bbob/plugin-helper" "^2.9.0" 16 | 17 | "@bbob/plugin-helper@^2.9.0": 18 | version "2.9.0" 19 | resolved "https://registry.npmjs.org/@bbob/plugin-helper/-/plugin-helper-2.9.0.tgz" 20 | integrity sha512-idpUcNQ2co6T1oU/7/DG/ZRfipSSkTn9Ozw9f5vaXH7nzV3qhqZnhFVlHTzGGnRlzKlBwWOBzOdWi4Zeqg1c5A== 21 | 22 | "@doctormckay/stdlib@^1.14.1", "@doctormckay/stdlib@^1.6.0": 23 | version "1.16.1" 24 | resolved "https://registry.npmjs.org/@doctormckay/stdlib/-/stdlib-1.16.1.tgz" 25 | integrity sha512-XhuUOzElz6fnNdt70IYNKqhPAEpGaL4JHOhAvklRh0hAhVPW+/wLxaWT3DWUbaG5Dta5YvIp7+cZK3GhIpAuug== 26 | 27 | "@doctormckay/stdlib@^2.7.1": 28 | version "2.10.0" 29 | resolved "https://mirrors.cloud.tencent.com/npm/@doctormckay/stdlib/-/stdlib-2.10.0.tgz" 30 | integrity sha512-bwy+gPn6oa2KTpfxJKX3leZoV/wHDVtO0/gq3usPvqPswG//dcf3jVB8LcbRRsKO3BXCt5DqctOQ+Xb07ivxnw== 31 | dependencies: 32 | psl "^1.9.0" 33 | 34 | "@doctormckay/stdlib@^2.9.0": 35 | version "2.10.0" 36 | resolved "https://mirrors.cloud.tencent.com/npm/@doctormckay/stdlib/-/stdlib-2.10.0.tgz" 37 | integrity sha512-bwy+gPn6oa2KTpfxJKX3leZoV/wHDVtO0/gq3usPvqPswG//dcf3jVB8LcbRRsKO3BXCt5DqctOQ+Xb07ivxnw== 38 | dependencies: 39 | psl "^1.9.0" 40 | 41 | "@doctormckay/stdlib@^2.9.1": 42 | version "2.10.0" 43 | resolved "https://mirrors.cloud.tencent.com/npm/@doctormckay/stdlib/-/stdlib-2.10.0.tgz" 44 | integrity sha512-bwy+gPn6oa2KTpfxJKX3leZoV/wHDVtO0/gq3usPvqPswG//dcf3jVB8LcbRRsKO3BXCt5DqctOQ+Xb07ivxnw== 45 | dependencies: 46 | psl "^1.9.0" 47 | 48 | "@doctormckay/steam-crypto@^1.2.0": 49 | version "1.2.0" 50 | resolved "https://registry.npmjs.org/@doctormckay/steam-crypto/-/steam-crypto-1.2.0.tgz" 51 | integrity sha512-lsxgLw640gEdZBOXpVIcYWcYD+V+QbtEsMPzRvjmjz2XXKc7QeEMyHL07yOFRmay+cUwO4ObKTJO0dSInEuq5g== 52 | 53 | "@doctormckay/user-agents@^1.0.0": 54 | version "1.0.0" 55 | resolved "https://mirrors.cloud.tencent.com/npm/@doctormckay/user-agents/-/user-agents-1.0.0.tgz" 56 | integrity sha512-F+sL1YmebZTY2CnjoR9BXFEULpq7y8dxyLx48LZVa0BSDseXdLG/DtPISfM1iNv1XKCeiBzVNfAT/MOQ69v1Zw== 57 | 58 | "@eslint-community/eslint-utils@^4.2.0": 59 | version "4.4.0" 60 | resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" 61 | integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== 62 | dependencies: 63 | eslint-visitor-keys "^3.3.0" 64 | 65 | "@eslint-community/regexpp@^4.6.1": 66 | version "4.10.0" 67 | resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz" 68 | integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== 69 | 70 | "@eslint/eslintrc@^2.1.4": 71 | version "2.1.4" 72 | resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" 73 | integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== 74 | dependencies: 75 | ajv "^6.12.4" 76 | debug "^4.3.2" 77 | espree "^9.6.0" 78 | globals "^13.19.0" 79 | ignore "^5.2.0" 80 | import-fresh "^3.2.1" 81 | js-yaml "^4.1.0" 82 | minimatch "^3.1.2" 83 | strip-json-comments "^3.1.1" 84 | 85 | "@eslint/js@8.56.0": 86 | version "8.56.0" 87 | resolved "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz" 88 | integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== 89 | 90 | "@humanwhocodes/config-array@^0.11.13": 91 | version "0.11.14" 92 | resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" 93 | integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== 94 | dependencies: 95 | "@humanwhocodes/object-schema" "^2.0.2" 96 | debug "^4.3.1" 97 | minimatch "^3.0.5" 98 | 99 | "@humanwhocodes/module-importer@^1.0.1": 100 | version "1.0.1" 101 | resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" 102 | integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== 103 | 104 | "@humanwhocodes/object-schema@^2.0.2": 105 | version "2.0.2" 106 | resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz" 107 | integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== 108 | 109 | "@nodelib/fs.scandir@2.1.5": 110 | version "2.1.5" 111 | resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" 112 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 113 | dependencies: 114 | "@nodelib/fs.stat" "2.0.5" 115 | run-parallel "^1.1.9" 116 | 117 | "@nodelib/fs.stat@2.0.5": 118 | version "2.0.5" 119 | resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" 120 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 121 | 122 | "@nodelib/fs.walk@^1.2.8": 123 | version "1.2.8" 124 | resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" 125 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 126 | dependencies: 127 | "@nodelib/fs.scandir" "2.1.5" 128 | fastq "^1.6.0" 129 | 130 | "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": 131 | version "1.1.2" 132 | resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" 133 | integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== 134 | 135 | "@protobufjs/base64@^1.1.2": 136 | version "1.1.2" 137 | resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" 138 | integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== 139 | 140 | "@protobufjs/codegen@^2.0.4": 141 | version "2.0.4" 142 | resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" 143 | integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== 144 | 145 | "@protobufjs/eventemitter@^1.1.0": 146 | version "1.1.0" 147 | resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" 148 | integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== 149 | 150 | "@protobufjs/fetch@^1.1.0": 151 | version "1.1.0" 152 | resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" 153 | integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== 154 | dependencies: 155 | "@protobufjs/aspromise" "^1.1.1" 156 | "@protobufjs/inquire" "^1.1.0" 157 | 158 | "@protobufjs/float@^1.0.2": 159 | version "1.0.2" 160 | resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" 161 | integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== 162 | 163 | "@protobufjs/inquire@^1.1.0": 164 | version "1.1.0" 165 | resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" 166 | integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== 167 | 168 | "@protobufjs/path@^1.1.2": 169 | version "1.1.2" 170 | resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" 171 | integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== 172 | 173 | "@protobufjs/pool@^1.1.0": 174 | version "1.1.0" 175 | resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" 176 | integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== 177 | 178 | "@protobufjs/utf8@^1.1.0": 179 | version "1.1.0" 180 | resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" 181 | integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== 182 | 183 | "@types/long@^4.0.1": 184 | version "4.0.2" 185 | resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" 186 | integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== 187 | 188 | "@types/node@>=13.7.0": 189 | version "20.11.17" 190 | resolved "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz" 191 | integrity sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw== 192 | dependencies: 193 | undici-types "~5.26.4" 194 | 195 | "@ungap/structured-clone@^1.2.0": 196 | version "1.2.0" 197 | resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" 198 | integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== 199 | 200 | accepts@~1.3.4, accepts@~1.3.8: 201 | version "1.3.8" 202 | resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" 203 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== 204 | dependencies: 205 | mime-types "~2.1.34" 206 | negotiator "0.6.3" 207 | 208 | acorn-jsx@^5.3.2: 209 | version "5.3.2" 210 | resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" 211 | integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 212 | 213 | "acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0: 214 | version "8.11.3" 215 | resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" 216 | integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== 217 | 218 | adm-zip@^0.5.10: 219 | version "0.5.10" 220 | resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz" 221 | integrity sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ== 222 | 223 | after@0.8.2: 224 | version "0.8.2" 225 | resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz" 226 | integrity sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA== 227 | 228 | agent-base@^6.0.2: 229 | version "6.0.2" 230 | resolved "https://mirrors.cloud.tencent.com/npm/agent-base/-/agent-base-6.0.2.tgz" 231 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 232 | dependencies: 233 | debug "4" 234 | 235 | ajv@^6.12.4: 236 | version "6.12.6" 237 | resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" 238 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 239 | dependencies: 240 | fast-deep-equal "^3.1.1" 241 | fast-json-stable-stringify "^2.0.0" 242 | json-schema-traverse "^0.4.1" 243 | uri-js "^4.2.2" 244 | 245 | ansi-regex@^5.0.1: 246 | version "5.0.1" 247 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" 248 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 249 | 250 | ansi-styles@^4.1.0: 251 | version "4.3.0" 252 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" 253 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 254 | dependencies: 255 | color-convert "^2.0.1" 256 | 257 | argparse@^2.0.1: 258 | version "2.0.1" 259 | resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" 260 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 261 | 262 | array-back@^3.0.1, array-back@^3.1.0: 263 | version "3.1.0" 264 | resolved "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz" 265 | integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== 266 | 267 | array-flatten@1.1.1: 268 | version "1.1.1" 269 | resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" 270 | integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== 271 | 272 | arraybuffer.slice@~0.0.7: 273 | version "0.0.7" 274 | resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz" 275 | integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== 276 | 277 | async@^2.6.4: 278 | version "2.6.4" 279 | resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" 280 | integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== 281 | dependencies: 282 | lodash "^4.17.14" 283 | 284 | backo2@1.0.2: 285 | version "1.0.2" 286 | resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz" 287 | integrity sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA== 288 | 289 | balanced-match@^1.0.0: 290 | version "1.0.2" 291 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" 292 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 293 | 294 | base64-arraybuffer@0.1.4: 295 | version "0.1.4" 296 | resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz" 297 | integrity sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg== 298 | 299 | base64id@2.0.0: 300 | version "2.0.0" 301 | resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz" 302 | integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== 303 | 304 | big-number@^2.0.0: 305 | version "2.0.0" 306 | resolved "https://registry.npmjs.org/big-number/-/big-number-2.0.0.tgz" 307 | integrity sha512-C67Su0g+XsmXADX/UM9L/+xSbqqwq0D/qGJs2ky6Noy2FDuCZnC38ZSXODiaBvqWma2VYRZEXgm4H74PS6tCDg== 308 | 309 | binarykvparser@^2.2.0: 310 | version "2.2.0" 311 | resolved "https://registry.npmjs.org/binarykvparser/-/binarykvparser-2.2.0.tgz" 312 | integrity sha512-mGBKngQF9ui53THcMjgjd0LrBH/HsI2Vywfjq52udSAmRGG87h0vjhkqun0kF+iC4rQ2jLZqldwJE7YN2ueiWw== 313 | dependencies: 314 | long "^3.2.0" 315 | 316 | blob@0.0.5: 317 | version "0.0.5" 318 | resolved "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz" 319 | integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== 320 | 321 | body-parser@^1.19.0: 322 | version "1.20.2" 323 | resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" 324 | integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== 325 | dependencies: 326 | bytes "3.1.2" 327 | content-type "~1.0.5" 328 | debug "2.6.9" 329 | depd "2.0.0" 330 | destroy "1.2.0" 331 | http-errors "2.0.0" 332 | iconv-lite "0.4.24" 333 | on-finished "2.4.1" 334 | qs "6.11.0" 335 | raw-body "2.5.2" 336 | type-is "~1.6.18" 337 | unpipe "1.0.0" 338 | 339 | body-parser@1.20.1: 340 | version "1.20.1" 341 | resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz" 342 | integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== 343 | dependencies: 344 | bytes "3.1.2" 345 | content-type "~1.0.4" 346 | debug "2.6.9" 347 | depd "2.0.0" 348 | destroy "1.2.0" 349 | http-errors "2.0.0" 350 | iconv-lite "0.4.24" 351 | on-finished "2.4.1" 352 | qs "6.11.0" 353 | raw-body "2.5.1" 354 | type-is "~1.6.18" 355 | unpipe "1.0.0" 356 | 357 | brace-expansion@^1.1.7: 358 | version "1.1.11" 359 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" 360 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 361 | dependencies: 362 | balanced-match "^1.0.0" 363 | concat-map "0.0.1" 364 | 365 | bson@~1.0.4: 366 | version "1.0.9" 367 | resolved "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz" 368 | integrity sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg== 369 | 370 | buffer-shims@~1.0.0: 371 | version "1.0.0" 372 | resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz" 373 | integrity sha512-Zy8ZXMyxIT6RMTeY7OP/bDndfj6bwCan7SS98CEndS6deHwWPpseeHlwarNcBim+etXnF9HBc1non5JgDaJU1g== 374 | 375 | buffer-writer@2.0.0: 376 | version "2.0.0" 377 | resolved "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz" 378 | integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== 379 | 380 | bytebuffer@^5.0.0, bytebuffer@^5.0.1: 381 | version "5.0.1" 382 | resolved "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz" 383 | integrity sha512-IuzSdmADppkZ6DlpycMkm8l9zeEq16fWtLvunEwFiYciR/BHo4E8/xs5piFquG+Za8OWmMqHF8zuRviz2LHvRQ== 384 | dependencies: 385 | long "~3" 386 | 387 | bytes@3.1.2: 388 | version "3.1.2" 389 | resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" 390 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 391 | 392 | call-bind@^1.0.6: 393 | version "1.0.6" 394 | resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz" 395 | integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== 396 | dependencies: 397 | es-errors "^1.3.0" 398 | function-bind "^1.1.2" 399 | get-intrinsic "^1.2.3" 400 | set-function-length "^1.2.0" 401 | 402 | callsites@^3.0.0: 403 | version "3.1.0" 404 | resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" 405 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 406 | 407 | chalk@^4.0.0: 408 | version "4.1.2" 409 | resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" 410 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 411 | dependencies: 412 | ansi-styles "^4.1.0" 413 | supports-color "^7.1.0" 414 | 415 | color-convert@^2.0.1: 416 | version "2.0.1" 417 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" 418 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 419 | dependencies: 420 | color-name "~1.1.4" 421 | 422 | color-name@~1.1.4: 423 | version "1.1.4" 424 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" 425 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 426 | 427 | colors@1.0.x: 428 | version "1.0.3" 429 | resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" 430 | integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== 431 | 432 | command-line-args@^5.1.1: 433 | version "5.2.1" 434 | resolved "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz" 435 | integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== 436 | dependencies: 437 | array-back "^3.1.0" 438 | find-replace "^3.0.0" 439 | lodash.camelcase "^4.3.0" 440 | typical "^4.0.0" 441 | 442 | component-bind@1.0.0: 443 | version "1.0.0" 444 | resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz" 445 | integrity sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw== 446 | 447 | component-emitter@~1.3.0: 448 | version "1.3.1" 449 | resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz" 450 | integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== 451 | 452 | component-emitter@1.2.1: 453 | version "1.2.1" 454 | resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz" 455 | integrity sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA== 456 | 457 | component-inherit@0.0.3: 458 | version "0.0.3" 459 | resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz" 460 | integrity sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA== 461 | 462 | concat-map@0.0.1: 463 | version "0.0.1" 464 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 465 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 466 | 467 | content-disposition@0.5.4: 468 | version "0.5.4" 469 | resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" 470 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 471 | dependencies: 472 | safe-buffer "5.2.1" 473 | 474 | content-type@~1.0.4, content-type@~1.0.5: 475 | version "1.0.5" 476 | resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" 477 | integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== 478 | 479 | cookie-signature@1.0.6: 480 | version "1.0.6" 481 | resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" 482 | integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== 483 | 484 | cookie@~0.4.1: 485 | version "0.4.2" 486 | resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" 487 | integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== 488 | 489 | cookie@0.5.0: 490 | version "0.5.0" 491 | resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" 492 | integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== 493 | 494 | core-util-is@~1.0.0: 495 | version "1.0.3" 496 | resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" 497 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 498 | 499 | cross-spawn@^7.0.2: 500 | version "7.0.3" 501 | resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" 502 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 503 | dependencies: 504 | path-key "^3.1.0" 505 | shebang-command "^2.0.0" 506 | which "^2.0.1" 507 | 508 | cuint@^0.2.1: 509 | version "0.2.2" 510 | resolved "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz" 511 | integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== 512 | 513 | cycle@1.0.x: 514 | version "1.0.3" 515 | resolved "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz" 516 | integrity sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA== 517 | 518 | debug@^4.3.1: 519 | version "4.3.4" 520 | resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" 521 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 522 | dependencies: 523 | ms "2.1.2" 524 | 525 | debug@^4.3.2: 526 | version "4.3.4" 527 | resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" 528 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 529 | dependencies: 530 | ms "2.1.2" 531 | 532 | debug@^4.3.3: 533 | version "4.3.7" 534 | resolved "https://mirrors.cloud.tencent.com/npm/debug/-/debug-4.3.7.tgz" 535 | integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== 536 | dependencies: 537 | ms "^2.1.3" 538 | 539 | debug@^4.3.4: 540 | version "4.3.7" 541 | resolved "https://mirrors.cloud.tencent.com/npm/debug/-/debug-4.3.7.tgz" 542 | integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== 543 | dependencies: 544 | ms "^2.1.3" 545 | 546 | debug@~3.1.0: 547 | version "3.1.0" 548 | resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz" 549 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 550 | dependencies: 551 | ms "2.0.0" 552 | 553 | debug@~4.1.0: 554 | version "4.1.1" 555 | resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz" 556 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== 557 | dependencies: 558 | ms "^2.1.1" 559 | 560 | debug@2.6.9: 561 | version "2.6.9" 562 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" 563 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 564 | dependencies: 565 | ms "2.0.0" 566 | 567 | debug@4: 568 | version "4.3.7" 569 | resolved "https://mirrors.cloud.tencent.com/npm/debug/-/debug-4.3.7.tgz" 570 | integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== 571 | dependencies: 572 | ms "^2.1.3" 573 | 574 | deep-is@^0.1.3: 575 | version "0.1.4" 576 | resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" 577 | integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 578 | 579 | define-data-property@^1.1.2: 580 | version "1.1.2" 581 | resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz" 582 | integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== 583 | dependencies: 584 | es-errors "^1.3.0" 585 | get-intrinsic "^1.2.2" 586 | gopd "^1.0.1" 587 | has-property-descriptors "^1.0.1" 588 | 589 | depd@2.0.0: 590 | version "2.0.0" 591 | resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" 592 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 593 | 594 | destroy@1.2.0: 595 | version "1.2.0" 596 | resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" 597 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 598 | 599 | doctrine@^3.0.0: 600 | version "3.0.0" 601 | resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" 602 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 603 | dependencies: 604 | esutils "^2.0.2" 605 | 606 | ee-first@1.1.1: 607 | version "1.1.1" 608 | resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" 609 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== 610 | 611 | encodeurl@~1.0.2: 612 | version "1.0.2" 613 | resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" 614 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== 615 | 616 | engine.io-client@~3.5.0: 617 | version "3.5.3" 618 | resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.3.tgz" 619 | integrity sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw== 620 | dependencies: 621 | component-emitter "~1.3.0" 622 | component-inherit "0.0.3" 623 | debug "~3.1.0" 624 | engine.io-parser "~2.2.0" 625 | has-cors "1.1.0" 626 | indexof "0.0.1" 627 | parseqs "0.0.6" 628 | parseuri "0.0.6" 629 | ws "~7.4.2" 630 | xmlhttprequest-ssl "~1.6.2" 631 | yeast "0.1.2" 632 | 633 | engine.io-parser@~2.2.0: 634 | version "2.2.1" 635 | resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz" 636 | integrity sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg== 637 | dependencies: 638 | after "0.8.2" 639 | arraybuffer.slice "~0.0.7" 640 | base64-arraybuffer "0.1.4" 641 | blob "0.0.5" 642 | has-binary2 "~1.0.2" 643 | 644 | engine.io@~3.6.0: 645 | version "3.6.1" 646 | resolved "https://registry.npmjs.org/engine.io/-/engine.io-3.6.1.tgz" 647 | integrity sha512-dfs8EVg/i7QjFsXxn7cCRQ+Wai1G1TlEvHhdYEi80fxn5R1vZ2K661O6v/rezj1FP234SZ14r9CmJke99iYDGg== 648 | dependencies: 649 | accepts "~1.3.4" 650 | base64id "2.0.0" 651 | cookie "~0.4.1" 652 | debug "~4.1.0" 653 | engine.io-parser "~2.2.0" 654 | ws "~7.4.2" 655 | 656 | es-errors@^1.3.0: 657 | version "1.3.0" 658 | resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" 659 | integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== 660 | 661 | es6-promise@3.2.1: 662 | version "3.2.1" 663 | resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz" 664 | integrity sha512-oj4jOSXvWglTsc3wrw86iom3LDPOx1nbipQk+jaG3dy+sMRM6ReSgVr/VlmBuF6lXUrflN9DCcQHeSbAwGUl4g== 665 | 666 | escape-html@~1.0.3: 667 | version "1.0.3" 668 | resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" 669 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== 670 | 671 | escape-string-regexp@^4.0.0: 672 | version "4.0.0" 673 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" 674 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 675 | 676 | eslint-config-google@^0.7.1: 677 | version "0.7.1" 678 | resolved "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.7.1.tgz" 679 | integrity sha512-ZdB0ZxvhhCJr5+mbd46bu47ILt2+MDNek1S+Rka0jmdsHm5EYRf0NELrgpMwR6aIcqohFfRGndZoo5WD3xM0+g== 680 | 681 | eslint-scope@^7.2.2: 682 | version "7.2.2" 683 | resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" 684 | integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== 685 | dependencies: 686 | esrecurse "^4.3.0" 687 | estraverse "^5.2.0" 688 | 689 | eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: 690 | version "3.4.3" 691 | resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" 692 | integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== 693 | 694 | "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8.56.0, eslint@>=3.8.1: 695 | version "8.56.0" 696 | resolved "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz" 697 | integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== 698 | dependencies: 699 | "@eslint-community/eslint-utils" "^4.2.0" 700 | "@eslint-community/regexpp" "^4.6.1" 701 | "@eslint/eslintrc" "^2.1.4" 702 | "@eslint/js" "8.56.0" 703 | "@humanwhocodes/config-array" "^0.11.13" 704 | "@humanwhocodes/module-importer" "^1.0.1" 705 | "@nodelib/fs.walk" "^1.2.8" 706 | "@ungap/structured-clone" "^1.2.0" 707 | ajv "^6.12.4" 708 | chalk "^4.0.0" 709 | cross-spawn "^7.0.2" 710 | debug "^4.3.2" 711 | doctrine "^3.0.0" 712 | escape-string-regexp "^4.0.0" 713 | eslint-scope "^7.2.2" 714 | eslint-visitor-keys "^3.4.3" 715 | espree "^9.6.1" 716 | esquery "^1.4.2" 717 | esutils "^2.0.2" 718 | fast-deep-equal "^3.1.3" 719 | file-entry-cache "^6.0.1" 720 | find-up "^5.0.0" 721 | glob-parent "^6.0.2" 722 | globals "^13.19.0" 723 | graphemer "^1.4.0" 724 | ignore "^5.2.0" 725 | imurmurhash "^0.1.4" 726 | is-glob "^4.0.0" 727 | is-path-inside "^3.0.3" 728 | js-yaml "^4.1.0" 729 | json-stable-stringify-without-jsonify "^1.0.1" 730 | levn "^0.4.1" 731 | lodash.merge "^4.6.2" 732 | minimatch "^3.1.2" 733 | natural-compare "^1.4.0" 734 | optionator "^0.9.3" 735 | strip-ansi "^6.0.1" 736 | text-table "^0.2.0" 737 | 738 | espree@^9.6.0, espree@^9.6.1: 739 | version "9.6.1" 740 | resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" 741 | integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== 742 | dependencies: 743 | acorn "^8.9.0" 744 | acorn-jsx "^5.3.2" 745 | eslint-visitor-keys "^3.4.1" 746 | 747 | esquery@^1.4.2: 748 | version "1.5.0" 749 | resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" 750 | integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== 751 | dependencies: 752 | estraverse "^5.1.0" 753 | 754 | esrecurse@^4.3.0: 755 | version "4.3.0" 756 | resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" 757 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 758 | dependencies: 759 | estraverse "^5.2.0" 760 | 761 | estraverse@^5.1.0, estraverse@^5.2.0: 762 | version "5.3.0" 763 | resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" 764 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 765 | 766 | esutils@^2.0.2: 767 | version "2.0.3" 768 | resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" 769 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 770 | 771 | etag@~1.8.1: 772 | version "1.8.1" 773 | resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" 774 | integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== 775 | 776 | express-rate-limit@^5.2.6: 777 | version "5.5.1" 778 | resolved "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz" 779 | integrity sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg== 780 | 781 | express@^4.17.1: 782 | version "4.18.2" 783 | resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz" 784 | integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== 785 | dependencies: 786 | accepts "~1.3.8" 787 | array-flatten "1.1.1" 788 | body-parser "1.20.1" 789 | content-disposition "0.5.4" 790 | content-type "~1.0.4" 791 | cookie "0.5.0" 792 | cookie-signature "1.0.6" 793 | debug "2.6.9" 794 | depd "2.0.0" 795 | encodeurl "~1.0.2" 796 | escape-html "~1.0.3" 797 | etag "~1.8.1" 798 | finalhandler "1.2.0" 799 | fresh "0.5.2" 800 | http-errors "2.0.0" 801 | merge-descriptors "1.0.1" 802 | methods "~1.1.2" 803 | on-finished "2.4.1" 804 | parseurl "~1.3.3" 805 | path-to-regexp "0.1.7" 806 | proxy-addr "~2.0.7" 807 | qs "6.11.0" 808 | range-parser "~1.2.1" 809 | safe-buffer "5.2.1" 810 | send "0.18.0" 811 | serve-static "1.15.0" 812 | setprototypeof "1.2.0" 813 | statuses "2.0.1" 814 | type-is "~1.6.18" 815 | utils-merge "1.0.1" 816 | vary "~1.1.2" 817 | 818 | eyes@0.1.x: 819 | version "0.1.8" 820 | resolved "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz" 821 | integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== 822 | 823 | fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: 824 | version "3.1.3" 825 | resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" 826 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 827 | 828 | fast-json-stable-stringify@^2.0.0: 829 | version "2.1.0" 830 | resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" 831 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 832 | 833 | fast-levenshtein@^2.0.6: 834 | version "2.0.6" 835 | resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" 836 | integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 837 | 838 | fastq@^1.6.0: 839 | version "1.17.1" 840 | resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz" 841 | integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== 842 | dependencies: 843 | reusify "^1.0.4" 844 | 845 | file-entry-cache@^6.0.1: 846 | version "6.0.1" 847 | resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" 848 | integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 849 | dependencies: 850 | flat-cache "^3.0.4" 851 | 852 | file-manager@^2.0.0: 853 | version "2.0.1" 854 | resolved "https://registry.npmjs.org/file-manager/-/file-manager-2.0.1.tgz" 855 | integrity sha512-y/K/1OCha04OXOxzo3cXJYtIzEk/CUMBb7Okipxueu0u+xCiuoocbwPyh1smUBasOobo4GAYmjgjD9Vh5zI51w== 856 | dependencies: 857 | "@doctormckay/stdlib" "^1.14.1" 858 | 859 | finalhandler@1.2.0: 860 | version "1.2.0" 861 | resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" 862 | integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== 863 | dependencies: 864 | debug "2.6.9" 865 | encodeurl "~1.0.2" 866 | escape-html "~1.0.3" 867 | on-finished "2.4.1" 868 | parseurl "~1.3.3" 869 | statuses "2.0.1" 870 | unpipe "~1.0.0" 871 | 872 | find-replace@^3.0.0: 873 | version "3.0.0" 874 | resolved "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz" 875 | integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== 876 | dependencies: 877 | array-back "^3.0.1" 878 | 879 | find-up@^5.0.0: 880 | version "5.0.0" 881 | resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" 882 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 883 | dependencies: 884 | locate-path "^6.0.0" 885 | path-exists "^4.0.0" 886 | 887 | flat-cache@^3.0.4: 888 | version "3.2.0" 889 | resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" 890 | integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== 891 | dependencies: 892 | flatted "^3.2.9" 893 | keyv "^4.5.3" 894 | rimraf "^3.0.2" 895 | 896 | flatted@^3.2.9: 897 | version "3.2.9" 898 | resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz" 899 | integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== 900 | 901 | forwarded@0.2.0: 902 | version "0.2.0" 903 | resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" 904 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 905 | 906 | fresh@0.5.2: 907 | version "0.5.2" 908 | resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" 909 | integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== 910 | 911 | fs.realpath@^1.0.0: 912 | version "1.0.0" 913 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" 914 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 915 | 916 | function-bind@^1.1.2: 917 | version "1.1.2" 918 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" 919 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 920 | 921 | get-intrinsic@^1.1.3, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: 922 | version "1.2.4" 923 | resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" 924 | integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== 925 | dependencies: 926 | es-errors "^1.3.0" 927 | function-bind "^1.1.2" 928 | has-proto "^1.0.1" 929 | has-symbols "^1.0.3" 930 | hasown "^2.0.0" 931 | 932 | glob-parent@^6.0.2: 933 | version "6.0.2" 934 | resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" 935 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 936 | dependencies: 937 | is-glob "^4.0.3" 938 | 939 | glob@^7.1.3: 940 | version "7.2.3" 941 | resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" 942 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 943 | dependencies: 944 | fs.realpath "^1.0.0" 945 | inflight "^1.0.4" 946 | inherits "2" 947 | minimatch "^3.1.1" 948 | once "^1.3.0" 949 | path-is-absolute "^1.0.0" 950 | 951 | globaloffensive-sharecode@^1.1.1: 952 | version "1.1.1" 953 | resolved "https://registry.npmjs.org/globaloffensive-sharecode/-/globaloffensive-sharecode-1.1.1.tgz" 954 | integrity sha512-L04gw1d1nNEJVLuXulo/+NeJUAFkvsO85vMiuHqArRNs8LvLKjC/6eLzxgMPl9v+0KMxjWp/6wITznWGZ0fRXQ== 955 | dependencies: 956 | big-number "^2.0.0" 957 | 958 | globaloffensive@^3.2.0: 959 | version "3.2.0" 960 | resolved "https://mirrors.cloud.tencent.com/npm/globaloffensive/-/globaloffensive-3.2.0.tgz" 961 | integrity sha512-4k1pCfWK7UYM18f3sYULTtT37owEPtDIHHLd6uBl4yTtHK+Px31+eiZ6Syt5/J6+/SF9gpMp7cIRrKhsjQkUZg== 962 | dependencies: 963 | bytebuffer "^5.0.1" 964 | globaloffensive-sharecode "^1.1.1" 965 | long "^5.2.3" 966 | protobufjs "^7.2.5" 967 | steamid "^2.0.0" 968 | 969 | globals@^13.19.0: 970 | version "13.24.0" 971 | resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" 972 | integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== 973 | dependencies: 974 | type-fest "^0.20.2" 975 | 976 | gopd@^1.0.1: 977 | version "1.0.1" 978 | resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" 979 | integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== 980 | dependencies: 981 | get-intrinsic "^1.1.3" 982 | 983 | graphemer@^1.4.0: 984 | version "1.4.0" 985 | resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" 986 | integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== 987 | 988 | has-binary2@~1.0.2: 989 | version "1.0.3" 990 | resolved "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz" 991 | integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== 992 | dependencies: 993 | isarray "2.0.1" 994 | 995 | has-cors@1.1.0: 996 | version "1.1.0" 997 | resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz" 998 | integrity sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA== 999 | 1000 | has-flag@^4.0.0: 1001 | version "4.0.0" 1002 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" 1003 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 1004 | 1005 | has-property-descriptors@^1.0.1: 1006 | version "1.0.1" 1007 | resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz" 1008 | integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== 1009 | dependencies: 1010 | get-intrinsic "^1.2.2" 1011 | 1012 | has-proto@^1.0.1: 1013 | version "1.0.1" 1014 | resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" 1015 | integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== 1016 | 1017 | has-symbols@^1.0.3: 1018 | version "1.0.3" 1019 | resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" 1020 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 1021 | 1022 | hasown@^2.0.0: 1023 | version "2.0.0" 1024 | resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" 1025 | integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== 1026 | dependencies: 1027 | function-bind "^1.1.2" 1028 | 1029 | http-errors@2.0.0: 1030 | version "2.0.0" 1031 | resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" 1032 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== 1033 | dependencies: 1034 | depd "2.0.0" 1035 | inherits "2.0.4" 1036 | setprototypeof "1.2.0" 1037 | statuses "2.0.1" 1038 | toidentifier "1.0.1" 1039 | 1040 | iconv-lite@0.4.24: 1041 | version "0.4.24" 1042 | resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" 1043 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 1044 | dependencies: 1045 | safer-buffer ">= 2.1.2 < 3" 1046 | 1047 | ignore@^5.2.0: 1048 | version "5.3.1" 1049 | resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" 1050 | integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== 1051 | 1052 | import-fresh@^3.2.1: 1053 | version "3.3.0" 1054 | resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" 1055 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 1056 | dependencies: 1057 | parent-module "^1.0.0" 1058 | resolve-from "^4.0.0" 1059 | 1060 | imurmurhash@^0.1.4: 1061 | version "0.1.4" 1062 | resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" 1063 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 1064 | 1065 | indexof@0.0.1: 1066 | version "0.0.1" 1067 | resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz" 1068 | integrity sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg== 1069 | 1070 | inflight@^1.0.4: 1071 | version "1.0.6" 1072 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" 1073 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 1074 | dependencies: 1075 | once "^1.3.0" 1076 | wrappy "1" 1077 | 1078 | inherits@~2.0.1, inherits@2, inherits@2.0.4: 1079 | version "2.0.4" 1080 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 1081 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1082 | 1083 | ip-address@^9.0.5: 1084 | version "9.0.5" 1085 | resolved "https://mirrors.cloud.tencent.com/npm/ip-address/-/ip-address-9.0.5.tgz" 1086 | integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== 1087 | dependencies: 1088 | jsbn "1.1.0" 1089 | sprintf-js "^1.1.3" 1090 | 1091 | ipaddr.js@1.9.1: 1092 | version "1.9.1" 1093 | resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" 1094 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 1095 | 1096 | is-extglob@^2.1.1: 1097 | version "2.1.1" 1098 | resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" 1099 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 1100 | 1101 | is-glob@^4.0.0, is-glob@^4.0.3: 1102 | version "4.0.3" 1103 | resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" 1104 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 1105 | dependencies: 1106 | is-extglob "^2.1.1" 1107 | 1108 | is-path-inside@^3.0.3: 1109 | version "3.0.3" 1110 | resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" 1111 | integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 1112 | 1113 | isarray@~1.0.0: 1114 | version "1.0.0" 1115 | resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" 1116 | integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== 1117 | 1118 | isarray@2.0.1: 1119 | version "2.0.1" 1120 | resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz" 1121 | integrity sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ== 1122 | 1123 | isexe@^2.0.0: 1124 | version "2.0.0" 1125 | resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" 1126 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 1127 | 1128 | isstream@0.1.x: 1129 | version "0.1.2" 1130 | resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" 1131 | integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== 1132 | 1133 | js-yaml@^4.1.0: 1134 | version "4.1.0" 1135 | resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" 1136 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 1137 | dependencies: 1138 | argparse "^2.0.1" 1139 | 1140 | jsbn@1.1.0: 1141 | version "1.1.0" 1142 | resolved "https://mirrors.cloud.tencent.com/npm/jsbn/-/jsbn-1.1.0.tgz" 1143 | integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== 1144 | 1145 | json-buffer@3.0.1: 1146 | version "3.0.1" 1147 | resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" 1148 | integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== 1149 | 1150 | json-schema-traverse@^0.4.1: 1151 | version "0.4.1" 1152 | resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" 1153 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 1154 | 1155 | json-stable-stringify-without-jsonify@^1.0.1: 1156 | version "1.0.1" 1157 | resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" 1158 | integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== 1159 | 1160 | keyv@^4.5.3: 1161 | version "4.5.4" 1162 | resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" 1163 | integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== 1164 | dependencies: 1165 | json-buffer "3.0.1" 1166 | 1167 | kvparser@^1.0.1: 1168 | version "1.0.2" 1169 | resolved "https://mirrors.cloud.tencent.com/npm/kvparser/-/kvparser-1.0.2.tgz" 1170 | integrity sha512-5P/5qpTAHjVYWqcI55B3yQwSY2FUrYYrJj5i65V1Wmg7/4W4OnBcaodaEvLyVuugeOnS+BAaKm9LbPazGJcRyA== 1171 | 1172 | levn@^0.4.1: 1173 | version "0.4.1" 1174 | resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" 1175 | integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== 1176 | dependencies: 1177 | prelude-ls "^1.2.1" 1178 | type-check "~0.4.0" 1179 | 1180 | locate-path@^6.0.0: 1181 | version "6.0.0" 1182 | resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" 1183 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 1184 | dependencies: 1185 | p-locate "^5.0.0" 1186 | 1187 | lodash.camelcase@^4.3.0: 1188 | version "4.3.0" 1189 | resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" 1190 | integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== 1191 | 1192 | lodash.merge@^4.6.2: 1193 | version "4.6.2" 1194 | resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" 1195 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 1196 | 1197 | lodash@^4.17.14: 1198 | version "4.17.21" 1199 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 1200 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 1201 | 1202 | long@^3.2.0, long@~3: 1203 | version "3.2.0" 1204 | resolved "https://registry.npmjs.org/long/-/long-3.2.0.tgz" 1205 | integrity sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg== 1206 | 1207 | long@^4.0.0: 1208 | version "4.0.0" 1209 | resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz" 1210 | integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== 1211 | 1212 | long@^5.0.0: 1213 | version "5.2.3" 1214 | resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" 1215 | integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== 1216 | 1217 | long@^5.2.3: 1218 | version "5.2.3" 1219 | resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" 1220 | integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== 1221 | 1222 | lzma@^2.3.2: 1223 | version "2.3.2" 1224 | resolved "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz" 1225 | integrity sha512-DcfiawQ1avYbW+hsILhF38IKAlnguc/fjHrychs9hdxe4qLykvhT5VTGNs5YRWgaNePh7NTxGD4uv4gKsRomCQ== 1226 | 1227 | media-typer@0.3.0: 1228 | version "0.3.0" 1229 | resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" 1230 | integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== 1231 | 1232 | merge-descriptors@1.0.1: 1233 | version "1.0.1" 1234 | resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" 1235 | integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== 1236 | 1237 | methods@~1.1.2: 1238 | version "1.1.2" 1239 | resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" 1240 | integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== 1241 | 1242 | mime-db@1.52.0: 1243 | version "1.52.0" 1244 | resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" 1245 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 1246 | 1247 | mime-types@~2.1.24, mime-types@~2.1.34: 1248 | version "2.1.35" 1249 | resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" 1250 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 1251 | dependencies: 1252 | mime-db "1.52.0" 1253 | 1254 | mime@1.6.0: 1255 | version "1.6.0" 1256 | resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" 1257 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 1258 | 1259 | minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: 1260 | version "3.1.2" 1261 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" 1262 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1263 | dependencies: 1264 | brace-expansion "^1.1.7" 1265 | 1266 | mongodb-core@2.1.20: 1267 | version "2.1.20" 1268 | resolved "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.20.tgz" 1269 | integrity sha512-IN57CX5/Q1bhDq6ShAR6gIv4koFsZP7L8WOK1S0lR0pVDQaScffSMV5jxubLsmZ7J+UdqmykKw4r9hG3XQEGgQ== 1270 | dependencies: 1271 | bson "~1.0.4" 1272 | require_optional "~1.0.0" 1273 | 1274 | mongodb@^2.2.36: 1275 | version "2.2.36" 1276 | resolved "https://registry.npmjs.org/mongodb/-/mongodb-2.2.36.tgz" 1277 | integrity sha512-P2SBLQ8Z0PVx71ngoXwo12+FiSfbNfGOClAao03/bant5DgLNkOPAck5IaJcEk4gKlQhDEURzfR3xuBG1/B+IA== 1278 | dependencies: 1279 | es6-promise "3.2.1" 1280 | mongodb-core "2.1.20" 1281 | readable-stream "2.2.7" 1282 | 1283 | ms@^2.1.1: 1284 | version "2.1.3" 1285 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" 1286 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1287 | 1288 | ms@^2.1.3: 1289 | version "2.1.3" 1290 | resolved "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.3.tgz" 1291 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1292 | 1293 | ms@2.0.0: 1294 | version "2.0.0" 1295 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 1296 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== 1297 | 1298 | ms@2.1.2: 1299 | version "2.1.2" 1300 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" 1301 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1302 | 1303 | ms@2.1.3: 1304 | version "2.1.3" 1305 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" 1306 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1307 | 1308 | natural-compare@^1.4.0: 1309 | version "1.4.0" 1310 | resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" 1311 | integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== 1312 | 1313 | negotiator@0.6.3: 1314 | version "0.6.3" 1315 | resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" 1316 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 1317 | 1318 | node-bignumber@^1.2.2: 1319 | version "1.2.2" 1320 | resolved "https://mirrors.cloud.tencent.com/npm/node-bignumber/-/node-bignumber-1.2.2.tgz" 1321 | integrity sha512-VoTZHmdFQpZH1+q1dz2qcHNCwTWsJg2T3PYwlAyDNFOfVhSYUKQBLFcCpCud+wJBGgCttGavZILaIggDIKqEQQ== 1322 | 1323 | object-inspect@^1.13.1: 1324 | version "1.13.1" 1325 | resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" 1326 | integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== 1327 | 1328 | on-finished@2.4.1: 1329 | version "2.4.1" 1330 | resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" 1331 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 1332 | dependencies: 1333 | ee-first "1.1.1" 1334 | 1335 | once@^1.3.0: 1336 | version "1.4.0" 1337 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" 1338 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 1339 | dependencies: 1340 | wrappy "1" 1341 | 1342 | optionator@^0.9.3: 1343 | version "0.9.3" 1344 | resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" 1345 | integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== 1346 | dependencies: 1347 | "@aashutoshrathi/word-wrap" "^1.2.3" 1348 | deep-is "^0.1.3" 1349 | fast-levenshtein "^2.0.6" 1350 | levn "^0.4.1" 1351 | prelude-ls "^1.2.1" 1352 | type-check "^0.4.0" 1353 | 1354 | p-limit@^3.0.2: 1355 | version "3.1.0" 1356 | resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" 1357 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 1358 | dependencies: 1359 | yocto-queue "^0.1.0" 1360 | 1361 | p-locate@^5.0.0: 1362 | version "5.0.0" 1363 | resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" 1364 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 1365 | dependencies: 1366 | p-limit "^3.0.2" 1367 | 1368 | packet-reader@1.0.0: 1369 | version "1.0.0" 1370 | resolved "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz" 1371 | integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== 1372 | 1373 | parent-module@^1.0.0: 1374 | version "1.0.1" 1375 | resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" 1376 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1377 | dependencies: 1378 | callsites "^3.0.0" 1379 | 1380 | parseqs@0.0.6: 1381 | version "0.0.6" 1382 | resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz" 1383 | integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w== 1384 | 1385 | parseuri@0.0.6: 1386 | version "0.0.6" 1387 | resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz" 1388 | integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow== 1389 | 1390 | parseurl@~1.3.3: 1391 | version "1.3.3" 1392 | resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" 1393 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 1394 | 1395 | path-exists@^4.0.0: 1396 | version "4.0.0" 1397 | resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" 1398 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 1399 | 1400 | path-is-absolute@^1.0.0: 1401 | version "1.0.1" 1402 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" 1403 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 1404 | 1405 | path-key@^3.1.0: 1406 | version "3.1.1" 1407 | resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" 1408 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 1409 | 1410 | path-to-regexp@0.1.7: 1411 | version "0.1.7" 1412 | resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" 1413 | integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== 1414 | 1415 | permessage-deflate@^0.1.7: 1416 | version "0.1.7" 1417 | resolved "https://mirrors.cloud.tencent.com/npm/permessage-deflate/-/permessage-deflate-0.1.7.tgz" 1418 | integrity sha512-EUNi/RIsyJ1P1u9QHFwMOUWMYetqlE22ZgGbad7YP856WF4BFF0B7DuNy6vEGsgNNud6c/SkdWzkne71hH8MjA== 1419 | dependencies: 1420 | safe-buffer "*" 1421 | 1422 | pg-cloudflare@^1.1.1: 1423 | version "1.1.1" 1424 | resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz" 1425 | integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== 1426 | 1427 | pg-connection-string@^2.6.2: 1428 | version "2.6.2" 1429 | resolved "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz" 1430 | integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA== 1431 | 1432 | pg-int8@1.0.1: 1433 | version "1.0.1" 1434 | resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" 1435 | integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== 1436 | 1437 | pg-pool@^3.6.1: 1438 | version "3.6.1" 1439 | resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz" 1440 | integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og== 1441 | 1442 | pg-protocol@^1.6.0: 1443 | version "1.6.0" 1444 | resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz" 1445 | integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q== 1446 | 1447 | pg-types@^2.1.0: 1448 | version "2.2.0" 1449 | resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" 1450 | integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== 1451 | dependencies: 1452 | pg-int8 "1.0.1" 1453 | postgres-array "~2.0.0" 1454 | postgres-bytea "~1.0.0" 1455 | postgres-date "~1.0.4" 1456 | postgres-interval "^1.1.0" 1457 | 1458 | pg@^8.10.0, pg@>=8.0: 1459 | version "8.11.3" 1460 | resolved "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz" 1461 | integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g== 1462 | dependencies: 1463 | buffer-writer "2.0.0" 1464 | packet-reader "1.0.0" 1465 | pg-connection-string "^2.6.2" 1466 | pg-pool "^3.6.1" 1467 | pg-protocol "^1.6.0" 1468 | pg-types "^2.1.0" 1469 | pgpass "1.x" 1470 | optionalDependencies: 1471 | pg-cloudflare "^1.1.1" 1472 | 1473 | pgpass@1.x: 1474 | version "1.0.5" 1475 | resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" 1476 | integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== 1477 | dependencies: 1478 | split2 "^4.1.0" 1479 | 1480 | postgres-array@~2.0.0: 1481 | version "2.0.0" 1482 | resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz" 1483 | integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== 1484 | 1485 | postgres-bytea@~1.0.0: 1486 | version "1.0.0" 1487 | resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz" 1488 | integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== 1489 | 1490 | postgres-date@~1.0.4: 1491 | version "1.0.7" 1492 | resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz" 1493 | integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== 1494 | 1495 | postgres-interval@^1.1.0: 1496 | version "1.2.0" 1497 | resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz" 1498 | integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== 1499 | dependencies: 1500 | xtend "^4.0.0" 1501 | 1502 | prelude-ls@^1.2.1: 1503 | version "1.2.1" 1504 | resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" 1505 | integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 1506 | 1507 | process-nextick-args@~1.0.6: 1508 | version "1.0.7" 1509 | resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" 1510 | integrity sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw== 1511 | 1512 | protobufjs@^6.8.8: 1513 | version "6.11.4" 1514 | resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" 1515 | integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== 1516 | dependencies: 1517 | "@protobufjs/aspromise" "^1.1.2" 1518 | "@protobufjs/base64" "^1.1.2" 1519 | "@protobufjs/codegen" "^2.0.4" 1520 | "@protobufjs/eventemitter" "^1.1.0" 1521 | "@protobufjs/fetch" "^1.1.0" 1522 | "@protobufjs/float" "^1.0.2" 1523 | "@protobufjs/inquire" "^1.1.0" 1524 | "@protobufjs/path" "^1.1.2" 1525 | "@protobufjs/pool" "^1.1.0" 1526 | "@protobufjs/utf8" "^1.1.0" 1527 | "@types/long" "^4.0.1" 1528 | "@types/node" ">=13.7.0" 1529 | long "^4.0.0" 1530 | 1531 | protobufjs@^7.1.0, protobufjs@^7.2.4, protobufjs@^7.2.5: 1532 | version "7.2.6" 1533 | resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz" 1534 | integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== 1535 | dependencies: 1536 | "@protobufjs/aspromise" "^1.1.2" 1537 | "@protobufjs/base64" "^1.1.2" 1538 | "@protobufjs/codegen" "^2.0.4" 1539 | "@protobufjs/eventemitter" "^1.1.0" 1540 | "@protobufjs/fetch" "^1.1.0" 1541 | "@protobufjs/float" "^1.0.2" 1542 | "@protobufjs/inquire" "^1.1.0" 1543 | "@protobufjs/path" "^1.1.2" 1544 | "@protobufjs/pool" "^1.1.0" 1545 | "@protobufjs/utf8" "^1.1.0" 1546 | "@types/node" ">=13.7.0" 1547 | long "^5.0.0" 1548 | 1549 | proxy-addr@~2.0.7: 1550 | version "2.0.7" 1551 | resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" 1552 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 1553 | dependencies: 1554 | forwarded "0.2.0" 1555 | ipaddr.js "1.9.1" 1556 | 1557 | psl@^1.9.0: 1558 | version "1.9.0" 1559 | resolved "https://mirrors.cloud.tencent.com/npm/psl/-/psl-1.9.0.tgz" 1560 | integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== 1561 | 1562 | punycode@^2.1.0: 1563 | version "2.3.1" 1564 | resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" 1565 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== 1566 | 1567 | qs@6.11.0: 1568 | version "6.11.0" 1569 | resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" 1570 | integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== 1571 | dependencies: 1572 | side-channel "^1.0.4" 1573 | 1574 | queue-microtask@^1.2.2: 1575 | version "1.2.3" 1576 | resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" 1577 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 1578 | 1579 | range-parser@~1.2.1: 1580 | version "1.2.1" 1581 | resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" 1582 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1583 | 1584 | raw-body@2.5.1: 1585 | version "2.5.1" 1586 | resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz" 1587 | integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== 1588 | dependencies: 1589 | bytes "3.1.2" 1590 | http-errors "2.0.0" 1591 | iconv-lite "0.4.24" 1592 | unpipe "1.0.0" 1593 | 1594 | raw-body@2.5.2: 1595 | version "2.5.2" 1596 | resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" 1597 | integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== 1598 | dependencies: 1599 | bytes "3.1.2" 1600 | http-errors "2.0.0" 1601 | iconv-lite "0.4.24" 1602 | unpipe "1.0.0" 1603 | 1604 | readable-stream@2.2.7: 1605 | version "2.2.7" 1606 | resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz" 1607 | integrity sha512-a6ibcfWFhgihuTw/chl+u3fB5ykBZFmnvpyZHebY0MCQE4vvYcsCLpCeaQ1BkH7HdJYavNSqF0WDLeo4IPHQaQ== 1608 | dependencies: 1609 | buffer-shims "~1.0.0" 1610 | core-util-is "~1.0.0" 1611 | inherits "~2.0.1" 1612 | isarray "~1.0.0" 1613 | process-nextick-args "~1.0.6" 1614 | string_decoder "~1.0.0" 1615 | util-deprecate "~1.0.1" 1616 | 1617 | require_optional@~1.0.0: 1618 | version "1.0.1" 1619 | resolved "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz" 1620 | integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== 1621 | dependencies: 1622 | resolve-from "^2.0.0" 1623 | semver "^5.1.0" 1624 | 1625 | resolve-from@^2.0.0: 1626 | version "2.0.0" 1627 | resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz" 1628 | integrity sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ== 1629 | 1630 | resolve-from@^4.0.0: 1631 | version "4.0.0" 1632 | resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" 1633 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1634 | 1635 | reusify@^1.0.4: 1636 | version "1.0.4" 1637 | resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" 1638 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 1639 | 1640 | rimraf@^3.0.2: 1641 | version "3.0.2" 1642 | resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" 1643 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1644 | dependencies: 1645 | glob "^7.1.3" 1646 | 1647 | run-parallel@^1.1.9: 1648 | version "1.2.0" 1649 | resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" 1650 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 1651 | dependencies: 1652 | queue-microtask "^1.2.2" 1653 | 1654 | safe-buffer@*, safe-buffer@5.2.1: 1655 | version "5.2.1" 1656 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" 1657 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1658 | 1659 | safe-buffer@~5.1.0: 1660 | version "5.1.2" 1661 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" 1662 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1663 | 1664 | "safer-buffer@>= 2.1.2 < 3": 1665 | version "2.1.2" 1666 | resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" 1667 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1668 | 1669 | semver@^5.1.0: 1670 | version "5.7.2" 1671 | resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" 1672 | integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== 1673 | 1674 | send@0.18.0: 1675 | version "0.18.0" 1676 | resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" 1677 | integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== 1678 | dependencies: 1679 | debug "2.6.9" 1680 | depd "2.0.0" 1681 | destroy "1.2.0" 1682 | encodeurl "~1.0.2" 1683 | escape-html "~1.0.3" 1684 | etag "~1.8.1" 1685 | fresh "0.5.2" 1686 | http-errors "2.0.0" 1687 | mime "1.6.0" 1688 | ms "2.1.3" 1689 | on-finished "2.4.1" 1690 | range-parser "~1.2.1" 1691 | statuses "2.0.1" 1692 | 1693 | serve-static@1.15.0: 1694 | version "1.15.0" 1695 | resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" 1696 | integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== 1697 | dependencies: 1698 | encodeurl "~1.0.2" 1699 | escape-html "~1.0.3" 1700 | parseurl "~1.3.3" 1701 | send "0.18.0" 1702 | 1703 | set-function-length@^1.2.0: 1704 | version "1.2.1" 1705 | resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz" 1706 | integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== 1707 | dependencies: 1708 | define-data-property "^1.1.2" 1709 | es-errors "^1.3.0" 1710 | function-bind "^1.1.2" 1711 | get-intrinsic "^1.2.3" 1712 | gopd "^1.0.1" 1713 | has-property-descriptors "^1.0.1" 1714 | 1715 | setprototypeof@1.2.0: 1716 | version "1.2.0" 1717 | resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" 1718 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 1719 | 1720 | shebang-command@^2.0.0: 1721 | version "2.0.0" 1722 | resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" 1723 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 1724 | dependencies: 1725 | shebang-regex "^3.0.0" 1726 | 1727 | shebang-regex@^3.0.0: 1728 | version "3.0.0" 1729 | resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" 1730 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 1731 | 1732 | side-channel@^1.0.4: 1733 | version "1.0.5" 1734 | resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz" 1735 | integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== 1736 | dependencies: 1737 | call-bind "^1.0.6" 1738 | es-errors "^1.3.0" 1739 | get-intrinsic "^1.2.4" 1740 | object-inspect "^1.13.1" 1741 | 1742 | simple-vdf@^1.1.1: 1743 | version "1.1.1" 1744 | resolved "https://registry.npmjs.org/simple-vdf/-/simple-vdf-1.1.1.tgz" 1745 | integrity sha512-IHz5fiOyWX0etTzlrzpWfKWxkwOhSwbbuZxcig+JuON0id1clnYlINBRbe4M4Pz4VnNvNvNaZiKiS7tdIYyF6g== 1746 | 1747 | smart-buffer@^4.2.0: 1748 | version "4.2.0" 1749 | resolved "https://mirrors.cloud.tencent.com/npm/smart-buffer/-/smart-buffer-4.2.0.tgz" 1750 | integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== 1751 | 1752 | socket.io-adapter@~1.1.0: 1753 | version "1.1.2" 1754 | resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz" 1755 | integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== 1756 | 1757 | socket.io-client@2.5.0: 1758 | version "2.5.0" 1759 | resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz" 1760 | integrity sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw== 1761 | dependencies: 1762 | backo2 "1.0.2" 1763 | component-bind "1.0.0" 1764 | component-emitter "~1.3.0" 1765 | debug "~3.1.0" 1766 | engine.io-client "~3.5.0" 1767 | has-binary2 "~1.0.2" 1768 | indexof "0.0.1" 1769 | parseqs "0.0.6" 1770 | parseuri "0.0.6" 1771 | socket.io-parser "~3.3.0" 1772 | to-array "0.1.4" 1773 | 1774 | socket.io-parser@~3.3.0: 1775 | version "3.3.3" 1776 | resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz" 1777 | integrity sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg== 1778 | dependencies: 1779 | component-emitter "~1.3.0" 1780 | debug "~3.1.0" 1781 | isarray "2.0.1" 1782 | 1783 | socket.io-parser@~3.4.0: 1784 | version "3.4.3" 1785 | resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.3.tgz" 1786 | integrity sha512-1rE4dZN3kCI/E5wixd393hmbqa78vVpkKmnEJhLeWoS/C5hbFYAbcSfnWoaVH43u9ToUVtzKjguxEZq+1XZfCQ== 1787 | dependencies: 1788 | component-emitter "1.2.1" 1789 | debug "~4.1.0" 1790 | isarray "2.0.1" 1791 | 1792 | socket.io@^2.4.0: 1793 | version "2.5.0" 1794 | resolved "https://registry.npmjs.org/socket.io/-/socket.io-2.5.0.tgz" 1795 | integrity sha512-gGunfS0od3VpwDBpGwVkzSZx6Aqo9uOcf1afJj2cKnKFAoyl16fvhpsUhmUFd4Ldbvl5JvRQed6eQw6oQp6n8w== 1796 | dependencies: 1797 | debug "~4.1.0" 1798 | engine.io "~3.6.0" 1799 | has-binary2 "~1.0.2" 1800 | socket.io-adapter "~1.1.0" 1801 | socket.io-client "2.5.0" 1802 | socket.io-parser "~3.4.0" 1803 | 1804 | socks-proxy-agent@^7.0.0: 1805 | version "7.0.0" 1806 | resolved "https://mirrors.cloud.tencent.com/npm/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz" 1807 | integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== 1808 | dependencies: 1809 | agent-base "^6.0.2" 1810 | debug "^4.3.3" 1811 | socks "^2.6.2" 1812 | 1813 | socks@^2.6.2: 1814 | version "2.8.3" 1815 | resolved "https://mirrors.cloud.tencent.com/npm/socks/-/socks-2.8.3.tgz" 1816 | integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== 1817 | dependencies: 1818 | ip-address "^9.0.5" 1819 | smart-buffer "^4.2.0" 1820 | 1821 | split2@^4.1.0: 1822 | version "4.2.0" 1823 | resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" 1824 | integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== 1825 | 1826 | sprintf-js@^1.1.3: 1827 | version "1.1.3" 1828 | resolved "https://mirrors.cloud.tencent.com/npm/sprintf-js/-/sprintf-js-1.1.3.tgz" 1829 | integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== 1830 | 1831 | stack-trace@0.0.x: 1832 | version "0.0.10" 1833 | resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" 1834 | integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== 1835 | 1836 | statuses@2.0.1: 1837 | version "2.0.1" 1838 | resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" 1839 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 1840 | 1841 | steam-appticket@^1.0.1: 1842 | version "1.0.1" 1843 | resolved "https://registry.npmjs.org/steam-appticket/-/steam-appticket-1.0.1.tgz" 1844 | integrity sha512-oYVInCvJlPPaQPYW1+iGcVP0N0ZvwtWiCDM1Z353XJ8l4DXQI/N+R5yyaRQcHRH5oQv3+BY6gPF40lu7gwEiJw== 1845 | dependencies: 1846 | "@doctormckay/stdlib" "^1.6.0" 1847 | "@doctormckay/steam-crypto" "^1.2.0" 1848 | bytebuffer "^5.0.1" 1849 | protobufjs "^6.8.8" 1850 | steamid "^1.1.0" 1851 | 1852 | steam-session@^1.8.0: 1853 | version "1.9.0" 1854 | resolved "https://mirrors.cloud.tencent.com/npm/steam-session/-/steam-session-1.9.0.tgz" 1855 | integrity sha512-CsCxy2ln70/LrRcho8nbixTLT2RMswqt/kzUualZYeT7DkTUF7nni8G/f1tBdT6ce2lKzl4Hq5xJlQ8C6rxg9A== 1856 | dependencies: 1857 | "@doctormckay/stdlib" "^2.9.0" 1858 | "@doctormckay/user-agents" "^1.0.0" 1859 | debug "^4.3.4" 1860 | kvparser "^1.0.1" 1861 | node-bignumber "^1.2.2" 1862 | protobufjs "^7.1.0" 1863 | socks-proxy-agent "^7.0.0" 1864 | steamid "^2.0.0" 1865 | tiny-typed-emitter "^2.1.0" 1866 | websocket13 "^4.0.0" 1867 | 1868 | steam-totp@^2.0.1, steam-totp@^2.1.2: 1869 | version "2.1.2" 1870 | resolved "https://registry.npmjs.org/steam-totp/-/steam-totp-2.1.2.tgz" 1871 | integrity sha512-bTKlc/NoIUQId+my+O556s55DDsNNXfVIPWFDNVu68beql7AJhV0c+GTjFxfwCDYfdc4NkAme+0WrDdnY2D2VA== 1872 | 1873 | steam-user@^5.2.0, steam-user@>=4.2.0: 1874 | version "5.2.0" 1875 | resolved "https://mirrors.cloud.tencent.com/npm/steam-user/-/steam-user-5.2.0.tgz" 1876 | integrity sha512-GzDou8anDZOw0VgkTj6TybnEKjqSktdizz756UtjDBgh1ONnvI8HCw/FXKmpKmFnyf8iTshHcw16ATLC3WLP/Q== 1877 | dependencies: 1878 | "@bbob/parser" "^2.2.0" 1879 | "@doctormckay/stdlib" "^2.9.1" 1880 | "@doctormckay/steam-crypto" "^1.2.0" 1881 | adm-zip "^0.5.10" 1882 | binarykvparser "^2.2.0" 1883 | bytebuffer "^5.0.0" 1884 | file-manager "^2.0.0" 1885 | kvparser "^1.0.1" 1886 | lzma "^2.3.2" 1887 | protobufjs "^7.2.4" 1888 | socks-proxy-agent "^7.0.0" 1889 | steam-appticket "^1.0.1" 1890 | steam-session "^1.8.0" 1891 | steam-totp "^2.0.1" 1892 | steamid "^2.0.0" 1893 | websocket13 "^4.0.0" 1894 | 1895 | steamid@^1.1.0: 1896 | version "1.1.3" 1897 | resolved "https://registry.npmjs.org/steamid/-/steamid-1.1.3.tgz" 1898 | integrity sha512-t86YjtP1LtPt8D+TaIARm6PtC9tBnF1FhxQeLFs6ohG7vDUfQuy/M8II14rx1TTUkVuYoWHP/7DlvTtoCGULcw== 1899 | dependencies: 1900 | cuint "^0.2.1" 1901 | 1902 | steamid@^2.0.0: 1903 | version "2.0.0" 1904 | resolved "https://registry.npmjs.org/steamid/-/steamid-2.0.0.tgz" 1905 | integrity sha512-+BFJMbo+IxzyfovLR37E7APkaNfmrL3S+88T7wTMRHnQ6LBhzEawPnjfWNKM9eUL/dH45j+7vhSX4WaGXoa4/Q== 1906 | 1907 | string_decoder@~1.0.0: 1908 | version "1.0.3" 1909 | resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz" 1910 | integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ== 1911 | dependencies: 1912 | safe-buffer "~5.1.0" 1913 | 1914 | strip-ansi@^6.0.1: 1915 | version "6.0.1" 1916 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" 1917 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1918 | dependencies: 1919 | ansi-regex "^5.0.1" 1920 | 1921 | strip-json-comments@^3.1.1: 1922 | version "3.1.1" 1923 | resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" 1924 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 1925 | 1926 | supports-color@^7.1.0: 1927 | version "7.2.0" 1928 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" 1929 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1930 | dependencies: 1931 | has-flag "^4.0.0" 1932 | 1933 | text-table@^0.2.0: 1934 | version "0.2.0" 1935 | resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" 1936 | integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 1937 | 1938 | tiny-typed-emitter@^2.1.0: 1939 | version "2.1.0" 1940 | resolved "https://mirrors.cloud.tencent.com/npm/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz" 1941 | integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== 1942 | 1943 | to-array@0.1.4: 1944 | version "0.1.4" 1945 | resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz" 1946 | integrity sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A== 1947 | 1948 | toidentifier@1.0.1: 1949 | version "1.0.1" 1950 | resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" 1951 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 1952 | 1953 | type-check@^0.4.0, type-check@~0.4.0: 1954 | version "0.4.0" 1955 | resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" 1956 | integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== 1957 | dependencies: 1958 | prelude-ls "^1.2.1" 1959 | 1960 | type-fest@^0.20.2: 1961 | version "0.20.2" 1962 | resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" 1963 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 1964 | 1965 | type-is@~1.6.18: 1966 | version "1.6.18" 1967 | resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" 1968 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1969 | dependencies: 1970 | media-typer "0.3.0" 1971 | mime-types "~2.1.24" 1972 | 1973 | typical@^4.0.0: 1974 | version "4.0.0" 1975 | resolved "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz" 1976 | integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== 1977 | 1978 | undici-types@~5.26.4: 1979 | version "5.26.5" 1980 | resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" 1981 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== 1982 | 1983 | unpipe@~1.0.0, unpipe@1.0.0: 1984 | version "1.0.0" 1985 | resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" 1986 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== 1987 | 1988 | uri-js@^4.2.2: 1989 | version "4.4.1" 1990 | resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" 1991 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 1992 | dependencies: 1993 | punycode "^2.1.0" 1994 | 1995 | util-deprecate@~1.0.1: 1996 | version "1.0.2" 1997 | resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" 1998 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 1999 | 2000 | utils-merge@1.0.1: 2001 | version "1.0.1" 2002 | resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" 2003 | integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== 2004 | 2005 | vary@~1.1.2: 2006 | version "1.1.2" 2007 | resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" 2008 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== 2009 | 2010 | websocket-extensions@^0.1.4: 2011 | version "0.1.4" 2012 | resolved "https://mirrors.cloud.tencent.com/npm/websocket-extensions/-/websocket-extensions-0.1.4.tgz" 2013 | integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== 2014 | 2015 | websocket13@^4.0.0: 2016 | version "4.0.0" 2017 | resolved "https://mirrors.cloud.tencent.com/npm/websocket13/-/websocket13-4.0.0.tgz" 2018 | integrity sha512-/ujP9ZfihyAZIXKGxcYpoe7Gj4r5o3WYSfP93o9lVNhhqoBtYba4m1s3mxdjKZu/HOhX5Mcqrt89dv/gC3b06A== 2019 | dependencies: 2020 | "@doctormckay/stdlib" "^2.7.1" 2021 | bytebuffer "^5.0.1" 2022 | permessage-deflate "^0.1.7" 2023 | tiny-typed-emitter "^2.1.0" 2024 | websocket-extensions "^0.1.4" 2025 | 2026 | which@^2.0.1: 2027 | version "2.0.2" 2028 | resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" 2029 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 2030 | dependencies: 2031 | isexe "^2.0.0" 2032 | 2033 | winston@^2.4.5: 2034 | version "2.4.7" 2035 | resolved "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz" 2036 | integrity sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg== 2037 | dependencies: 2038 | async "^2.6.4" 2039 | colors "1.0.x" 2040 | cycle "1.0.x" 2041 | eyes "0.1.x" 2042 | isstream "0.1.x" 2043 | stack-trace "0.0.x" 2044 | 2045 | wrappy@1: 2046 | version "1.0.2" 2047 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 2048 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 2049 | 2050 | ws@~7.4.2: 2051 | version "7.4.6" 2052 | resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" 2053 | integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== 2054 | 2055 | xmlhttprequest-ssl@~1.6.2: 2056 | version "1.6.3" 2057 | resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz" 2058 | integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q== 2059 | 2060 | xtend@^4.0.0: 2061 | version "4.0.2" 2062 | resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" 2063 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 2064 | 2065 | yeast@0.1.2: 2066 | version "0.1.2" 2067 | resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz" 2068 | integrity sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg== 2069 | 2070 | yocto-queue@^0.1.0: 2071 | version "0.1.0" 2072 | resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" 2073 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 2074 | --------------------------------------------------------------------------------