├── .dockerignore ├── .eslintrc.json ├── .gitignore ├── .gitlab-ci.yml ├── .gitpod.yml ├── .vscode └── launch.json ├── CODEOWNERS ├── Dockerfile ├── README.md ├── nodemon.json ├── package-lock.json ├── package.json ├── src ├── com │ ├── config.ts │ ├── database.ts │ ├── db │ │ ├── associations.ts │ │ ├── migrate.ts │ │ ├── migrations │ │ │ ├── version0.ts │ │ │ ├── version1.ts │ │ │ ├── version2.ts │ │ │ └── version3.ts │ │ └── models │ │ │ ├── migration.ts │ │ │ ├── user.ts │ │ │ └── userplayback.ts │ ├── log.ts │ └── rabbitmq.ts ├── controller.ts ├── index.ts ├── lib │ ├── lib.ts │ ├── message.ts │ ├── plex │ │ ├── component.ts │ │ ├── endpoints.ts │ │ ├── index.ts │ │ ├── library.ts │ │ ├── playback.ts │ │ ├── user.ts │ │ └── ws.ts │ └── ws.ts └── sideCar.ts ├── tests ├── copyDatabase.ts └── migration.ts ├── tsconfig.json └── tsconfig.testing.json /.dockerignore: -------------------------------------------------------------------------------- 1 | # other 2 | .dockerignore 3 | .eslintrc.json 4 | .eslintignore 5 | Dockerfile 6 | README.md 7 | 8 | # git and os 9 | .DS_Store 10 | .git 11 | .gitignore 12 | .github 13 | 14 | # javascript files 15 | dist 16 | node_modules 17 | test 18 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint" 6 | ], 7 | "extends": [ 8 | "airbnb-typescript" 9 | ], 10 | "parserOptions": { 11 | "project": "./tsconfig.testing.json" 12 | }, 13 | "rules": { 14 | "no-restricted-syntax": [ 15 | 2, 16 | "BinaryExpression[operator='in']" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | node_modules 3 | .vscode 4 | .DS_Store 5 | .nyc_output 6 | dist 7 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - test 3 | - deploy 4 | - trigger 5 | 6 | image: node:lts-alpine 7 | cache: 8 | key: ${CI_COMMIT_REF_SLUG} 9 | before_script: 10 | - npm install 11 | 12 | test: 13 | image: postgres:12 14 | variables: 15 | RABBITMQ_DEFAULT_USER: guest 16 | RABBITMQ_DEFAULT_PASS: guest 17 | RABBITMQ_URL: amqp://guest:guest@127.0.0.1:5672 18 | DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/postgres 19 | POSTGRES_DB: postgres 20 | POSTGRES_USER: postgres 21 | POSTGRES_PASSWORD: postgres 22 | NODE_ENV: development 23 | services: 24 | - rabbitmq 25 | - postgres 26 | stage: test 27 | before_script: 28 | - apt-get update 29 | - apt-get install -y curl 30 | - curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - 31 | - apt-get install -y nodejs gcc g++ make 32 | - npm install 33 | script: 34 | - npm test 35 | 36 | lint: 37 | stage: test 38 | script: 39 | - npx eslint src 40 | 41 | audit: 42 | stage: test 43 | script: 44 | - npm audit 45 | allow_failure: true 46 | 47 | deploy image: 48 | stage: deploy 49 | image: registry.yusufali.ca/containers/kaniko 50 | variables: 51 | GIT_SUBMODULE_STRATEGY: recursive 52 | before_script: 53 | - echo "Building $WRITE_REGISTRY_URL/$CI_PROJECT_PATH" 54 | script: 55 | - export IMAGE="$WRITE_REGISTRY_URL/$CI_PROJECT_PATH" 56 | - build 57 | 58 | deploy cluster: 59 | stage: trigger 60 | image: curlimages/curl 61 | only: 62 | - master 63 | before_script: 64 | - echo "About to deploy to cluster" 65 | script: 66 | - "curl -X POST -F token=$TOKEN -F ref=master https://$CI_SERVER_HOST/api/v4/projects/25/trigger/pipeline" 67 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: registry.yusufali.ca/gitpod/nodepostgres 2 | 3 | tasks: 4 | - name: restore database 5 | before: setup_environment 6 | init: | 7 | source ~/.profile 8 | pg_start 9 | PGHOSTADDR=$MAIN_DB_HOST PGPASSWORD=$MAIN_DB_PASSWORD pg_dump --no-acl --no-owner --clean --host=$MAIN_DB_HOST --username=$MAIN_DB_USERNAME --port=$MAIN_DB_PORT $MAIN_DB_DATABASE | psql -U gitpod --dbname postgres 10 | command: | 11 | source ~/.profile 12 | pg_start || true 13 | - name: npm modules 14 | init: | 15 | npm install 16 | git remote add template https://gitlab.yusufali.ca/elrond/templates/template.git 17 | git fetch origin 18 | command: source ~/.profile 19 | openMode: split-right 20 | 21 | vscode: 22 | extensions: 23 | - dbaeumer.vscode-eslint 24 | 25 | ports: 26 | - port: 5432 27 | onOpen: ignore 28 | visibility: private 29 | - port: 3000 30 | onOpen: ignore 31 | visibility: public 32 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/src/index.ts", 12 | "preLaunchTask": "npm: debug", 13 | "outFiles": [ 14 | "${workspaceFolder}/dist/**/*.js" 15 | ], 16 | "skipFiles": [ 17 | "/**" 18 | ], 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | .gitlab-ci.yml @drgroot 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine AS builder 2 | 3 | COPY src /src 4 | COPY tsconfig.json / 5 | COPY package.json / 6 | COPY package-lock.json / 7 | 8 | # Install build tool chain 9 | RUN apk add --no-cache --virtual python make g++ 10 | RUN npm install 11 | 12 | # run build script 13 | RUN npm run-script build \ 14 | && npm ci --production \ 15 | && npm cache clean --force 16 | 17 | FROM node:lts-alpine AS app 18 | 19 | WORKDIR /app 20 | 21 | COPY --from=builder /node_modules node_modules 22 | COPY --from=builder /dist dist 23 | COPY package.json . 24 | COPY package-lock.json . 25 | 26 | ENV NODE_ENV production 27 | USER node 28 | CMD ["node","dist/index.js"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PlexController 2 | 3 | [![GitHub stars](https://img.shields.io/github/stars/drgroot/plexcontroller)](https://github.com/drgroot/plexcontroller/stargazers) 4 | 5 | **Description** 6 | 7 | PlexController syncs playback status between servers using Postgres and RabbitMQ. When a user starts playing media on one server, the information is written to the Postgres database, and instructions are sent via RabbitMQ to synchronize the playback status. Periodically (using CRON), the controllers will confirm that the playback status on the Plex Server is aligned to the database. When a conflict arises, the database is the winner. 8 | 9 | ## Simple Setup 10 | 11 | docker-compose.yml 12 | ```yaml 13 | version: '3' 14 | services: 15 | 16 | plexServer1: 17 | container_name: plexServer1 18 | image: plexinc/pms-docker 19 | 20 | controller1: 21 | container_name: controller1 22 | image: yusufali/plexcontroller 23 | environment: 24 | # controllers use rabbitmq to send playback information to each other. 25 | # controllers use postgres to store persistant playback information. 26 | RABBITMQ_URL: ampq://rabbitmqHost/myVhost 27 | DATABASE_URL: postgres://user:pass@mypostgresHost:5432/mydatabase 28 | 29 | # specify credentials to log in to plex.tv. It needs to login to plex.tv 30 | # to get the authTokens for users signed into the server. These authTokens 31 | # is used to set playback information 32 | PLEXUSERNAME: myplexusername 33 | PLEXPASSWORD: myplexpassword 34 | 35 | # configure when daily and monthly tasks are to run. scheduled tasks are to 36 | # ensure that playback information is synced with playback information stored in 37 | # the database 38 | MONTHLY_CRON: '0 2 3 * *' 39 | DAILY_CRON: '5 4 * * *' 40 | CRON_TIMEZONE: 'America/Toronto' 41 | 42 | # specify the IP address of the server for this controller to control 43 | PLEXLOCAL_IP: plexServer1 44 | links: 45 | - plexServer1 46 | 47 | 48 | 49 | plexServer2: 50 | container_name: plexServer2 51 | image: plexinc/pms-docker 52 | 53 | controller2: 54 | container_name: controller2 55 | image: yusufali/plexcontroller 56 | environment: 57 | RABBITMQ_URL: ampq://rabbitmqHost/myVhost 58 | DATABASE_URL: postgres://user:pass@mypostgresHost:5432/mydatabase 59 | PLEXUSERNAME: myplexusername 60 | PLEXPASSWORD: myplexpassword 61 | MONTHLY_CRON: '0 2 3 * *' 62 | DAILY_CRON: '5 4 * * *' 63 | CRON_TIMEZONE: 'America/Toronto' 64 | PLEXLOCAL_IP: plexServer2 65 | links: 66 | - plexServer2 67 | ``` 68 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": [ 3 | "src" 4 | ], 5 | "ext": "ts", 6 | "exec": "ts-node --transpile-only ./src/index.ts" 7 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.11", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.10.4" 14 | } 15 | }, 16 | "@babel/helper-validator-identifier": { 17 | "version": "7.14.9", 18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", 19 | "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", 20 | "dev": true 21 | }, 22 | "@babel/highlight": { 23 | "version": "7.14.5", 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", 25 | "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", 26 | "dev": true, 27 | "requires": { 28 | "@babel/helper-validator-identifier": "^7.14.5", 29 | "chalk": "^2.0.0", 30 | "js-tokens": "^4.0.0" 31 | }, 32 | "dependencies": { 33 | "chalk": { 34 | "version": "2.4.2", 35 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 36 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 37 | "dev": true, 38 | "requires": { 39 | "ansi-styles": "^3.2.1", 40 | "escape-string-regexp": "^1.0.5", 41 | "supports-color": "^5.3.0" 42 | } 43 | }, 44 | "escape-string-regexp": { 45 | "version": "1.0.5", 46 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 47 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 48 | "dev": true 49 | } 50 | } 51 | }, 52 | "@babel/runtime": { 53 | "version": "7.15.3", 54 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz", 55 | "integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==", 56 | "dev": true, 57 | "requires": { 58 | "regenerator-runtime": "^0.13.4" 59 | } 60 | }, 61 | "@babel/runtime-corejs3": { 62 | "version": "7.15.3", 63 | "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz", 64 | "integrity": "sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A==", 65 | "dev": true, 66 | "requires": { 67 | "core-js-pure": "^3.16.0", 68 | "regenerator-runtime": "^0.13.4" 69 | } 70 | }, 71 | "@eslint/eslintrc": { 72 | "version": "0.4.3", 73 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", 74 | "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", 75 | "dev": true, 76 | "requires": { 77 | "ajv": "^6.12.4", 78 | "debug": "^4.1.1", 79 | "espree": "^7.3.0", 80 | "globals": "^13.9.0", 81 | "ignore": "^4.0.6", 82 | "import-fresh": "^3.2.1", 83 | "js-yaml": "^3.13.1", 84 | "minimatch": "^3.0.4", 85 | "strip-json-comments": "^3.1.1" 86 | }, 87 | "dependencies": { 88 | "debug": { 89 | "version": "4.3.2", 90 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 91 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 92 | "dev": true, 93 | "requires": { 94 | "ms": "2.1.2" 95 | } 96 | }, 97 | "ignore": { 98 | "version": "4.0.6", 99 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 100 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 101 | "dev": true 102 | }, 103 | "ms": { 104 | "version": "2.1.2", 105 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 106 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 107 | "dev": true 108 | } 109 | } 110 | }, 111 | "@nodelib/fs.scandir": { 112 | "version": "2.1.5", 113 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 114 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 115 | "dev": true, 116 | "requires": { 117 | "@nodelib/fs.stat": "2.0.5", 118 | "run-parallel": "^1.1.9" 119 | } 120 | }, 121 | "@nodelib/fs.stat": { 122 | "version": "2.0.5", 123 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 124 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 125 | "dev": true 126 | }, 127 | "@nodelib/fs.walk": { 128 | "version": "1.2.8", 129 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 130 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 131 | "dev": true, 132 | "requires": { 133 | "@nodelib/fs.scandir": "2.1.5", 134 | "fastq": "^1.6.0" 135 | } 136 | }, 137 | "@tsconfig/node10": { 138 | "version": "1.0.8", 139 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", 140 | "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", 141 | "dev": true 142 | }, 143 | "@tsconfig/node12": { 144 | "version": "1.0.9", 145 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", 146 | "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", 147 | "dev": true 148 | }, 149 | "@tsconfig/node14": { 150 | "version": "1.0.1", 151 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", 152 | "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", 153 | "dev": true 154 | }, 155 | "@tsconfig/node16": { 156 | "version": "1.0.2", 157 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", 158 | "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", 159 | "dev": true 160 | }, 161 | "@types/amqplib": { 162 | "version": "0.8.0", 163 | "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.8.0.tgz", 164 | "integrity": "sha512-RDojJ8WACs43HIfWSQGnAVwgNzjMGx4YMNeW7jptgAFgkG1EpNQqts+cND5HYWdYgTM58b+RHe675b0i4A9WpQ==", 165 | "dev": true, 166 | "requires": { 167 | "@types/bluebird": "*", 168 | "@types/node": "*" 169 | } 170 | }, 171 | "@types/axios": { 172 | "version": "0.14.0", 173 | "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", 174 | "integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=", 175 | "dev": true, 176 | "requires": { 177 | "axios": "*" 178 | } 179 | }, 180 | "@types/bluebird": { 181 | "version": "3.5.36", 182 | "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.36.tgz", 183 | "integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==", 184 | "dev": true 185 | }, 186 | "@types/chai": { 187 | "version": "4.2.18", 188 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.18.tgz", 189 | "integrity": "sha512-rS27+EkB/RE1Iz3u0XtVL5q36MGDWbgYe7zWiodyKNUnthxY0rukK5V36eiUCtCisB7NN8zKYH6DO2M37qxFEQ==", 190 | "dev": true 191 | }, 192 | "@types/cron": { 193 | "version": "1.7.2", 194 | "resolved": "https://registry.npmjs.org/@types/cron/-/cron-1.7.2.tgz", 195 | "integrity": "sha512-AEpNLRcsVSc5AdseJKNHpz0d4e8+ow+abTaC0fKDbAU86rF1evoFF0oC2fV9FdqtfVXkG2LKshpLTJCFOpyvTg==", 196 | "dev": true, 197 | "requires": { 198 | "@types/node": "*", 199 | "moment": ">=2.14.0" 200 | } 201 | }, 202 | "@types/json-schema": { 203 | "version": "7.0.9", 204 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", 205 | "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", 206 | "dev": true 207 | }, 208 | "@types/json5": { 209 | "version": "0.0.29", 210 | "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", 211 | "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", 212 | "dev": true 213 | }, 214 | "@types/mocha": { 215 | "version": "8.2.2", 216 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz", 217 | "integrity": "sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==", 218 | "dev": true 219 | }, 220 | "@types/node": { 221 | "version": "16.7.6", 222 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.6.tgz", 223 | "integrity": "sha512-VESVNFoa/ahYA62xnLBjo5ur6gPsgEE5cNRy8SrdnkZ2nwJSW0kJ4ufbFr2zuU9ALtHM8juY53VcRoTA7htXSg==" 224 | }, 225 | "@types/ws": { 226 | "version": "7.4.5", 227 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.5.tgz", 228 | "integrity": "sha512-8mbDgtc8xpxDDem5Gwj76stBDJX35KQ3YBoayxlqUQcL5BZUthiqP/VQ4PQnLHqM4PmlbyO74t98eJpURO+gPA==", 229 | "dev": true, 230 | "requires": { 231 | "@types/node": "*" 232 | } 233 | }, 234 | "@typescript-eslint/eslint-plugin": { 235 | "version": "4.27.0", 236 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz", 237 | "integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==", 238 | "dev": true, 239 | "requires": { 240 | "@typescript-eslint/experimental-utils": "4.27.0", 241 | "@typescript-eslint/scope-manager": "4.27.0", 242 | "debug": "^4.3.1", 243 | "functional-red-black-tree": "^1.0.1", 244 | "lodash": "^4.17.21", 245 | "regexpp": "^3.1.0", 246 | "semver": "^7.3.5", 247 | "tsutils": "^3.21.0" 248 | }, 249 | "dependencies": { 250 | "debug": { 251 | "version": "4.3.2", 252 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 253 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 254 | "dev": true, 255 | "requires": { 256 | "ms": "2.1.2" 257 | } 258 | }, 259 | "ms": { 260 | "version": "2.1.2", 261 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 262 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 263 | "dev": true 264 | } 265 | } 266 | }, 267 | "@typescript-eslint/experimental-utils": { 268 | "version": "4.27.0", 269 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz", 270 | "integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==", 271 | "dev": true, 272 | "requires": { 273 | "@types/json-schema": "^7.0.7", 274 | "@typescript-eslint/scope-manager": "4.27.0", 275 | "@typescript-eslint/types": "4.27.0", 276 | "@typescript-eslint/typescript-estree": "4.27.0", 277 | "eslint-scope": "^5.1.1", 278 | "eslint-utils": "^3.0.0" 279 | } 280 | }, 281 | "@typescript-eslint/parser": { 282 | "version": "4.27.0", 283 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz", 284 | "integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==", 285 | "dev": true, 286 | "requires": { 287 | "@typescript-eslint/scope-manager": "4.27.0", 288 | "@typescript-eslint/types": "4.27.0", 289 | "@typescript-eslint/typescript-estree": "4.27.0", 290 | "debug": "^4.3.1" 291 | }, 292 | "dependencies": { 293 | "debug": { 294 | "version": "4.3.2", 295 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 296 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 297 | "dev": true, 298 | "requires": { 299 | "ms": "2.1.2" 300 | } 301 | }, 302 | "ms": { 303 | "version": "2.1.2", 304 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 305 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 306 | "dev": true 307 | } 308 | } 309 | }, 310 | "@typescript-eslint/scope-manager": { 311 | "version": "4.27.0", 312 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz", 313 | "integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==", 314 | "dev": true, 315 | "requires": { 316 | "@typescript-eslint/types": "4.27.0", 317 | "@typescript-eslint/visitor-keys": "4.27.0" 318 | } 319 | }, 320 | "@typescript-eslint/types": { 321 | "version": "4.27.0", 322 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz", 323 | "integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA==", 324 | "dev": true 325 | }, 326 | "@typescript-eslint/typescript-estree": { 327 | "version": "4.27.0", 328 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz", 329 | "integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==", 330 | "dev": true, 331 | "requires": { 332 | "@typescript-eslint/types": "4.27.0", 333 | "@typescript-eslint/visitor-keys": "4.27.0", 334 | "debug": "^4.3.1", 335 | "globby": "^11.0.3", 336 | "is-glob": "^4.0.1", 337 | "semver": "^7.3.5", 338 | "tsutils": "^3.21.0" 339 | }, 340 | "dependencies": { 341 | "debug": { 342 | "version": "4.3.2", 343 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 344 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 345 | "dev": true, 346 | "requires": { 347 | "ms": "2.1.2" 348 | } 349 | }, 350 | "ms": { 351 | "version": "2.1.2", 352 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 353 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 354 | "dev": true 355 | } 356 | } 357 | }, 358 | "@typescript-eslint/visitor-keys": { 359 | "version": "4.27.0", 360 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz", 361 | "integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==", 362 | "dev": true, 363 | "requires": { 364 | "@typescript-eslint/types": "4.27.0", 365 | "eslint-visitor-keys": "^2.0.0" 366 | } 367 | }, 368 | "@ungap/promise-all-settled": { 369 | "version": "1.1.2", 370 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 371 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 372 | "dev": true 373 | }, 374 | "acorn": { 375 | "version": "7.4.1", 376 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 377 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 378 | "dev": true 379 | }, 380 | "acorn-jsx": { 381 | "version": "5.3.2", 382 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 383 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 384 | "dev": true 385 | }, 386 | "ajv": { 387 | "version": "6.12.6", 388 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 389 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 390 | "requires": { 391 | "fast-deep-equal": "^3.1.1", 392 | "fast-json-stable-stringify": "^2.0.0", 393 | "json-schema-traverse": "^0.4.1", 394 | "uri-js": "^4.2.2" 395 | } 396 | }, 397 | "amqplib": { 398 | "version": "0.8.0", 399 | "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.8.0.tgz", 400 | "integrity": "sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA==", 401 | "requires": { 402 | "bitsyntax": "~0.1.0", 403 | "bluebird": "^3.7.2", 404 | "buffer-more-ints": "~1.0.0", 405 | "readable-stream": "1.x >=1.1.9", 406 | "safe-buffer": "~5.2.1", 407 | "url-parse": "~1.5.1" 408 | } 409 | }, 410 | "ansi-colors": { 411 | "version": "4.1.1", 412 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 413 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 414 | "dev": true 415 | }, 416 | "ansi-regex": { 417 | "version": "5.0.0", 418 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 419 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 420 | "dev": true 421 | }, 422 | "ansi-styles": { 423 | "version": "3.2.1", 424 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 425 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 426 | "dev": true, 427 | "requires": { 428 | "color-convert": "^1.9.0" 429 | } 430 | }, 431 | "any-promise": { 432 | "version": "1.3.0", 433 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 434 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" 435 | }, 436 | "anymatch": { 437 | "version": "3.1.2", 438 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 439 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 440 | "dev": true, 441 | "requires": { 442 | "normalize-path": "^3.0.0", 443 | "picomatch": "^2.0.4" 444 | } 445 | }, 446 | "arg": { 447 | "version": "4.1.3", 448 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 449 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 450 | "dev": true 451 | }, 452 | "argparse": { 453 | "version": "1.0.10", 454 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 455 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 456 | "dev": true, 457 | "requires": { 458 | "sprintf-js": "~1.0.2" 459 | } 460 | }, 461 | "aria-query": { 462 | "version": "4.2.2", 463 | "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", 464 | "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", 465 | "dev": true, 466 | "requires": { 467 | "@babel/runtime": "^7.10.2", 468 | "@babel/runtime-corejs3": "^7.10.2" 469 | } 470 | }, 471 | "array-includes": { 472 | "version": "3.1.3", 473 | "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", 474 | "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", 475 | "dev": true, 476 | "requires": { 477 | "call-bind": "^1.0.2", 478 | "define-properties": "^1.1.3", 479 | "es-abstract": "^1.18.0-next.2", 480 | "get-intrinsic": "^1.1.1", 481 | "is-string": "^1.0.5" 482 | } 483 | }, 484 | "array-union": { 485 | "version": "2.1.0", 486 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 487 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 488 | "dev": true 489 | }, 490 | "array.prototype.flat": { 491 | "version": "1.2.4", 492 | "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", 493 | "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", 494 | "dev": true, 495 | "requires": { 496 | "call-bind": "^1.0.0", 497 | "define-properties": "^1.1.3", 498 | "es-abstract": "^1.18.0-next.1" 499 | } 500 | }, 501 | "array.prototype.flatmap": { 502 | "version": "1.2.4", 503 | "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", 504 | "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", 505 | "dev": true, 506 | "requires": { 507 | "call-bind": "^1.0.0", 508 | "define-properties": "^1.1.3", 509 | "es-abstract": "^1.18.0-next.1", 510 | "function-bind": "^1.1.1" 511 | } 512 | }, 513 | "asn1": { 514 | "version": "0.2.4", 515 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 516 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 517 | "requires": { 518 | "safer-buffer": "~2.1.0" 519 | } 520 | }, 521 | "assert-plus": { 522 | "version": "1.0.0", 523 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 524 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 525 | }, 526 | "assertion-error": { 527 | "version": "1.1.0", 528 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 529 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 530 | "dev": true 531 | }, 532 | "ast-types-flow": { 533 | "version": "0.0.7", 534 | "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", 535 | "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", 536 | "dev": true 537 | }, 538 | "astral-regex": { 539 | "version": "2.0.0", 540 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", 541 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", 542 | "dev": true 543 | }, 544 | "asynckit": { 545 | "version": "0.4.0", 546 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 547 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 548 | }, 549 | "aws-sign2": { 550 | "version": "0.7.0", 551 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 552 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 553 | }, 554 | "aws4": { 555 | "version": "1.11.0", 556 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", 557 | "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" 558 | }, 559 | "axe-core": { 560 | "version": "4.3.3", 561 | "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz", 562 | "integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==", 563 | "dev": true 564 | }, 565 | "axios": { 566 | "version": "0.21.1", 567 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", 568 | "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", 569 | "requires": { 570 | "follow-redirects": "^1.10.0" 571 | } 572 | }, 573 | "axobject-query": { 574 | "version": "2.2.0", 575 | "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", 576 | "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", 577 | "dev": true 578 | }, 579 | "balanced-match": { 580 | "version": "1.0.2", 581 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 582 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 583 | "dev": true 584 | }, 585 | "bcrypt-pbkdf": { 586 | "version": "1.0.2", 587 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 588 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 589 | "requires": { 590 | "tweetnacl": "^0.14.3" 591 | } 592 | }, 593 | "binary-extensions": { 594 | "version": "2.2.0", 595 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 596 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 597 | "dev": true 598 | }, 599 | "bitsyntax": { 600 | "version": "0.1.0", 601 | "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz", 602 | "integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==", 603 | "requires": { 604 | "buffer-more-ints": "~1.0.0", 605 | "debug": "~2.6.9", 606 | "safe-buffer": "~5.1.2" 607 | }, 608 | "dependencies": { 609 | "safe-buffer": { 610 | "version": "5.1.2", 611 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 612 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 613 | } 614 | } 615 | }, 616 | "bluebird": { 617 | "version": "3.7.2", 618 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 619 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" 620 | }, 621 | "brace-expansion": { 622 | "version": "1.1.11", 623 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 624 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 625 | "dev": true, 626 | "requires": { 627 | "balanced-match": "^1.0.0", 628 | "concat-map": "0.0.1" 629 | } 630 | }, 631 | "braces": { 632 | "version": "3.0.2", 633 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 634 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 635 | "dev": true, 636 | "requires": { 637 | "fill-range": "^7.0.1" 638 | } 639 | }, 640 | "browser-stdout": { 641 | "version": "1.3.1", 642 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 643 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 644 | "dev": true 645 | }, 646 | "buffer-from": { 647 | "version": "1.1.2", 648 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 649 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 650 | "dev": true 651 | }, 652 | "buffer-more-ints": { 653 | "version": "1.0.0", 654 | "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", 655 | "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" 656 | }, 657 | "buffer-writer": { 658 | "version": "2.0.0", 659 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 660 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" 661 | }, 662 | "call-bind": { 663 | "version": "1.0.2", 664 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 665 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 666 | "dev": true, 667 | "requires": { 668 | "function-bind": "^1.1.1", 669 | "get-intrinsic": "^1.0.2" 670 | } 671 | }, 672 | "callsites": { 673 | "version": "3.1.0", 674 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 675 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 676 | "dev": true 677 | }, 678 | "camelcase": { 679 | "version": "6.2.0", 680 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", 681 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", 682 | "dev": true 683 | }, 684 | "caseless": { 685 | "version": "0.12.0", 686 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 687 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 688 | }, 689 | "chai": { 690 | "version": "4.3.4", 691 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", 692 | "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", 693 | "dev": true, 694 | "requires": { 695 | "assertion-error": "^1.1.0", 696 | "check-error": "^1.0.2", 697 | "deep-eql": "^3.0.1", 698 | "get-func-name": "^2.0.0", 699 | "pathval": "^1.1.1", 700 | "type-detect": "^4.0.5" 701 | } 702 | }, 703 | "chalk": { 704 | "version": "4.1.2", 705 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 706 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 707 | "dev": true, 708 | "requires": { 709 | "ansi-styles": "^4.1.0", 710 | "supports-color": "^7.1.0" 711 | }, 712 | "dependencies": { 713 | "ansi-styles": { 714 | "version": "4.3.0", 715 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 716 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 717 | "dev": true, 718 | "requires": { 719 | "color-convert": "^2.0.1" 720 | } 721 | }, 722 | "color-convert": { 723 | "version": "2.0.1", 724 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 725 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 726 | "dev": true, 727 | "requires": { 728 | "color-name": "~1.1.4" 729 | } 730 | }, 731 | "color-name": { 732 | "version": "1.1.4", 733 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 734 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 735 | "dev": true 736 | }, 737 | "has-flag": { 738 | "version": "4.0.0", 739 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 740 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 741 | "dev": true 742 | }, 743 | "supports-color": { 744 | "version": "7.2.0", 745 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 746 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 747 | "dev": true, 748 | "requires": { 749 | "has-flag": "^4.0.0" 750 | } 751 | } 752 | } 753 | }, 754 | "check-error": { 755 | "version": "1.0.2", 756 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 757 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 758 | "dev": true 759 | }, 760 | "chokidar": { 761 | "version": "3.5.1", 762 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", 763 | "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", 764 | "dev": true, 765 | "requires": { 766 | "anymatch": "~3.1.1", 767 | "braces": "~3.0.2", 768 | "fsevents": "~2.3.1", 769 | "glob-parent": "~5.1.0", 770 | "is-binary-path": "~2.1.0", 771 | "is-glob": "~4.0.1", 772 | "normalize-path": "~3.0.0", 773 | "readdirp": "~3.5.0" 774 | } 775 | }, 776 | "cliui": { 777 | "version": "7.0.4", 778 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 779 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 780 | "dev": true, 781 | "requires": { 782 | "string-width": "^4.2.0", 783 | "strip-ansi": "^6.0.0", 784 | "wrap-ansi": "^7.0.0" 785 | } 786 | }, 787 | "color-convert": { 788 | "version": "1.9.3", 789 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 790 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 791 | "dev": true, 792 | "requires": { 793 | "color-name": "1.1.3" 794 | } 795 | }, 796 | "color-name": { 797 | "version": "1.1.3", 798 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 799 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 800 | "dev": true 801 | }, 802 | "combined-stream": { 803 | "version": "1.0.8", 804 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 805 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 806 | "requires": { 807 | "delayed-stream": "~1.0.0" 808 | } 809 | }, 810 | "concat-map": { 811 | "version": "0.0.1", 812 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 813 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 814 | "dev": true 815 | }, 816 | "confusing-browser-globals": { 817 | "version": "1.0.10", 818 | "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", 819 | "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", 820 | "dev": true 821 | }, 822 | "core-js-pure": { 823 | "version": "3.16.4", 824 | "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.4.tgz", 825 | "integrity": "sha512-bY1K3/1Jy9D8Jd12eoeVahNXHLfHFb4TXWI8SQ4y8bImR9qDPmGITBAfmcffTkgUvbJn87r8dILOTWW5kZzkgA==", 826 | "dev": true 827 | }, 828 | "core-util-is": { 829 | "version": "1.0.2", 830 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 831 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 832 | }, 833 | "create-require": { 834 | "version": "1.1.1", 835 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 836 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 837 | "dev": true 838 | }, 839 | "cron": { 840 | "version": "1.8.2", 841 | "resolved": "https://registry.npmjs.org/cron/-/cron-1.8.2.tgz", 842 | "integrity": "sha512-Gk2c4y6xKEO8FSAUTklqtfSr7oTq0CiPQeLBG5Fl0qoXpZyMcj1SG59YL+hqq04bu6/IuEA7lMkYDAplQNKkyg==", 843 | "requires": { 844 | "moment-timezone": "^0.5.x" 845 | } 846 | }, 847 | "cross-spawn": { 848 | "version": "7.0.3", 849 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 850 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 851 | "dev": true, 852 | "requires": { 853 | "path-key": "^3.1.0", 854 | "shebang-command": "^2.0.0", 855 | "which": "^2.0.1" 856 | } 857 | }, 858 | "damerau-levenshtein": { 859 | "version": "1.0.7", 860 | "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", 861 | "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==", 862 | "dev": true 863 | }, 864 | "dashdash": { 865 | "version": "1.14.1", 866 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 867 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 868 | "requires": { 869 | "assert-plus": "^1.0.0" 870 | } 871 | }, 872 | "debug": { 873 | "version": "2.6.9", 874 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 875 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 876 | "requires": { 877 | "ms": "2.0.0" 878 | } 879 | }, 880 | "decamelize": { 881 | "version": "4.0.0", 882 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 883 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 884 | "dev": true 885 | }, 886 | "deep-eql": { 887 | "version": "3.0.1", 888 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 889 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 890 | "dev": true, 891 | "requires": { 892 | "type-detect": "^4.0.0" 893 | } 894 | }, 895 | "deep-is": { 896 | "version": "0.1.3", 897 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 898 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 899 | "dev": true 900 | }, 901 | "define-properties": { 902 | "version": "1.1.3", 903 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 904 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 905 | "dev": true, 906 | "requires": { 907 | "object-keys": "^1.0.12" 908 | } 909 | }, 910 | "delayed-stream": { 911 | "version": "1.0.0", 912 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 913 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 914 | }, 915 | "diff": { 916 | "version": "5.0.0", 917 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 918 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 919 | "dev": true 920 | }, 921 | "dir-glob": { 922 | "version": "3.0.1", 923 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 924 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 925 | "dev": true, 926 | "requires": { 927 | "path-type": "^4.0.0" 928 | } 929 | }, 930 | "doctrine": { 931 | "version": "3.0.0", 932 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 933 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 934 | "dev": true, 935 | "requires": { 936 | "esutils": "^2.0.2" 937 | } 938 | }, 939 | "dottie": { 940 | "version": "2.0.2", 941 | "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", 942 | "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" 943 | }, 944 | "ecc-jsbn": { 945 | "version": "0.1.2", 946 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 947 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 948 | "requires": { 949 | "jsbn": "~0.1.0", 950 | "safer-buffer": "^2.1.0" 951 | } 952 | }, 953 | "emoji-regex": { 954 | "version": "8.0.0", 955 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 956 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 957 | "dev": true 958 | }, 959 | "enquirer": { 960 | "version": "2.3.6", 961 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 962 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 963 | "dev": true, 964 | "requires": { 965 | "ansi-colors": "^4.1.1" 966 | } 967 | }, 968 | "error-ex": { 969 | "version": "1.3.2", 970 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 971 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 972 | "dev": true, 973 | "requires": { 974 | "is-arrayish": "^0.2.1" 975 | } 976 | }, 977 | "es-abstract": { 978 | "version": "1.18.5", 979 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", 980 | "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", 981 | "dev": true, 982 | "requires": { 983 | "call-bind": "^1.0.2", 984 | "es-to-primitive": "^1.2.1", 985 | "function-bind": "^1.1.1", 986 | "get-intrinsic": "^1.1.1", 987 | "has": "^1.0.3", 988 | "has-symbols": "^1.0.2", 989 | "internal-slot": "^1.0.3", 990 | "is-callable": "^1.2.3", 991 | "is-negative-zero": "^2.0.1", 992 | "is-regex": "^1.1.3", 993 | "is-string": "^1.0.6", 994 | "object-inspect": "^1.11.0", 995 | "object-keys": "^1.1.1", 996 | "object.assign": "^4.1.2", 997 | "string.prototype.trimend": "^1.0.4", 998 | "string.prototype.trimstart": "^1.0.4", 999 | "unbox-primitive": "^1.0.1" 1000 | } 1001 | }, 1002 | "es-to-primitive": { 1003 | "version": "1.2.1", 1004 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 1005 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 1006 | "dev": true, 1007 | "requires": { 1008 | "is-callable": "^1.1.4", 1009 | "is-date-object": "^1.0.1", 1010 | "is-symbol": "^1.0.2" 1011 | } 1012 | }, 1013 | "escalade": { 1014 | "version": "3.1.1", 1015 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1016 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1017 | "dev": true 1018 | }, 1019 | "escape-string-regexp": { 1020 | "version": "4.0.0", 1021 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1022 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1023 | "dev": true 1024 | }, 1025 | "eslint": { 1026 | "version": "7.29.0", 1027 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz", 1028 | "integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==", 1029 | "dev": true, 1030 | "requires": { 1031 | "@babel/code-frame": "7.12.11", 1032 | "@eslint/eslintrc": "^0.4.2", 1033 | "ajv": "^6.10.0", 1034 | "chalk": "^4.0.0", 1035 | "cross-spawn": "^7.0.2", 1036 | "debug": "^4.0.1", 1037 | "doctrine": "^3.0.0", 1038 | "enquirer": "^2.3.5", 1039 | "escape-string-regexp": "^4.0.0", 1040 | "eslint-scope": "^5.1.1", 1041 | "eslint-utils": "^2.1.0", 1042 | "eslint-visitor-keys": "^2.0.0", 1043 | "espree": "^7.3.1", 1044 | "esquery": "^1.4.0", 1045 | "esutils": "^2.0.2", 1046 | "fast-deep-equal": "^3.1.3", 1047 | "file-entry-cache": "^6.0.1", 1048 | "functional-red-black-tree": "^1.0.1", 1049 | "glob-parent": "^5.1.2", 1050 | "globals": "^13.6.0", 1051 | "ignore": "^4.0.6", 1052 | "import-fresh": "^3.0.0", 1053 | "imurmurhash": "^0.1.4", 1054 | "is-glob": "^4.0.0", 1055 | "js-yaml": "^3.13.1", 1056 | "json-stable-stringify-without-jsonify": "^1.0.1", 1057 | "levn": "^0.4.1", 1058 | "lodash.merge": "^4.6.2", 1059 | "minimatch": "^3.0.4", 1060 | "natural-compare": "^1.4.0", 1061 | "optionator": "^0.9.1", 1062 | "progress": "^2.0.0", 1063 | "regexpp": "^3.1.0", 1064 | "semver": "^7.2.1", 1065 | "strip-ansi": "^6.0.0", 1066 | "strip-json-comments": "^3.1.0", 1067 | "table": "^6.0.9", 1068 | "text-table": "^0.2.0", 1069 | "v8-compile-cache": "^2.0.3" 1070 | }, 1071 | "dependencies": { 1072 | "debug": { 1073 | "version": "4.3.2", 1074 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 1075 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 1076 | "dev": true, 1077 | "requires": { 1078 | "ms": "2.1.2" 1079 | } 1080 | }, 1081 | "eslint-utils": { 1082 | "version": "2.1.0", 1083 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", 1084 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", 1085 | "dev": true, 1086 | "requires": { 1087 | "eslint-visitor-keys": "^1.1.0" 1088 | }, 1089 | "dependencies": { 1090 | "eslint-visitor-keys": { 1091 | "version": "1.3.0", 1092 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 1093 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 1094 | "dev": true 1095 | } 1096 | } 1097 | }, 1098 | "ignore": { 1099 | "version": "4.0.6", 1100 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 1101 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 1102 | "dev": true 1103 | }, 1104 | "ms": { 1105 | "version": "2.1.2", 1106 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1107 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1108 | "dev": true 1109 | } 1110 | } 1111 | }, 1112 | "eslint-config-airbnb": { 1113 | "version": "18.2.1", 1114 | "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", 1115 | "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", 1116 | "dev": true, 1117 | "requires": { 1118 | "eslint-config-airbnb-base": "^14.2.1", 1119 | "object.assign": "^4.1.2", 1120 | "object.entries": "^1.1.2" 1121 | } 1122 | }, 1123 | "eslint-config-airbnb-base": { 1124 | "version": "14.2.1", 1125 | "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", 1126 | "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", 1127 | "dev": true, 1128 | "requires": { 1129 | "confusing-browser-globals": "^1.0.10", 1130 | "object.assign": "^4.1.2", 1131 | "object.entries": "^1.1.2" 1132 | } 1133 | }, 1134 | "eslint-config-airbnb-typescript": { 1135 | "version": "12.3.1", 1136 | "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-12.3.1.tgz", 1137 | "integrity": "sha512-ql/Pe6/hppYuRp4m3iPaHJqkBB7dgeEmGPQ6X0UNmrQOfTF+dXw29/ZjU2kQ6RDoLxaxOA+Xqv07Vbef6oVTWw==", 1138 | "dev": true, 1139 | "requires": { 1140 | "@typescript-eslint/parser": "^4.4.1", 1141 | "eslint-config-airbnb": "^18.2.0", 1142 | "eslint-config-airbnb-base": "^14.2.0" 1143 | } 1144 | }, 1145 | "eslint-import-resolver-node": { 1146 | "version": "0.3.6", 1147 | "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", 1148 | "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", 1149 | "dev": true, 1150 | "requires": { 1151 | "debug": "^3.2.7", 1152 | "resolve": "^1.20.0" 1153 | }, 1154 | "dependencies": { 1155 | "debug": { 1156 | "version": "3.2.7", 1157 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 1158 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 1159 | "dev": true, 1160 | "requires": { 1161 | "ms": "^2.1.1" 1162 | } 1163 | }, 1164 | "ms": { 1165 | "version": "2.1.3", 1166 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1167 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1168 | "dev": true 1169 | } 1170 | } 1171 | }, 1172 | "eslint-module-utils": { 1173 | "version": "2.6.2", 1174 | "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", 1175 | "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", 1176 | "dev": true, 1177 | "requires": { 1178 | "debug": "^3.2.7", 1179 | "pkg-dir": "^2.0.0" 1180 | }, 1181 | "dependencies": { 1182 | "debug": { 1183 | "version": "3.2.7", 1184 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 1185 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 1186 | "dev": true, 1187 | "requires": { 1188 | "ms": "^2.1.1" 1189 | } 1190 | }, 1191 | "ms": { 1192 | "version": "2.1.3", 1193 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1194 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1195 | "dev": true 1196 | } 1197 | } 1198 | }, 1199 | "eslint-plugin-import": { 1200 | "version": "2.23.4", 1201 | "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", 1202 | "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", 1203 | "dev": true, 1204 | "requires": { 1205 | "array-includes": "^3.1.3", 1206 | "array.prototype.flat": "^1.2.4", 1207 | "debug": "^2.6.9", 1208 | "doctrine": "^2.1.0", 1209 | "eslint-import-resolver-node": "^0.3.4", 1210 | "eslint-module-utils": "^2.6.1", 1211 | "find-up": "^2.0.0", 1212 | "has": "^1.0.3", 1213 | "is-core-module": "^2.4.0", 1214 | "minimatch": "^3.0.4", 1215 | "object.values": "^1.1.3", 1216 | "pkg-up": "^2.0.0", 1217 | "read-pkg-up": "^3.0.0", 1218 | "resolve": "^1.20.0", 1219 | "tsconfig-paths": "^3.9.0" 1220 | }, 1221 | "dependencies": { 1222 | "doctrine": { 1223 | "version": "2.1.0", 1224 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 1225 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 1226 | "dev": true, 1227 | "requires": { 1228 | "esutils": "^2.0.2" 1229 | } 1230 | } 1231 | } 1232 | }, 1233 | "eslint-plugin-jsx-a11y": { 1234 | "version": "6.4.1", 1235 | "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", 1236 | "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", 1237 | "dev": true, 1238 | "requires": { 1239 | "@babel/runtime": "^7.11.2", 1240 | "aria-query": "^4.2.2", 1241 | "array-includes": "^3.1.1", 1242 | "ast-types-flow": "^0.0.7", 1243 | "axe-core": "^4.0.2", 1244 | "axobject-query": "^2.2.0", 1245 | "damerau-levenshtein": "^1.0.6", 1246 | "emoji-regex": "^9.0.0", 1247 | "has": "^1.0.3", 1248 | "jsx-ast-utils": "^3.1.0", 1249 | "language-tags": "^1.0.5" 1250 | }, 1251 | "dependencies": { 1252 | "emoji-regex": { 1253 | "version": "9.2.2", 1254 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 1255 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 1256 | "dev": true 1257 | } 1258 | } 1259 | }, 1260 | "eslint-plugin-react": { 1261 | "version": "7.24.0", 1262 | "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", 1263 | "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", 1264 | "dev": true, 1265 | "requires": { 1266 | "array-includes": "^3.1.3", 1267 | "array.prototype.flatmap": "^1.2.4", 1268 | "doctrine": "^2.1.0", 1269 | "has": "^1.0.3", 1270 | "jsx-ast-utils": "^2.4.1 || ^3.0.0", 1271 | "minimatch": "^3.0.4", 1272 | "object.entries": "^1.1.4", 1273 | "object.fromentries": "^2.0.4", 1274 | "object.values": "^1.1.4", 1275 | "prop-types": "^15.7.2", 1276 | "resolve": "^2.0.0-next.3", 1277 | "string.prototype.matchall": "^4.0.5" 1278 | }, 1279 | "dependencies": { 1280 | "doctrine": { 1281 | "version": "2.1.0", 1282 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 1283 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 1284 | "dev": true, 1285 | "requires": { 1286 | "esutils": "^2.0.2" 1287 | } 1288 | }, 1289 | "resolve": { 1290 | "version": "2.0.0-next.3", 1291 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", 1292 | "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", 1293 | "dev": true, 1294 | "requires": { 1295 | "is-core-module": "^2.2.0", 1296 | "path-parse": "^1.0.6" 1297 | } 1298 | } 1299 | } 1300 | }, 1301 | "eslint-plugin-react-hooks": { 1302 | "version": "4.2.0", 1303 | "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", 1304 | "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", 1305 | "dev": true 1306 | }, 1307 | "eslint-scope": { 1308 | "version": "5.1.1", 1309 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 1310 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 1311 | "dev": true, 1312 | "requires": { 1313 | "esrecurse": "^4.3.0", 1314 | "estraverse": "^4.1.1" 1315 | } 1316 | }, 1317 | "eslint-utils": { 1318 | "version": "3.0.0", 1319 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", 1320 | "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", 1321 | "dev": true, 1322 | "requires": { 1323 | "eslint-visitor-keys": "^2.0.0" 1324 | } 1325 | }, 1326 | "eslint-visitor-keys": { 1327 | "version": "2.1.0", 1328 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", 1329 | "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", 1330 | "dev": true 1331 | }, 1332 | "espree": { 1333 | "version": "7.3.1", 1334 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", 1335 | "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", 1336 | "dev": true, 1337 | "requires": { 1338 | "acorn": "^7.4.0", 1339 | "acorn-jsx": "^5.3.1", 1340 | "eslint-visitor-keys": "^1.3.0" 1341 | }, 1342 | "dependencies": { 1343 | "eslint-visitor-keys": { 1344 | "version": "1.3.0", 1345 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 1346 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 1347 | "dev": true 1348 | } 1349 | } 1350 | }, 1351 | "esprima": { 1352 | "version": "4.0.1", 1353 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 1354 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 1355 | "dev": true 1356 | }, 1357 | "esquery": { 1358 | "version": "1.4.0", 1359 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", 1360 | "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", 1361 | "dev": true, 1362 | "requires": { 1363 | "estraverse": "^5.1.0" 1364 | }, 1365 | "dependencies": { 1366 | "estraverse": { 1367 | "version": "5.2.0", 1368 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 1369 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 1370 | "dev": true 1371 | } 1372 | } 1373 | }, 1374 | "esrecurse": { 1375 | "version": "4.3.0", 1376 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1377 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1378 | "dev": true, 1379 | "requires": { 1380 | "estraverse": "^5.2.0" 1381 | }, 1382 | "dependencies": { 1383 | "estraverse": { 1384 | "version": "5.2.0", 1385 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 1386 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 1387 | "dev": true 1388 | } 1389 | } 1390 | }, 1391 | "estraverse": { 1392 | "version": "4.3.0", 1393 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 1394 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 1395 | "dev": true 1396 | }, 1397 | "esutils": { 1398 | "version": "2.0.3", 1399 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1400 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 1401 | "dev": true 1402 | }, 1403 | "extend": { 1404 | "version": "3.0.2", 1405 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 1406 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 1407 | }, 1408 | "extsprintf": { 1409 | "version": "1.3.0", 1410 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 1411 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 1412 | }, 1413 | "fast-deep-equal": { 1414 | "version": "3.1.3", 1415 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1416 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 1417 | }, 1418 | "fast-glob": { 1419 | "version": "3.2.7", 1420 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", 1421 | "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", 1422 | "dev": true, 1423 | "requires": { 1424 | "@nodelib/fs.stat": "^2.0.2", 1425 | "@nodelib/fs.walk": "^1.2.3", 1426 | "glob-parent": "^5.1.2", 1427 | "merge2": "^1.3.0", 1428 | "micromatch": "^4.0.4" 1429 | } 1430 | }, 1431 | "fast-json-stable-stringify": { 1432 | "version": "2.1.0", 1433 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1434 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 1435 | }, 1436 | "fast-levenshtein": { 1437 | "version": "2.0.6", 1438 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1439 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 1440 | "dev": true 1441 | }, 1442 | "fastq": { 1443 | "version": "1.12.0", 1444 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", 1445 | "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", 1446 | "dev": true, 1447 | "requires": { 1448 | "reusify": "^1.0.4" 1449 | } 1450 | }, 1451 | "file-entry-cache": { 1452 | "version": "6.0.1", 1453 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 1454 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 1455 | "dev": true, 1456 | "requires": { 1457 | "flat-cache": "^3.0.4" 1458 | } 1459 | }, 1460 | "fill-range": { 1461 | "version": "7.0.1", 1462 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1463 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1464 | "dev": true, 1465 | "requires": { 1466 | "to-regex-range": "^5.0.1" 1467 | } 1468 | }, 1469 | "find-up": { 1470 | "version": "2.1.0", 1471 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 1472 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 1473 | "dev": true, 1474 | "requires": { 1475 | "locate-path": "^2.0.0" 1476 | } 1477 | }, 1478 | "flat": { 1479 | "version": "5.0.2", 1480 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 1481 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 1482 | "dev": true 1483 | }, 1484 | "flat-cache": { 1485 | "version": "3.0.4", 1486 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 1487 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 1488 | "dev": true, 1489 | "requires": { 1490 | "flatted": "^3.1.0", 1491 | "rimraf": "^3.0.2" 1492 | } 1493 | }, 1494 | "flatted": { 1495 | "version": "3.2.2", 1496 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", 1497 | "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", 1498 | "dev": true 1499 | }, 1500 | "follow-redirects": { 1501 | "version": "1.14.2", 1502 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz", 1503 | "integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==" 1504 | }, 1505 | "forever-agent": { 1506 | "version": "0.6.1", 1507 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 1508 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 1509 | }, 1510 | "form-data": { 1511 | "version": "2.3.3", 1512 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 1513 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 1514 | "requires": { 1515 | "asynckit": "^0.4.0", 1516 | "combined-stream": "^1.0.6", 1517 | "mime-types": "^2.1.12" 1518 | } 1519 | }, 1520 | "fs.realpath": { 1521 | "version": "1.0.0", 1522 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1523 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 1524 | "dev": true 1525 | }, 1526 | "fsevents": { 1527 | "version": "2.3.2", 1528 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1529 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1530 | "dev": true, 1531 | "optional": true 1532 | }, 1533 | "function-bind": { 1534 | "version": "1.1.1", 1535 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1536 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1537 | "dev": true 1538 | }, 1539 | "functional-red-black-tree": { 1540 | "version": "1.0.1", 1541 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 1542 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 1543 | "dev": true 1544 | }, 1545 | "get-caller-file": { 1546 | "version": "2.0.5", 1547 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1548 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1549 | "dev": true 1550 | }, 1551 | "get-func-name": { 1552 | "version": "2.0.0", 1553 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 1554 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 1555 | "dev": true 1556 | }, 1557 | "get-intrinsic": { 1558 | "version": "1.1.1", 1559 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", 1560 | "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", 1561 | "dev": true, 1562 | "requires": { 1563 | "function-bind": "^1.1.1", 1564 | "has": "^1.0.3", 1565 | "has-symbols": "^1.0.1" 1566 | } 1567 | }, 1568 | "getpass": { 1569 | "version": "0.1.7", 1570 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 1571 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 1572 | "requires": { 1573 | "assert-plus": "^1.0.0" 1574 | } 1575 | }, 1576 | "glob": { 1577 | "version": "7.1.7", 1578 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", 1579 | "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", 1580 | "dev": true, 1581 | "requires": { 1582 | "fs.realpath": "^1.0.0", 1583 | "inflight": "^1.0.4", 1584 | "inherits": "2", 1585 | "minimatch": "^3.0.4", 1586 | "once": "^1.3.0", 1587 | "path-is-absolute": "^1.0.0" 1588 | } 1589 | }, 1590 | "glob-parent": { 1591 | "version": "5.1.2", 1592 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1593 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1594 | "dev": true, 1595 | "requires": { 1596 | "is-glob": "^4.0.1" 1597 | } 1598 | }, 1599 | "globals": { 1600 | "version": "13.11.0", 1601 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", 1602 | "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", 1603 | "dev": true, 1604 | "requires": { 1605 | "type-fest": "^0.20.2" 1606 | } 1607 | }, 1608 | "globby": { 1609 | "version": "11.0.4", 1610 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", 1611 | "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", 1612 | "dev": true, 1613 | "requires": { 1614 | "array-union": "^2.1.0", 1615 | "dir-glob": "^3.0.1", 1616 | "fast-glob": "^3.1.1", 1617 | "ignore": "^5.1.4", 1618 | "merge2": "^1.3.0", 1619 | "slash": "^3.0.0" 1620 | } 1621 | }, 1622 | "graceful-fs": { 1623 | "version": "4.2.8", 1624 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", 1625 | "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", 1626 | "dev": true 1627 | }, 1628 | "growl": { 1629 | "version": "1.10.5", 1630 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 1631 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 1632 | "dev": true 1633 | }, 1634 | "har-schema": { 1635 | "version": "2.0.0", 1636 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 1637 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 1638 | }, 1639 | "har-validator": { 1640 | "version": "5.1.5", 1641 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", 1642 | "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", 1643 | "requires": { 1644 | "ajv": "^6.12.3", 1645 | "har-schema": "^2.0.0" 1646 | } 1647 | }, 1648 | "has": { 1649 | "version": "1.0.3", 1650 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1651 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1652 | "dev": true, 1653 | "requires": { 1654 | "function-bind": "^1.1.1" 1655 | } 1656 | }, 1657 | "has-bigints": { 1658 | "version": "1.0.1", 1659 | "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", 1660 | "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", 1661 | "dev": true 1662 | }, 1663 | "has-flag": { 1664 | "version": "3.0.0", 1665 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1666 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1667 | "dev": true 1668 | }, 1669 | "has-symbols": { 1670 | "version": "1.0.2", 1671 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", 1672 | "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", 1673 | "dev": true 1674 | }, 1675 | "has-tostringtag": { 1676 | "version": "1.0.0", 1677 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 1678 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 1679 | "dev": true, 1680 | "requires": { 1681 | "has-symbols": "^1.0.2" 1682 | } 1683 | }, 1684 | "he": { 1685 | "version": "1.2.0", 1686 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1687 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1688 | "dev": true 1689 | }, 1690 | "hosted-git-info": { 1691 | "version": "2.8.9", 1692 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", 1693 | "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", 1694 | "dev": true 1695 | }, 1696 | "http-signature": { 1697 | "version": "1.2.0", 1698 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 1699 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 1700 | "requires": { 1701 | "assert-plus": "^1.0.0", 1702 | "jsprim": "^1.2.2", 1703 | "sshpk": "^1.7.0" 1704 | } 1705 | }, 1706 | "ignore": { 1707 | "version": "5.1.8", 1708 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", 1709 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", 1710 | "dev": true 1711 | }, 1712 | "import-fresh": { 1713 | "version": "3.3.0", 1714 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1715 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1716 | "dev": true, 1717 | "requires": { 1718 | "parent-module": "^1.0.0", 1719 | "resolve-from": "^4.0.0" 1720 | } 1721 | }, 1722 | "imurmurhash": { 1723 | "version": "0.1.4", 1724 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1725 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 1726 | "dev": true 1727 | }, 1728 | "inflection": { 1729 | "version": "1.12.0", 1730 | "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", 1731 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" 1732 | }, 1733 | "inflight": { 1734 | "version": "1.0.6", 1735 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1736 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1737 | "dev": true, 1738 | "requires": { 1739 | "once": "^1.3.0", 1740 | "wrappy": "1" 1741 | } 1742 | }, 1743 | "inherits": { 1744 | "version": "2.0.4", 1745 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1746 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1747 | }, 1748 | "internal-slot": { 1749 | "version": "1.0.3", 1750 | "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", 1751 | "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", 1752 | "dev": true, 1753 | "requires": { 1754 | "get-intrinsic": "^1.1.0", 1755 | "has": "^1.0.3", 1756 | "side-channel": "^1.0.4" 1757 | } 1758 | }, 1759 | "is-arrayish": { 1760 | "version": "0.2.1", 1761 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1762 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 1763 | "dev": true 1764 | }, 1765 | "is-bigint": { 1766 | "version": "1.0.4", 1767 | "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", 1768 | "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", 1769 | "dev": true, 1770 | "requires": { 1771 | "has-bigints": "^1.0.1" 1772 | } 1773 | }, 1774 | "is-binary-path": { 1775 | "version": "2.1.0", 1776 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1777 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1778 | "dev": true, 1779 | "requires": { 1780 | "binary-extensions": "^2.0.0" 1781 | } 1782 | }, 1783 | "is-boolean-object": { 1784 | "version": "1.1.2", 1785 | "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", 1786 | "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", 1787 | "dev": true, 1788 | "requires": { 1789 | "call-bind": "^1.0.2", 1790 | "has-tostringtag": "^1.0.0" 1791 | } 1792 | }, 1793 | "is-callable": { 1794 | "version": "1.2.4", 1795 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", 1796 | "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", 1797 | "dev": true 1798 | }, 1799 | "is-core-module": { 1800 | "version": "2.6.0", 1801 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", 1802 | "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", 1803 | "dev": true, 1804 | "requires": { 1805 | "has": "^1.0.3" 1806 | } 1807 | }, 1808 | "is-date-object": { 1809 | "version": "1.0.5", 1810 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", 1811 | "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", 1812 | "dev": true, 1813 | "requires": { 1814 | "has-tostringtag": "^1.0.0" 1815 | } 1816 | }, 1817 | "is-extglob": { 1818 | "version": "2.1.1", 1819 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1820 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1821 | "dev": true 1822 | }, 1823 | "is-fullwidth-code-point": { 1824 | "version": "3.0.0", 1825 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1826 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1827 | "dev": true 1828 | }, 1829 | "is-glob": { 1830 | "version": "4.0.1", 1831 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1832 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1833 | "dev": true, 1834 | "requires": { 1835 | "is-extglob": "^2.1.1" 1836 | } 1837 | }, 1838 | "is-negative-zero": { 1839 | "version": "2.0.1", 1840 | "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", 1841 | "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", 1842 | "dev": true 1843 | }, 1844 | "is-number": { 1845 | "version": "7.0.0", 1846 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1847 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1848 | "dev": true 1849 | }, 1850 | "is-number-object": { 1851 | "version": "1.0.6", 1852 | "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", 1853 | "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", 1854 | "dev": true, 1855 | "requires": { 1856 | "has-tostringtag": "^1.0.0" 1857 | } 1858 | }, 1859 | "is-plain-obj": { 1860 | "version": "2.1.0", 1861 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1862 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1863 | "dev": true 1864 | }, 1865 | "is-regex": { 1866 | "version": "1.1.4", 1867 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", 1868 | "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", 1869 | "dev": true, 1870 | "requires": { 1871 | "call-bind": "^1.0.2", 1872 | "has-tostringtag": "^1.0.0" 1873 | } 1874 | }, 1875 | "is-string": { 1876 | "version": "1.0.7", 1877 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", 1878 | "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", 1879 | "dev": true, 1880 | "requires": { 1881 | "has-tostringtag": "^1.0.0" 1882 | } 1883 | }, 1884 | "is-symbol": { 1885 | "version": "1.0.4", 1886 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", 1887 | "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", 1888 | "dev": true, 1889 | "requires": { 1890 | "has-symbols": "^1.0.2" 1891 | } 1892 | }, 1893 | "is-typedarray": { 1894 | "version": "1.0.0", 1895 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 1896 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 1897 | }, 1898 | "is-unicode-supported": { 1899 | "version": "0.1.0", 1900 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 1901 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 1902 | "dev": true 1903 | }, 1904 | "isarray": { 1905 | "version": "0.0.1", 1906 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1907 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 1908 | }, 1909 | "isexe": { 1910 | "version": "2.0.0", 1911 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1912 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1913 | "dev": true 1914 | }, 1915 | "isstream": { 1916 | "version": "0.1.2", 1917 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 1918 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 1919 | }, 1920 | "js-tokens": { 1921 | "version": "4.0.0", 1922 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1923 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1924 | "dev": true 1925 | }, 1926 | "js-yaml": { 1927 | "version": "3.14.1", 1928 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 1929 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 1930 | "dev": true, 1931 | "requires": { 1932 | "argparse": "^1.0.7", 1933 | "esprima": "^4.0.0" 1934 | } 1935 | }, 1936 | "jsbn": { 1937 | "version": "0.1.1", 1938 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 1939 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 1940 | }, 1941 | "json-parse-better-errors": { 1942 | "version": "1.0.2", 1943 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 1944 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 1945 | "dev": true 1946 | }, 1947 | "json-schema": { 1948 | "version": "0.2.3", 1949 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 1950 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 1951 | }, 1952 | "json-schema-traverse": { 1953 | "version": "0.4.1", 1954 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1955 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 1956 | }, 1957 | "json-stable-stringify-without-jsonify": { 1958 | "version": "1.0.1", 1959 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1960 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1961 | "dev": true 1962 | }, 1963 | "json-stringify-safe": { 1964 | "version": "5.0.1", 1965 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 1966 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 1967 | }, 1968 | "json5": { 1969 | "version": "1.0.1", 1970 | "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", 1971 | "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", 1972 | "dev": true, 1973 | "requires": { 1974 | "minimist": "^1.2.0" 1975 | } 1976 | }, 1977 | "jsprim": { 1978 | "version": "1.4.1", 1979 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 1980 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 1981 | "requires": { 1982 | "assert-plus": "1.0.0", 1983 | "extsprintf": "1.3.0", 1984 | "json-schema": "0.2.3", 1985 | "verror": "1.10.0" 1986 | } 1987 | }, 1988 | "jsx-ast-utils": { 1989 | "version": "3.2.0", 1990 | "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", 1991 | "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", 1992 | "dev": true, 1993 | "requires": { 1994 | "array-includes": "^3.1.2", 1995 | "object.assign": "^4.1.2" 1996 | } 1997 | }, 1998 | "language-subtag-registry": { 1999 | "version": "0.3.21", 2000 | "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", 2001 | "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", 2002 | "dev": true 2003 | }, 2004 | "language-tags": { 2005 | "version": "1.0.5", 2006 | "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", 2007 | "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", 2008 | "dev": true, 2009 | "requires": { 2010 | "language-subtag-registry": "~0.3.2" 2011 | } 2012 | }, 2013 | "levn": { 2014 | "version": "0.4.1", 2015 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 2016 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 2017 | "dev": true, 2018 | "requires": { 2019 | "prelude-ls": "^1.2.1", 2020 | "type-check": "~0.4.0" 2021 | } 2022 | }, 2023 | "load-json-file": { 2024 | "version": "4.0.0", 2025 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", 2026 | "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", 2027 | "dev": true, 2028 | "requires": { 2029 | "graceful-fs": "^4.1.2", 2030 | "parse-json": "^4.0.0", 2031 | "pify": "^3.0.0", 2032 | "strip-bom": "^3.0.0" 2033 | } 2034 | }, 2035 | "locate-path": { 2036 | "version": "2.0.0", 2037 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 2038 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 2039 | "dev": true, 2040 | "requires": { 2041 | "p-locate": "^2.0.0", 2042 | "path-exists": "^3.0.0" 2043 | } 2044 | }, 2045 | "lodash": { 2046 | "version": "4.17.21", 2047 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 2048 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 2049 | }, 2050 | "lodash.clonedeep": { 2051 | "version": "4.5.0", 2052 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 2053 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", 2054 | "dev": true 2055 | }, 2056 | "lodash.merge": { 2057 | "version": "4.6.2", 2058 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 2059 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 2060 | "dev": true 2061 | }, 2062 | "lodash.truncate": { 2063 | "version": "4.4.2", 2064 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", 2065 | "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", 2066 | "dev": true 2067 | }, 2068 | "log-symbols": { 2069 | "version": "4.1.0", 2070 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 2071 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 2072 | "dev": true, 2073 | "requires": { 2074 | "chalk": "^4.1.0", 2075 | "is-unicode-supported": "^0.1.0" 2076 | } 2077 | }, 2078 | "loose-envify": { 2079 | "version": "1.4.0", 2080 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 2081 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 2082 | "dev": true, 2083 | "requires": { 2084 | "js-tokens": "^3.0.0 || ^4.0.0" 2085 | } 2086 | }, 2087 | "lru-cache": { 2088 | "version": "6.0.0", 2089 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 2090 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 2091 | "requires": { 2092 | "yallist": "^4.0.0" 2093 | } 2094 | }, 2095 | "make-error": { 2096 | "version": "1.3.6", 2097 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 2098 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 2099 | "dev": true 2100 | }, 2101 | "merge2": { 2102 | "version": "1.4.1", 2103 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 2104 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 2105 | "dev": true 2106 | }, 2107 | "micromatch": { 2108 | "version": "4.0.4", 2109 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", 2110 | "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", 2111 | "dev": true, 2112 | "requires": { 2113 | "braces": "^3.0.1", 2114 | "picomatch": "^2.2.3" 2115 | } 2116 | }, 2117 | "mime-db": { 2118 | "version": "1.49.0", 2119 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", 2120 | "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" 2121 | }, 2122 | "mime-types": { 2123 | "version": "2.1.32", 2124 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", 2125 | "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", 2126 | "requires": { 2127 | "mime-db": "1.49.0" 2128 | } 2129 | }, 2130 | "minimatch": { 2131 | "version": "3.0.4", 2132 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 2133 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 2134 | "dev": true, 2135 | "requires": { 2136 | "brace-expansion": "^1.1.7" 2137 | } 2138 | }, 2139 | "minimist": { 2140 | "version": "1.2.5", 2141 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 2142 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 2143 | "dev": true 2144 | }, 2145 | "mocha": { 2146 | "version": "9.0.1", 2147 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.0.1.tgz", 2148 | "integrity": "sha512-9zwsavlRO+5csZu6iRtl3GHImAbhERoDsZwdRkdJ/bE+eVplmoxNKE901ZJ9LdSchYBjSCPbjKc5XvcAri2ylw==", 2149 | "dev": true, 2150 | "requires": { 2151 | "@ungap/promise-all-settled": "1.1.2", 2152 | "ansi-colors": "4.1.1", 2153 | "browser-stdout": "1.3.1", 2154 | "chokidar": "3.5.1", 2155 | "debug": "4.3.1", 2156 | "diff": "5.0.0", 2157 | "escape-string-regexp": "4.0.0", 2158 | "find-up": "5.0.0", 2159 | "glob": "7.1.7", 2160 | "growl": "1.10.5", 2161 | "he": "1.2.0", 2162 | "js-yaml": "4.1.0", 2163 | "log-symbols": "4.1.0", 2164 | "minimatch": "3.0.4", 2165 | "ms": "2.1.3", 2166 | "nanoid": "3.1.23", 2167 | "serialize-javascript": "5.0.1", 2168 | "strip-json-comments": "3.1.1", 2169 | "supports-color": "8.1.1", 2170 | "which": "2.0.2", 2171 | "wide-align": "1.1.3", 2172 | "workerpool": "6.1.4", 2173 | "yargs": "16.2.0", 2174 | "yargs-parser": "20.2.4", 2175 | "yargs-unparser": "2.0.0" 2176 | }, 2177 | "dependencies": { 2178 | "argparse": { 2179 | "version": "2.0.1", 2180 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 2181 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 2182 | "dev": true 2183 | }, 2184 | "debug": { 2185 | "version": "4.3.1", 2186 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 2187 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 2188 | "dev": true, 2189 | "requires": { 2190 | "ms": "2.1.2" 2191 | }, 2192 | "dependencies": { 2193 | "ms": { 2194 | "version": "2.1.2", 2195 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2196 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 2197 | "dev": true 2198 | } 2199 | } 2200 | }, 2201 | "find-up": { 2202 | "version": "5.0.0", 2203 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 2204 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 2205 | "dev": true, 2206 | "requires": { 2207 | "locate-path": "^6.0.0", 2208 | "path-exists": "^4.0.0" 2209 | } 2210 | }, 2211 | "has-flag": { 2212 | "version": "4.0.0", 2213 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 2214 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 2215 | "dev": true 2216 | }, 2217 | "js-yaml": { 2218 | "version": "4.1.0", 2219 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 2220 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 2221 | "dev": true, 2222 | "requires": { 2223 | "argparse": "^2.0.1" 2224 | } 2225 | }, 2226 | "locate-path": { 2227 | "version": "6.0.0", 2228 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 2229 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 2230 | "dev": true, 2231 | "requires": { 2232 | "p-locate": "^5.0.0" 2233 | } 2234 | }, 2235 | "ms": { 2236 | "version": "2.1.3", 2237 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2238 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 2239 | "dev": true 2240 | }, 2241 | "p-limit": { 2242 | "version": "3.1.0", 2243 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2244 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2245 | "dev": true, 2246 | "requires": { 2247 | "yocto-queue": "^0.1.0" 2248 | } 2249 | }, 2250 | "p-locate": { 2251 | "version": "5.0.0", 2252 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2253 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2254 | "dev": true, 2255 | "requires": { 2256 | "p-limit": "^3.0.2" 2257 | } 2258 | }, 2259 | "path-exists": { 2260 | "version": "4.0.0", 2261 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2262 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 2263 | "dev": true 2264 | }, 2265 | "supports-color": { 2266 | "version": "8.1.1", 2267 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 2268 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 2269 | "dev": true, 2270 | "requires": { 2271 | "has-flag": "^4.0.0" 2272 | } 2273 | } 2274 | } 2275 | }, 2276 | "moment": { 2277 | "version": "2.29.1", 2278 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", 2279 | "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" 2280 | }, 2281 | "moment-timezone": { 2282 | "version": "0.5.33", 2283 | "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", 2284 | "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", 2285 | "requires": { 2286 | "moment": ">= 2.9.0" 2287 | } 2288 | }, 2289 | "ms": { 2290 | "version": "2.0.0", 2291 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2292 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 2293 | }, 2294 | "nanoid": { 2295 | "version": "3.1.23", 2296 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", 2297 | "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", 2298 | "dev": true 2299 | }, 2300 | "natural-compare": { 2301 | "version": "1.4.0", 2302 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 2303 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 2304 | "dev": true 2305 | }, 2306 | "nodejsmq": { 2307 | "version": "1.0.3", 2308 | "resolved": "https://registry.npmjs.org/nodejsmq/-/nodejsmq-1.0.3.tgz", 2309 | "integrity": "sha512-Nsell4inkoA5zASBBVZwYYWCqcmZljP+1FH2tAr+AvQbnpChp258hY1dQEKPke1U5x/Xg681Ib2tG4x2fJesPA==", 2310 | "requires": { 2311 | "amqplib": "0.8.0" 2312 | } 2313 | }, 2314 | "normalize-package-data": { 2315 | "version": "2.5.0", 2316 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 2317 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 2318 | "dev": true, 2319 | "requires": { 2320 | "hosted-git-info": "^2.1.4", 2321 | "resolve": "^1.10.0", 2322 | "semver": "2 || 3 || 4 || 5", 2323 | "validate-npm-package-license": "^3.0.1" 2324 | }, 2325 | "dependencies": { 2326 | "semver": { 2327 | "version": "5.7.1", 2328 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 2329 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 2330 | "dev": true 2331 | } 2332 | } 2333 | }, 2334 | "normalize-path": { 2335 | "version": "3.0.0", 2336 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 2337 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 2338 | "dev": true 2339 | }, 2340 | "oauth-sign": { 2341 | "version": "0.9.0", 2342 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 2343 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 2344 | }, 2345 | "object-assign": { 2346 | "version": "4.1.1", 2347 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 2348 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 2349 | "dev": true 2350 | }, 2351 | "object-inspect": { 2352 | "version": "1.11.0", 2353 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", 2354 | "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", 2355 | "dev": true 2356 | }, 2357 | "object-keys": { 2358 | "version": "1.1.1", 2359 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 2360 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 2361 | "dev": true 2362 | }, 2363 | "object.assign": { 2364 | "version": "4.1.2", 2365 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", 2366 | "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", 2367 | "dev": true, 2368 | "requires": { 2369 | "call-bind": "^1.0.0", 2370 | "define-properties": "^1.1.3", 2371 | "has-symbols": "^1.0.1", 2372 | "object-keys": "^1.1.1" 2373 | } 2374 | }, 2375 | "object.entries": { 2376 | "version": "1.1.4", 2377 | "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", 2378 | "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", 2379 | "dev": true, 2380 | "requires": { 2381 | "call-bind": "^1.0.2", 2382 | "define-properties": "^1.1.3", 2383 | "es-abstract": "^1.18.2" 2384 | } 2385 | }, 2386 | "object.fromentries": { 2387 | "version": "2.0.4", 2388 | "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", 2389 | "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", 2390 | "dev": true, 2391 | "requires": { 2392 | "call-bind": "^1.0.2", 2393 | "define-properties": "^1.1.3", 2394 | "es-abstract": "^1.18.0-next.2", 2395 | "has": "^1.0.3" 2396 | } 2397 | }, 2398 | "object.values": { 2399 | "version": "1.1.4", 2400 | "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", 2401 | "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", 2402 | "dev": true, 2403 | "requires": { 2404 | "call-bind": "^1.0.2", 2405 | "define-properties": "^1.1.3", 2406 | "es-abstract": "^1.18.2" 2407 | } 2408 | }, 2409 | "once": { 2410 | "version": "1.4.0", 2411 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2412 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 2413 | "dev": true, 2414 | "requires": { 2415 | "wrappy": "1" 2416 | } 2417 | }, 2418 | "optionator": { 2419 | "version": "0.9.1", 2420 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 2421 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", 2422 | "dev": true, 2423 | "requires": { 2424 | "deep-is": "^0.1.3", 2425 | "fast-levenshtein": "^2.0.6", 2426 | "levn": "^0.4.1", 2427 | "prelude-ls": "^1.2.1", 2428 | "type-check": "^0.4.0", 2429 | "word-wrap": "^1.2.3" 2430 | } 2431 | }, 2432 | "p-limit": { 2433 | "version": "1.3.0", 2434 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 2435 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 2436 | "dev": true, 2437 | "requires": { 2438 | "p-try": "^1.0.0" 2439 | } 2440 | }, 2441 | "p-locate": { 2442 | "version": "2.0.0", 2443 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 2444 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 2445 | "dev": true, 2446 | "requires": { 2447 | "p-limit": "^1.1.0" 2448 | } 2449 | }, 2450 | "p-try": { 2451 | "version": "1.0.0", 2452 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 2453 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 2454 | "dev": true 2455 | }, 2456 | "packet-reader": { 2457 | "version": "1.0.0", 2458 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 2459 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 2460 | }, 2461 | "parent-module": { 2462 | "version": "1.0.1", 2463 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2464 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2465 | "dev": true, 2466 | "requires": { 2467 | "callsites": "^3.0.0" 2468 | } 2469 | }, 2470 | "parse-json": { 2471 | "version": "4.0.0", 2472 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", 2473 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", 2474 | "dev": true, 2475 | "requires": { 2476 | "error-ex": "^1.3.1", 2477 | "json-parse-better-errors": "^1.0.1" 2478 | } 2479 | }, 2480 | "path-exists": { 2481 | "version": "3.0.0", 2482 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 2483 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 2484 | "dev": true 2485 | }, 2486 | "path-is-absolute": { 2487 | "version": "1.0.1", 2488 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2489 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 2490 | "dev": true 2491 | }, 2492 | "path-key": { 2493 | "version": "3.1.1", 2494 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2495 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2496 | "dev": true 2497 | }, 2498 | "path-parse": { 2499 | "version": "1.0.7", 2500 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 2501 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 2502 | "dev": true 2503 | }, 2504 | "path-type": { 2505 | "version": "4.0.0", 2506 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 2507 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 2508 | "dev": true 2509 | }, 2510 | "pathval": { 2511 | "version": "1.1.1", 2512 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 2513 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 2514 | "dev": true 2515 | }, 2516 | "performance-now": { 2517 | "version": "2.1.0", 2518 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 2519 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 2520 | }, 2521 | "pg": { 2522 | "version": "8.7.1", 2523 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", 2524 | "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", 2525 | "requires": { 2526 | "buffer-writer": "2.0.0", 2527 | "packet-reader": "1.0.0", 2528 | "pg-connection-string": "^2.5.0", 2529 | "pg-pool": "^3.4.1", 2530 | "pg-protocol": "^1.5.0", 2531 | "pg-types": "^2.1.0", 2532 | "pgpass": "1.x" 2533 | } 2534 | }, 2535 | "pg-connection-string": { 2536 | "version": "2.5.0", 2537 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 2538 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 2539 | }, 2540 | "pg-hstore": { 2541 | "version": "2.3.4", 2542 | "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz", 2543 | "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==", 2544 | "requires": { 2545 | "underscore": "^1.13.1" 2546 | } 2547 | }, 2548 | "pg-int8": { 2549 | "version": "1.0.1", 2550 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 2551 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" 2552 | }, 2553 | "pg-pool": { 2554 | "version": "3.4.1", 2555 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", 2556 | "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==" 2557 | }, 2558 | "pg-protocol": { 2559 | "version": "1.5.0", 2560 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 2561 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 2562 | }, 2563 | "pg-types": { 2564 | "version": "2.2.0", 2565 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 2566 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 2567 | "requires": { 2568 | "pg-int8": "1.0.1", 2569 | "postgres-array": "~2.0.0", 2570 | "postgres-bytea": "~1.0.0", 2571 | "postgres-date": "~1.0.4", 2572 | "postgres-interval": "^1.1.0" 2573 | } 2574 | }, 2575 | "pgpass": { 2576 | "version": "1.0.4", 2577 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", 2578 | "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", 2579 | "requires": { 2580 | "split2": "^3.1.1" 2581 | } 2582 | }, 2583 | "picomatch": { 2584 | "version": "2.3.0", 2585 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", 2586 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", 2587 | "dev": true 2588 | }, 2589 | "pify": { 2590 | "version": "3.0.0", 2591 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 2592 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 2593 | "dev": true 2594 | }, 2595 | "pkg-dir": { 2596 | "version": "2.0.0", 2597 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", 2598 | "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", 2599 | "dev": true, 2600 | "requires": { 2601 | "find-up": "^2.1.0" 2602 | } 2603 | }, 2604 | "pkg-up": { 2605 | "version": "2.0.0", 2606 | "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", 2607 | "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", 2608 | "dev": true, 2609 | "requires": { 2610 | "find-up": "^2.1.0" 2611 | } 2612 | }, 2613 | "plex-api": { 2614 | "version": "5.3.1", 2615 | "resolved": "https://registry.npmjs.org/plex-api/-/plex-api-5.3.1.tgz", 2616 | "integrity": "sha512-WQVNOEqTCRx0/3oW5Orc+0OLAyQiDisCQ36mSVQHZOuuwXVj+l6WY9EksJzDXclp7Az3U8I/BNFDnopP1NxAFw==", 2617 | "requires": { 2618 | "plex-api-credentials": "3.0.1", 2619 | "plex-api-headers": "1.1.0", 2620 | "request": "^2.87.0", 2621 | "uuid": "2.0.2", 2622 | "xml2js": "0.4.16" 2623 | } 2624 | }, 2625 | "plex-api-credentials": { 2626 | "version": "3.0.1", 2627 | "resolved": "https://registry.npmjs.org/plex-api-credentials/-/plex-api-credentials-3.0.1.tgz", 2628 | "integrity": "sha512-E0PdSVSqE5rmdEFNsIvFPDJQZPdBX7UR4sgkm9HF4V8VNbX0N4elASnMuoste8i9eTh4hCIqt761NQfzl45XnQ==", 2629 | "requires": { 2630 | "bluebird": "^3.3.5", 2631 | "plex-api-headers": "1.1.0", 2632 | "request-promise": "4.2.4", 2633 | "xml2js": "0.4.19" 2634 | }, 2635 | "dependencies": { 2636 | "xml2js": { 2637 | "version": "0.4.19", 2638 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", 2639 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", 2640 | "requires": { 2641 | "sax": ">=0.6.0", 2642 | "xmlbuilder": "~9.0.1" 2643 | } 2644 | } 2645 | } 2646 | }, 2647 | "plex-api-headers": { 2648 | "version": "1.1.0", 2649 | "resolved": "https://registry.npmjs.org/plex-api-headers/-/plex-api-headers-1.1.0.tgz", 2650 | "integrity": "sha1-TONkcV2WSMzPLAZFgyee+HwS+/I=" 2651 | }, 2652 | "postgres-array": { 2653 | "version": "2.0.0", 2654 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 2655 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" 2656 | }, 2657 | "postgres-bytea": { 2658 | "version": "1.0.0", 2659 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 2660 | "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" 2661 | }, 2662 | "postgres-date": { 2663 | "version": "1.0.7", 2664 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 2665 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" 2666 | }, 2667 | "postgres-interval": { 2668 | "version": "1.2.0", 2669 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 2670 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 2671 | "requires": { 2672 | "xtend": "^4.0.0" 2673 | } 2674 | }, 2675 | "prelude-ls": { 2676 | "version": "1.2.1", 2677 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 2678 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 2679 | "dev": true 2680 | }, 2681 | "progress": { 2682 | "version": "2.0.3", 2683 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 2684 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 2685 | "dev": true 2686 | }, 2687 | "prop-types": { 2688 | "version": "15.7.2", 2689 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", 2690 | "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", 2691 | "dev": true, 2692 | "requires": { 2693 | "loose-envify": "^1.4.0", 2694 | "object-assign": "^4.1.1", 2695 | "react-is": "^16.8.1" 2696 | } 2697 | }, 2698 | "psl": { 2699 | "version": "1.8.0", 2700 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", 2701 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" 2702 | }, 2703 | "punycode": { 2704 | "version": "2.1.1", 2705 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 2706 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 2707 | }, 2708 | "qs": { 2709 | "version": "6.5.2", 2710 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 2711 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 2712 | }, 2713 | "querystringify": { 2714 | "version": "2.2.0", 2715 | "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", 2716 | "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" 2717 | }, 2718 | "queue-microtask": { 2719 | "version": "1.2.3", 2720 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 2721 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 2722 | "dev": true 2723 | }, 2724 | "randombytes": { 2725 | "version": "2.1.0", 2726 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 2727 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 2728 | "dev": true, 2729 | "requires": { 2730 | "safe-buffer": "^5.1.0" 2731 | } 2732 | }, 2733 | "react-is": { 2734 | "version": "16.13.1", 2735 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 2736 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", 2737 | "dev": true 2738 | }, 2739 | "read-pkg": { 2740 | "version": "3.0.0", 2741 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", 2742 | "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", 2743 | "dev": true, 2744 | "requires": { 2745 | "load-json-file": "^4.0.0", 2746 | "normalize-package-data": "^2.3.2", 2747 | "path-type": "^3.0.0" 2748 | }, 2749 | "dependencies": { 2750 | "path-type": { 2751 | "version": "3.0.0", 2752 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", 2753 | "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", 2754 | "dev": true, 2755 | "requires": { 2756 | "pify": "^3.0.0" 2757 | } 2758 | } 2759 | } 2760 | }, 2761 | "read-pkg-up": { 2762 | "version": "3.0.0", 2763 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", 2764 | "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", 2765 | "dev": true, 2766 | "requires": { 2767 | "find-up": "^2.0.0", 2768 | "read-pkg": "^3.0.0" 2769 | } 2770 | }, 2771 | "readable-stream": { 2772 | "version": "1.1.14", 2773 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 2774 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 2775 | "requires": { 2776 | "core-util-is": "~1.0.0", 2777 | "inherits": "~2.0.1", 2778 | "isarray": "0.0.1", 2779 | "string_decoder": "~0.10.x" 2780 | } 2781 | }, 2782 | "readdirp": { 2783 | "version": "3.5.0", 2784 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", 2785 | "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", 2786 | "dev": true, 2787 | "requires": { 2788 | "picomatch": "^2.2.1" 2789 | } 2790 | }, 2791 | "regenerator-runtime": { 2792 | "version": "0.13.9", 2793 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", 2794 | "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", 2795 | "dev": true 2796 | }, 2797 | "regexp.prototype.flags": { 2798 | "version": "1.3.1", 2799 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", 2800 | "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", 2801 | "dev": true, 2802 | "requires": { 2803 | "call-bind": "^1.0.2", 2804 | "define-properties": "^1.1.3" 2805 | } 2806 | }, 2807 | "regexpp": { 2808 | "version": "3.2.0", 2809 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", 2810 | "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", 2811 | "dev": true 2812 | }, 2813 | "request": { 2814 | "version": "2.88.2", 2815 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", 2816 | "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", 2817 | "requires": { 2818 | "aws-sign2": "~0.7.0", 2819 | "aws4": "^1.8.0", 2820 | "caseless": "~0.12.0", 2821 | "combined-stream": "~1.0.6", 2822 | "extend": "~3.0.2", 2823 | "forever-agent": "~0.6.1", 2824 | "form-data": "~2.3.2", 2825 | "har-validator": "~5.1.3", 2826 | "http-signature": "~1.2.0", 2827 | "is-typedarray": "~1.0.0", 2828 | "isstream": "~0.1.2", 2829 | "json-stringify-safe": "~5.0.1", 2830 | "mime-types": "~2.1.19", 2831 | "oauth-sign": "~0.9.0", 2832 | "performance-now": "^2.1.0", 2833 | "qs": "~6.5.2", 2834 | "safe-buffer": "^5.1.2", 2835 | "tough-cookie": "~2.5.0", 2836 | "tunnel-agent": "^0.6.0", 2837 | "uuid": "^3.3.2" 2838 | }, 2839 | "dependencies": { 2840 | "uuid": { 2841 | "version": "3.4.0", 2842 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", 2843 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" 2844 | } 2845 | } 2846 | }, 2847 | "request-promise": { 2848 | "version": "4.2.4", 2849 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz", 2850 | "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==", 2851 | "requires": { 2852 | "bluebird": "^3.5.0", 2853 | "request-promise-core": "1.1.2", 2854 | "stealthy-require": "^1.1.1", 2855 | "tough-cookie": "^2.3.3" 2856 | } 2857 | }, 2858 | "request-promise-core": { 2859 | "version": "1.1.2", 2860 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", 2861 | "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", 2862 | "requires": { 2863 | "lodash": "^4.17.11" 2864 | } 2865 | }, 2866 | "require-directory": { 2867 | "version": "2.1.1", 2868 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 2869 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 2870 | "dev": true 2871 | }, 2872 | "require-from-string": { 2873 | "version": "2.0.2", 2874 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 2875 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 2876 | "dev": true 2877 | }, 2878 | "requires-port": { 2879 | "version": "1.0.0", 2880 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 2881 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" 2882 | }, 2883 | "resolve": { 2884 | "version": "1.20.0", 2885 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 2886 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 2887 | "dev": true, 2888 | "requires": { 2889 | "is-core-module": "^2.2.0", 2890 | "path-parse": "^1.0.6" 2891 | } 2892 | }, 2893 | "resolve-from": { 2894 | "version": "4.0.0", 2895 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2896 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2897 | "dev": true 2898 | }, 2899 | "retry-as-promised": { 2900 | "version": "3.2.0", 2901 | "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", 2902 | "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", 2903 | "requires": { 2904 | "any-promise": "^1.3.0" 2905 | } 2906 | }, 2907 | "reusify": { 2908 | "version": "1.0.4", 2909 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 2910 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 2911 | "dev": true 2912 | }, 2913 | "rimraf": { 2914 | "version": "3.0.2", 2915 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 2916 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 2917 | "dev": true, 2918 | "requires": { 2919 | "glob": "^7.1.3" 2920 | } 2921 | }, 2922 | "run-parallel": { 2923 | "version": "1.2.0", 2924 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 2925 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 2926 | "dev": true, 2927 | "requires": { 2928 | "queue-microtask": "^1.2.2" 2929 | } 2930 | }, 2931 | "safe-buffer": { 2932 | "version": "5.2.1", 2933 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2934 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 2935 | }, 2936 | "safer-buffer": { 2937 | "version": "2.1.2", 2938 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2939 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 2940 | }, 2941 | "sax": { 2942 | "version": "1.2.4", 2943 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 2944 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 2945 | }, 2946 | "semver": { 2947 | "version": "7.3.5", 2948 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", 2949 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", 2950 | "requires": { 2951 | "lru-cache": "^6.0.0" 2952 | } 2953 | }, 2954 | "sequelize": { 2955 | "version": "6.6.2", 2956 | "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.6.2.tgz", 2957 | "integrity": "sha512-H/zrzmTK+tis9PJaSigkuXI57nKBvNCtPQol0yxCvau1iWLzSOuq8t3tMOVeQ+Ep8QH2HoD9/+FCCIAqzUr/BQ==", 2958 | "requires": { 2959 | "debug": "^4.1.1", 2960 | "dottie": "^2.0.0", 2961 | "inflection": "1.12.0", 2962 | "lodash": "^4.17.20", 2963 | "moment": "^2.26.0", 2964 | "moment-timezone": "^0.5.31", 2965 | "retry-as-promised": "^3.2.0", 2966 | "semver": "^7.3.2", 2967 | "sequelize-pool": "^6.0.0", 2968 | "toposort-class": "^1.0.1", 2969 | "uuid": "^8.1.0", 2970 | "validator": "^10.11.0", 2971 | "wkx": "^0.5.0" 2972 | }, 2973 | "dependencies": { 2974 | "debug": { 2975 | "version": "4.3.2", 2976 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 2977 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 2978 | "requires": { 2979 | "ms": "2.1.2" 2980 | } 2981 | }, 2982 | "ms": { 2983 | "version": "2.1.2", 2984 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2985 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 2986 | }, 2987 | "uuid": { 2988 | "version": "8.3.2", 2989 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 2990 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" 2991 | } 2992 | } 2993 | }, 2994 | "sequelize-pool": { 2995 | "version": "6.1.0", 2996 | "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", 2997 | "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==" 2998 | }, 2999 | "serialize-javascript": { 3000 | "version": "5.0.1", 3001 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", 3002 | "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", 3003 | "dev": true, 3004 | "requires": { 3005 | "randombytes": "^2.1.0" 3006 | } 3007 | }, 3008 | "shebang-command": { 3009 | "version": "2.0.0", 3010 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 3011 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 3012 | "dev": true, 3013 | "requires": { 3014 | "shebang-regex": "^3.0.0" 3015 | } 3016 | }, 3017 | "shebang-regex": { 3018 | "version": "3.0.0", 3019 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 3020 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 3021 | "dev": true 3022 | }, 3023 | "side-channel": { 3024 | "version": "1.0.4", 3025 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 3026 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 3027 | "dev": true, 3028 | "requires": { 3029 | "call-bind": "^1.0.0", 3030 | "get-intrinsic": "^1.0.2", 3031 | "object-inspect": "^1.9.0" 3032 | } 3033 | }, 3034 | "slash": { 3035 | "version": "3.0.0", 3036 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 3037 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 3038 | "dev": true 3039 | }, 3040 | "slice-ansi": { 3041 | "version": "4.0.0", 3042 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", 3043 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", 3044 | "dev": true, 3045 | "requires": { 3046 | "ansi-styles": "^4.0.0", 3047 | "astral-regex": "^2.0.0", 3048 | "is-fullwidth-code-point": "^3.0.0" 3049 | }, 3050 | "dependencies": { 3051 | "ansi-styles": { 3052 | "version": "4.3.0", 3053 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 3054 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 3055 | "dev": true, 3056 | "requires": { 3057 | "color-convert": "^2.0.1" 3058 | } 3059 | }, 3060 | "color-convert": { 3061 | "version": "2.0.1", 3062 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 3063 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 3064 | "dev": true, 3065 | "requires": { 3066 | "color-name": "~1.1.4" 3067 | } 3068 | }, 3069 | "color-name": { 3070 | "version": "1.1.4", 3071 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 3072 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 3073 | "dev": true 3074 | } 3075 | } 3076 | }, 3077 | "source-map": { 3078 | "version": "0.6.1", 3079 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 3080 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 3081 | "dev": true 3082 | }, 3083 | "source-map-support": { 3084 | "version": "0.5.19", 3085 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 3086 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 3087 | "dev": true, 3088 | "requires": { 3089 | "buffer-from": "^1.0.0", 3090 | "source-map": "^0.6.0" 3091 | } 3092 | }, 3093 | "spdx-correct": { 3094 | "version": "3.1.1", 3095 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", 3096 | "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", 3097 | "dev": true, 3098 | "requires": { 3099 | "spdx-expression-parse": "^3.0.0", 3100 | "spdx-license-ids": "^3.0.0" 3101 | } 3102 | }, 3103 | "spdx-exceptions": { 3104 | "version": "2.3.0", 3105 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", 3106 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", 3107 | "dev": true 3108 | }, 3109 | "spdx-expression-parse": { 3110 | "version": "3.0.1", 3111 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", 3112 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", 3113 | "dev": true, 3114 | "requires": { 3115 | "spdx-exceptions": "^2.1.0", 3116 | "spdx-license-ids": "^3.0.0" 3117 | } 3118 | }, 3119 | "spdx-license-ids": { 3120 | "version": "3.0.10", 3121 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", 3122 | "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", 3123 | "dev": true 3124 | }, 3125 | "split2": { 3126 | "version": "3.2.2", 3127 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 3128 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 3129 | "requires": { 3130 | "readable-stream": "^3.0.0" 3131 | }, 3132 | "dependencies": { 3133 | "readable-stream": { 3134 | "version": "3.6.0", 3135 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 3136 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 3137 | "requires": { 3138 | "inherits": "^2.0.3", 3139 | "string_decoder": "^1.1.1", 3140 | "util-deprecate": "^1.0.1" 3141 | } 3142 | }, 3143 | "string_decoder": { 3144 | "version": "1.3.0", 3145 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 3146 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 3147 | "requires": { 3148 | "safe-buffer": "~5.2.0" 3149 | } 3150 | } 3151 | } 3152 | }, 3153 | "sprintf-js": { 3154 | "version": "1.0.3", 3155 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 3156 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 3157 | "dev": true 3158 | }, 3159 | "sshpk": { 3160 | "version": "1.16.1", 3161 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 3162 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 3163 | "requires": { 3164 | "asn1": "~0.2.3", 3165 | "assert-plus": "^1.0.0", 3166 | "bcrypt-pbkdf": "^1.0.0", 3167 | "dashdash": "^1.12.0", 3168 | "ecc-jsbn": "~0.1.1", 3169 | "getpass": "^0.1.1", 3170 | "jsbn": "~0.1.0", 3171 | "safer-buffer": "^2.0.2", 3172 | "tweetnacl": "~0.14.0" 3173 | } 3174 | }, 3175 | "stealthy-require": { 3176 | "version": "1.1.1", 3177 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 3178 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 3179 | }, 3180 | "string-width": { 3181 | "version": "4.2.2", 3182 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", 3183 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", 3184 | "dev": true, 3185 | "requires": { 3186 | "emoji-regex": "^8.0.0", 3187 | "is-fullwidth-code-point": "^3.0.0", 3188 | "strip-ansi": "^6.0.0" 3189 | } 3190 | }, 3191 | "string.prototype.matchall": { 3192 | "version": "4.0.5", 3193 | "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", 3194 | "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", 3195 | "dev": true, 3196 | "requires": { 3197 | "call-bind": "^1.0.2", 3198 | "define-properties": "^1.1.3", 3199 | "es-abstract": "^1.18.2", 3200 | "get-intrinsic": "^1.1.1", 3201 | "has-symbols": "^1.0.2", 3202 | "internal-slot": "^1.0.3", 3203 | "regexp.prototype.flags": "^1.3.1", 3204 | "side-channel": "^1.0.4" 3205 | } 3206 | }, 3207 | "string.prototype.trimend": { 3208 | "version": "1.0.4", 3209 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", 3210 | "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", 3211 | "dev": true, 3212 | "requires": { 3213 | "call-bind": "^1.0.2", 3214 | "define-properties": "^1.1.3" 3215 | } 3216 | }, 3217 | "string.prototype.trimstart": { 3218 | "version": "1.0.4", 3219 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", 3220 | "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", 3221 | "dev": true, 3222 | "requires": { 3223 | "call-bind": "^1.0.2", 3224 | "define-properties": "^1.1.3" 3225 | } 3226 | }, 3227 | "string_decoder": { 3228 | "version": "0.10.31", 3229 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 3230 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 3231 | }, 3232 | "strip-ansi": { 3233 | "version": "6.0.0", 3234 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 3235 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 3236 | "dev": true, 3237 | "requires": { 3238 | "ansi-regex": "^5.0.0" 3239 | } 3240 | }, 3241 | "strip-bom": { 3242 | "version": "3.0.0", 3243 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 3244 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 3245 | "dev": true 3246 | }, 3247 | "strip-json-comments": { 3248 | "version": "3.1.1", 3249 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 3250 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 3251 | "dev": true 3252 | }, 3253 | "supports-color": { 3254 | "version": "5.5.0", 3255 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 3256 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 3257 | "dev": true, 3258 | "requires": { 3259 | "has-flag": "^3.0.0" 3260 | } 3261 | }, 3262 | "table": { 3263 | "version": "6.7.1", 3264 | "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", 3265 | "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", 3266 | "dev": true, 3267 | "requires": { 3268 | "ajv": "^8.0.1", 3269 | "lodash.clonedeep": "^4.5.0", 3270 | "lodash.truncate": "^4.4.2", 3271 | "slice-ansi": "^4.0.0", 3272 | "string-width": "^4.2.0", 3273 | "strip-ansi": "^6.0.0" 3274 | }, 3275 | "dependencies": { 3276 | "ajv": { 3277 | "version": "8.6.2", 3278 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", 3279 | "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", 3280 | "dev": true, 3281 | "requires": { 3282 | "fast-deep-equal": "^3.1.1", 3283 | "json-schema-traverse": "^1.0.0", 3284 | "require-from-string": "^2.0.2", 3285 | "uri-js": "^4.2.2" 3286 | } 3287 | }, 3288 | "json-schema-traverse": { 3289 | "version": "1.0.0", 3290 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 3291 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 3292 | "dev": true 3293 | } 3294 | } 3295 | }, 3296 | "text-table": { 3297 | "version": "0.2.0", 3298 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 3299 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 3300 | "dev": true 3301 | }, 3302 | "to-regex-range": { 3303 | "version": "5.0.1", 3304 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 3305 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 3306 | "dev": true, 3307 | "requires": { 3308 | "is-number": "^7.0.0" 3309 | } 3310 | }, 3311 | "toposort-class": { 3312 | "version": "1.0.1", 3313 | "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", 3314 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" 3315 | }, 3316 | "tough-cookie": { 3317 | "version": "2.5.0", 3318 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", 3319 | "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", 3320 | "requires": { 3321 | "psl": "^1.1.28", 3322 | "punycode": "^2.1.1" 3323 | } 3324 | }, 3325 | "ts-node": { 3326 | "version": "10.0.0", 3327 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz", 3328 | "integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==", 3329 | "dev": true, 3330 | "requires": { 3331 | "@tsconfig/node10": "^1.0.7", 3332 | "@tsconfig/node12": "^1.0.7", 3333 | "@tsconfig/node14": "^1.0.0", 3334 | "@tsconfig/node16": "^1.0.1", 3335 | "arg": "^4.1.0", 3336 | "create-require": "^1.1.0", 3337 | "diff": "^4.0.1", 3338 | "make-error": "^1.1.1", 3339 | "source-map-support": "^0.5.17", 3340 | "yn": "3.1.1" 3341 | }, 3342 | "dependencies": { 3343 | "diff": { 3344 | "version": "4.0.2", 3345 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 3346 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 3347 | "dev": true 3348 | } 3349 | } 3350 | }, 3351 | "tsconfig-paths": { 3352 | "version": "3.11.0", 3353 | "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", 3354 | "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", 3355 | "dev": true, 3356 | "requires": { 3357 | "@types/json5": "^0.0.29", 3358 | "json5": "^1.0.1", 3359 | "minimist": "^1.2.0", 3360 | "strip-bom": "^3.0.0" 3361 | } 3362 | }, 3363 | "tslib": { 3364 | "version": "1.14.1", 3365 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 3366 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 3367 | "dev": true 3368 | }, 3369 | "tsutils": { 3370 | "version": "3.21.0", 3371 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", 3372 | "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", 3373 | "dev": true, 3374 | "requires": { 3375 | "tslib": "^1.8.1" 3376 | } 3377 | }, 3378 | "tunnel-agent": { 3379 | "version": "0.6.0", 3380 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 3381 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 3382 | "requires": { 3383 | "safe-buffer": "^5.0.1" 3384 | } 3385 | }, 3386 | "tweetnacl": { 3387 | "version": "0.14.5", 3388 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 3389 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 3390 | }, 3391 | "type-check": { 3392 | "version": "0.4.0", 3393 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 3394 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 3395 | "dev": true, 3396 | "requires": { 3397 | "prelude-ls": "^1.2.1" 3398 | } 3399 | }, 3400 | "type-detect": { 3401 | "version": "4.0.8", 3402 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 3403 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 3404 | "dev": true 3405 | }, 3406 | "type-fest": { 3407 | "version": "0.20.2", 3408 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 3409 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 3410 | "dev": true 3411 | }, 3412 | "typescript": { 3413 | "version": "4.3.4", 3414 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", 3415 | "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", 3416 | "dev": true 3417 | }, 3418 | "unbox-primitive": { 3419 | "version": "1.0.1", 3420 | "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", 3421 | "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", 3422 | "dev": true, 3423 | "requires": { 3424 | "function-bind": "^1.1.1", 3425 | "has-bigints": "^1.0.1", 3426 | "has-symbols": "^1.0.2", 3427 | "which-boxed-primitive": "^1.0.2" 3428 | } 3429 | }, 3430 | "underscore": { 3431 | "version": "1.13.1", 3432 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", 3433 | "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" 3434 | }, 3435 | "uri-js": { 3436 | "version": "4.4.1", 3437 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 3438 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 3439 | "requires": { 3440 | "punycode": "^2.1.0" 3441 | } 3442 | }, 3443 | "url-parse": { 3444 | "version": "1.5.3", 3445 | "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", 3446 | "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", 3447 | "requires": { 3448 | "querystringify": "^2.1.1", 3449 | "requires-port": "^1.0.0" 3450 | } 3451 | }, 3452 | "util-deprecate": { 3453 | "version": "1.0.2", 3454 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 3455 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 3456 | }, 3457 | "uuid": { 3458 | "version": "2.0.2", 3459 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.2.tgz", 3460 | "integrity": "sha1-SL1WmPBnfjx5AaHEbvFbFkN5RyY=" 3461 | }, 3462 | "v8-compile-cache": { 3463 | "version": "2.3.0", 3464 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", 3465 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", 3466 | "dev": true 3467 | }, 3468 | "validate-npm-package-license": { 3469 | "version": "3.0.4", 3470 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 3471 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 3472 | "dev": true, 3473 | "requires": { 3474 | "spdx-correct": "^3.0.0", 3475 | "spdx-expression-parse": "^3.0.0" 3476 | } 3477 | }, 3478 | "validator": { 3479 | "version": "10.11.0", 3480 | "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", 3481 | "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" 3482 | }, 3483 | "verror": { 3484 | "version": "1.10.0", 3485 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 3486 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 3487 | "requires": { 3488 | "assert-plus": "^1.0.0", 3489 | "core-util-is": "1.0.2", 3490 | "extsprintf": "^1.2.0" 3491 | } 3492 | }, 3493 | "which": { 3494 | "version": "2.0.2", 3495 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 3496 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 3497 | "dev": true, 3498 | "requires": { 3499 | "isexe": "^2.0.0" 3500 | } 3501 | }, 3502 | "which-boxed-primitive": { 3503 | "version": "1.0.2", 3504 | "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", 3505 | "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", 3506 | "dev": true, 3507 | "requires": { 3508 | "is-bigint": "^1.0.1", 3509 | "is-boolean-object": "^1.1.0", 3510 | "is-number-object": "^1.0.4", 3511 | "is-string": "^1.0.5", 3512 | "is-symbol": "^1.0.3" 3513 | } 3514 | }, 3515 | "wide-align": { 3516 | "version": "1.1.3", 3517 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 3518 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 3519 | "dev": true, 3520 | "requires": { 3521 | "string-width": "^1.0.2 || 2" 3522 | }, 3523 | "dependencies": { 3524 | "ansi-regex": { 3525 | "version": "3.0.0", 3526 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 3527 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 3528 | "dev": true 3529 | }, 3530 | "is-fullwidth-code-point": { 3531 | "version": "2.0.0", 3532 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 3533 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 3534 | "dev": true 3535 | }, 3536 | "string-width": { 3537 | "version": "2.1.1", 3538 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 3539 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 3540 | "dev": true, 3541 | "requires": { 3542 | "is-fullwidth-code-point": "^2.0.0", 3543 | "strip-ansi": "^4.0.0" 3544 | } 3545 | }, 3546 | "strip-ansi": { 3547 | "version": "4.0.0", 3548 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 3549 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 3550 | "dev": true, 3551 | "requires": { 3552 | "ansi-regex": "^3.0.0" 3553 | } 3554 | } 3555 | } 3556 | }, 3557 | "wkx": { 3558 | "version": "0.5.0", 3559 | "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", 3560 | "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", 3561 | "requires": { 3562 | "@types/node": "*" 3563 | } 3564 | }, 3565 | "word-wrap": { 3566 | "version": "1.2.3", 3567 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 3568 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 3569 | "dev": true 3570 | }, 3571 | "workerpool": { 3572 | "version": "6.1.4", 3573 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.4.tgz", 3574 | "integrity": "sha512-jGWPzsUqzkow8HoAvqaPWTUPCrlPJaJ5tY8Iz7n1uCz3tTp6s3CDG0FF1NsX42WNlkRSW6Mr+CDZGnNoSsKa7g==", 3575 | "dev": true 3576 | }, 3577 | "wrap-ansi": { 3578 | "version": "7.0.0", 3579 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 3580 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 3581 | "dev": true, 3582 | "requires": { 3583 | "ansi-styles": "^4.0.0", 3584 | "string-width": "^4.1.0", 3585 | "strip-ansi": "^6.0.0" 3586 | }, 3587 | "dependencies": { 3588 | "ansi-styles": { 3589 | "version": "4.3.0", 3590 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 3591 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 3592 | "dev": true, 3593 | "requires": { 3594 | "color-convert": "^2.0.1" 3595 | } 3596 | }, 3597 | "color-convert": { 3598 | "version": "2.0.1", 3599 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 3600 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 3601 | "dev": true, 3602 | "requires": { 3603 | "color-name": "~1.1.4" 3604 | } 3605 | }, 3606 | "color-name": { 3607 | "version": "1.1.4", 3608 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 3609 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 3610 | "dev": true 3611 | } 3612 | } 3613 | }, 3614 | "wrappy": { 3615 | "version": "1.0.2", 3616 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 3617 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 3618 | "dev": true 3619 | }, 3620 | "ws": { 3621 | "version": "7.5.0", 3622 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", 3623 | "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==" 3624 | }, 3625 | "xml2js": { 3626 | "version": "0.4.16", 3627 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.16.tgz", 3628 | "integrity": "sha1-+C/M0vlUDX4Km12sFj50cRlcnbM=", 3629 | "requires": { 3630 | "sax": ">=0.6.0", 3631 | "xmlbuilder": "^4.1.0" 3632 | }, 3633 | "dependencies": { 3634 | "xmlbuilder": { 3635 | "version": "4.2.1", 3636 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", 3637 | "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", 3638 | "requires": { 3639 | "lodash": "^4.0.0" 3640 | } 3641 | } 3642 | } 3643 | }, 3644 | "xmlbuilder": { 3645 | "version": "9.0.7", 3646 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", 3647 | "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" 3648 | }, 3649 | "xtend": { 3650 | "version": "4.0.2", 3651 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 3652 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 3653 | }, 3654 | "y18n": { 3655 | "version": "5.0.8", 3656 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 3657 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 3658 | "dev": true 3659 | }, 3660 | "yallist": { 3661 | "version": "4.0.0", 3662 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 3663 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 3664 | }, 3665 | "yargs": { 3666 | "version": "16.2.0", 3667 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 3668 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 3669 | "dev": true, 3670 | "requires": { 3671 | "cliui": "^7.0.2", 3672 | "escalade": "^3.1.1", 3673 | "get-caller-file": "^2.0.5", 3674 | "require-directory": "^2.1.1", 3675 | "string-width": "^4.2.0", 3676 | "y18n": "^5.0.5", 3677 | "yargs-parser": "^20.2.2" 3678 | } 3679 | }, 3680 | "yargs-parser": { 3681 | "version": "20.2.4", 3682 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 3683 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 3684 | "dev": true 3685 | }, 3686 | "yargs-unparser": { 3687 | "version": "2.0.0", 3688 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 3689 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 3690 | "dev": true, 3691 | "requires": { 3692 | "camelcase": "^6.0.0", 3693 | "decamelize": "^4.0.0", 3694 | "flat": "^5.0.2", 3695 | "is-plain-obj": "^2.1.0" 3696 | } 3697 | }, 3698 | "yn": { 3699 | "version": "3.1.1", 3700 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 3701 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 3702 | "dev": true 3703 | }, 3704 | "yocto-queue": { 3705 | "version": "0.1.0", 3706 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 3707 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 3708 | "dev": true 3709 | } 3710 | } 3711 | } 3712 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "main": "dist/index.js", 7 | "scripts": { 8 | "build": "NODE_ENV=production tsc -p tsconfig.json", 9 | "debug": "rm -rf dist && NODE_ENV=production tsc -p tsconfig.json --sourceMap", 10 | "test": "TS_NODE_PROJECT='./tsconfig.testing.json' mocha --exit -r ts-node/register tests/**/*.ts" 11 | }, 12 | "devDependencies": { 13 | "@types/amqplib": "0.8.0", 14 | "@types/axios": "0.14.0", 15 | "@types/chai": "4.2.18", 16 | "@types/cron": "1.7.2", 17 | "@types/mocha": "8.2.2", 18 | "@types/ws": "7.4.5", 19 | "@typescript-eslint/eslint-plugin": "4.27.0", 20 | "@typescript-eslint/parser": "4.27.0", 21 | "chai": "4.3.4", 22 | "eslint": "7.29.0", 23 | "eslint-config-airbnb-typescript": "12.3.1", 24 | "eslint-plugin-import": "2.23.4", 25 | "eslint-plugin-jsx-a11y": "6.4.1", 26 | "eslint-plugin-react": "7.24.0", 27 | "eslint-plugin-react-hooks": "4.2.0", 28 | "mocha": "9.0.1", 29 | "ts-node": "10.0.0", 30 | "typescript": "4.3.4" 31 | }, 32 | "dependencies": { 33 | "axios": "0.21.1", 34 | "cron": "1.8.2", 35 | "nodejsmq": "1.0.3", 36 | "pg": "8.7.1", 37 | "pg-hstore": "2.3.4", 38 | "plex-api": "5.3.1", 39 | "sequelize": "6.6.2", 40 | "ws": "7.5.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/config.ts: -------------------------------------------------------------------------------- 1 | export const { 2 | RABBITMQ_URL, 3 | DATABASE_URL, 4 | QUEUE_NAME = 'plex', 5 | BUILD = 'production', 6 | NODENAME = 'localhost', 7 | 8 | PLEXUSERNAME, 9 | PLEXPASSWORD, 10 | STARTUP_DELAY = '0', 11 | OPERATION_MODE = 'sidecar', 12 | SCAN_LIMIT = 10, 13 | 14 | KUBERNETES_IP, 15 | PLEXLOCAL_IP = '127.0.0.1', 16 | MONTHLY_CRON, 17 | DAILY_CRON, 18 | CRON_TIMEZONE, 19 | } = process.env; 20 | 21 | export const DEVMODE = (process.env.DEVMODE || process.env.NODE_ENV) === 'development'; 22 | export const controllerMode = OPERATION_MODE === 'controller'; 23 | export const queueName = (controllerMode) ? QUEUE_NAME : `${QUEUE_NAME}.${NODENAME}`; 24 | export const routingKey = ''; 25 | export const exchangeName = 'amq.fanout'; 26 | -------------------------------------------------------------------------------- /src/com/database.ts: -------------------------------------------------------------------------------- 1 | import { Sequelize, QueryTypes } from 'sequelize'; 2 | import { DATABASE_URL, DEVMODE } from './config'; 3 | import { error } from './log'; 4 | 5 | const sequelize = new Sequelize( 6 | DATABASE_URL || '', 7 | { 8 | logging: DEVMODE, 9 | dialect: 'postgres', 10 | }, 11 | ); 12 | 13 | sequelize 14 | .authenticate() 15 | .catch((e) => { 16 | error('database: error connecting to database', e.message || e); 17 | process.exit(1); 18 | }); 19 | 20 | export const type = QueryTypes.SELECT; 21 | 22 | export const close = () => sequelize.close(); 23 | 24 | export default sequelize; 25 | -------------------------------------------------------------------------------- /src/com/db/associations.ts: -------------------------------------------------------------------------------- 1 | import User from './models/user'; 2 | import UserPlayback from './models/userplayback'; 3 | 4 | const makeAssociations = () => User.hasMany(UserPlayback); 5 | 6 | export default makeAssociations; 7 | -------------------------------------------------------------------------------- /src/com/db/migrate.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import { QUEUE_NAME as service } from '../config'; 4 | import sequelize from '../database'; 5 | import Migration from './models/migration'; 6 | import MakeAssociation from './associations'; 7 | import { critical, info } from '../log'; 8 | 9 | interface MigrationType { 10 | run(): Promise, 11 | version: number, 12 | } 13 | 14 | const migrationPath = path.join(__dirname, 'migrations'); 15 | const migrations: Promise = Promise.all( 16 | fs.readdirSync(migrationPath) 17 | .map( 18 | (f) => import(path.join(migrationPath, f)) 19 | .then((module) => ({ 20 | run: module.default, 21 | version: parseInt(f.replace(/\D+/g, ''), 10), 22 | })), 23 | ), 24 | ); 25 | 26 | const migrate = async (tasks: MigrationType[] | false = false): Promise => { 27 | if (tasks === false) { 28 | info('Starting to run migrations'); 29 | await sequelize.authenticate(); 30 | await Migration.sync(); 31 | const Migrations = await migrations; 32 | const Version = await Migration.findOne({ where: { service }, order: [['version', 'DESC']] }); 33 | 34 | if (Version) { 35 | const version = await migrate( 36 | Migrations 37 | .filter((m) => m.version > Version.version) 38 | .sort((a, b) => a.version - b.version), 39 | ); 40 | info('Finished running migrations'); 41 | await MakeAssociation(); 42 | return version; 43 | } 44 | 45 | // handle where there is no version 46 | const latestVersion = Migrations.sort((a, b) => a.version - b.version); 47 | const firstVersion = Migrations.find((a) => a.version === 0); 48 | if (firstVersion) { 49 | await firstVersion.run(); 50 | } 51 | await Migration.create({ service, version: latestVersion[latestVersion.length - 1].version }); 52 | return migrate(false); 53 | } 54 | 55 | if (tasks.length === 0) { 56 | const Version = await Migration.findOne({ where: { service }, order: [['version', 'DESC']] }); 57 | if (Version) { 58 | return Version.version; 59 | } 60 | return -1; 61 | } 62 | 63 | const [{ run, version }] = tasks; 64 | tasks.shift(); 65 | info('Running migration version:', version); 66 | 67 | return run() 68 | .then(() => Migration.create({ service, version })) 69 | .then(() => info('Upgraded to version', version)) 70 | .catch((e) => { 71 | critical('Migration version', version, 'failed', e.message || e); 72 | process.exit(1); 73 | }) 74 | .then(() => migrate(tasks)); 75 | }; 76 | 77 | export default migrate; 78 | -------------------------------------------------------------------------------- /src/com/db/migrations/version0.ts: -------------------------------------------------------------------------------- 1 | import User from '../models/user'; 2 | import UserPlayback from '../models/userplayback'; 3 | 4 | const run = () => Promise.all([ 5 | User.sync({ force: true }), 6 | UserPlayback.sync({ force: true }), 7 | ]); 8 | 9 | export default run; 10 | -------------------------------------------------------------------------------- /src/com/db/migrations/version1.ts: -------------------------------------------------------------------------------- 1 | import { QueryTypes } from 'sequelize'; 2 | import sequelize from '../../database'; 3 | import { setPlayback } from '../models/user'; 4 | import UserPlayback from '../models/userplayback'; 5 | 6 | const run = () => sequelize.query( 7 | 'SELECT * FROM userplaybacks', 8 | { type: QueryTypes.SELECT }, 9 | ) 10 | .then( 11 | // @ts-ignore 12 | ( 13 | playbacks: { email: string, libraryTitle: string, title: string, time: number }[], 14 | ) => { 15 | const rawPlaybacks: { 16 | email: string, libraryTitle: string, title: string, time: number, 17 | }[] = playbacks.map( 18 | ({ 19 | email, libraryTitle, title, time, 20 | }) => ({ 21 | email, libraryTitle, title, time, 22 | }), 23 | ); 24 | 25 | return UserPlayback.sync({ force: true }) 26 | .then( 27 | () => Promise.all([ 28 | rawPlaybacks 29 | .map( 30 | // @ts-ignore 31 | (p) => setPlayback( 32 | p.email, 33 | p.libraryTitle, 34 | p.title, 35 | p.time, 36 | ), 37 | ), 38 | ]), 39 | ); 40 | }, 41 | ); 42 | 43 | export default run; 44 | -------------------------------------------------------------------------------- /src/com/db/migrations/version2.ts: -------------------------------------------------------------------------------- 1 | import User from '../models/user'; 2 | import UserPlayback from '../models/userplayback'; 3 | 4 | const run = async () => { 5 | await User.sync({ force: true }); 6 | await UserPlayback.sync({ force: true }); 7 | }; 8 | 9 | export default run; 10 | -------------------------------------------------------------------------------- /src/com/db/migrations/version3.ts: -------------------------------------------------------------------------------- 1 | import UserPlayback from '../models/userplayback'; 2 | 3 | const run = () => UserPlayback.sync({ force: true }); 4 | 5 | export default run; 6 | -------------------------------------------------------------------------------- /src/com/db/models/migration.ts: -------------------------------------------------------------------------------- 1 | import { DataTypes, Model, Optional } from 'sequelize'; 2 | import sequelize from '../../database'; 3 | 4 | interface MigrationAttributes { 5 | id: number, 6 | service: string, 7 | version: number, 8 | } 9 | 10 | interface MigrationCreationAttributes extends Optional { } 11 | 12 | export default class Migration extends Model 13 | implements MigrationAttributes { 14 | public id!: number; 15 | 16 | public service!: string; 17 | 18 | public version!: number; 19 | 20 | public readonly createdAt!: Date; 21 | 22 | public readonly updatedAt!: Date; 23 | } 24 | 25 | Migration.init( 26 | { 27 | id: { 28 | type: DataTypes.INTEGER.UNSIGNED, 29 | autoIncrement: true, 30 | primaryKey: true, 31 | }, 32 | service: { 33 | type: DataTypes.STRING, 34 | allowNull: false, 35 | }, 36 | version: { 37 | type: DataTypes.INTEGER, 38 | allowNull: false, 39 | }, 40 | }, 41 | { 42 | sequelize, 43 | tableName: 'migrations', 44 | indexes: [ 45 | { 46 | unique: true, 47 | fields: ['service', 'version'], 48 | }, 49 | ], 50 | }, 51 | ); 52 | -------------------------------------------------------------------------------- /src/com/db/models/user.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Association, 3 | DataTypes, 4 | HasManyAddAssociationMixin, 5 | HasManyCreateAssociationMixin, 6 | HasManyGetAssociationsMixin, 7 | HasManyHasAssociationMixin, 8 | Model, 9 | Optional, 10 | Op, 11 | } from 'sequelize'; 12 | import sequelize from '../../database'; 13 | import UserPlayback from './userplayback'; 14 | 15 | interface UserAttributes { 16 | id: number, 17 | name: string, 18 | email: string, 19 | } 20 | 21 | interface UserCreationAttributes extends Optional { } 22 | 23 | export default class User extends Model 24 | implements UserAttributes { 25 | public id!: number; 26 | 27 | public name!: string; 28 | 29 | public email!: string; 30 | 31 | public readonly createdAt!: Date; 32 | 33 | public readonly updatedAt!: Date; 34 | 35 | public getUserPlaybacks!: HasManyGetAssociationsMixin; 36 | 37 | public addUserPlayback!: HasManyAddAssociationMixin; 38 | 39 | public hasUserPlayback!: HasManyHasAssociationMixin; 40 | 41 | public createUserPlayback!: HasManyCreateAssociationMixin; 42 | 43 | public readonly UserPlaybacks?: UserPlayback[]; 44 | 45 | public static associations: { 46 | UserPlaybacks: Association; 47 | }; 48 | } 49 | 50 | User.init( 51 | { 52 | id: { 53 | type: DataTypes.INTEGER.UNSIGNED, 54 | autoIncrement: true, 55 | primaryKey: true, 56 | }, 57 | name: { 58 | type: DataTypes.STRING, 59 | allowNull: false, 60 | }, 61 | email: { 62 | type: DataTypes.STRING, 63 | allowNull: false, 64 | }, 65 | }, 66 | { 67 | sequelize, 68 | indexes: [ 69 | { 70 | unique: true, 71 | fields: ['email'], 72 | }, 73 | ], 74 | }, 75 | ); 76 | 77 | export const getUserByEmail = (email: string): Promise => User 78 | .findOne({ where: { email } }); 79 | 80 | export const getUser = (name: string): Promise => User.findOne({ where: { name } }); 81 | 82 | export const newUser = (name: string, email: string): Promise => getUserByEmail(email) 83 | .then( 84 | async (user: User | null) => { 85 | if (user) { 86 | // update username 87 | if (user.name !== name) { 88 | // eslint-disable-next-line no-param-reassign 89 | user.name = name; 90 | await user.save({ fields: ['name'] }); 91 | } 92 | 93 | return user; 94 | } 95 | 96 | await User.create({ name, email }); 97 | return getUserByEmail(email); 98 | }, 99 | ); 100 | 101 | export const setPlayback = async ( 102 | email: string, 103 | libraryTitle: string, 104 | title: string, 105 | time: number, 106 | ratingKey: string, 107 | ): Promise => { 108 | const user = await getUserByEmail(email); 109 | if (!user) return false; 110 | 111 | const allPlaybacks = await user.getUserPlaybacks(); 112 | const playback = allPlaybacks 113 | .find((f) => f.libraryTitle === libraryTitle && f.ratingKey === ratingKey); 114 | 115 | if (!playback) { 116 | await user.createUserPlayback({ 117 | libraryTitle, title, time, ratingKey, 118 | }); 119 | return true; 120 | } 121 | 122 | if (playback.title !== title) { 123 | playback.title = title; 124 | await playback.save({ fields: ['title'] }); 125 | } 126 | 127 | if (playback.time !== time) { 128 | playback.time = time; 129 | await playback.save({ fields: ['time'] }); 130 | return true; 131 | } 132 | 133 | return false; 134 | }; 135 | 136 | export const getPlaybacks = (now = new Date()) => User.findAll({ 137 | include: { 138 | model: UserPlayback, 139 | required: true, 140 | where: { 141 | updatedAt: { 142 | [Op.between]: [ 143 | new Date(now.getFullYear(), now.getMonth(), now.getDate() - 4, 0, 0, 0, 0), 144 | now, 145 | ], 146 | }, 147 | }, 148 | }, 149 | }); 150 | -------------------------------------------------------------------------------- /src/com/db/models/userplayback.ts: -------------------------------------------------------------------------------- 1 | import { DataTypes, Model, Optional } from 'sequelize'; 2 | import sequelize from '../../database'; 3 | 4 | interface UserPlaybackAttributes { 5 | id: number, 6 | UserId: number, 7 | libraryTitle: string, 8 | title: string, 9 | ratingKey: string, 10 | time: number, 11 | } 12 | 13 | interface UserPlaybackCreationAttributes extends Optional { } 14 | 15 | export default class UserPlayback 16 | extends Model 17 | implements UserPlaybackAttributes { 18 | public id!: number; 19 | 20 | public UserId!: number; 21 | 22 | public libraryTitle!: string; 23 | 24 | public title!: string; 25 | 26 | public ratingKey!: string; 27 | 28 | public time!: number; 29 | 30 | public readonly createdAt!: Date; 31 | 32 | public readonly updatedAt!: Date; 33 | } 34 | 35 | UserPlayback.init( 36 | { 37 | id: { 38 | type: DataTypes.INTEGER.UNSIGNED, 39 | autoIncrement: true, 40 | primaryKey: true, 41 | }, 42 | UserId: { 43 | type: DataTypes.INTEGER.UNSIGNED, 44 | allowNull: false, 45 | }, 46 | libraryTitle: { 47 | type: DataTypes.STRING, 48 | allowNull: false, 49 | }, 50 | title: { 51 | type: DataTypes.STRING, 52 | allowNull: false, 53 | }, 54 | time: { 55 | type: DataTypes.INTEGER, 56 | allowNull: false, 57 | }, 58 | ratingKey: { 59 | type: DataTypes.STRING, 60 | allowNull: false, 61 | }, 62 | }, 63 | { 64 | sequelize, 65 | indexes: [ 66 | { 67 | unique: true, 68 | fields: ['UserId', 'libraryTitle', 'ratingKey'], 69 | }, 70 | ], 71 | }, 72 | ); 73 | -------------------------------------------------------------------------------- /src/com/log.ts: -------------------------------------------------------------------------------- 1 | import os from 'os'; 2 | import rabbitMQ from './rabbitmq'; 3 | import { QUEUE_NAME, DEVMODE, BUILD } from './config'; 4 | 5 | // eslint-disable-next-line no-console 6 | const print = (...args: any[]) => Promise.resolve(console.log(...args)); 7 | const hostname: string = os.hostname(); 8 | 9 | const CRITICAL = 'critical'; 10 | const ERROR = 'error'; 11 | const DEBUG = 'debug'; 12 | const INFO = 'info'; 13 | const WARN = 'warn'; 14 | 15 | const log = (level: string, ...messages: any[]): Promise => { 16 | if (DEVMODE || BUILD.toLowerCase() === 'canary') { 17 | print(new Date(), level.toUpperCase(), ...messages); 18 | } 19 | 20 | if (!DEVMODE) { 21 | return rabbitMQ.publish( 22 | 'logs', 23 | { 24 | hostname, 25 | service: QUEUE_NAME, 26 | level, 27 | message: messages 28 | .map((i) => ((typeof i === 'string') ? i : JSON.stringify(i))) 29 | .join(' '), 30 | }, 31 | ) 32 | .then(() => true); 33 | } 34 | 35 | return Promise.resolve(true); 36 | }; 37 | 38 | export const critical = (...args: any[]): Promise => log(CRITICAL, ...args); 39 | export const error = (...args: any[]): Promise => log(ERROR, ...args); 40 | export const debug = (...args: any[]): Promise => log(DEBUG, ...args); 41 | export const info = (...args: any[]): Promise => log(INFO, ...args); 42 | export const warn = (...args: any[]): Promise => log(WARN, ...args); 43 | -------------------------------------------------------------------------------- /src/com/rabbitmq.ts: -------------------------------------------------------------------------------- 1 | import type { Connection } from 'amqplib'; 2 | import RabbitMQ from 'nodejsmq'; 3 | import { RABBITMQ_URL } from './config'; 4 | 5 | const consumer = new RabbitMQ(RABBITMQ_URL || ''); 6 | consumer.connection 7 | .then( 8 | (conn: Connection) => conn.on('error', (e) => { 9 | // eslint-disable-next-line no-console 10 | console.log(e.message || e); 11 | process.exit(1); 12 | }), 13 | ); 14 | 15 | export default consumer; 16 | -------------------------------------------------------------------------------- /src/controller.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | import { debug } from './com/log'; 3 | import send from './lib/message'; 4 | import Plex, { HOSTNAMES } from './lib/plex'; 5 | import { LibraryCommands } from './lib/plex/library'; 6 | 7 | export default class Controller { 8 | private server: Promise; 9 | 10 | constructor() { 11 | this.server = Plex.build(HOSTNAMES.KUBERNETES); 12 | 13 | this.onConsuming = this.onConsuming.bind(this); 14 | this.onMessage = this.onMessage.bind(this); 15 | } 16 | 17 | // eslint-disable-next-line class-methods-use-this 18 | onConsuming() { 19 | debug('staring to consume'); 20 | } 21 | 22 | // eslint-disable-next-line class-methods-use-this 23 | onMessage() { 24 | return Promise.resolve(true); 25 | } 26 | 27 | async scanFullLibrary() { 28 | const server = await this.server; 29 | const libraries = await server.library.getAllLibraries(); 30 | for (const library of libraries) { 31 | await send( 32 | 'library', 33 | { 34 | command: LibraryCommands.SCAN_LIBRARY, 35 | values: [library.title], 36 | }, 37 | ); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import rabbitMQ from './com/rabbitmq'; 2 | import { 3 | queueName, 4 | exchangeName, 5 | STARTUP_DELAY, 6 | controllerMode, 7 | } from './com/config'; 8 | import migrate from './com/db/migrate'; 9 | import { 10 | critical, info, error, 11 | } from './com/log'; 12 | import type { QueueMessage } from './lib/message'; 13 | import SideCar from './sideCar'; 14 | import Controller from './controller'; 15 | import { sleep } from './lib/lib'; 16 | 17 | process.on( 18 | 'unhandledRejection', 19 | (e: Error) => critical('unhandled rejection', e.message || e) 20 | .then(() => error('unhandled rejection', e)) 21 | .catch(() => true) 22 | .then(() => process.exit()), 23 | ); 24 | 25 | interface MessageHandle { 26 | (message: QueueMessage): Promise 27 | } 28 | 29 | const consumer = (onMessage: MessageHandle, onConsuming: () => void) => rabbitMQ 30 | .consume({ 31 | queueName, 32 | routingKey: controllerMode ? queueName : '', 33 | exchangeName: controllerMode ? '' : exchangeName, 34 | onMessage: (msg, channel, body: QueueMessage) => { 35 | if (msg) { 36 | onMessage(body) 37 | .then((isSuccess) => { 38 | if (isSuccess) { 39 | info('onmsg', 'Successfully processed message'); 40 | channel.ack(msg); 41 | } else { 42 | error('onmsg', 'Unsuccessfully processed message'); 43 | channel.nack(msg); 44 | } 45 | }); 46 | } 47 | }, 48 | consumeCallback: () => { 49 | info( 50 | 'Awaiting tasks on', 51 | queueName, 52 | 'bound to', 53 | controllerMode ? queueName : '', 54 | 'on exchange', 55 | controllerMode ? '' : exchangeName, 56 | ); 57 | onConsuming(); 58 | }, 59 | }); 60 | 61 | if (require.main === module) { 62 | migrate() 63 | .then(() => sleep(parseInt(STARTUP_DELAY, 10))) 64 | .then(() => { 65 | const Worker = controllerMode ? Controller : SideCar; 66 | const worker = new Worker(); 67 | return consumer(worker.onMessage, worker.onConsuming); 68 | }); 69 | } 70 | 71 | export default consumer; 72 | -------------------------------------------------------------------------------- /src/lib/lib.ts: -------------------------------------------------------------------------------- 1 | export const sleep = (minutes: number) => new Promise((r) => setTimeout(r, 1000 * 60 * minutes)); 2 | 3 | export default sleep; 4 | -------------------------------------------------------------------------------- /src/lib/message.ts: -------------------------------------------------------------------------------- 1 | import rabbitMQ from '../com/rabbitmq'; 2 | import { queueName, exchangeName } from '../com/config'; 3 | 4 | export interface Message { 5 | command: string, 6 | values: (string | number)[]; 7 | } 8 | 9 | export interface QueueMessage extends Message { 10 | module: string, 11 | sentFrom: string, 12 | } 13 | 14 | export const toMe = `toMe.${queueName}`; 15 | 16 | const sendG = (module: string, message: Message, sentFrom = queueName): Promise => { 17 | const queueMessage: QueueMessage = { 18 | ...message, 19 | module, 20 | sentFrom, 21 | }; 22 | 23 | return rabbitMQ.publish('', queueMessage, { exchangeName }) 24 | .then(() => true); 25 | }; 26 | 27 | const send = (module: string, message: Message) => sendG(module, message, queueName); 28 | 29 | export const sendToMe = (module: string, message: Message) => sendG(module, message, toMe); 30 | 31 | export default send; 32 | -------------------------------------------------------------------------------- /src/lib/plex/component.ts: -------------------------------------------------------------------------------- 1 | import type Plex from './index'; 2 | 3 | export default class PlexComponent { 4 | protected PlexInstance: Plex; 5 | 6 | constructor(plex: Plex) { 7 | this.PlexInstance = plex; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/plex/endpoints.ts: -------------------------------------------------------------------------------- 1 | export const websocket = (hostname: string, port: number, token: string) => `ws://${hostname}:${port}/:/websockets/notifications?X-Plex-Token=${token}`; 2 | 3 | export const servers = () => '/pms/servers.xml'; 4 | export const getUsers = () => '/api/users'; 5 | export const getSharedServers = (machineId: string) => `/api/servers/${machineId}/shared_servers`; 6 | 7 | export const getLibraries = () => '/library/sections'; 8 | export const getLibraryItems = (libraryKey: string) => `/library/sections/${libraryKey}/all`; 9 | export const getItemByKey = (ratingKey: string) => `/library/metadata/${ratingKey}`; 10 | export const scanLibrary = (libraryKey: string) => `library/sections/${libraryKey}/refresh`; 11 | export const scanLibraryPath = (libraryKey: string, path: string) => `${scanLibrary(libraryKey)}?path=${path}`; 12 | 13 | export const getSessionById = (sessionId: string) => `/status/sessions?sessionKey=${sessionId}`; 14 | export const markWatched = (ratingKey: string) => `/:/scrobble?key=${ratingKey}&identifier=com.plexapp.plugins.library`; 15 | export const markUnWatched = (ratingKey: string) => `/:/unscrobble?key=${ratingKey}&identifier=com.plexapp.plugins.library`; 16 | export const setPlayback = (ratingKey: string, timems: number, duration: number, state = 'stopped') => { 17 | if (timems === -1) { 18 | return markWatched(ratingKey); 19 | } 20 | 21 | if (timems === 0) { 22 | return markUnWatched(ratingKey); 23 | } 24 | 25 | return `/:/timeline?ratingKey=${ratingKey}&identifier=com.plexapp.plugins.library&time=${timems}&state=${state}&duration=${duration}`; 26 | }; 27 | -------------------------------------------------------------------------------- /src/lib/plex/index.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | // @ts-ignore 3 | import PlexAPI from 'plex-api'; 4 | import { 5 | PLEXPASSWORD as password, 6 | PLEXUSERNAME as username, 7 | KUBERNETES_IP, 8 | STARTUP_DELAY, 9 | PLEXLOCAL_IP, 10 | } from '../../com/config'; 11 | import { servers } from './endpoints'; 12 | import { sleep } from '../lib'; 13 | import Library from './library'; 14 | import PlexWebSocket from './ws'; 15 | import PlayBack from './playback'; 16 | import User, { getToken } from './user'; 17 | import { critical, debug } from '../../com/log'; 18 | 19 | type IPADDRESS = string; 20 | 21 | type HOSTNAMELOOKUP = { 22 | [key: string]: IPADDRESS 23 | }; 24 | 25 | export const HOSTNAMES: HOSTNAMELOOKUP = { 26 | LOCAL: PLEXLOCAL_IP, 27 | PLEX: 'plex.tv', 28 | KUBERNETES: KUBERNETES_IP || 'elrond.yusufali.ca:32400', 29 | }; 30 | 31 | const options = { 32 | identifier: '28543486-48df-4adc-890f-fa673b10fc43', 33 | product: 'Plex Controller', 34 | verion: '1.0', 35 | deviceName: 'Plex Controller', 36 | platform: 'Node.js', 37 | }; 38 | 39 | const myAuthOptions = { 40 | username, 41 | password, 42 | options, 43 | }; 44 | 45 | const serverConnections: { [key: string]: PlexAPI } = { 46 | [HOSTNAMES.PLEX]: new PlexAPI({ port: 443, ...myAuthOptions, hostname: HOSTNAMES.PLEX }), 47 | }; 48 | 49 | serverConnections[HOSTNAMES.PLEX] 50 | .serverMachineIdentifier = sleep(parseInt(STARTUP_DELAY, 10) * 0.75) 51 | .then(() => serverConnections[HOSTNAMES.PLEX] 52 | .query(servers()) 53 | // @ts-ignore 54 | .then(({ MediaContainer: { Server: [server] } }) => server.attributes.machineIdentifier)); 55 | 56 | export default class Plex { 57 | public server: PlexAPI; 58 | 59 | public plexTV: PlexAPI; 60 | 61 | public user: User; 62 | 63 | public library: Library; 64 | 65 | public websocket: PlexWebSocket; 66 | 67 | public playback: PlayBack; 68 | 69 | constructor(server: PlexAPI) { 70 | this.server = server; 71 | this.plexTV = serverConnections[HOSTNAMES.PLEX]; 72 | 73 | this.user = new User(this); 74 | this.library = new Library(this); 75 | this.websocket = new PlexWebSocket(this); 76 | this.playback = new PlayBack(this); 77 | } 78 | 79 | // eslint-disable-next-line class-methods-use-this 80 | async syncPlayBack( 81 | email: string, libraryTitle: string, title: string, time: number, ratingKey: string, 82 | ) { 83 | const userServer = await Plex.build(HOSTNAMES.LOCAL, email); 84 | return userServer.playback.sync(libraryTitle, title, time, ratingKey); 85 | } 86 | 87 | static async build(host: IPADDRESS, useremail?: string): Promise { 88 | const serverConnectionName = useremail || host; 89 | if (!serverConnections[serverConnectionName]) { 90 | const port = 32400; 91 | let server; 92 | 93 | if (useremail) { 94 | const hostname = HOSTNAMES.LOCAL; 95 | 96 | const plexTV = serverConnections[HOSTNAMES.PLEX]; 97 | const machineIdentifier = await plexTV.serverMachineIdentifier; 98 | const token = await getToken(plexTV, machineIdentifier, useremail); 99 | if (token) { 100 | const userServer = new PlexAPI({ 101 | port: 32400, 102 | token, 103 | hostname, 104 | ...options, 105 | }); 106 | server = userServer; 107 | } 108 | } else { 109 | server = new PlexAPI({ port, ...myAuthOptions, hostname: host }); 110 | await server.query('/system'); 111 | } 112 | serverConnections[serverConnectionName] = server; 113 | } 114 | 115 | return new Plex(serverConnections[serverConnectionName]); 116 | } 117 | 118 | performGet(rpath: string, parameters: { [key: string]: string } = {}): Promise { 119 | axios.defaults.baseURL = `http://${this.server.serverUrl}`; 120 | debug('get', 'sending', parameters, 'to url', rpath); 121 | return axios.get( 122 | rpath, 123 | { 124 | params: { 125 | ...parameters, 126 | 'X-Plex-Token': this.server.authToken, 127 | }, 128 | }, 129 | ) 130 | .then(() => true) 131 | .catch((err) => critical(err)); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/lib/plex/library.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | import path from 'path'; 3 | import { critical, debug, warn } from '../../com/log'; 4 | import { sleep } from '../lib'; 5 | import type { Message } from '../message'; 6 | import type Plex from '.'; 7 | import Component from './component'; 8 | import { 9 | getItemByKey, getLibraries, getLibraryItems, scanLibrary, scanLibraryPath, 10 | } from './endpoints'; 11 | 12 | export const LibraryCommands: { [key: string]: string } = { 13 | SCAN_PATH: 'scan.path', 14 | SCAN_LIBRARY: 'scan.library', 15 | }; 16 | 17 | interface LibraryItem { 18 | ratingKey: string, 19 | key: string, 20 | Media?: { Part: { file: string }[] }[] 21 | title: string 22 | librarySectionTitle: string, 23 | duration: number, 24 | } 25 | 26 | type ItemSort = [LibraryDef, number]; 27 | 28 | interface LibraryLocation { 29 | path: string 30 | } 31 | 32 | interface LibraryDef extends LibraryItem { 33 | Location: LibraryLocation[] 34 | } 35 | 36 | /** 37 | * @description Queries an endpoint and its children until it comes across items that contain 38 | * the propertyName 'needle' 39 | */ 40 | const findNeedleWithKey = async ( 41 | PlexInstance: Plex, 42 | startKey: string, 43 | needle: string, 44 | ): Promise => { 45 | const { MediaContainer: { Metadata: Items } } = await PlexInstance.server.query(startKey); 46 | const needles = []; 47 | 48 | for (const item of Items) { 49 | if (!item[needle]) { 50 | const deepNeedles = await findNeedleWithKey(PlexInstance, item.key, needle); 51 | needles.push(...deepNeedles); 52 | } else { 53 | needles.push(item); 54 | } 55 | } 56 | 57 | return needles; 58 | }; 59 | 60 | export default class Library extends Component { 61 | async getAllLibraries(): Promise { 62 | const response = await this.PlexInstance.server.query(getLibraries()); 63 | if (response?.MediaContainer?.Directory) { 64 | return response.MediaContainer.Directory; 65 | } 66 | return []; 67 | } 68 | 69 | async getByTitle(libraryTitle: string) { 70 | const libraries = await this.getAllLibraries(); 71 | return libraries 72 | .find(({ title }) => title === libraryTitle) || null; 73 | } 74 | 75 | async getMediaItem( 76 | libraryTitle: string, mediaTitle: string, ratingKey: string | null = null, 77 | ): Promise { 78 | debug('lib/library.js', 'finding media item', { mediaTitle, libraryTitle, ratingKey }); 79 | 80 | if (ratingKey) { 81 | let response: false | { MediaContainer: { size: number, Metadata: LibraryItem[] } } = false; 82 | try { 83 | response = await this.PlexInstance.server.query(getItemByKey(ratingKey)); 84 | } catch (e) { 85 | // pass 86 | } 87 | 88 | if (response && response?.MediaContainer?.size) { 89 | const Items: LibraryItem[] = response.MediaContainer.Metadata; 90 | const item = Items 91 | .find((i) => i.title === mediaTitle && i.librarySectionTitle === libraryTitle); 92 | if (item) { 93 | return item; 94 | } 95 | } 96 | } 97 | 98 | // find the library 99 | const library = await this.getByTitle(libraryTitle); 100 | if (!library) { 101 | warn('lib/library.js', 'unable to find library', libraryTitle); 102 | return null; 103 | } 104 | 105 | // get all items and find the item 106 | const Items = await findNeedleWithKey(this.PlexInstance, getLibraryItems(library.key), 'Media'); 107 | const item = Items.find(({ title }) => title === mediaTitle); 108 | if (!item) { 109 | warn('lib/library.js', 'unable to find item wth title', { mediaTitle, libraryTitle }); 110 | return null; 111 | } 112 | 113 | return item; 114 | } 115 | 116 | async getRatingKey(libraryTitle: string, mediaTitle: string): Promise { 117 | const mediaItem = await this.getMediaItem(libraryTitle, mediaTitle); 118 | if (mediaItem) { 119 | return mediaItem.ratingKey; 120 | } 121 | return null; 122 | } 123 | 124 | async hasItem(fname: string): Promise<[boolean, string]> { 125 | const basef = path.basename(fname); 126 | debug('lib/library.js', 'finding if item basef exists', { fname, basef }); 127 | 128 | // determine what library the file will most likely beling to 129 | const splitFolders = fname.split('/'); 130 | const libraries = await this.getAllLibraries(); 131 | const library: LibraryDef | null = libraries.map((clibrary) => { 132 | let score: number = 0; 133 | for (const { path: libraryPath } of clibrary.Location) { 134 | for (const item of libraryPath.split('/')) { 135 | if (splitFolders.includes(item)) { 136 | score += 1; 137 | } 138 | } 139 | } 140 | 141 | const sortable: ItemSort = [clibrary, score]; 142 | return sortable; 143 | }) 144 | .sort(([, scoreA], [, scoreB]) => scoreB - scoreA) 145 | .map((sortable: ItemSort) => sortable[0]) 146 | .find(() => true) || null; 147 | if (!library) { 148 | return [false, '']; 149 | } 150 | debug('lib/library.js', 'hasItem', 'matched', fname, 'to library', library.title); 151 | 152 | // loop through the items of the library and determine if the file exists on the disk 153 | const response = await this.PlexInstance.server.query(getLibraryItems(library.key)); 154 | if (response?.MediaContainer?.Metadata) { 155 | for (const item of response?.MediaContainer?.Metadata) { 156 | const mediaFiles = await findNeedleWithKey(this.PlexInstance, item.key, 'Media'); 157 | for (const media of mediaFiles) { 158 | if (media.Media) { 159 | for (const { Part } of media.Media) { 160 | for (const { file } of Part) { 161 | if (path.basename(file) === basef) { 162 | return [true, library.title]; 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | } 170 | 171 | return [false, library.title]; 172 | } 173 | 174 | async scan(libraryTitle: string, rpath?: string) { 175 | const library = await this.getByTitle(libraryTitle); 176 | if (!library) return false; 177 | 178 | // scan whole library 179 | if (!rpath) { 180 | await this.PlexInstance.performGet(scanLibrary(library.key)); 181 | return true; 182 | } 183 | 184 | // match the folder path to the library root path since there can be 185 | // multiple parts inside of the library 186 | const splitFolders = rpath.split('/'); 187 | const libraryRootPath = library.Location 188 | .map(({ path: lpath }) => { 189 | let score = 0; 190 | for (const item of lpath.split('/')) { 191 | if (splitFolders.includes(item)) { 192 | score += 1; 193 | } 194 | } 195 | 196 | const retScore: [string, number] = [lpath, score]; 197 | return retScore; 198 | }) 199 | .sort((a, b) => b[1] - a[1]) 200 | .map(([a]) => a) 201 | .find(() => true); 202 | if (!libraryRootPath) return false; 203 | 204 | // construct folder to scan 205 | const scanPath: string[] = []; 206 | for (const item of [...libraryRootPath.split('/'), ...splitFolders]) { 207 | if (!scanPath.includes(item) && item) { 208 | scanPath.push(item); 209 | } 210 | } 211 | 212 | // perform scan 213 | const scanpathFinal = `/${scanPath.join('/')}`; 214 | debug('scan', 'scanning', scanLibraryPath(library.key, scanpathFinal)); 215 | await this.PlexInstance.performGet( 216 | scanLibrary(library.key), 217 | { 218 | path: scanpathFinal, 219 | }, 220 | ); 221 | await sleep(5); 222 | return true; 223 | } 224 | 225 | async message({ command, values }: Message) { 226 | debug('library.message', 'recieved message', { command, values }); 227 | if (!Object.values(LibraryCommands).includes(command)) { 228 | critical('library.message', 'unknown action', { command }); 229 | return false; 230 | } 231 | 232 | if (command === LibraryCommands.SCAN_PATH && values.length === 2) { 233 | return this.scan(`${values[0]}`, `${values[1]}`); 234 | } 235 | 236 | if (command === LibraryCommands.SCAN_LIBRARY && values.length === 1) { 237 | return this.scan(`${values[0]}`); 238 | } 239 | 240 | return false; 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/lib/plex/playback.ts: -------------------------------------------------------------------------------- 1 | import { 2 | critical, error, debug, info, 3 | } from '../../com/log'; 4 | import { 5 | getUser, 6 | newUser, 7 | setPlayback, 8 | getPlaybacks, 9 | } from '../../com/db/models/user'; 10 | import send from '../message'; 11 | import Component from './component'; 12 | import { getSessionById, setPlayback as setPlexPlayback } from './endpoints'; 13 | 14 | interface Session { 15 | title: string 16 | ratingKey: string, 17 | librarySectionTitle: string 18 | duration: string 19 | viewOffset: string, 20 | User: { title: string } 21 | } 22 | 23 | export default class PlayBack extends Component { 24 | async sync(libraryTitle: string, title: string, time: number, ratingKey: string) { 25 | debug('playback', 'syncing item', { 26 | libraryTitle, title, time, ratingKey, 27 | }); 28 | const item = await this.PlexInstance.library.getMediaItem(libraryTitle, title, ratingKey); 29 | 30 | if (item) { 31 | await this.PlexInstance.server.query( 32 | setPlexPlayback( 33 | item.ratingKey, 34 | (time <= item.duration) ? time : item.duration, 35 | item.duration, 36 | ), 37 | ); 38 | debug('playback', 'set playback information', { libraryTitle, title, time }); 39 | return true; 40 | } 41 | 42 | error('playback', 'unable to sync, item not found', { libraryTitle, title, time }); 43 | return false; 44 | } 45 | 46 | async saveSessionInfo(id: string): Promise { 47 | const response = await this.PlexInstance.server.query(getSessionById(id)); 48 | if (!response?.MediaContainer?.Metadata) return; 49 | 50 | const Sessions: Session[] = response.MediaContainer.Metadata; 51 | if (Sessions.length === 0) return; 52 | const [Session] = Sessions; 53 | const [duration, t] = [Session.duration, Session.viewOffset].map((f) => parseInt(f, 10)); 54 | const time = (t / duration >= 0.95) ? -1 : t; 55 | 56 | // get user session 57 | const User = await getUser(Session.User.title); 58 | if (!User) { 59 | info('playback', 'adding new user', Session.User.title); 60 | const newEmail = await this.PlexInstance.user.getEmail(Session.User.title); 61 | if (!newEmail) return; 62 | 63 | await newUser(Session.User.title, newEmail); 64 | await this.saveSessionInfo(id); 65 | return; 66 | } 67 | 68 | const updated = await setPlayback( 69 | User.email, Session.librarySectionTitle, Session.title, time, Session.ratingKey, 70 | ); 71 | if (updated) { 72 | await send( 73 | 'playback', 74 | { 75 | command: 'sync', 76 | values: [User.email, Session.librarySectionTitle, Session.title, time, Session.ratingKey], 77 | }, 78 | ); 79 | } 80 | } 81 | 82 | async applyDatabasePlaybacks() { 83 | const Users = await getPlaybacks(); 84 | const jobs = []; 85 | for (const user of Users) { 86 | if (user.UserPlaybacks) { 87 | for (const playback of user.UserPlaybacks) { 88 | jobs.push(this.PlexInstance.syncPlayBack( 89 | user.email, 90 | playback.libraryTitle, 91 | playback.title, 92 | playback.time, 93 | playback.ratingKey, 94 | )); 95 | } 96 | } 97 | } 98 | 99 | return Promise.all(jobs); 100 | } 101 | 102 | async websocketHandle(data: any) { 103 | if (!data.size) return; 104 | 105 | if (data.PlaySessionStateNotification) { 106 | for (const session of data.PlaySessionStateNotification) { 107 | if (session.state !== 'buffering') { 108 | this.saveSessionInfo(session.sessionKey); 109 | } 110 | } 111 | } else { 112 | critical('unrecoginized playback payload'); 113 | critical('unrecoginized playback payload', data); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/lib/plex/user.ts: -------------------------------------------------------------------------------- 1 | import { warn } from '../../com/log'; 2 | import Component from './component'; 3 | import { getUsers, getSharedServers } from './endpoints'; 4 | 5 | interface PlexUserAccount { 6 | id: string; 7 | username: string; 8 | email: string; 9 | accessToken: string; 10 | } 11 | 12 | export const getToken = async ( 13 | plexTV: any, machineIdentifier: string, email: string, 14 | ): Promise => { 15 | const response = await plexTV.query(getSharedServers(machineIdentifier)); 16 | if (response?.MediaContainer?.SharedServer) { 17 | const user = response.MediaContainer.SharedServer.find( 18 | ({ attributes }: { attributes: PlexUserAccount }) => attributes.email === email, 19 | ); 20 | if (user) return user.attributes.accessToken; 21 | warn('users', 'cannot find token for user', email); 22 | return null; 23 | } 24 | 25 | return null; 26 | }; 27 | 28 | export default class User extends Component { 29 | async getAllAccounts(): Promise { 30 | const response = await this.PlexInstance.plexTV.query(getUsers()); 31 | if (response?.MediaContainer?.User) { 32 | return response.MediaContainer.User 33 | .map( 34 | ({ attributes: user }: { attributes: PlexUserAccount }) => ({ 35 | id: user.id, 36 | username: user.username, 37 | email: user.email, 38 | }), 39 | ); 40 | } 41 | return []; 42 | } 43 | 44 | async getEmail(username: string): Promise { 45 | const accounts = await this.getAllAccounts(); 46 | return ( 47 | accounts.find((a) => a.username === username) || { email: null } 48 | ) 49 | .email; 50 | } 51 | 52 | getToken(machineIdentifier: string, email: string): Promise { 53 | return getToken( 54 | this.PlexInstance.plexTV, 55 | machineIdentifier, 56 | email, 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/lib/plex/ws.ts: -------------------------------------------------------------------------------- 1 | import { debug, critical } from '../../com/log'; 2 | import WebSocket from '../ws'; 3 | import type { PACKETTYPE } from '../ws'; 4 | import { websocket } from './endpoints'; 5 | import Component from './component'; 6 | 7 | const PLEXPACKETS: PACKETTYPE = { 8 | UPDATESTATECHANGE: 'update.statechange', 9 | PLAYING: 'playing', 10 | BACKGROUNDPROCESSINGQUEUE: 'backgroundProcessingQueue', 11 | PROGRESS: 'progress', 12 | ACTIVITY: 'activity', 13 | PREFERENCE: 'preference', 14 | 15 | ACCOUNT: 'account', 16 | 17 | TRANSCODE_UPDATE: 'transcodeSession.update', 18 | TRANSCODE_END: 'transcodeSession.end', 19 | TRANSCODE_START: 'transcodeSession.start', 20 | 21 | TIMELINE: 'timeline', 22 | STATUS: 'status', 23 | }; 24 | 25 | export default class PlexWebSocket extends Component { 26 | listen() { 27 | const socket = new WebSocket( 28 | this.PlexInstance.server.hostname, 29 | websocket( 30 | this.PlexInstance.server.hostname, 31 | this.PlexInstance.server.port, 32 | this.PlexInstance.server.authToken, 33 | ), 34 | (type, data) => { 35 | debug('plex websocket', data); 36 | if (type === PLEXPACKETS.PLAYING) { 37 | return this.PlexInstance.playback.websocketHandle(data); 38 | } 39 | 40 | if (!Object.values(PLEXPACKETS).includes(type)) { 41 | critical('new websocket plex observed', type); 42 | critical('websocket payload', data); 43 | } 44 | 45 | return true; 46 | }, 47 | ); 48 | socket.init(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/lib/ws.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | import WS from 'ws'; 3 | import { critical, info } from '../com/log'; 4 | 5 | export interface PACKETTYPE { 6 | [key: string]: string, 7 | } 8 | 9 | interface HandlePacket { 10 | (type: string, data: any): any 11 | } 12 | 13 | export default class Websocket extends EventEmitter { 14 | private id: string; 15 | 16 | private url: string; 17 | 18 | private packet: HandlePacket; 19 | 20 | private connecting: boolean = true; 21 | 22 | private ws: WS | null = null; 23 | 24 | constructor(address: string, url: string, packet: HandlePacket) { 25 | super(); 26 | this.id = address; 27 | this.url = url; 28 | 29 | if (!this.id 30 | || typeof this.id !== 'string') { 31 | throw new TypeError('Websocket : ID must be a string'); 32 | } 33 | if (!this.url 34 | || typeof this.url !== 'string') { 35 | throw new TypeError('Websocket : URL must be a string'); 36 | } 37 | if (typeof packet === 'function') { 38 | /** 39 | * @type {(type: types, data: object) => void} 40 | */ 41 | this.packet = packet; 42 | } else { 43 | throw new TypeError('Websocket : PACKET must be a function'); 44 | } 45 | 46 | this.onOpen = this.onOpen.bind(this); 47 | this.onMessage = this.onMessage.bind(this); 48 | this.onError = this.onError.bind(this); 49 | this.onClose = this.onClose.bind(this); 50 | 51 | let attempts = 0; 52 | this.on('connect', () => info('websocket connection made')); 53 | this.on('error', (e) => { 54 | if (attempts > 10) { 55 | critical('websocket error', e.message); 56 | process.exit(1); 57 | } 58 | 59 | this.init(); 60 | attempts += 1; 61 | }); 62 | } 63 | 64 | init(): Websocket { 65 | this.ws = new WS(this.url); 66 | this.ws.on('open', this.onOpen); 67 | this.ws.on('message', this.onMessage); 68 | this.ws.on('error', this.onError); 69 | this.ws.on('close', this.onClose); 70 | 71 | setTimeout(() => { 72 | if (this.connecting) { 73 | return new Error('Connection timed out'); 74 | } 75 | return true; 76 | }, 30000); 77 | this.connecting = true; 78 | return this; 79 | } 80 | 81 | onOpen() { 82 | this.emit('connect', this.id); 83 | } 84 | 85 | onMessage(dataInput: string | null | undefined) { 86 | try { 87 | const dataParsed = (dataInput) ? JSON.parse(dataInput) : {}; 88 | if (dataParsed.NotificationContainer) { 89 | this.connecting = false; 90 | const data = dataParsed.NotificationContainer; 91 | if (data.type) { 92 | this.packet(data.type, data); 93 | } 94 | } 95 | } catch (err) { 96 | this.emit('error', err, this.id); 97 | } 98 | } 99 | 100 | onError(err: Error) { 101 | this.emit('error', err, this.id); 102 | critical('websocket error', err.message); 103 | if (this.ws) { 104 | this.ws.terminate(); 105 | } 106 | process.exit(); 107 | } 108 | 109 | onClose(code: number, reason: string) { 110 | this.emit('debug', `WS Disconnected - ${JSON.stringify({ code, reason })}`); 111 | let err = !code || code === 1000 ? null : new Error(`${code}: ${reason}`); 112 | if (code) { 113 | this.emit('debug', `${code === 1000 ? 'Clean' : 'Unclean'} WS Close: ${code} - ${reason}`, this.id); 114 | if (code >= 4000 || code <= 4999) { 115 | err = new Error(`Plex error code: ${code}`); 116 | } else if (code !== 1000 && reason) { 117 | err = new Error(`${code} - ${reason}`); 118 | } 119 | if (err) { 120 | // @ts-ignore 121 | err.code = code; 122 | } 123 | } else { 124 | this.emit('debug', `WS close: unknown code - ${reason}`, this.id); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/sideCar.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | import { CronJob } from 'cron'; 3 | import { 4 | queueName, DAILY_CRON, CRON_TIMEZONE, 5 | } from './com/config'; 6 | import { critical, debug } from './com/log'; 7 | import type { QueueMessage } from './lib/message'; 8 | import { toMe } from './lib/message'; 9 | import Plex, { HOSTNAMES } from './lib/plex'; 10 | 11 | export default class SideCar { 12 | private server: Promise; 13 | 14 | constructor() { 15 | this.server = Plex.build(HOSTNAMES.LOCAL); 16 | this.onConsuming = this.onConsuming.bind(this); 17 | this.onMessage = this.onMessage.bind(this); 18 | 19 | if (DAILY_CRON) { 20 | const sideCar = this; 21 | 22 | // apply database playback 23 | const jobPlayback = new CronJob( 24 | DAILY_CRON, 25 | () => sideCar.server 26 | .then((plexServer) => plexServer.playback.applyDatabasePlaybacks()), 27 | null, 28 | true, 29 | CRON_TIMEZONE, 30 | ); 31 | jobPlayback.start(); 32 | } 33 | } 34 | 35 | async onConsuming() { 36 | const server = await this.server; 37 | server.websocket.listen(); 38 | server.playback.applyDatabasePlaybacks(); 39 | } 40 | 41 | async onMessage(message: QueueMessage) { 42 | const server = await this.server; 43 | debug('worker', message); 44 | 45 | if (message.sentFrom === queueName) { 46 | return true; 47 | } 48 | 49 | if (message.sentFrom.indexOf('toMe') > -1 && message.sentFrom !== toMe) { 50 | return true; 51 | } 52 | 53 | if (message.module === 'playback') { 54 | if (message.command === 'sync') { 55 | return server.syncPlayBack( 56 | `${message.values[0]}`, 57 | `${message.values[1]}`, 58 | `${message.values[2]}`, 59 | (typeof message.values[3] !== 'string') ? message.values[3] : parseInt(message.values[3], 10), 60 | `${message.values[4]}`, 61 | ); 62 | } 63 | } 64 | 65 | if (message.module === 'library') { 66 | return server.library.message(message); 67 | } 68 | 69 | critical('cannot handle message:', message); 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/copyDatabase.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import fs from 'fs'; 3 | import { spawn } from 'child_process'; 4 | import url from 'url'; 5 | 6 | const defaultDB = { 7 | port: 5432, hostname: '127.0.0.1', pathname: '/db', auth: 'postgres:postgres', 8 | }; 9 | const pgDumpLocation = '/tmp/backup'; 10 | 11 | const deleteBackup = () => { 12 | if (fs.existsSync(pgDumpLocation)) { 13 | fs.unlinkSync(pgDumpLocation); 14 | } 15 | }; 16 | 17 | const run = ( 18 | cmd: string, 19 | args: string[], 20 | env: { [key: string]: string }, 21 | ): Promise => new Promise( 22 | (resolve, reject) => { 23 | // @ts-ignore 24 | console.log(cmd, args); 25 | const child = spawn(cmd, args, { env }); 26 | 27 | child.on('error', (e) => reject(e)); 28 | child.on('close', (code) => resolve(code)); 29 | child.on('exit', (code) => resolve(code)); 30 | }, 31 | ); 32 | 33 | const copyTables = async () => { 34 | deleteBackup(); 35 | const readURL = url.parse(process.env.DATABASE_READ_URL || '') || defaultDB; 36 | const dbURL = url.parse(process.env.DATABASE_URL || '') || defaultDB; 37 | 38 | // run backup 39 | if (readURL.hostname && readURL.auth && readURL.port && readURL.pathname) { 40 | await run( 41 | 'pg_dump', 42 | [ 43 | '-Fc', 44 | '--no-acl', 45 | '--no-owner', 46 | '-h', readURL.hostname, 47 | '-U', readURL.auth.split(':')[0], 48 | '-p', readURL.port.toString(), 49 | '-f', pgDumpLocation, 50 | readURL.pathname.replace('/', ''), 51 | ], 52 | { PGPASSWORD: readURL.auth.split(':')[1] }, 53 | ); 54 | } 55 | 56 | if (dbURL.auth && dbURL.pathname && dbURL.hostname && dbURL.port) { 57 | await run( 58 | 'pg_restore', 59 | [ 60 | '--verbose', 61 | '--clean', 62 | '--no-acl', 63 | '--no-owner', 64 | '-U', dbURL.auth.split(':')[0], 65 | '-d', dbURL.pathname.replace('/', ''), 66 | '-h', dbURL.hostname, 67 | '-p', dbURL.port.toString(), 68 | pgDumpLocation, 69 | ], 70 | { PGPASSWORD: dbURL.auth.split(':')[1] }, 71 | ); 72 | } 73 | 74 | deleteBackup(); 75 | }; 76 | 77 | export default copyTables; 78 | -------------------------------------------------------------------------------- /tests/migration.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import copy from './copyDatabase'; 3 | import { QUEUE_NAME as service } from '../src/com/config'; 4 | import migrate from '../src/com/db/migrate'; 5 | import Migration from '../src/com/db/models/migration'; 6 | 7 | // eslint-disable-next-line func-names 8 | describe('Database migrations', function () { 9 | this.timeout(10000); 10 | before(() => copy()); 11 | 12 | it('migrate without error', () => migrate()); 13 | 14 | let migrationCount = 0; 15 | it('should migrate the database', () => Migration 16 | .findAll({ where: { service } }) 17 | .then((migrations) => { migrationCount = migrations.length; })); 18 | 19 | it('should migrate the database', () => Migration 20 | .findAll({ where: { service } }) 21 | .then((migrations) => assert.isAtLeast(migrations.length, migrationCount))); 22 | }); 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "lib": [ 6 | "ES2019.Array" 7 | ], 8 | "declaration": false, 9 | "outDir": "./dist", 10 | "rootDir": "./src", 11 | "strict": true, 12 | "sourceMap": false, 13 | "noUnusedLocals": true, /* Report errors on unused locals. */ 14 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 15 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 16 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 17 | "esModuleInterop": true, 18 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 19 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 20 | }, 21 | "types": [ 22 | "amqplib", 23 | "cron", 24 | "ws", 25 | "axios" 26 | ], 27 | "include": [ 28 | "src/**/*.ts", 29 | ] 30 | } -------------------------------------------------------------------------------- /tsconfig.testing.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true 6 | }, 7 | "include": [ 8 | "tests/**/*.ts", 9 | "src/**/*.ts" 10 | ] 11 | } --------------------------------------------------------------------------------